diff --git a/include/PICA/pica_simd.hpp b/include/PICA/pica_simd.hpp index dfd528fc..c315f8b5 100644 --- a/include/PICA/pica_simd.hpp +++ b/include/PICA/pica_simd.hpp @@ -250,4 +250,25 @@ namespace PICA::IndexBuffer { return analyzePortable<useShortIndices>(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 <bool useShortIndices> + void subtractBaseIndex(u8* indexBuffer, u32 vertexCount, 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<u16*>(indexBuffer); + + for (u32 i = 0; i < vertexCount; i++) { + indexBuffer16[i] -= baseIndex; + } + } else { + u8 baseIndex8 = u8(baseIndex); + + for (u32 i = 0; i < vertexCount; i++) { + indexBuffer[i] -= baseIndex8; + } + } + } } // namespace PICA::IndexBuffer diff --git a/include/renderer_gl/gl_driver.hpp b/include/renderer_gl/gl_driver.hpp index a15c061f..c7109b01 100644 --- a/include/renderer_gl/gl_driver.hpp +++ b/include/renderer_gl/gl_driver.hpp @@ -6,6 +6,8 @@ namespace OpenGL { struct Driver { bool supportsExtFbFetch = false; bool supportsArmFbFetch = false; + // Does this driver support glDraw(Range)ElementsBaseVertex? + bool supportsDrawElementsBaseVertex = false; bool supportFbFetch() const { return supportsExtFbFetch || supportsArmFbFetch; } }; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 30f9be91..ba051615 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,9 @@ 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); + driverInfo.supportsDrawElementsBaseVertex = (glDrawRangeElementsBaseVertex != nullptr); // Initialize the default vertex shader used with shadergen std::string defaultShadergenVSSource = fragShaderGen.getDefaultVertexShader(); @@ -519,10 +521,20 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> 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, 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 +1182,12 @@ void RendererGL::accelerateVertexUpload(ShaderUnit& shaderUnit, PICA::DrawAccele hwIndexBufferOffset = reinterpret_cast<void*>(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 (!driverInfo.supportsDrawElementsBaseVertex) [[unlikely]] { + usingShortIndices ? PICA::IndexBuffer::subtractBaseIndex<true>((u8*)indexBufferRes.pointer, vertexCount, accel->minimumIndex) + : PICA::IndexBuffer::subtractBaseIndex<false>((u8*)indexBufferRes.pointer, vertexCount, accel->minimumIndex); + } + hwIndexBuffer->Unmap(indexBufferSize); }