|
| 1 | +--- |
| 2 | +title: 'My Screen is Black' |
| 3 | +slug: 'my-screen-is-black' |
| 4 | +description: 'This shall be a little guide to help you troubleshoot graphics problems. Focussing mainly on OpenGL.' |
| 5 | +date: '2024-11-01' |
| 6 | +authors: ['deccer'] |
| 7 | +tags: ['opengl', 'troubleshoot', 'guide', 'article', 'debug'] |
| 8 | +image: 'https://raw.githubusercontent.com/graphicsprogramming/blog/main/blog/2024/2024-11-01-my-screen-is-black/arrested-for-opengl-crimes-full.png' |
| 9 | +--- |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +<!-- truncate --> |
| 14 | + |
| 15 | +Those were my findings over the months and years of exposing myself to OpenGL. I hope it helps anyone. |
| 16 | + |
| 17 | +### First Things To Do |
| 18 | + |
| 19 | +Hook up [RenderDoc](https://renderdoc.org). If you have not read its getting-started, read it before anything else. |
| 20 | +There is also a plugin available "Where is my drawcall" hook it up by following the instructions on RenderDoc's site. |
| 21 | + |
| 22 | +Setup `glDebugMessageCallback` see [here](https://deccer.github.io/OpenGL-Getting-Started/02-debugging/02-debug-callback/) for example code. |
| 23 | + |
| 24 | +If you use `glGetError` with or without macros like `GLCALL` or `GLCHECK` or rolled your own, get rid of it. `glDebugMessageCallback` will replace those. There is a high chance that you used it incorrectly anyway because you copy pasted it from some questionable source. |
| 25 | + |
| 26 | +Make sure you check that shader compilation _and_ linking was successful. See `glGetShaderiv` & `glGetProgramiv` on compile and link status. |
| 27 | + |
| 28 | +### You are on a Mac |
| 29 | + |
| 30 | +Seriously port your engine to `metal`, or `webgpu` at least. There is no support for `KHR_debug` and you cannot use anything > gl 4.1 is enough reason |
| 31 | + |
| 32 | +You are getting `UNSUPPORTED (log once): POSSIBLE ISSUE: unit 0 GLD_TEXTURE_INDEX_2D is unloadable and bound to sampler type (Float) - using zero texture because texture unloadable`. You need to call glGenerateMipmap(GL_TEXTURE_2D) after glTexImage2D() or set max level to 0 if you dont need/want mips. |
| 33 | + |
| 34 | +### RenderDoc is crashing when trying to run your application |
| 35 | + |
| 36 | +This is most likely **not** RenderDoc's fault, but yours. Something in your code is fishy and RenderDoc doesnt like it. Use a debugger/code-sanitizer to figure out |
| 37 | +what is going on in your application. Most likely some problem around memory allocation/freeing/UB related thing. |
| 38 | + |
| 39 | +Another reason why RenderDoc is crashing is that it doesnt like certain extensions you might be using in your code. RenderDoc used to tell you usually and not just |
| 40 | +crash, but that behaviour has changed since 1.36 or so. I don't know why. I have not bothered asking baldur yet. But what you can do is check your code for |
| 41 | +things involving bindless textures, and bindless buffers. Stuff like `glMakeTextureResidentARB`, `glProgramUniform...64NV`, `glGetTextureHandleARB`. RenderDoc also does |
| 42 | +not support legacy OpenGL. Make sure you arent using those either `glVertexXy`, `glNormalXy` etc. To debug old school stuff, use `apitrace` or nVidia's NSight Graphics. |
| 43 | +Older versions of `gEDebugger` or `CodeXL` might work too. |
| 44 | + |
| 45 | +### You use GLAD but it is giving you a hard time about symbols not found and multiple definitions or the likes |
| 46 | + |
| 47 | +It is most likely that the headers you are using are just outdated. Regenerate the header on dav1d's site. Or check your build system that it is |
| 48 | +pulling a recent version of glad. |
| 49 | + |
| 50 | +### Debug Callback Says... |
| 51 | + |
| 52 | +- `GL_INVALID_OPERATION error generated. Array object is not active.`: |
| 53 | + You didn't bind a VAO. Core Context OpenGL requires a VAO bound at all times. Bind one. |
| 54 | + |
| 55 | +### Shader Compiler Log Says... |
| 56 | + |
| 57 | +- `function "main" is already defined` |
| 58 | + You probably compile your fragment shader as vertex shader or other way around |
| 59 | + |
| 60 | +### You are unable to figure out if an extension is supported |
| 61 | + |
| 62 | +`GL_NV_conservative_raster` for example despite calling `glGetString(GL_EXTENSIONS)` and all that. |
| 63 | +You either need to query extensions with a forward compatible context or you switch to query `GL_NUM_EXTENSIONS` first and |
| 64 | +then iterate over all of them with `glGetStringi` and then check if the extension is part of that list. The latter requires a core OpenGL context. |
| 65 | + |
| 66 | +### Exception when calling glDrawElements - aka "0xC0000005" |
| 67 | + |
| 68 | +You most likely have no indexbuffer is bound. Or it is not associated to/with the current VAO. |
| 69 | + |
| 70 | +### Exception when calling glDrawArrays / or worse the driver is crashing |
| 71 | + |
| 72 | +You probably want to draw more primitives than you have in your vertexbuffer, check arguments of your `glDrawArrays` call. |
| 73 | +Potentially you might not have set the vertex count variable and that contains an ununitialized value because you used c/c++ and are a doofus. |
| 74 | + |
| 75 | +### Textures are black |
| 76 | + |
| 77 | +- no textures bound |
| 78 | +- are your textures complete? if not should produce an output in debug callback, so, go check that (hmm this might not be the case for glXXXTextureStorage i might take this one off the list) |
| 79 | +- no samplers bound (check your sampler objects if you use them as separate objects) |
| 80 | +- fucked uvs |
| 81 | +- you might be sampling from a corner of your texture where its actually black, check uvs |
| 82 | + |
| 83 | +### Your Tringle is black |
| 84 | + |
| 85 | +- smells like your vao is fucked. make sure you setup the attributes (and stride when binding le vbo using DSA) |
| 86 | +- fucked uvs? |
| 87 | +- forgot to bind a texture? |
| 88 | + |
| 89 | +### Screen is Black |
| 90 | + |
| 91 | +- check if your screen is on/connected properly |
| 92 | +- camera (projection/view matrices are fucked) is not looking at the scene in question |
| 93 | +- no texture is sampled due to missing or wrong uvs => default value is 0 aka black (depends on the driver) |
| 94 | +- no shader bound (especially fragment shader) |
| 95 | +- fragment shader doesnt write anything to its output |
| 96 | +- no viewport is set/is too small |
| 97 | +- you might be rendering to a framebuffer, but not blitting that framebuffer to the default one |
| 98 | +- let clearcolor be something else than pure black |
| 99 | +- are you doing MRT? |
| 100 | + - if yes, check that you called the right `gl(Named)DrawBuffers` and not n times `gl(Named)DrawBuffer` one per render target |
| 101 | +- are you playing with depth pre pass-isms? |
| 102 | + - make sure the gl state between passes is the same, face winding, cullmode, etc, see Appending A.3 in the gl spec for more clues |
| 103 | +- check winding order and cullmode, you might be looking at the wrong side of your faces |
| 104 | +- you check renderdoc and wonder why the vertex list contains the same (perhaps even first element) only, for all vertices => make sure your `glDrawElements(..., ..., GL_UNSIGNED_INT, ...)` or whatever datatype your indexbuffer consists of matches that parameter |
| 105 | + |
| 106 | +### Textures look funny, like a garbled version of the actual image |
| 107 | + |
| 108 | +- make sure your internalformat and actual pixel format match. You probably used stb_image to load, but used 0 as the last parameter, |
| 109 | + and pixel data has 3 components, instead of the 4 (GL_RGBA) you told OpenGL about -> request 4 channels from stb_image |
| 110 | + |
| 111 | +### Textures look like one color component is more prominent than others |
| 112 | + |
| 113 | +- Colors are more shifted towards blue |
| 114 | + |
| 115 | + - You probably messed up the format and asked for GL_BRG.. of sorts => make sure they match |
| 116 | + |
| 117 | +- Colors are more shifted towards red |
| 118 | + |
| 119 | + - Original pixeldata was probably in BGR... but you asked for GL_RGB... of sorts => make sure they match |
| 120 | + |
| 121 | +### Textures seem to work, but mesh also appear to be shaded weirdly as if black Fog is on |
| 122 | + |
| 123 | +Did you generate mipmaps? |
| 124 | + |
| 125 | +### Render artifacts like small missing tiles on a floor |
| 126 | + |
| 127 | +- synchronization issues - perhaps a missing glMemoryBarrier at the right spot |
| 128 | +- ubo/ssbo alignment issue - check std140/430 rule in the glsl spec |
| 129 | +- binding multiple textures to the same slot - check your glBindTextureUnit calls |
| 130 | +- you might be using a float to index into a buffer to grab material/texture info, use a flat int |
| 131 | + |
| 132 | +### Depth buffer not cleared |
| 133 | + |
| 134 | +- Despite calling `glClear(GL_DEPTH_BUFFER_BIT)` => check if `glDepthMask` was set to `GL_FALSE`. When you use FBOs migrate to glClearNamedFramebuffer() if you havent already (still requires glDepthMask set properly) |
| 135 | + |
| 136 | +### Weird "Z-fighting" |
| 137 | + |
| 138 | +- check your depth buffer, near and far planes... try near 0.1f and 512/1024 as farplane |
| 139 | +- your depth buffer might be too small and is set to D16 only, set it to something D24 or D32 |
| 140 | +- you use SDL2 and on your platform the default might be set to D16, find the SDL2_GL_Set_Attribute which sets the depth bits for the default fbo |
0 commit comments