Bindless textures + glClear() doesn't work on AMD

This issue is similar to
https://community.khronos.org/t/using-bindless-textures-with-framebuffer-objects-causes-artifacts/107468
as well as
https://computergraphics.stackexchange.com/questions/5337/glclears-result-cant-be-seen-when-using-bindless-texture

However I’d also like to present my case since I haven’t found any satisfying workarounds for this.

I am writing a 2D engine using bindless textures and OpenGL 4.3. In the engine, you can create “surfaces”, that is, a structure that holds data for a framebuffer object. The app uses an “application surface” to draw stuff on it by default, but users can create other surfaces, set them as draw targets, draw stuff in them, draw the surfaces themselves etc. Essentially it’s a wrapping for framebuffer objects. The code for them is nothing special:

		SurfaceID SurfaceAdd(int width, int height) {
			static SurfaceID SurfaceFreeID = 1;
			Surface surf;
			surf.width = width;
			surf.height = height;
			surf.tex = XETEXTURE::InitEmptyTexture(width, height);
			surf.fbo = XETEXTURE::TexCreateFrameBufferColor(surf.tex);
			surf.texHandle = glGetTextureHandleARB(surf.tex);
			glMakeTextureHandleResidentARB(surf.texHandle); //making texture resident before creating the fbo completely glitches the fbo in AMD
			SurfaceID myID = SurfaceFreeID++;
			surf.ID = myID;
			vecSurface.push_back(surf);
			mapSurfaceIDIndex.insert({ myID, (SurfaceIndex)(vecSurface.size() - 1) });
			return surf.ID;
		}

	GLuint InitEmptyTexture(GLuint _width, GLuint _height) {
		size_t size = _width * _height * 4;
		GLubyte* emptydata = (GLubyte*)malloc(size);
		memset(emptydata, 0, size);
		GLuint texPage;
		glGenTextures(1, &texPage);
		glBindTexture(GL_TEXTURE_2D, texPage);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, emptydata);
		free(emptydata);
		return texPage;
	}

	GLuint TexCreateFrameBufferColor(GLuint texid) {
		int fboPrev = -1;
		if (XEDRAW::currentSurface != -1) {
			XEDRAW::Surface& surfC = XEDRAW::SurfaceGetStruct(XEDRAW::currentSurface);
			fboPrev = surfC.fbo;
		}
		GLuint fbo_tPage;
		glGenFramebuffers(1, &fbo_tPage);
		glBindFramebuffer(GL_FRAMEBUFFER, fbo_tPage);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texid, 0);
		if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { //this check stops fbo from glitching out in AMD. glreadpixels() works too
			PLOGDE << "Framebuffer incomplete.";
			std::terminate();
		}
		if (fboPrev != -1) {
			glBindFramebuffer(GL_FRAMEBUFFER, fboPrev);
		}
		return fbo_tPage;
	}

		void Clear(uint32_t colorRGBA) {
			int b = BreakBatch();
			glClearColor((GLfloat)ColorGetRed(colorRGBA) / 255.0f, (GLfloat)ColorGetGreen(colorRGBA) / 255.0f, (GLfloat)ColorGetBlue(colorRGBA) / 255.0f, (GLfloat)ColorGetAlpha(colorRGBA) / 255.0f);
			glClear(GL_COLOR_BUFFER_BIT);
			numBatches += !b;
			GLubyte pixels[4]; glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); //this prevents AMD from glitching out
		}

As you may have seen in the code above, AMD drivers have trouble understanding bindless textures.
On my NVIDIA GPU, I get a perfectly normal result:


However, on my AMD GPU, the following things are of note:

  1. Making the surface’s texture handle resident after attaching it to the fbo causes artifacts:
  2. Making the surface’s texture handle resident before attaching it to the fbo works only if I either:
    a) Adding a framebuffer completeness check after attaching the texture to the fbo:
		if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 
			PLOGDE << "Framebuffer incomplete.";
			std::terminate();
		}

b) doing a glReadPixels() after attaching the texture to the fbo.
3. glClear() doesn’t work unless I also do a glReadPixels() right after it.
4. Putting glFinish() / glTextureBarrier() in various places doesn’t do anything.
5. Using the aforementioned workarounds for AMD (also see commented lines in code above) makes things seemingly work on AMD.

I would like some input on whether I have some rookie mistake somewhere in my code (I really hope I do), and also if there is any workaround that doesn’t involve glReadPixels() or any other cpu/gpu sync buzzkill. Let me know if you need more info and I’ll be more than happy to provide it.

Hi, just raising attention to my question.
I am particularly interested in Solving issue #3 (glClear() doesn’t work unless I also do a glReadPixels() right after it). As it is right now, using glClear() frequently because eg one has a lot of “surfaces” that need clearing before drawing in them, will cause “Bindless” mode to run slower than bound texture mode!

Hey,
do the issues still exist in the recent AMD driver? What GPU and OS do You use? Can You create simple app that reproduces the issues?

Based on the above, it’s far from clear whether the issues experienced by the OP (@vdweller) are due to spec violations in their code or problems in the AMD driver’s OpenGL implementation (…for some unspecified driver version). We’d need to see a full stand-alone test program (including shader code, and with raw GL – no wrapper APIs/classes) to get a better read on that. Specifying the AMD driver version tested on would be useful for tracking this issue to.

What’s apparent is that the OP’s code is trying to use FBOs to render to a texture that it makes resident (bindless accessible), and this may be triggering artifacts. Cause unclear. We have no C++ or shader drawing code for this, so we have no clue even what’s generating the above images, or if/how the rendered FBO/bindless texture are even involved here.

Anyway, if your use case involves the more usual case of just reading from uploaded bindless textures on the GPU, then you possibly wouldn’t hit this. And of course, make sure you’re running on the latest AMD driver version.

Perhaps the OP’s code is violating the dynamically uniform requirement for bindless texture access on AMD hardware? The spec requires this. But NVIDIA’s driver+GPUs relax this restriction, allowing you to come up with the bindless texture handle pretty much however you want, dynamically uniform or not. For details, see Bindless_Texture#GLSL_handle_usage. And that’s just one example. Bottom line: just because it works on NVIDIA and doesn’t work on AMD doesn’t mean it’s an AMD driver bug.

1 Like

So the reason I’m asking is because in June 2022 AMD has released a completely new OpenGL driver on Windows. I have already seen that lots of people are reporting number of bugs on forums (like Reddit, etc.).