Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problem Using Compute Shader To Write To Texture

Started by multifractal Aug 9, 2016 at 4:46 AM 3 replies 7.1k views
Original Post
multifractal
multifractal

Hello.

I've recently been attempting to render 3D textures in a compute shader for an upcoming project of mine. However, I have met an unexpected issue I cannot solve. No matter what I tried the texture was not written to. In order to ascertain what is causing the defect I set up a simple test case consisting of an all red 16x16 texture being created on a compute shader and then rendered to the screen using a full-screen quad. Yet the issue persists. I'm not too sure where to go next. I've tried substituting glTexImage2D(...) with glTexStorage2D(...) to no avail. I am at a loss here so any help would be very much appreciated.

Relevant Code:

compute shader:


#version 450 core
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f) uniform image2D destination;

void main(void)
{
	ivec2 index = ivec2(gl_GlobalInvocationID.xy);
	imageStore(destination, index, vec4(1.0f, 0.0f, 0.0f, 1.0f));
}

compute shader dispatch method:


void draw_texture(GLuint *texture_handle, GLuint draw_program)
{
	GLuint tex;
	glGenTextures(1, &tex);
	glActiveTexture(GL_TEXTURE0 + 0);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 16, 0, GL_RGBA, GL_FLOAT, NULL);
	glUseProgram(draw_program);
	glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
	GLuint uniform_location = glGetUniformLocation(draw_program, "destination");
	glBindImageTexture(uniform_location, tex, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
	glDispatchCompute(16, 16, 1);
	glUseProgram(0);
        glBindTexture(0);
	*texture_handle = tex;
} 

Thanks for your time!

agleed
agleed

How do you attempt to read the data? With image load/store you need manual synchronization (using glMemoryBarrier, ) to make sure the data is available in successive drawing operations or compute calls. For example if you want to fetch from the texture in a shader directly after writing to it, you need a glMemoryBarrier(GL_TEXTURE_FETCH_MEMORY_BIT) in between the dispatch call and the draw call that uses the texture.

edit: Whoops, saw you already have a memory barrier in there. Still, you should make sure the correct flag is set. With the SHADER_IMAGE_ACCESS_BARRIER_BIT the correct synchronization is only guaranteed if you use this image in subsequent calls by reading from it with image load/store as well (so no normal texture fetching for example).

yet another edit: Also, the memoryBarrier call is before the dispatch. If you access the texture after, you still need another barrier after the dispatch call. The barrier before it only ensures synchronization with everything that happens before it.

Hodgman
Hodgman

I assume you're checking for GL errors and have none? Have you tried running it via a debugger such as RenderDoc, and using it to check the contents of the texture before / after the dispatch?

Matias Goldberg
Matias Goldberg
  • I strongly suggest you create your texture via glTexStorage2D, not glTexImage2D
  • Your glMemoryBarrier call needs to be performed after the dispatch call, not before. Additionally, it should be GL_TEXTURE_FETCH_BARRIER_BIT not GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, because you're writing to it as an image, but you want the reads as texture fetch to be correct.
  • Beware a local_size_x = 1 and local_size_y = 1 is very inefficient. You'll literally be using one wave per wavefront. (performance). I suggest local_size_x = 8 and local_size_y = 8, with a glDispatchCompute( 2, 2, 1 );
  • Make sure to use performance keywords, i.e. layout(rgba32f) uniform restrict writeonly image2D destination; (performance)
  • Becareful with glUseProgramStages. Could be disabling your compute / vertex / pixel shaders.
  • Check for GL errors. Enable the Debug extension (you need to create the GL context with Debug flag as well).
  • Use RenderDoc.
multifractal
multifractal

Thanks for all the replies. I've switched to glTexStorage2D, removed the memory barrier call from before the dispatch and moved it after along with changing the flag to GL_TEXTURE_FETCH_BARRIER_BIT, and added calls to glGetError. This has revealed the following errors:

Invalid value error after the following call:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 16);

I'll check out RenderDoc and attempt to debug this.

EDIT: I had accidentally set levels to 0 rather than 1. Fixing this has allowed the texture to be rendered from the compute shader.

Thanks for all the help!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.