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)
{
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<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));
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,

View file

@ -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<const GPUPipeline::VertexAttribute> 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<GL::Context> m_gl_context;
std::unique_ptr<OpenGLStreamBuffer> m_vertex_buffer;
@ -178,12 +180,12 @@ private:
GPUFramebufferManager<GLuint, CreateFramebuffer, DestroyFramebuffer> 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<std::pair<GLuint, GLuint>, MAX_TEXTURE_SAMPLERS> m_last_samplers = {};
GLuint m_last_ssbo = 0;

View file

@ -360,7 +360,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
{
glBindAttribLocation(program_id, i,
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);
}
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<const GPUPipeline::VertexAttribute>(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<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);
}
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<GPUPipeline> 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<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::Gra
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)]));
}
@ -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())
{

View file

@ -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;