From cdc61ea95a3c101a7c311054e96a8b3e28f98c92 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 23 Oct 2024 22:43:58 +0300 Subject: [PATCH] GL renderer: Add fallback for when driver doesn't provide glDrawRangeElementsBaseVertex (#617) * GL: Add fallback for when driver doesn't provide glDrawRangeElementsBaseVertex * GL: Fix fallback when glDrawRangeElementsBaseVertex is absent --- include/PICA/pica_simd.hpp | 21 +++++++++++++++++++ src/core/renderer_gl/renderer_gl.cpp | 30 ++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/include/PICA/pica_simd.hpp b/include/PICA/pica_simd.hpp index dfd528fc..ae7d04eb 100644 --- a/include/PICA/pica_simd.hpp +++ b/include/PICA/pica_simd.hpp @@ -250,4 +250,25 @@ namespace PICA::IndexBuffer { return analyzePortable(indexBuffer, vertexCount); #endif } + + // In some really unfortunate scenarios (eg Android Studio emulator), we don't have access to glDrawRangeElementsBaseVertex + // So we need to subtract the base vertex index from every index in the index buffer ourselves + // This is not really common, so we do it without SIMD for the moment, just to be able to run on Android Studio + template + void subtractBaseIndex(u8* indexBuffer, u32 indexCount, u16 baseIndex) { + // Calculate the minimum and maximum indices used in the index buffer, so we'll only upload them + if constexpr (useShortIndices) { + u16* indexBuffer16 = reinterpret_cast(indexBuffer); + + for (u32 i = 0; i < indexCount; i++) { + indexBuffer16[i] -= baseIndex; + } + } else { + u8 baseIndex8 = u8(baseIndex); + + for (u32 i = 0; i < indexCount; i++) { + indexBuffer[i] -= baseIndex8; + } + } + } } // namespace PICA::IndexBuffer diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 30f9be91..90b8f910 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -8,6 +8,7 @@ #include "PICA/float_types.hpp" #include "PICA/gpu.hpp" #include "PICA/pica_frag_uniforms.hpp" +#include "PICA/pica_simd.hpp" #include "PICA/regs.hpp" #include "PICA/shader_decompiler.hpp" #include "config.hpp" @@ -192,8 +193,8 @@ void RendererGL::initGraphicsContextInternal() { reset(); // Populate our driver info structure - driverInfo.supportsExtFbFetch = GLAD_GL_EXT_shader_framebuffer_fetch != 0; - driverInfo.supportsArmFbFetch = GLAD_GL_ARM_shader_framebuffer_fetch != 0; + driverInfo.supportsExtFbFetch = (GLAD_GL_EXT_shader_framebuffer_fetch != 0); + driverInfo.supportsArmFbFetch = (GLAD_GL_ARM_shader_framebuffer_fetch != 0); // Initialize the default vertex shader used with shadergen std::string defaultShadergenVSSource = fragShaderGen.getDefaultVertexShader(); @@ -519,10 +520,20 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span v if (performIndexedRender) { // When doing indexed rendering, use glDrawRangeElementsBaseVertex to issue the indexed draw hwIndexBuffer->Bind(); - glDrawRangeElementsBaseVertex( - primitiveTopology, minimumIndex, maximumIndex, GLsizei(vertices.size()), usingShortIndices ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, - hwIndexBufferOffset, -GLint(minimumIndex) - ); + + if (glDrawRangeElementsBaseVertex != nullptr) [[likely]] { + glDrawRangeElementsBaseVertex( + primitiveTopology, minimumIndex, maximumIndex, GLsizei(vertices.size()), usingShortIndices ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, + hwIndexBufferOffset, -GLint(minimumIndex) + ); + } else { + // If glDrawRangeElementsBaseVertex is not available then prepareForDraw will have subtracted the base vertex from the index buffer + // for us, so just use glDrawRangeElements + glDrawRangeElements( + primitiveTopology, 0, GLint(maximumIndex - minimumIndex), GLsizei(vertices.size()), + usingShortIndices ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, hwIndexBufferOffset + ); + } } else { // When doing non-indexed rendering, just use glDrawArrays OpenGL::draw(primitiveTopology, GLsizei(vertices.size())); @@ -1170,6 +1181,13 @@ void RendererGL::accelerateVertexUpload(ShaderUnit& shaderUnit, PICA::DrawAccele hwIndexBufferOffset = reinterpret_cast(usize(indexBufferRes.buffer_offset)); std::memcpy(indexBufferRes.pointer, accel->indexBuffer, indexBufferSize); + // If we don't have glDrawRangeElementsBaseVertex, we must subtract the base index value from our index buffer manually + if (glDrawRangeElementsBaseVertex == nullptr) [[unlikely]] { + const u32 indexCount = regs[PICA::InternalRegs::VertexCountReg]; + usingShortIndices ? PICA::IndexBuffer::subtractBaseIndex((u8*)indexBufferRes.pointer, indexCount, accel->minimumIndex) + : PICA::IndexBuffer::subtractBaseIndex((u8*)indexBufferRes.pointer, indexCount, accel->minimumIndex); + } + hwIndexBuffer->Unmap(indexBufferSize); }