From 758ad3f75d49be811237c297265038f80c16ee8c Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 29 Dec 2019 01:28:53 -0300 Subject: [PATCH] gl_state_tracker: Add dirty flags for buffers and divisors --- .../renderer_opengl/gl_rasterizer.cpp | 51 +++++++++++-------- .../renderer_opengl/gl_state_tracker.cpp | 21 ++++++++ .../renderer_opengl/gl_state_tracker.h | 4 ++ .../renderer_opengl/renderer_opengl.cpp | 2 + 4 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 211b11489..bb89985cc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -164,12 +164,22 @@ void RasterizerOpenGL::SetupVertexFormat() { void RasterizerOpenGL::SetupVertexBuffer() { auto& gpu = system.GPU().Maxwell3D(); - const auto& regs = gpu.regs; + auto& flags = gpu.dirty.flags; + if (!flags[Dirty::VertexBuffers]) { + return; + } + flags[Dirty::VertexBuffers] = false; MICROPROFILE_SCOPE(OpenGL_VB); // Upload all guest vertex arrays sequentially to our buffer - for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { + const auto& regs = gpu.regs; + for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { + if (!flags[Dirty::VertexBuffer0 + index]) { + continue; + } + flags[Dirty::VertexBuffer0 + index] = false; + const auto& vertex_array = regs.vertex_array[index]; if (!vertex_array.IsEnabled()) { continue; @@ -183,33 +193,30 @@ void RasterizerOpenGL::SetupVertexBuffer() { const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size); // Bind the vertex array to the buffer at the current offset. - 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. - glVertexBindingDivisor(index, vertex_array.divisor); - } else { - // Disable the vertex buffer instancing. - glVertexBindingDivisor(index, 0); - } + vertex_array_pushbuffer.SetVertexBuffer(static_cast(index), vertex_buffer, + vertex_buffer_offset, vertex_array.stride); } } void RasterizerOpenGL::SetupVertexInstances() { auto& gpu = system.GPU().Maxwell3D(); - const auto& regs = gpu.regs; + auto& flags = gpu.dirty.flags; + if (!flags[Dirty::VertexInstances]) { + return; + } + flags[Dirty::VertexInstances] = false; - // Upload all guest vertex arrays sequentially to our buffer - for (u32 index = 0; index < 16; ++index) { - if (regs.instanced_arrays.IsInstancingEnabled(index) && - regs.vertex_array[index].divisor != 0) { - // Enable vertex buffer instancing with the specified divisor. - glVertexBindingDivisor(index, regs.vertex_array[index].divisor); - } else { - // Disable the vertex buffer instancing. - glVertexBindingDivisor(index, 0); + const auto& regs = gpu.regs; + for (std::size_t index = 0; index < 16; ++index) { + if (!flags[Dirty::VertexInstance0 + index]) { + continue; } + flags[Dirty::VertexInstance0 + index] = false; + + const auto gl_index = static_cast(index); + const bool instancing_enabled = regs.instanced_arrays.IsInstancingEnabled(gl_index); + const GLuint divisor = instancing_enabled ? regs.vertex_array[index].divisor : 0; + glVertexBindingDivisor(gl_index, divisor); } } diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp index 319fd825b..7150b9247 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.cpp +++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp @@ -71,6 +71,26 @@ void SetupDirtyColorMasks(Tables& tables) { FillBlock(tables[1], OFF(color_mask), NUM(color_mask), ColorMasks); } +void SetupDirtyVertexArrays(Tables& tables) { + static constexpr std::size_t num_array = 3; + static constexpr std::size_t instance_base_offset = 3; + for (std::size_t i = 0; i < Regs::NumVertexArrays; ++i) { + const std::size_t array_offset = OFF(vertex_array) + i * NUM(vertex_array[0]); + const std::size_t limit_offset = OFF(vertex_array_limit) + i * NUM(vertex_array_limit[0]); + + FillBlock(tables, array_offset, num_array, VertexBuffer0 + i, VertexBuffers); + FillBlock(tables, limit_offset, NUM(vertex_array_limit), VertexBuffer0 + i, VertexBuffers); + + const std::size_t instance_array_offset = array_offset + instance_base_offset; + tables[0][instance_array_offset] = static_cast(VertexInstance0 + i); + tables[1][instance_array_offset] = VertexInstances; + + const std::size_t instance_offset = OFF(instanced_arrays) + i; + tables[0][instance_offset] = static_cast(VertexInstance0 + i); + tables[1][instance_offset] = VertexInstances; + } +} + void SetupDirtyVertexFormat(Tables& tables) { for (std::size_t i = 0; i < Regs::NumVertexAttributes; ++i) { const std::size_t offset = OFF(vertex_attrib_format) + i * NUM(vertex_attrib_format[0]); @@ -115,6 +135,7 @@ void StateTracker::Initialize() { SetupDirtyColorMasks(tables); SetupDirtyViewports(tables); SetupDirtyScissors(tables); + SetupDirtyVertexArrays(tables); SetupDirtyVertexFormat(tables); auto& store = dirty.on_write_stores; diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h index a368aefd7..85667cee1 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.h +++ b/src/video_core/renderer_opengl/gl_state_tracker.h @@ -78,6 +78,10 @@ public: flags[OpenGL::Dirty::VertexBuffers] = true; flags[OpenGL::Dirty::VertexBuffer0] = true; + + flags[OpenGL::Dirty::VertexInstances] = true; + flags[OpenGL::Dirty::VertexInstance0 + 0] = true; + flags[OpenGL::Dirty::VertexInstance0 + 1] = true; } void NotifyViewport0() { diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index caa193c50..cbe916488 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -611,6 +611,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { glEnableVertexAttribArray(PositionLocation); glEnableVertexAttribArray(TexCoordLocation); + glVertexAttribDivisor(PositionLocation, 0); + glVertexAttribDivisor(TexCoordLocation, 0); glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, offsetof(ScreenRectVertex, position)); glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,