mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Workaround ARM driver bug with core promoted function. Closes #1322
* glRenderbufferStorageMultisample and glRenderbufferStorageMultisampleEXT should be interchangeable, with the only difference being the EXT version specifies that tile resolves may happen and MSAA data won't be preserved. * When aliasing the functions RenderDoc will call the core version if available even if the application called into the EXT, assuming them to be interchangeable (and in this case the core function is a superset of functionality). Unfortunately on ARM's driver attachments of different types are not handled properly and FBOs can fail to create. * The only available workaround for this is to copy-paste the function implementation and keep them separate, and assume that the application does the right thing and ends up with compatible attachments. The app could easily break in the same way, but at least then RenderDoc is not forcing a bug to be hit.
This commit is contained in:
@@ -312,7 +312,7 @@ struct GLDispatchTable
|
||||
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; // aliases glDeleteFramebuffersEXT
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; // aliases glGenRenderbuffersEXT
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; // aliases glRenderbufferStorageEXT
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample; // aliases glRenderbufferStorageMultisampleEXT
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
|
||||
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; // aliases glDeleteRenderbuffersEXT
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; // aliases glBindRenderbufferEXT
|
||||
PFNGLFENCESYNCPROC glFenceSync;
|
||||
@@ -616,6 +616,9 @@ struct GLDispatchTable
|
||||
|
||||
// GLES: EXT_multisampled_render_to_texture
|
||||
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
|
||||
// this function should be an alias of glRenderBufferStorage2DMultisample, except there are driver
|
||||
// issues that prevent the functions from being treated interchangeably.
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
|
||||
|
||||
// GLES: EXT_discard_framebuffer
|
||||
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
|
||||
|
||||
@@ -463,7 +463,6 @@
|
||||
FUNC(glRenderbufferStorage, glRenderbufferStorage); \
|
||||
FUNC(glRenderbufferStorage, glRenderbufferStorageEXT); \
|
||||
FUNC(glRenderbufferStorageMultisample, glRenderbufferStorageMultisample); \
|
||||
FUNC(glRenderbufferStorageMultisample, glRenderbufferStorageMultisampleEXT); \
|
||||
FUNC(glDeleteRenderbuffers, glDeleteRenderbuffers); \
|
||||
FUNC(glDeleteRenderbuffers, glDeleteRenderbuffersEXT); \
|
||||
FUNC(glBindRenderbuffer, glBindRenderbuffer); \
|
||||
@@ -981,6 +980,7 @@
|
||||
FUNC(glPrimitiveBoundingBox, glPrimitiveBoundingBoxOES); \
|
||||
FUNC(glBlendBarrier, glBlendBarrier); \
|
||||
FUNC(glFramebufferTexture2DMultisampleEXT, glFramebufferTexture2DMultisampleEXT); \
|
||||
FUNC(glRenderbufferStorageMultisampleEXT, glRenderbufferStorageMultisampleEXT); \
|
||||
FUNC(glDiscardFramebufferEXT, glDiscardFramebufferEXT); \
|
||||
FUNC(glDepthRangeArrayfvOES, glDepthRangeArrayfvOES); \
|
||||
FUNC(glDepthRangeArrayfvOES, glDepthRangeArrayfvNV); \
|
||||
@@ -1723,7 +1723,6 @@
|
||||
FuncWrapper4(void, glRenderbufferStorage, GLenum, target, GLenum, internalformat, GLsizei, width, GLsizei, height); \
|
||||
AliasWrapper4(void, glRenderbufferStorageEXT, glRenderbufferStorage, GLenum, target, GLenum, internalformat, GLsizei, width, GLsizei, height); \
|
||||
FuncWrapper5(void, glRenderbufferStorageMultisample, GLenum, target, GLsizei, samples, GLenum, internalformat, GLsizei, width, GLsizei, height); \
|
||||
AliasWrapper5(void, glRenderbufferStorageMultisampleEXT, glRenderbufferStorageMultisample, GLenum, target, GLsizei, samples, GLenum, internalformat, GLsizei, width, GLsizei, height); \
|
||||
FuncWrapper2(void, glDeleteRenderbuffers, GLsizei, n, const GLuint *, renderbuffers); \
|
||||
AliasWrapper2(void, glDeleteRenderbuffersEXT, glDeleteRenderbuffers, GLsizei, n, const GLuint *, renderbuffers); \
|
||||
FuncWrapper2(void, glBindRenderbuffer, GLenum, target, GLuint, renderbuffer); \
|
||||
@@ -2241,6 +2240,7 @@
|
||||
AliasWrapper8(void, glPrimitiveBoundingBoxOES, glPrimitiveBoundingBox, GLfloat, minX, GLfloat, minY, GLfloat, minZ, GLfloat, minW, GLfloat, maxX, GLfloat, maxY, GLfloat, maxZ, GLfloat, maxW); \
|
||||
FuncWrapper0(void, glBlendBarrier); \
|
||||
FuncWrapper6(void, glFramebufferTexture2DMultisampleEXT, GLenum, target, GLenum, attachment, GLenum, textarget, GLuint, texture, GLint, level, GLsizei, samples); \
|
||||
FuncWrapper5(void, glRenderbufferStorageMultisampleEXT, GLenum, target, GLsizei, samples, GLenum, internalformat, GLsizei, width, GLsizei, height); \
|
||||
FuncWrapper3(void, glDiscardFramebufferEXT, GLenum, target, GLsizei, numAttachments, const GLenum *, attachments); \
|
||||
FuncWrapper3(void, glDepthRangeArrayfvOES, GLuint, first, GLsizei, count, const GLfloat *, v); \
|
||||
AliasWrapper3(void, glDepthRangeArrayfvNV, glDepthRangeArrayfvOES, GLuint, first, GLsizei, count, const GLfloat *, v); \
|
||||
|
||||
@@ -3394,11 +3394,14 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk)
|
||||
case GLChunk::glNamedRenderbufferStorageEXT:
|
||||
return Serialise_glNamedRenderbufferStorageEXT(ser, 0, eGL_NONE, 0, 0);
|
||||
case GLChunk::glRenderbufferStorageMultisample:
|
||||
case GLChunk::glRenderbufferStorageMultisampleEXT:
|
||||
case GLChunk::glNamedRenderbufferStorageMultisample:
|
||||
case GLChunk::glNamedRenderbufferStorageMultisampleEXT:
|
||||
return Serialise_glNamedRenderbufferStorageMultisampleEXT(ser, 0, 0, eGL_NONE, 0, 0);
|
||||
|
||||
// needs to be separate from glRenderbufferStorageMultisample due to driver issues
|
||||
case GLChunk::glRenderbufferStorageMultisampleEXT:
|
||||
return Serialise_glRenderbufferStorageMultisampleEXT(ser, 0, 0, eGL_NONE, 0, 0);
|
||||
|
||||
case GLChunk::wglDXRegisterObjectNV:
|
||||
return Serialise_wglDXRegisterObjectNV(ser, GLResource(MakeNullResource), eGL_NONE, 0);
|
||||
case GLChunk::wglDXLockObjectsNV:
|
||||
|
||||
@@ -2289,6 +2289,14 @@ public:
|
||||
void glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level, GLsizei samples);
|
||||
|
||||
// needs to be separate from glRenderbufferStorageMultisample due to driver issues
|
||||
template <typename SerialiserType>
|
||||
bool Serialise_glRenderbufferStorageMultisampleEXT(SerialiserType &ser, GLuint renderbufferHandle,
|
||||
GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
void glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
|
||||
IMPLEMENT_FUNCTION_SERIALISED(void, glSpecializeShader, GLuint shader, const GLchar *pEntryPoint,
|
||||
GLuint numSpecializationConstants, const GLuint *pConstantIndex,
|
||||
const GLuint *pConstantValue);
|
||||
|
||||
@@ -2574,6 +2574,167 @@ void WrappedOpenGL::glRenderbufferStorageMultisample(GLenum target, GLsizei samp
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// We need a separate implementation of glRenderbufferStorageMultisampleEXT because on some drivers
|
||||
// there are issues with aliasing it with the core version of the function.
|
||||
|
||||
template <typename SerialiserType>
|
||||
bool WrappedOpenGL::Serialise_glRenderbufferStorageMultisampleEXT(SerialiserType &ser,
|
||||
GLuint renderbufferHandle,
|
||||
GLsizei samples,
|
||||
GLenum internalformat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
SERIALISE_ELEMENT_LOCAL(renderbuffer, RenderbufferRes(GetCtx(), renderbufferHandle));
|
||||
SERIALISE_ELEMENT(samples);
|
||||
SERIALISE_ELEMENT(internalformat);
|
||||
SERIALISE_ELEMENT(width);
|
||||
SERIALISE_ELEMENT(height);
|
||||
|
||||
SERIALISE_CHECK_READ_ERRORS();
|
||||
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
ResourceId liveId = GetResourceManager()->GetID(renderbuffer);
|
||||
TextureData &texDetails = m_Textures[liveId];
|
||||
|
||||
GLenum fmt = GetBaseFormat(internalformat);
|
||||
|
||||
texDetails.width = width;
|
||||
texDetails.height = height;
|
||||
texDetails.depth = 1;
|
||||
texDetails.samples = samples;
|
||||
texDetails.curType = eGL_RENDERBUFFER;
|
||||
texDetails.internalFormat = internalformat;
|
||||
texDetails.mipsValid = 1;
|
||||
|
||||
GLuint oldRB = 0;
|
||||
GL.glGetIntegerv(eGL_RENDERBUFFER_BINDING, (GLint *)&oldRB);
|
||||
|
||||
GL.glBindRenderbuffer(eGL_RENDERBUFFER, renderbuffer.name);
|
||||
|
||||
GL.glRenderbufferStorageMultisampleEXT(eGL_RENDERBUFFER, samples, internalformat, width, height);
|
||||
|
||||
if(internalformat == eGL_DEPTH_COMPONENT || internalformat == eGL_DEPTH_STENCIL ||
|
||||
internalformat == eGL_STENCIL || internalformat == eGL_STENCIL_INDEX)
|
||||
{
|
||||
// fetch the exact sized depth-stencil formats corresponding to whatever unsized format was
|
||||
// specified.
|
||||
GLint depth = 0;
|
||||
GLint stencil = 0;
|
||||
GL.glGetNamedRenderbufferParameterivEXT(renderbuffer.name, eGL_RENDERBUFFER_DEPTH_SIZE, &depth);
|
||||
GL.glGetNamedRenderbufferParameterivEXT(renderbuffer.name, eGL_RENDERBUFFER_STENCIL_SIZE,
|
||||
&stencil);
|
||||
|
||||
if(depth == 16 && stencil == 0)
|
||||
internalformat = eGL_DEPTH_COMPONENT16;
|
||||
else if(depth == 24 && stencil == 0)
|
||||
internalformat = eGL_DEPTH_COMPONENT24;
|
||||
else if(depth == 24 && stencil == 8)
|
||||
internalformat = eGL_DEPTH24_STENCIL8;
|
||||
else if(depth == 32 && stencil == 0)
|
||||
internalformat = eGL_DEPTH_COMPONENT32F;
|
||||
else if(depth == 32 && stencil == 8)
|
||||
internalformat = eGL_DEPTH32F_STENCIL8;
|
||||
else if(depth == 0 && stencil == 8)
|
||||
internalformat = eGL_STENCIL_INDEX8;
|
||||
}
|
||||
else if(internalformat == eGL_RGBA || internalformat == eGL_RGBA_INTEGER ||
|
||||
internalformat == eGL_RGB || internalformat == eGL_RGB_INTEGER ||
|
||||
internalformat == eGL_RG || internalformat == eGL_RG_INTEGER ||
|
||||
internalformat == eGL_RED || internalformat == eGL_RED_INTEGER)
|
||||
{
|
||||
// if the color format is unsized, find the corresponding sized format
|
||||
|
||||
GLint red = 0, green = 0, blue = 0, alpha = 0;
|
||||
GL.glGetNamedRenderbufferParameterivEXT(renderbuffer.name, eGL_RENDERBUFFER_RED_SIZE, &red);
|
||||
GL.glGetNamedRenderbufferParameterivEXT(renderbuffer.name, eGL_RENDERBUFFER_GREEN_SIZE, &green);
|
||||
GL.glGetNamedRenderbufferParameterivEXT(renderbuffer.name, eGL_RENDERBUFFER_BLUE_SIZE, &blue);
|
||||
GL.glGetNamedRenderbufferParameterivEXT(renderbuffer.name, eGL_RENDERBUFFER_ALPHA_SIZE, &alpha);
|
||||
|
||||
// we only handle a straight regular format here
|
||||
RDCASSERT(red > 0);
|
||||
RDCASSERT(green == 0 || green == red);
|
||||
RDCASSERT(blue == 0 || green == red);
|
||||
RDCASSERT(alpha == 0 || green == red);
|
||||
|
||||
// to start with, create resource format based on the unsized internalformat
|
||||
ResourceFormat resfmt = MakeResourceFormat(eGL_TEXTURE_2D, internalformat);
|
||||
|
||||
// then set the byte size
|
||||
resfmt.compByteWidth = uint8_t(red / 8);
|
||||
|
||||
internalformat = MakeGLFormat(resfmt);
|
||||
}
|
||||
|
||||
// create read-from texture for displaying this render buffer
|
||||
GL.glGenTextures(1, &texDetails.renderbufferReadTex);
|
||||
GL.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE, texDetails.renderbufferReadTex);
|
||||
GL.glTextureStorage2DMultisampleEXT(texDetails.renderbufferReadTex, eGL_TEXTURE_2D_MULTISAMPLE,
|
||||
samples, internalformat, width, height, true);
|
||||
|
||||
GL.glGenFramebuffers(2, texDetails.renderbufferFBOs);
|
||||
GL.glBindFramebuffer(eGL_FRAMEBUFFER, texDetails.renderbufferFBOs[0]);
|
||||
GL.glBindFramebuffer(eGL_FRAMEBUFFER, texDetails.renderbufferFBOs[1]);
|
||||
|
||||
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;
|
||||
GL.glNamedFramebufferRenderbufferEXT(texDetails.renderbufferFBOs[0], attach, eGL_RENDERBUFFER,
|
||||
renderbuffer.name);
|
||||
GL.glNamedFramebufferTexture2DEXT(texDetails.renderbufferFBOs[1], attach,
|
||||
eGL_TEXTURE_2D_MULTISAMPLE, texDetails.renderbufferReadTex, 0);
|
||||
|
||||
AddResourceInitChunk(renderbuffer);
|
||||
|
||||
GL.glBindRenderbuffer(eGL_RENDERBUFFER, oldRB);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WrappedOpenGL::glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples,
|
||||
GLenum internalformat, GLsizei width,
|
||||
GLsizei height)
|
||||
{
|
||||
SERIALISE_TIME_CALL(
|
||||
GL.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height));
|
||||
|
||||
ResourceId rb = GetCtxData().m_Renderbuffer;
|
||||
|
||||
if(IsCaptureMode(m_State))
|
||||
{
|
||||
GLResourceRecord *record = GetResourceManager()->GetResourceRecord(rb);
|
||||
RDCASSERTMSG("Couldn't identify implicit renderbuffer. Not bound?", record);
|
||||
|
||||
if(record)
|
||||
{
|
||||
USE_SCRATCH_SERIALISER();
|
||||
SCOPED_SERIALISE_CHUNK(gl_CurChunk);
|
||||
Serialise_glRenderbufferStorageMultisampleEXT(ser, record->Resource.name, samples,
|
||||
internalformat, width, height);
|
||||
|
||||
record->AddChunk(scope.Get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
m_Textures[rb].width = width;
|
||||
m_Textures[rb].height = height;
|
||||
m_Textures[rb].depth = 1;
|
||||
m_Textures[rb].samples = samples;
|
||||
m_Textures[rb].curType = eGL_RENDERBUFFER;
|
||||
m_Textures[rb].dimension = 2;
|
||||
m_Textures[rb].internalFormat = internalformat;
|
||||
m_Textures[rb].mipsValid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_FUNCTION_SERIALISED(void, glGenFramebuffers, GLsizei n, GLuint *framebuffers);
|
||||
INSTANTIATE_FUNCTION_SERIALISED(void, glCreateFramebuffers, GLsizei n, GLuint *framebuffers);
|
||||
INSTANTIATE_FUNCTION_SERIALISED(void, glNamedFramebufferTextureEXT, GLuint framebufferHandle,
|
||||
@@ -2621,3 +2782,6 @@ INSTANTIATE_FUNCTION_SERIALISED(void, glNamedRenderbufferStorageEXT, GLuint rend
|
||||
INSTANTIATE_FUNCTION_SERIALISED(void, glNamedRenderbufferStorageMultisampleEXT,
|
||||
GLuint renderbufferHandle, GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
INSTANTIATE_FUNCTION_SERIALISED(void, glRenderbufferStorageMultisampleEXT,
|
||||
GLuint renderbufferHandle, GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
|
||||
Reference in New Issue
Block a user