From 16dd0b77f49a21f5a2d113ff2b635d9a35001d1f Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 25 Nov 2014 23:58:04 +0000 Subject: [PATCH] Move bound vertex buffers from general state to VAO state --- renderdoc/driver/gl/gl_common.cpp | 33 +++++++++ renderdoc/driver/gl/gl_common.h | 2 + renderdoc/driver/gl/gl_manager.cpp | 94 +++++++++++++++++++------- renderdoc/driver/gl/gl_renderstate.cpp | 66 ------------------ renderdoc/driver/gl/gl_renderstate.h | 7 -- renderdoc/driver/gl/gl_replay.cpp | 11 +-- 6 files changed, 113 insertions(+), 100 deletions(-) diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index fa3afbb9b..9fb411381 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -170,6 +170,39 @@ GLenum ShaderEnum(size_t idx) return eGL_NONE; } +GLuint GetBoundVertexBuffer(const GLHookSet &gl, GLuint i) +{ + static int hackAMDBugVBBinding = -1; + + // linux AMD driver doesn't recognise GL_VERTEX_BINDING_BUFFER, see below. + if(hackAMDBugVBBinding == -1) + { + GLenum err = gl.glGetError(); + while(err != eGL_NONE) err = gl.glGetError(); + GLint dummy = 0; + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, 0, &dummy); + err = gl.glGetError(); + + hackAMDBugVBBinding = (err == eGL_NONE ? 0 : 1); + + if(hackAMDBugVBBinding) + RDCWARN("Using AMD hack to avoid GL_VERTEX_BINDING_BUFFER"); + } + + GLuint buffer = 0; + + // the linux AMD driver has a "two wrongs make a right" type deal. Instead of returning the buffer that the + // i'th index is bound to (as above, vbslot) for GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, it returns the i'th + // vertex buffer which is exactly what we wanted from GL_VERTEX_BINDING_BUFFER! + // see: http://devgurus.amd.com/message/1306745#1306745 + if(hackAMDBugVBBinding) + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *)&buffer); + else + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, (GLint *)&buffer); + + return buffer; +} + ResourceFormat MakeResourceFormat(WrappedOpenGL &gl, GLenum target, GLenum fmt) { ResourceFormat ret; diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 722875b8a..cf2427a0a 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -82,6 +82,8 @@ GLenum ShaderEnum(size_t idx); ResourceFormat MakeResourceFormat(WrappedOpenGL &gl, GLenum target, GLenum fmt); GLenum MakeGLFormat(WrappedOpenGL &gl, GLenum target, ResourceFormat fmt); +GLuint GetBoundVertexBuffer(const GLHookSet &gl, GLuint idx); + extern int GLCoreVersion; void UpdateExtensionSupport(const GLHookSet &gl); bool ExtensionSupported(const char *ext); diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp index 0208d1ee2..1b0d300aa 100644 --- a/renderdoc/driver/gl/gl_manager.cpp +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -26,9 +26,9 @@ #include "driver/gl/gl_manager.h" #include "driver/gl/gl_driver.h" -struct VertexArrayInitialData +struct VertexAttribInitialData { - VertexArrayInitialData() + VertexAttribInitialData() { RDCEraseEl(*this); } @@ -41,8 +41,26 @@ struct VertexArrayInitialData uint32_t size; }; +struct VertexBufferInitialData +{ + VertexBufferInitialData() + { + RDCEraseEl(*this); + } + ResourceId Buffer; + uint64_t Stride; + uint64_t Offset; + uint32_t Divisor; +}; + +struct VAOInitialData +{ + VertexAttribInitialData VertexAttribs[16]; + VertexBufferInitialData VertexBuffers[16]; +}; + template<> -void Serialiser::Serialise(const char *name, VertexArrayInitialData &el) +void Serialiser::Serialise(const char *name, VertexAttribInitialData &el) { ScopedContext scope(this, this, name, "VertexArrayInitialData", 0, true); Serialise("enabled", el.enabled); @@ -54,6 +72,16 @@ void Serialiser::Serialise(const char *name, VertexArrayInitialData &el) Serialise("size", el.size); } +template<> +void Serialiser::Serialise(const char *name, VertexBufferInitialData &el) +{ + ScopedContext scope(this, this, name, "VertexBufferInitialData", 0, true); + Serialise("Buffer", el.Buffer); + Serialise("Stride", el.Stride); + Serialise("Offset", el.Offset); + Serialise("Divisor", el.Divisor); +} + struct TextureStateInitialData { TextureStateInitialData() @@ -240,17 +268,25 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) gl.glBindVertexArray(res.name); - VertexArrayInitialData *data = (VertexArrayInitialData *)Serialiser::AllocAlignedBuffer(sizeof(VertexArrayInitialData)*16); - + VAOInitialData *data = (VAOInitialData *)Serialiser::AllocAlignedBuffer(sizeof(VAOInitialData)); + for(GLuint i=0; i < 16; i++) { - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *)&data[i].enabled); - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_BINDING, (GLint *)&data[i].vbslot); - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_RELATIVE_OFFSET, (GLint*)&data[i].offset); - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&data[i].type); - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *)&data[i].normalized); - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_INTEGER, (GLint *)&data[i].integer); - gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, (GLint *)&data[i].size); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *)&data->VertexAttribs[i].enabled); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_BINDING, (GLint *)&data->VertexAttribs[i].vbslot); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_RELATIVE_OFFSET, (GLint*)&data->VertexAttribs[i].offset); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&data->VertexAttribs[i].type); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *)&data->VertexAttribs[i].normalized); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_INTEGER, (GLint *)&data->VertexAttribs[i].integer); + gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, (GLint *)&data->VertexAttribs[i].size); + + GLuint buffer = GetBoundVertexBuffer(gl, i); + + data->VertexBuffers[i].Buffer = GetID(BufferRes(res.Context, buffer)); + + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&data->VertexBuffers[i].Stride); + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&data->VertexBuffers[i].Offset); + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&data->VertexBuffers[i].Divisor); } SetInitialContents(Id, InitialContentData(GLResource(MakeNullResource), 0, (byte *)data)); @@ -687,21 +723,24 @@ bool GLResourceManager::Serialise_InitialState(GLResource res) } else if(res.Namespace == eResVertexArray) { - VertexArrayInitialData data[16]; + VAOInitialData data; if(m_State >= WRITING) { - VertexArrayInitialData *initialdata = (VertexArrayInitialData *)GetInitialContents(Id).blob; - memcpy(data, initialdata, sizeof(data)); + VAOInitialData *initialdata = (VAOInitialData *)GetInitialContents(Id).blob; + memcpy(&data, initialdata, sizeof(data)); } for(GLuint i=0; i < 16; i++) - m_pSerialiser->Serialise("data[]", data[i]); + { + m_pSerialiser->Serialise("VertexAttrib[]", data.VertexAttribs[i]); + m_pSerialiser->Serialise("VertexBuffer[]", data.VertexBuffers[i]); + } if(m_State < WRITING) { byte *blob = Serialiser::AllocAlignedBuffer(sizeof(data)); - memcpy(blob, data, sizeof(data)); + memcpy(blob, &data, sizeof(data)); SetInitialContents(Id, InitialContentData(GLResource(MakeNullResource), 0, blob)); } @@ -799,21 +838,30 @@ void GLResourceManager::Apply_InitialState(GLResource live, InitialContentData i gl.glBindVertexArray(live.name); - VertexArrayInitialData *initialdata = (VertexArrayInitialData *)initial.blob; + VAOInitialData *initialdata = (VAOInitialData *)initial.blob; for(GLuint i=0; i < 16; i++) { - if(initialdata[i].enabled) + VertexAttribInitialData &attrib = initialdata->VertexAttribs[i]; + + if(attrib.enabled) gl.glEnableVertexAttribArray(i); else gl.glDisableVertexAttribArray(i); - gl.glVertexAttribBinding(i, initialdata[i].vbslot); + gl.glVertexAttribBinding(i, attrib.vbslot); - if(initialdata[i].integer == 0) - gl.glVertexAttribFormat(i, initialdata[i].size, initialdata[i].type, (GLboolean)initialdata[i].normalized, initialdata[i].offset); + if(initialdata->VertexAttribs[i].integer == 0) + gl.glVertexAttribFormat(i, attrib.size, attrib.type, (GLboolean)attrib.normalized, attrib.offset); else - gl.glVertexAttribIFormat(i, initialdata[i].size, initialdata[i].type, initialdata[i].offset); + gl.glVertexAttribIFormat(i, attrib.size, attrib.type, attrib.offset); + + VertexBufferInitialData &buf = initialdata->VertexBuffers[i]; + + GLuint buffer = GetLiveResource(buf.Buffer).name; + + gl.glBindVertexBuffer(i, buffer, (GLintptr)buf.Offset, (GLsizei)buf.Stride); + gl.glVertexBindingDivisor(i, buf.Divisor); } gl.glBindVertexArray(VAO); diff --git a/renderdoc/driver/gl/gl_renderstate.cpp b/renderdoc/driver/gl/gl_renderstate.cpp index 90883795c..5d685f2e5 100644 --- a/renderdoc/driver/gl/gl_renderstate.cpp +++ b/renderdoc/driver/gl/gl_renderstate.cpp @@ -95,53 +95,6 @@ void GLRenderState::FetchState() m_Real->glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&VAO); - static int hackAMDBugVBBinding = -1; - - if(hackAMDBugVBBinding == -1) - { - GLenum err = m_Real->glGetError(); - while(err != eGL_NONE) err = m_Real->glGetError(); - GLint dummy = 0; - m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, 0, &dummy); - err = m_Real->glGetError(); - - hackAMDBugVBBinding = (err == eGL_NONE ? 0 : 1); - - if(hackAMDBugVBBinding) - RDCWARN("Using AMD hack to avoid GL_VERTEX_BINDING_BUFFER"); - } - - if(VAO != 0) - { - GLuint hackVAO = 0; - if(hackAMDBugVBBinding) - { - // create 'pass through' VAO so we can use GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING to fetch buffers - m_Real->glGenVertexArrays(1, &hackVAO); - m_Real->glBindVertexArray(hackVAO); - for(GLuint i=0; i < (GLuint)ARRAY_COUNT(VertexBuffers); i++) - m_Real->glVertexAttribBinding(i, i); - } - - for(GLuint i=0; i < (GLuint)ARRAY_COUNT(VertexBuffers); i++) - { - if(hackAMDBugVBBinding) - m_Real->glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *)&VertexBuffers[i].Buffer); - else - m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, (GLint *)&VertexBuffers[i].Buffer); - - m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&VertexBuffers[i].Stride); - m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&VertexBuffers[i].Offset); - m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&VertexBuffers[i].Divisor); - } - - if(hackAMDBugVBBinding) - { - m_Real->glBindVertexArray(VAO); - m_Real->glDeleteVertexArrays(1, &hackVAO); - } - } - // the spec says that you can only query for the format that was previously set, or you get // undefined results. Ie. if someone set ints, this might return anything. However there's also // no way to query for the type so we just have to hope for the best and hope most people are @@ -367,14 +320,6 @@ void GLRenderState::ApplyState() m_Real->glActiveTexture(ActiveTexture); m_Real->glBindVertexArray(VAO); - if(VAO != 0) - { - for(GLuint i=0; i < (GLuint)ARRAY_COUNT(VertexBuffers); i++) - { - m_Real->glBindVertexBuffer(i, VertexBuffers[i].Buffer, (GLintptr)VertexBuffers[i].Offset, (GLsizei)VertexBuffers[i].Stride); - m_Real->glVertexBindingDivisor(i, VertexBuffers[i].Divisor); - } - } // See FetchState(). The spec says that you have to SET the right format for the shader too, // but we couldn't query for the format so we can't set it here. @@ -568,7 +513,6 @@ void GLRenderState::Clear() RDCEraseEl(Subroutines); RDCEraseEl(VAO); - RDCEraseEl(VertexBuffers); RDCEraseEl(GenericVertexAttribs); @@ -652,16 +596,6 @@ void GLRenderState::Serialise(LogState state, void *ctx, WrappedOpenGL *gl) m_pSerialiser->Serialise("GL_VERTEX_ARRAY_BINDING", ID); if(state < WRITING && ID != ResourceId()) VAO = rm->GetLiveResource(ID).name; } - for(size_t i=0; i < ARRAY_COUNT(VertexBuffers); i++) - { - ResourceId ID = ResourceId(); - if(state >= WRITING) ID = rm->GetID(BufferRes(ctx, VertexBuffers[i].Buffer)); - m_pSerialiser->Serialise("GL_VERTEX_BINDING_BUFFER", ID); - m_pSerialiser->Serialise("GL_VERTEX_BINDING_DIVISOR", VertexBuffers[i].Divisor); - m_pSerialiser->Serialise("GL_VERTEX_BINDING_OFFSET", VertexBuffers[i].Offset); - m_pSerialiser->Serialise("GL_VERTEX_BINDING_STRIDE", VertexBuffers[i].Stride); - if(state < WRITING && ID != ResourceId()) VertexBuffers[i].Buffer = rm->GetLiveResource(ID).name; - } for(size_t i=0; i < ARRAY_COUNT(GenericVertexAttribs); i++) { diff --git a/renderdoc/driver/gl/gl_renderstate.h b/renderdoc/driver/gl/gl_renderstate.h index 62eb94fe3..b030e46ee 100644 --- a/renderdoc/driver/gl/gl_renderstate.h +++ b/renderdoc/driver/gl/gl_renderstate.h @@ -106,13 +106,6 @@ struct GLRenderState eBufIdx_Texture, }; - struct VertexBuffer - { - GLuint Buffer; - uint64_t Stride; - uint64_t Offset; - uint32_t Divisor; - } VertexBuffers[16]; GLuint VAO; Vec4f GenericVertexAttribs[32]; diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 32599fa28..83f41e63b 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -797,11 +797,14 @@ void GLReplay::SavePipelineState() for(GLuint i=0; i < (GLuint)numVBufferBindings; i++) { - pipe.m_VtxIn.vbuffers[i].Buffer = rm->GetOriginalID(rm->GetID(BufferRes(ctx, rs.VertexBuffers[i].Buffer))); + GLuint buffer = GetBoundVertexBuffer(gl.m_Real, i); + + pipe.m_VtxIn.vbuffers[i].Buffer = rm->GetOriginalID(rm->GetID(BufferRes(ctx, buffer))); + + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Stride); + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Offset); + gl.glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Divisor); - pipe.m_VtxIn.vbuffers[i].Stride = (uint32_t)rs.VertexBuffers[i].Stride; - pipe.m_VtxIn.vbuffers[i].Offset = (uint32_t)rs.VertexBuffers[i].Offset; - pipe.m_VtxIn.vbuffers[i].Divisor = rs.VertexBuffers[i].Divisor; pipe.m_VtxIn.vbuffers[i].PerInstance = (pipe.m_VtxIn.vbuffers[i].Divisor != 0); }