diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 4b7fa1e32..7a6c085a8 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -560,17 +560,19 @@ void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sl bool GLReplay::RenderTexture(TextureDisplay cfg) { - MakeCurrentReplayContext(m_DebugCtx); - WrappedOpenGL &gl = *m_pDriver; - gl.glUseProgram(DebugData.texDisplayProg); - auto &texDetails = m_pDriver->m_Textures[cfg.texid]; + bool renderbuffer = false; + int resType; switch (texDetails.curType) { + case eGL_RENDERBUFFER: + resType = RESTYPE_TEX2D; + renderbuffer = true; + break; case eGL_TEXTURE_1D: resType = RESTYPE_TEX1D; break; @@ -596,6 +598,39 @@ bool GLReplay::RenderTexture(TextureDisplay cfg) break; } + GLuint texname = texDetails.resource.name; + GLenum target = texDetails.curType; + + // do blit from renderbuffer to texture, then sample from texture + if(renderbuffer) + { + // need replay context active to do blit (as FBOs aren't shared) + MakeCurrentReplayContext(&m_ReplayCtx); + + GLuint curDrawFBO = 0; + GLuint curReadFBO = 0; + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&curDrawFBO); + gl.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint*)&curReadFBO); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, texDetails.renderbufferFBOs[1]); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, texDetails.renderbufferFBOs[0]); + + gl.glBlitFramebuffer(0, 0, texDetails.width, texDetails.height, + 0, 0, texDetails.width, texDetails.height, + GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT, + eGL_NEAREST); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, curDrawFBO); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curReadFBO); + + texname = texDetails.renderbufferReadTex; + target = eGL_TEXTURE_2D; + } + + MakeCurrentReplayContext(m_DebugCtx); + + gl.glUseProgram(DebugData.texDisplayProg); + RDCGLenum dsTexMode = eGL_NONE; if(IsDepthStencilFormat(texDetails.internalFormat)) { @@ -640,13 +675,13 @@ bool GLReplay::RenderTexture(TextureDisplay cfg) } gl.glActiveTexture((RDCGLenum)(eGL_TEXTURE0 + resType)); - gl.glBindTexture(texDetails.curType, texDetails.resource.name); + gl.glBindTexture(target, texname); GLint origDSTexMode = eGL_DEPTH_COMPONENT; if (dsTexMode != eGL_NONE) { - gl.glGetTexParameteriv(texDetails.curType, eGL_DEPTH_STENCIL_TEXTURE_MODE, &origDSTexMode); - gl.glTexParameteri(texDetails.curType, eGL_DEPTH_STENCIL_TEXTURE_MODE, dsTexMode); + gl.glGetTexParameteriv(target, eGL_DEPTH_STENCIL_TEXTURE_MODE, &origDSTexMode); + gl.glTexParameteri(target, eGL_DEPTH_STENCIL_TEXTURE_MODE, dsTexMode); } if(cfg.mip == 0 && cfg.scale < 1.0f && dsTexMode == eGL_NONE) @@ -752,7 +787,7 @@ bool GLReplay::RenderTexture(TextureDisplay cfg) gl.glBindSampler(0, 0); if (dsTexMode != eGL_NONE) - gl.glTexParameteri(texDetails.curType, eGL_DEPTH_STENCIL_TEXTURE_MODE, origDSTexMode); + gl.glTexParameteri(target, eGL_DEPTH_STENCIL_TEXTURE_MODE, origDSTexMode); return true; } diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 2eb5ecc09..118f53a46 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -183,14 +183,24 @@ class WrappedOpenGL struct TextureData { - TextureData() : dimension(0), width(0), height(0), depth(0), samples(0), creationFlags(0), internalFormat(eGL_NONE), renderbuffer(false) {} + TextureData() + : dimension(0), width(0), height(0), depth(0), samples(0), creationFlags(0), internalFormat(eGL_NONE), + renderbufferReadTex(0) + { + renderbufferFBOs[0] = renderbufferFBOs[1] = 0; + } GLResource resource; GLenum curType; GLint dimension; GLint width, height, depth, samples; uint32_t creationFlags; GLenum internalFormat; - bool renderbuffer; + + // since renderbuffers cannot be read from, we have to create a texture of identical size/format, + // and define FBOs for blitting to it - the renderbuffer is attached to the first FBO and the texture is + // bound to the second. + GLuint renderbufferReadTex; + GLuint renderbufferFBOs[2]; }; map m_Textures; diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 565c647a9..e30f67c20 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -93,9 +93,17 @@ vector GLReplay::GetBuffers() vector GLReplay::GetTextures() { vector ret; + ret.reserve(m_pDriver->m_Textures.size()); for(auto it=m_pDriver->m_Textures.begin(); it != m_pDriver->m_Textures.end(); ++it) { + auto &res = m_pDriver->m_Textures[it->first]; + + // skip textures that aren't from the log (except the 'default backbuffer' textures) + if(res.resource.name != m_pDriver->m_FakeBB_Color && + res.resource.name != m_pDriver->m_FakeBB_DepthStencil && + m_pDriver->GetResourceManager()->GetOriginalID(it->first) == it->first) continue; + ret.push_back(it->first); CacheTexture(it->first); } @@ -332,7 +340,10 @@ void GLReplay::CacheTexture(ResourceId id) MakeCurrentReplayContext(&m_ReplayCtx); auto &res = m_pDriver->m_Textures[id]; - + WrappedOpenGL &gl = *m_pDriver; + + tex.ID = m_pDriver->GetResourceManager()->GetOriginalID(id); + if(res.resource.Namespace == eResUnknown || res.curType == eGL_NONE) { if(res.resource.Namespace == eResUnknown) @@ -356,9 +367,56 @@ void GLReplay::CacheTexture(ResourceId id) return; } - WrappedOpenGL &gl = *m_pDriver; - - tex.ID = m_pDriver->GetResourceManager()->GetOriginalID(id); + if(res.resource.Namespace == eResRenderbuffer || res.curType == eGL_RENDERBUFFER) + { + tex.dimension = 2; + tex.width = res.width; + tex.height = res.height; + tex.depth = 1; + tex.cubemap = false; + tex.mips = 1; + tex.arraysize = 1; + tex.numSubresources = 1; + tex.creationFlags = eTextureCreate_RTV; + tex.msQual = 0; + tex.msSamp = res.samples; + + tex.format = MakeResourceFormat(gl, eGL_TEXTURE_2D, res.internalFormat); + + if(IsDepthStencilFormat(res.internalFormat)) + tex.creationFlags |= eTextureCreate_DSV; + + tex.byteSize = (tex.width*tex.height)*(tex.format.compByteWidth*tex.format.compCount); + + string str = ""; + char name[128] = {0}; + gl.glGetObjectLabel(eGL_RENDERBUFFER, res.resource.name, 127, NULL, name); + str = name; + tex.customName = true; + + if(str == "") + { + const char *suffix = ""; + const char *ms = ""; + + if(tex.msSamp > 1) + ms = "MS"; + + if(tex.creationFlags & eTextureCreate_RTV) + suffix = " RTV"; + if(tex.creationFlags & eTextureCreate_DSV) + suffix = " DSV"; + + tex.customName = false; + + str = StringFormat::Fmt("Renderbuffer%s%s %llu", ms, suffix, tex.ID); + } + + tex.name = str; + + m_CachedTextures[id] = tex; + return; + } GLenum target = TextureTarget(res.curType); @@ -504,8 +562,8 @@ void GLReplay::CacheTexture(ResourceId id) tex.msQual = tex.msSamp = 0; tex.byteSize = 0; - gl.glGetTextureLevelParameterivEXT(res.resource.name, levelQueryType, 0, eGL_TEXTURE_BUFFER_SIZE, (GLint *)&tex.width); - tex.byteSize = tex.width/(tex.format.compByteWidth*tex.format.compCount); + gl.glGetTextureLevelParameterivEXT(res.resource.name, levelQueryType, 0, eGL_TEXTURE_BUFFER_SIZE, (GLint *)&tex.byteSize); + tex.width = uint32_t(tex.byteSize/(tex.format.compByteWidth*tex.format.compCount)); m_CachedTextures[id] = tex; return; @@ -1258,6 +1316,9 @@ void GLReplay::SavePipelineState() GLint numCols = 8; gl.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &numCols); + bool rbCol[32] = { false }; + bool rbDepth = false; + bool rbStencil = false; GLuint curCol[32] = { 0 }; GLuint curDepth = 0; GLuint curStencil = 0; @@ -1268,19 +1329,29 @@ void GLReplay::SavePipelineState() RDCASSERT(curFBO != 0); { + GLenum type = eGL_TEXTURE; for(GLint i=0; i < numCols; i++) + { gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0+i), eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curCol[i]); + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0+i), eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint*)&type); + if(type == eGL_RENDERBUFFER) rbCol[i] = true; + } + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curDepth); + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint*)&type); + if(type == eGL_RENDERBUFFER) rbDepth = true; gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curStencil); + gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint*)&type); + if(type == eGL_RENDERBUFFER) rbStencil = true; } pipe.m_FB.FBO = rm->GetOriginalID(rm->GetID(FramebufferRes(ctx, curFBO))); create_array_uninit(pipe.m_FB.Color, numCols); for(GLint i=0; i < numCols; i++) - pipe.m_FB.Color[i] = rm->GetOriginalID(rm->GetID(TextureRes(ctx, curCol[i]))); + pipe.m_FB.Color[i] = rm->GetOriginalID(rm->GetID(rbCol[i] ? RenderbufferRes(ctx, curCol[i]) : TextureRes(ctx, curCol[i]))); - pipe.m_FB.Depth = rm->GetOriginalID(rm->GetID(TextureRes(ctx, curDepth))); - pipe.m_FB.Stencil = rm->GetOriginalID(rm->GetID(TextureRes(ctx, curStencil))); + pipe.m_FB.Depth = rm->GetOriginalID(rm->GetID(rbDepth ? RenderbufferRes(ctx, curDepth) : TextureRes(ctx, curDepth))); + pipe.m_FB.Stencil = rm->GetOriginalID(rm->GetID(rbStencil ? RenderbufferRes(ctx, curStencil) : TextureRes(ctx, curStencil))); } void GLReplay::FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, bool rowMajor, diff --git a/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp index cd248c3a6..63adb0784 100644 --- a/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_framebuffer_funcs.cpp @@ -480,7 +480,6 @@ bool WrappedOpenGL::Serialise_glNamedFramebufferRenderbufferEXT(GLuint framebuff if(m_State == READING) { m_Textures[GetResourceManager()->GetLiveID(id)].creationFlags |= eTextureCreate_RTV; - m_Textures[GetResourceManager()->GetLiveID(id)].renderbuffer = true; } } @@ -1001,6 +1000,9 @@ bool WrappedOpenGL::Serialise_glGenRenderbuffers(GLsizei n, GLuint* renderbuffer ResourceId live = m_ResourceManager->RegisterResource(res); GetResourceManager()->AddLiveResource(id, res); + + m_Textures[live].resource = res; + m_Textures[live].curType = eGL_RENDERBUFFER; } return true; @@ -1074,14 +1076,37 @@ bool WrappedOpenGL::Serialise_glRenderbufferStorage(GLenum target, GLenum intern if(m_State == READING) { ResourceId liveId = GetResourceManager()->GetLiveID(id); - m_Textures[liveId].width = Width; - m_Textures[liveId].height = Height; - m_Textures[liveId].depth = 1; - m_Textures[liveId].curType = eGL_RENDERBUFFER; - m_Textures[liveId].internalFormat = Format; + TextureData& texDetails = m_Textures[liveId]; - m_Real.glBindRenderbuffer(eGL_RENDERBUFFER, GetResourceManager()->GetLiveResource(id).name); + texDetails.width = Width; + texDetails.height = Height; + texDetails.depth = 1; + texDetails.samples = 1; + texDetails.curType = eGL_RENDERBUFFER; + texDetails.internalFormat = Format; + + GLuint real = GetResourceManager()->GetLiveResource(id).name; + + m_Real.glBindRenderbuffer(eGL_RENDERBUFFER, real); m_Real.glRenderbufferStorage(eGL_RENDERBUFFER, Format, Width, Height); + + // create read-from texture for displaying this render buffer + m_Real.glGenTextures(1, &texDetails.renderbufferReadTex); + m_Real.glBindTexture(eGL_TEXTURE_2D, texDetails.renderbufferReadTex); + m_Real.glTextureStorage2DEXT(texDetails.renderbufferReadTex, eGL_TEXTURE_2D, 1, Format, Width, Height); + + m_Real.glGenFramebuffers(2, texDetails.renderbufferFBOs); + m_Real.glBindFramebuffer(eGL_FRAMEBUFFER, texDetails.renderbufferFBOs[0]); + m_Real.glBindFramebuffer(eGL_FRAMEBUFFER, texDetails.renderbufferFBOs[1]); + + GLenum fmt = GetBaseFormat(Format); + + GLenum attach = eGL_COLOR_ATTACHMENT0; + if(fmt == eGL_DEPTH_COMPONENT) attach = eGL_DEPTH_ATTACHMENT; + if(fmt == eGL_STENCIL) attach = eGL_STENCIL_ATTACHMENT; + if(fmt == eGL_DEPTH_STENCIL) attach = eGL_DEPTH_STENCIL_ATTACHMENT; + m_Real.glNamedFramebufferRenderbufferEXT(texDetails.renderbufferFBOs[0], attach, eGL_RENDERBUFFER, real); + m_Real.glNamedFramebufferTexture2DEXT(texDetails.renderbufferFBOs[1], attach, eGL_TEXTURE_2D, texDetails.renderbufferReadTex, 0); } return true; @@ -1106,6 +1131,7 @@ void WrappedOpenGL::glRenderbufferStorage(GLenum target, GLenum internalformat, m_Textures[m_Renderbuffer].width = width; m_Textures[m_Renderbuffer].height = height; m_Textures[m_Renderbuffer].depth = 1; + m_Textures[m_Renderbuffer].samples = 1; m_Textures[m_Renderbuffer].curType = eGL_RENDERBUFFER; m_Textures[m_Renderbuffer].dimension = 2; m_Textures[m_Renderbuffer].internalFormat = internalformat; @@ -1123,14 +1149,37 @@ bool WrappedOpenGL::Serialise_glRenderbufferStorageMultisample(GLenum target, GL if(m_State == READING) { ResourceId liveId = GetResourceManager()->GetLiveID(id); - m_Textures[liveId].width = Width; - m_Textures[liveId].height = Height; - m_Textures[liveId].depth = 1; - m_Textures[liveId].curType = eGL_RENDERBUFFER; - m_Textures[liveId].internalFormat = Format; + TextureData& texDetails = m_Textures[liveId]; + + texDetails.width = Width; + texDetails.height = Height; + texDetails.depth = 1; + texDetails.samples = Samples; + texDetails.curType = eGL_RENDERBUFFER; + texDetails.internalFormat = Format; + + GLuint real = GetResourceManager()->GetLiveResource(id).name; m_Real.glBindRenderbuffer(eGL_RENDERBUFFER, GetResourceManager()->GetLiveResource(id).name); m_Real.glRenderbufferStorageMultisample(eGL_RENDERBUFFER, Samples, Format, Width, Height); + + // create read-from texture for displaying this render buffer + m_Real.glGenTextures(1, &texDetails.renderbufferReadTex); + m_Real.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE, texDetails.renderbufferReadTex); + m_Real.glTextureStorage2DMultisampleEXT(texDetails.renderbufferReadTex, eGL_TEXTURE_2D_MULTISAMPLE, Samples, Format, Width, Height, true); + + m_Real.glGenFramebuffers(2, texDetails.renderbufferFBOs); + m_Real.glBindFramebuffer(eGL_FRAMEBUFFER, texDetails.renderbufferFBOs[0]); + m_Real.glBindFramebuffer(eGL_FRAMEBUFFER, texDetails.renderbufferFBOs[1]); + + GLenum fmt = GetBaseFormat(Format); + + GLenum attach = eGL_COLOR_ATTACHMENT0; + if(fmt == eGL_DEPTH_COMPONENT) attach = eGL_DEPTH_ATTACHMENT; + if(fmt == eGL_STENCIL) attach = eGL_STENCIL_ATTACHMENT; + if(fmt == eGL_DEPTH_STENCIL) attach = eGL_DEPTH_STENCIL_ATTACHMENT; + m_Real.glNamedFramebufferRenderbufferEXT(texDetails.renderbufferFBOs[0], attach, eGL_RENDERBUFFER, real); + m_Real.glNamedFramebufferTexture2DEXT(texDetails.renderbufferFBOs[1], attach, eGL_TEXTURE_2D_MULTISAMPLE, texDetails.renderbufferReadTex, 0); } return true; @@ -1154,7 +1203,8 @@ void WrappedOpenGL::glRenderbufferStorageMultisample(GLenum target, GLsizei samp { m_Textures[m_Renderbuffer].width = width; m_Textures[m_Renderbuffer].height = height; - m_Textures[m_Renderbuffer].depth = samples; + m_Textures[m_Renderbuffer].depth = 1; + m_Textures[m_Renderbuffer].samples = samples; m_Textures[m_Renderbuffer].curType = eGL_RENDERBUFFER; m_Textures[m_Renderbuffer].dimension = 2; m_Textures[m_Renderbuffer].internalFormat = internalformat;