diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index a08314d5a..58b8d2421 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -667,6 +667,23 @@ void DoVendorChecks(const GLHookSet &gl, GLPlatform &platform, GLWindowingData c // I'm not sure if that's correct (weird) behaviour or buggy, but we can work around it just by // avoiding use of the DSA function and always doing our emulated version. VendorCheck[VendorCheck_AMD_vertex_array_elem_buffer_query] = true; + + if(IsGLES) + { + // Check whether reading from the depth, stencil and depth-stencil buffers using glReadPixels is + // supported or not. + if(!HasExt[NV_read_depth]) + RDCWARN( + "Reading from the depth buffer using glReadPixels is not supported (GL_NV_read_depth)"); + if(!HasExt[NV_read_stencil]) + RDCWARN( + "Reading from the stencil buffer using glReadPixels is not supported " + "(GL_NV_read_stencil)"); + if(!HasExt[NV_read_depth_stencil]) + RDCWARN( + "Reading from the packed depth-stencil buffers using glReadPixels is not supported " + "(GL_NV_read_depth_stencil)"); + } } const GLHookSet *GLMarkerRegion::gl; diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 785a3c8df..156a0cb92 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -313,6 +313,9 @@ extern bool IsGLES; EXT_TO_CHECK(99, EXT_clip_cull_distance) \ EXT_TO_CHECK(99, EXT_multisample_compatibility) \ EXT_TO_CHECK(99, NV_polygon_mode) \ + EXT_TO_CHECK(99, NV_read_depth) \ + EXT_TO_CHECK(99, NV_read_stencil) \ + EXT_TO_CHECK(99, NV_read_depth_stencil) \ EXT_TO_CHECK(99, OES_sample_shading) // extensions we know we want to check for are precached, indexd by this enum diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index 6fa1768fb..08f7def06 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -1218,6 +1218,91 @@ void APIENTRY _glClearBufferData(GLenum target, GLenum internalformat, GLenum fo #pragma endregion +#pragma region GLES Compatibility + +void APIENTRY _glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels) +{ + if((format == eGL_DEPTH_COMPONENT && !HasExt[NV_read_depth]) || + (format == eGL_STENCIL && !HasExt[NV_read_stencil]) || + (format == eGL_DEPTH_STENCIL && !HasExt[NV_read_depth_stencil])) + { + // TODO create a workaround for this + // return silently, check was made during startup + return; + } + + switch(target) + { + case eGL_TEXTURE_1D: + case eGL_TEXTURE_1D_ARRAY: + RDCWARN("1d and 1d array textures are not supported by GLES"); + return; + + case eGL_TEXTURE_BUFFER: + // TODO implement this + GLNOTIMP("Reading pixels from texture buffer"); + return; + + default: break; + } + + GLint width = 0, height = 0, depth = 0; + internalGL->glGetTexLevelParameteriv(target, level, eGL_TEXTURE_WIDTH, &width); + internalGL->glGetTexLevelParameteriv(target, level, eGL_TEXTURE_HEIGHT, &height); + internalGL->glGetTexLevelParameteriv(target, level, eGL_TEXTURE_DEPTH, &depth); + + GLint texture = 0; + internalGL->glGetIntegerv(TextureBinding(target), (GLint *)&texture); + + GLenum attachment = eGL_COLOR_ATTACHMENT0; + if(format == eGL_DEPTH_COMPONENT) + attachment = eGL_DEPTH_ATTACHMENT; + else if(format == eGL_STENCIL) + attachment = eGL_STENCIL_ATTACHMENT; + else if(format == eGL_DEPTH_STENCIL) + attachment = eGL_DEPTH_STENCIL_ATTACHMENT; + + GLuint fbo = 0; + internalGL->glGenFramebuffers(1, &fbo); + + PushPopFramebuffer(eGL_FRAMEBUFFER, fbo); + + size_t sliceSize = GetByteSize(width, height, 1, format, type); + + for(GLint d = 0; d < depth; ++d) + { + switch(target) + { + case eGL_TEXTURE_3D: + case eGL_TEXTURE_2D_ARRAY: + case eGL_TEXTURE_CUBE_MAP_ARRAY: + case eGL_TEXTURE_2D_MULTISAMPLE_ARRAY: + internalGL->glFramebufferTextureLayer(eGL_FRAMEBUFFER, attachment, texture, level, d); + break; + + case eGL_TEXTURE_CUBE_MAP: + case eGL_TEXTURE_CUBE_MAP_POSITIVE_X: + case eGL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case eGL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case eGL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case eGL_TEXTURE_2D: + case eGL_TEXTURE_2D_MULTISAMPLE: + default: + internalGL->glFramebufferTexture2D(eGL_FRAMEBUFFER, attachment, target, texture, level); + break; + } + + byte *dst = (byte *)pixels + d * sliceSize; + internalGL->glReadPixels(0, 0, width, height, format, type, (void *)dst); + } + + internalGL->glDeleteFramebuffers(1, &fbo); +} + +#pragma endregion + void EmulateRequiredExtensions(const GLHookSet *real, GLHookSet *hooks) { #define EMULATE_FUNC(func) hooks->func = &CONCAT(_, func); @@ -1253,6 +1338,7 @@ void EmulateRequiredExtensions(const GLHookSet *real, GLHookSet *hooks) if(IsGLES) { EMULATE_FUNC(glGetBufferSubData); + EMULATE_FUNC(glGetTexImage); } // Emulate the EXT_dsa functions that we'll need.