From 9cdc576f6055cbb308551f09e3566b34233b226e Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 20 Jun 2019 03:44:06 -0300 Subject: [PATCH] gl_rasterizer: Fix vertex and index data invalidations --- .../renderer_opengl/gl_rasterizer.cpp | 14 ++++----- .../renderer_opengl/gl_rasterizer.h | 3 +- src/video_core/renderer_opengl/utils.cpp | 31 +++++++++++++++++++ src/video_core/renderer_opengl/utils.h | 27 ++++++++++++++++ 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b57d60856..f3527d65b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -198,9 +198,8 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size); // Bind the vertex array to the buffer at the current offset. - // FIXME(Rodrigo): This dereferenced pointer might be invalidated in future uploads. - glVertexArrayVertexBuffer(vao, index, *vertex_buffer, vertex_buffer_offset, - vertex_array.stride); + vertex_array_pushbuffer.SetVertexBuffer(index, vertex_buffer, vertex_buffer_offset, + vertex_array.stride); if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) { // Enable vertex buffer instancing with the specified divisor. @@ -214,7 +213,7 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { gpu.dirty_flags.vertex_array.reset(); } -GLintptr RasterizerOpenGL::SetupIndexBuffer(GLuint vao) { +GLintptr RasterizerOpenGL::SetupIndexBuffer() { if (accelerate_draw != AccelDraw::Indexed) { return 0; } @@ -222,8 +221,7 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer(GLuint vao) { const auto& regs = system.GPU().Maxwell3D().regs; const std::size_t size = CalculateIndexBufferSize(); const auto [buffer, offset] = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size); - // FIXME(Rodrigo): This dereferenced pointer might be invalidated in future uploads. - glVertexArrayElementBuffer(vao, *buffer); + vertex_array_pushbuffer.SetIndexBuffer(buffer); return offset; } @@ -644,10 +642,11 @@ void RasterizerOpenGL::DrawArrays() { // Prepare vertex array format. const GLuint vao = SetupVertexFormat(); + vertex_array_pushbuffer.Setup(vao); // Upload vertex and index data. SetupVertexBuffer(vao); - const GLintptr index_buffer_offset = SetupIndexBuffer(vao); + const GLintptr index_buffer_offset = SetupIndexBuffer(); // Setup draw parameters. It will automatically choose what glDraw* method to use. const DrawParameters params = SetupDraw(index_buffer_offset); @@ -667,6 +666,7 @@ void RasterizerOpenGL::DrawArrays() { const bool invalidate = buffer_cache.Unmap(); // Now that we are no longer uploading data, we can safely bind the buffers to OpenGL. + vertex_array_pushbuffer.Bind(); bind_ubo_pushbuffer.Bind(); bind_ssbo_pushbuffer.Bind(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 7067ad5b4..1c915fd7f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -207,6 +207,7 @@ private: static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; OGLBufferCache buffer_cache; + VertexArrayPushBuffer vertex_array_pushbuffer; BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; @@ -219,7 +220,7 @@ private: void SetupVertexBuffer(GLuint vao); - GLintptr SetupIndexBuffer(GLuint vao); + GLintptr SetupIndexBuffer(); DrawParameters SetupDraw(GLintptr index_buffer_offset); diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp index 22eefa1d7..c504a2c1a 100644 --- a/src/video_core/renderer_opengl/utils.cpp +++ b/src/video_core/renderer_opengl/utils.cpp @@ -13,6 +13,37 @@ namespace OpenGL { +VertexArrayPushBuffer::VertexArrayPushBuffer() = default; + +VertexArrayPushBuffer::~VertexArrayPushBuffer() = default; + +void VertexArrayPushBuffer::Setup(GLuint vao_) { + vao = vao_; + index_buffer = nullptr; + vertex_buffers.clear(); +} + +void VertexArrayPushBuffer::SetIndexBuffer(const GLuint* buffer) { + index_buffer = buffer; +} + +void VertexArrayPushBuffer::SetVertexBuffer(GLuint binding_index, const GLuint* buffer, + GLintptr offset, GLsizei stride) { + vertex_buffers.push_back(Entry{binding_index, buffer, offset, stride}); +} + +void VertexArrayPushBuffer::Bind() { + if (index_buffer) { + glVertexArrayElementBuffer(vao, *index_buffer); + } + + // TODO(Rodrigo): Find a way to ARB_multi_bind this + for (const auto& entry : vertex_buffers) { + glVertexArrayVertexBuffer(vao, entry.binding_index, *entry.buffer, entry.offset, + entry.stride); + } +} + BindBuffersRangePushBuffer::BindBuffersRangePushBuffer(GLenum target) : target{target} {} BindBuffersRangePushBuffer::~BindBuffersRangePushBuffer() = default; diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h index d2a3d25d9..6c2b45546 100644 --- a/src/video_core/renderer_opengl/utils.h +++ b/src/video_core/renderer_opengl/utils.h @@ -11,6 +11,33 @@ namespace OpenGL { +class VertexArrayPushBuffer final { +public: + explicit VertexArrayPushBuffer(); + ~VertexArrayPushBuffer(); + + void Setup(GLuint vao_); + + void SetIndexBuffer(const GLuint* buffer); + + void SetVertexBuffer(GLuint binding_index, const GLuint* buffer, GLintptr offset, + GLsizei stride); + + void Bind(); + +private: + struct Entry { + GLuint binding_index{}; + const GLuint* buffer{}; + GLintptr offset{}; + GLsizei stride{}; + }; + + GLuint vao{}; + const GLuint* index_buffer{}; + std::vector vertex_buffers; +}; + class BindBuffersRangePushBuffer final { public: explicit BindBuffersRangePushBuffer(GLenum target);