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:
baldurk
2014-12-01 14:29:43 +00:00
parent 829647a924
commit 7add9a63dd
4 changed files with 198 additions and 32 deletions
+43 -8
View File
@@ -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;
}
+12 -2
View File
@@ -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;
+80 -9
View File
@@ -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;