mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-26 08:26:50 +00:00
Better handling for renderbuffer FBO attachments. See gl-320-fbo-blit
* To display them, we create a texture of the same size/format at creation time and do an FBO blit to it, then display that texture
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<ResourceId, TextureData> m_Textures;
|
||||
|
||||
@@ -93,9 +93,17 @@ vector<ResourceId> GLReplay::GetBuffers()
|
||||
vector<ResourceId> GLReplay::GetTextures()
|
||||
{
|
||||
vector<ResourceId> 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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user