3

ここに貼り付けるには長すぎるコードを書きましたが、バインドレスの imageLoad と imageStore を使用するフラグメント シェーダーを介して 3D 1 コンポーネント フロート テクスチャにレンダリングされます。

そのコードは間違いなく機能しています。

次に、いくつかの GLSL コンパイラのバグを回避する必要があったため、上記の 3D テクスチャを glGetTexImage を介してホストに読み戻したいと考えました。はい、glMemoryBarrierEXT(GL_ALL_BARRIER_BITS) を実行しました。glGetTexLevelparameteriv() を介してテクスチャ情報を確認したところ、すべて一致していました。OpenGL エラーを確認しましたが、エラーはありませんでした。

残念ながら、glGetTexImage は、フラグメント シェーダーによって書き込まれたものを決して読み取らないようです。代わりに、テクスチャを作成するために glTexImage3D() を呼び出したときに入力した偽の値のみを返します。

それは期待される動作ですか?ドキュメントはそうでないことを暗示しています。

glGetTexImage が実際にそのように機能する場合、その 3D テクスチャ (デバイス上に常駐) のデータを読み戻すにはどうすればよいですか? 確かに、この単純なことを行う簡単な方法があります...


glGetTexImage がそのように機能するかどうかを尋ねていました。コードは次のとおりです。

void Bindless3DArray::dump_array(Array3D<float> &out)
{  
bool was_mapped = m_image_mapped;
if (was_mapped)
    unmap_array();          // unmap array so it's accessible to opengl

out.resize(m_depth, m_height, m_width);

glBindTexture(GL_TEXTURE_3D, m_textureid);  // from glGenTextures()

#if 0
int w,h,d;
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &h);
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &d);
int internal_format;
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
int data_type_r, data_type_g;
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_RED_TYPE, &data_type_r);
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_GREEN_TYPE, &data_type_g);
int size_r, size_g;
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_RED_SIZE, &size_r);
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_GREEN_SIZE, &size_g);
#endif

glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, &out(0,0,0));
glBindTexture(GL_TEXTURE_3D, 0);
CHECK_GLERROR();

if (was_mapped)
    map_array_to_cuda();    // restore state
}

バインドレス配列を作成するコードは次のとおりです。

void Bindless3DArray::allocate(int w, int h, int d, ElementType t)
{
if (!m_textureid)
    glGenTextures(1, &m_textureid);
m_type = t;
m_width = w;
m_height = h;
m_depth = d;

glBindTexture(GL_TEXTURE_3D, m_textureid);
CHECK_GLERROR();
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);    // ensure only 1 miplevel is allocated
CHECK_GLERROR();

Array3D<float> foo(d, h, w);
// DEBUG -- glGetTexImage returns THIS data, not what's on device
for (int z=0; z<m_depth; ++z)
for (int y=0; y<m_height; ++y)
for (int x=0; x<m_width; ++x)
    foo(z,y,x) = 3.14159;

//-- Texture creation
if (t == ElementInteger)
    glTexImage3D(GL_TEXTURE_3D, 0, GL_R32UI, w, h, d, 0, GL_RED_INTEGER, GL_INT, 0);
else if (t == ElementFloat)
    glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F,  w, h, d, 0, GL_RED, GL_FLOAT, &foo(0,0,0));
else
    throw "Invalid type for Bindless3DArray";
CHECK_GLERROR();

m_handle = glGetImageHandleNV(m_textureid, 0, true, 0, (t == ElementInteger) ? GL_R32UI : GL_R32F);
glMakeImageHandleResidentNV(m_handle, GL_READ_WRITE);
CHECK_GLERROR();

#ifdef USE_CUDA
checkCuda(cudaGraphicsGLRegisterImage(&m_image_resource, m_textureid, GL_TEXTURE_3D, cudaGraphicsRegisterFlagsSurfaceLoadStore));
#endif
}

配列を割り当て、OpenGL フラグメント プログラムを介してレンダリングし、dump_array() を呼び出してデータを読み戻します。悲しいことに、割り当て呼び出しでロードしたものしか取得できません。

レンダリングプログラムは次のようになります

void App::clear_deepz()
{
deepz_clear_program.bind();

deepz_clear_program.setUniformValue("sentinel", SENTINEL);
deepz_clear_program.setUniformValue("deepz", deepz_array.handle());
deepz_clear_program.setUniformValue("sem", semaphore_array.handle());

run_program();

glMemoryBarrierEXT(GL_ALL_BARRIER_BITS);
//  glMemoryBarrierEXT(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
//  glMemoryBarrierEXT(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV);

deepz_clear_program.release();
}

フラグメントプログラムは次のとおりです。

#version 420\n

in vec4 gl_FragCoord;
uniform float sentinel;
coherent uniform layout(size1x32) image3D deepz;
coherent uniform layout(size1x32) uimage3D sem;

void main(void)
{
ivec3 coords = ivec3(gl_FragCoord.x, gl_FragCoord.y, 0);
imageStore(deepz, coords, vec4(sentinel));
imageStore(sem, coords, ivec4(0));
discard;    // don't write to FBO at all
}
4

2 に答える 2

2
discard;    // don't write to FBO at all

という意味ではありませんdiscard。あ、そういう意味です。ただし、これは、すべての Image Load/Store 書き込みも破棄されることを意味します確かに、コンパイラはそのステートメントを見て、フラグメント シェーダー全体に対して何もしない可能性があります。

フラグメント シェーダを実行するだけの場合は、空のフレームバッファ オブジェクトを持つ GL 4.3 機能 (NVIDIA ハードウェアで利用可能) を使用できます。または、計算シェーダーを使用できます。GL 4.3 をまだ使用できない場合は、書き込みマスクを使用してすべてのカラー書き込みをオフにします。

于 2013-06-06T23:08:27.553 に答える
1

Nicol が上で述べたように、画像の読み込みと保存だけの副作用が必要な場合は、空のフレーム バッファー オブジェクトを使用するのが適切な方法です。

glGetTexImage() とバインドレス テクスチャの混合のバグは、実際にはドライバーのバグであり、ドライバー バージョン 335.23 で修正されています。バグを報告し、コードが正常に動作することを確認しました。

コードで空のフレーム バッファ オブジェクトを使用しており、「破棄」を使用しないことに注意してください。

于 2014-05-29T23:11:36.907 に答える