OpenGLDevice: Work around lack of base_vertex in GLES3.1

This commit is contained in:
Stenzek 2023-12-28 18:22:12 +10:00
parent e60654de38
commit 344d2ccd5d
No known key found for this signature in database
4 changed files with 54 additions and 24 deletions

View file

@ -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<GLsizei>(stride));
}
}
void OpenGLDevice::Draw(u32 vertex_count, u32 base_vertex) 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) void OpenGLDevice::DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex)
{ {
if (glDrawElementsBaseVertex) [[likely]]
{
const void* indices = reinterpret_cast<const void*>(static_cast<uintptr_t>(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<const void*>(static_cast<uintptr_t>(base_index) * sizeof(u16)); const void* indices = reinterpret_cast<const void*>(static_cast<uintptr_t>(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, void OpenGLDevice::MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space,

View file

@ -107,7 +107,7 @@ public:
void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id); void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id);
void UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key); 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<const GPUPipeline::VertexAttribute> attributes, u32 stride); GLuint CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride);
void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key); void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key);
@ -165,6 +165,8 @@ private:
void ApplyDepthState(GPUPipeline::DepthState ds); void ApplyDepthState(GPUPipeline::DepthState ds);
void ApplyBlendState(GPUPipeline::BlendState bs); void ApplyBlendState(GPUPipeline::BlendState bs);
void SetVertexBufferOffsets(u32 base_vertex);
std::unique_ptr<GL::Context> m_gl_context; std::unique_ptr<GL::Context> m_gl_context;
std::unique_ptr<OpenGLStreamBuffer> m_vertex_buffer; std::unique_ptr<OpenGLStreamBuffer> m_vertex_buffer;
@ -178,12 +180,12 @@ private:
GPUFramebufferManager<GLuint, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager; GPUFramebufferManager<GLuint, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager;
// VAO cache - fixed max as key // VAO cache - fixed max as key
OpenGLPipeline::VertexArrayCache::const_iterator m_last_vao = m_vao_cache.cend();
GPUPipeline::BlendState m_last_blend_state = {}; GPUPipeline::BlendState m_last_blend_state = {};
GPUPipeline::RasterizationState m_last_rasterization_state = {}; GPUPipeline::RasterizationState m_last_rasterization_state = {};
GPUPipeline::DepthState m_last_depth_state = {}; GPUPipeline::DepthState m_last_depth_state = {};
GLuint m_uniform_buffer_alignment = 1; GLuint m_uniform_buffer_alignment = 1;
GLuint m_last_program = 0; GLuint m_last_program = 0;
GLuint m_last_vao = 0;
u32 m_last_texture_unit = 0; u32 m_last_texture_unit = 0;
std::array<std::pair<GLuint, GLuint>, MAX_TEXTURE_SAMPLERS> m_last_samplers = {}; std::array<std::pair<GLuint, GLuint>, MAX_TEXTURE_SAMPLERS> m_last_samplers = {};
GLuint m_last_ssbo = 0; GLuint m_last_ssbo = 0;

View file

@ -360,7 +360,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
{ {
glBindAttribLocation(program_id, i, glBindAttribLocation(program_id, i,
TinyString::from_format("{}{}", semantic_vars[static_cast<u8>(va.semantic.GetValue())], TinyString::from_format("{}{}", semantic_vars[static_cast<u8>(va.semantic.GetValue())],
static_cast<u8>(va.semantic_index))); static_cast<u8>(va.semantic_index)));
} }
} }
@ -451,13 +451,13 @@ void OpenGLDevice::UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key)
m_program_cache.erase(it); 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()) if (it != m_vao_cache.end())
{ {
it->second.reference_count++; it->second.reference_count++;
return it->second.vao_id; return it;
} }
OpenGLPipeline::VertexArrayCacheItem item; OpenGLPipeline::VertexArrayCacheItem item;
@ -465,11 +465,10 @@ GLuint OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& k
CreateVAO(std::span<const GPUPipeline::VertexAttribute>(key.vertex_attributes, key.num_vertex_attributes), CreateVAO(std::span<const GPUPipeline::VertexAttribute>(key.vertex_attributes, key.num_vertex_attributes),
key.vertex_attribute_stride); key.vertex_attribute_stride);
if (item.vao_id == 0) if (item.vao_id == 0)
return 0; return m_vao_cache.cend();
item.reference_count = 1; item.reference_count = 1;
m_vao_cache.emplace(key, item); return m_vao_cache.emplace(key, item).first;
return item.vao_id;
} }
GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride) GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride)
@ -518,7 +517,8 @@ GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> att
glVertexAttribPointer(i, va.components, m.type, m.normalized, stride, ptr); 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; return vao;
} }
@ -531,9 +531,9 @@ void OpenGLDevice::UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key)
if ((--it->second.reference_count) > 0) if ((--it->second.reference_count) > 0)
return; 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); glBindVertexArray(0);
} }
@ -541,8 +541,9 @@ void OpenGLDevice::UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key)
m_vao_cache.erase(it); m_vao_cache.erase(it);
} }
OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, GLuint vao, const RasterizationState& rs, OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao,
const DepthState& ds, const BlendState& bs, GLenum topology) 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_key(key), m_program(program), m_vao(vao), m_blend_state(bs), m_rasterization_state(rs), m_depth_state(ds),
m_topology(topology) m_topology(topology)
{ {
@ -572,8 +573,8 @@ std::unique_ptr<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::Gra
if (program_id == 0) if (program_id == 0)
return {}; return {};
const GLuint vao_id = LookupVAOCache(pkey.va_key); const OpenGLPipeline::VertexArrayCache::const_iterator vao = LookupVAOCache(pkey.va_key);
if (vao_id == 0) if (vao == m_vao_cache.cend())
{ {
UnrefProgram(pkey); UnrefProgram(pkey);
return {}; return {};
@ -586,7 +587,7 @@ std::unique_ptr<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::Gra
GL_TRIANGLE_STRIP, // TriangleStrips GL_TRIANGLE_STRIP, // TriangleStrips
}}; }};
return std::unique_ptr<GPUPipeline>(new OpenGLPipeline(pkey, program_id, vao_id, config.rasterization, config.depth, return std::unique_ptr<GPUPipeline>(new OpenGLPipeline(pkey, program_id, vao, config.rasterization, config.depth,
config.blend, primitives[static_cast<u8>(config.primitive)])); config.blend, primitives[static_cast<u8>(config.primitive)]));
} }
@ -716,7 +717,7 @@ void OpenGLDevice::SetPipeline(GPUPipeline* pipeline)
if (m_last_vao != P->GetVAO()) if (m_last_vao != P->GetVAO())
{ {
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()) if (m_last_program != P->GetProgram())
{ {

View file

@ -97,7 +97,7 @@ public:
~OpenGLPipeline() override; ~OpenGLPipeline() override;
ALWAYS_INLINE GLuint GetProgram() const { return m_program; } 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 RasterizationState& GetRasterizationState() const { return m_rasterization_state; }
ALWAYS_INLINE const DepthState& GetDepthState() const { return m_depth_state; } ALWAYS_INLINE const DepthState& GetDepthState() const { return m_depth_state; }
ALWAYS_INLINE const BlendState& GetBlendState() const { return m_blend_state; } ALWAYS_INLINE const BlendState& GetBlendState() const { return m_blend_state; }
@ -106,12 +106,12 @@ public:
void SetDebugName(const std::string_view& name) override; void SetDebugName(const std::string_view& name) override;
private: private:
OpenGLPipeline(const ProgramCacheKey& key, GLuint program, GLuint vao, const RasterizationState& rs, OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao,
const DepthState& ds, const BlendState& bs, GLenum topology); const RasterizationState& rs, const DepthState& ds, const BlendState& bs, GLenum topology);
ProgramCacheKey m_key; ProgramCacheKey m_key;
VertexArrayCache::const_iterator m_vao;
GLuint m_program; GLuint m_program;
GLuint m_vao;
BlendState m_blend_state; BlendState m_blend_state;
RasterizationState m_rasterization_state; RasterizationState m_rasterization_state;
DepthState m_depth_state; DepthState m_depth_state;