diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index 5ad769b80..354d1ff97 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -1014,15 +1014,42 @@ void OpenGLDevice::UnbindPipeline(const OpenGLPipeline* pl) } } +ALWAYS_INLINE_RELEASE void OpenGLDevice::SetVertexBufferOffsets(u32 base_vertex) +{ + const OpenGLPipeline::VertexArrayCacheKey& va = m_last_vao->first; + const size_t stride = va.vertex_attribute_stride; + for (u32 i = 0; i < va.num_vertex_attributes; i++) + { + glBindVertexBuffer(i, m_vertex_buffer->GetGLBufferId(), base_vertex * stride + va.vertex_attributes[i].offset, + static_cast(stride)); + } +} + void OpenGLDevice::Draw(u32 vertex_count, u32 base_vertex) { - glDrawArrays(m_current_pipeline->GetTopology(), base_vertex, vertex_count); + if (glDrawElementsBaseVertex) [[likely]] + { + glDrawArrays(m_current_pipeline->GetTopology(), base_vertex, vertex_count); + return; + } + + SetVertexBufferOffsets(base_vertex); + glDrawArrays(m_current_pipeline->GetTopology(), 0, vertex_count); } void OpenGLDevice::DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex) { + if (glDrawElementsBaseVertex) [[likely]] + { + const void* indices = reinterpret_cast(static_cast(base_index) * sizeof(u16)); + glDrawElementsBaseVertex(m_current_pipeline->GetTopology(), index_count, GL_UNSIGNED_SHORT, indices, base_vertex); + return; + } + + SetVertexBufferOffsets(base_vertex); + const void* indices = reinterpret_cast(static_cast(base_index) * sizeof(u16)); - glDrawElementsBaseVertex(m_current_pipeline->GetTopology(), index_count, GL_UNSIGNED_SHORT, indices, base_vertex); + glDrawElements(m_current_pipeline->GetTopology(), index_count, GL_UNSIGNED_SHORT, indices); } void OpenGLDevice::MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space, diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index afdb89546..140a76814 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -107,7 +107,7 @@ public: void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id); void UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key); - GLuint LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key); + OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key); GLuint CreateVAO(std::span attributes, u32 stride); void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key); @@ -165,6 +165,8 @@ private: void ApplyDepthState(GPUPipeline::DepthState ds); void ApplyBlendState(GPUPipeline::BlendState bs); + void SetVertexBufferOffsets(u32 base_vertex); + std::unique_ptr m_gl_context; std::unique_ptr m_vertex_buffer; @@ -178,12 +180,12 @@ private: GPUFramebufferManager m_framebuffer_manager; // VAO cache - fixed max as key + OpenGLPipeline::VertexArrayCache::const_iterator m_last_vao = m_vao_cache.cend(); GPUPipeline::BlendState m_last_blend_state = {}; GPUPipeline::RasterizationState m_last_rasterization_state = {}; GPUPipeline::DepthState m_last_depth_state = {}; GLuint m_uniform_buffer_alignment = 1; GLuint m_last_program = 0; - GLuint m_last_vao = 0; u32 m_last_texture_unit = 0; std::array, MAX_TEXTURE_SAMPLERS> m_last_samplers = {}; GLuint m_last_ssbo = 0; diff --git a/src/util/opengl_pipeline.cpp b/src/util/opengl_pipeline.cpp index 4ca522d7b..3d2d3fe92 100644 --- a/src/util/opengl_pipeline.cpp +++ b/src/util/opengl_pipeline.cpp @@ -360,7 +360,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig) { glBindAttribLocation(program_id, i, TinyString::from_format("{}{}", semantic_vars[static_cast(va.semantic.GetValue())], - static_cast(va.semantic_index))); + static_cast(va.semantic_index))); } } @@ -451,13 +451,13 @@ void OpenGLDevice::UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key) m_program_cache.erase(it); } -GLuint OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key) +OpenGLPipeline::VertexArrayCache::const_iterator OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key) { - auto it = m_vao_cache.find(key); + OpenGLPipeline::VertexArrayCache::iterator it = m_vao_cache.find(key); if (it != m_vao_cache.end()) { it->second.reference_count++; - return it->second.vao_id; + return it; } OpenGLPipeline::VertexArrayCacheItem item; @@ -465,11 +465,10 @@ GLuint OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& k CreateVAO(std::span(key.vertex_attributes, key.num_vertex_attributes), key.vertex_attribute_stride); if (item.vao_id == 0) - return 0; + return m_vao_cache.cend(); item.reference_count = 1; - m_vao_cache.emplace(key, item); - return item.vao_id; + return m_vao_cache.emplace(key, item).first; } GLuint OpenGLDevice::CreateVAO(std::span attributes, u32 stride) @@ -518,7 +517,8 @@ GLuint OpenGLDevice::CreateVAO(std::span att glVertexAttribPointer(i, va.components, m.type, m.normalized, stride, ptr); } - glBindVertexArray(m_last_vao); + if (m_last_vao != m_vao_cache.cend()) + glBindVertexArray(m_last_vao->second.vao_id); return vao; } @@ -531,9 +531,9 @@ void OpenGLDevice::UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key) if ((--it->second.reference_count) > 0) return; - if (m_last_vao == it->second.vao_id) + if (m_last_vao == it) { - m_last_vao = 0; + m_last_vao = m_vao_cache.cend(); glBindVertexArray(0); } @@ -541,8 +541,9 @@ void OpenGLDevice::UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key) m_vao_cache.erase(it); } -OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, GLuint vao, const RasterizationState& rs, - const DepthState& ds, const BlendState& bs, GLenum topology) +OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao, + const RasterizationState& rs, const DepthState& ds, const BlendState& bs, + GLenum topology) : m_key(key), m_program(program), m_vao(vao), m_blend_state(bs), m_rasterization_state(rs), m_depth_state(ds), m_topology(topology) { @@ -572,8 +573,8 @@ std::unique_ptr OpenGLDevice::CreatePipeline(const GPUPipeline::Gra if (program_id == 0) return {}; - const GLuint vao_id = LookupVAOCache(pkey.va_key); - if (vao_id == 0) + const OpenGLPipeline::VertexArrayCache::const_iterator vao = LookupVAOCache(pkey.va_key); + if (vao == m_vao_cache.cend()) { UnrefProgram(pkey); return {}; @@ -586,7 +587,7 @@ std::unique_ptr OpenGLDevice::CreatePipeline(const GPUPipeline::Gra GL_TRIANGLE_STRIP, // TriangleStrips }}; - return std::unique_ptr(new OpenGLPipeline(pkey, program_id, vao_id, config.rasterization, config.depth, + return std::unique_ptr(new OpenGLPipeline(pkey, program_id, vao, config.rasterization, config.depth, config.blend, primitives[static_cast(config.primitive)])); } @@ -716,7 +717,7 @@ void OpenGLDevice::SetPipeline(GPUPipeline* pipeline) if (m_last_vao != P->GetVAO()) { m_last_vao = P->GetVAO(); - glBindVertexArray(m_last_vao); + glBindVertexArray(m_last_vao->second.vao_id); } if (m_last_program != P->GetProgram()) { diff --git a/src/util/opengl_pipeline.h b/src/util/opengl_pipeline.h index 72bc3158c..a936c5723 100644 --- a/src/util/opengl_pipeline.h +++ b/src/util/opengl_pipeline.h @@ -97,7 +97,7 @@ public: ~OpenGLPipeline() override; ALWAYS_INLINE GLuint GetProgram() const { return m_program; } - ALWAYS_INLINE GLuint GetVAO() const { return m_vao; } + ALWAYS_INLINE VertexArrayCache::const_iterator GetVAO() const { return m_vao; } ALWAYS_INLINE const RasterizationState& GetRasterizationState() const { return m_rasterization_state; } ALWAYS_INLINE const DepthState& GetDepthState() const { return m_depth_state; } ALWAYS_INLINE const BlendState& GetBlendState() const { return m_blend_state; } @@ -106,12 +106,12 @@ public: void SetDebugName(const std::string_view& name) override; private: - OpenGLPipeline(const ProgramCacheKey& key, GLuint program, GLuint vao, const RasterizationState& rs, - const DepthState& ds, const BlendState& bs, GLenum topology); + OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao, + const RasterizationState& rs, const DepthState& ds, const BlendState& bs, GLenum topology); ProgramCacheKey m_key; + VertexArrayCache::const_iterator m_vao; GLuint m_program; - GLuint m_vao; BlendState m_blend_state; RasterizationState m_rasterization_state; DepthState m_depth_state;