Sfoglia il codice sorgente

Merge pull request #3057 from ReinUsesLisp/buffer-sub-data

gl_rasterizer: Upload constant buffers with glNamedBufferSubData
bunnei 6 anni fa
parent
commit
468576284d

+ 11 - 3
src/video_core/buffer_cache/buffer_cache.h

@@ -30,7 +30,7 @@ public:
     using BufferInfo = std::pair<const TBufferType*, u64>;
 
     BufferInfo UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
-                            bool is_written = false) {
+                            bool is_written = false, bool use_fast_cbuf = false) {
         std::lock_guard lock{mutex};
 
         auto& memory_manager = system.GPU().MemoryManager();
@@ -43,9 +43,13 @@ public:
         // Cache management is a big overhead, so only cache entries with a given size.
         // TODO: Figure out which size is the best for given games.
         constexpr std::size_t max_stream_size = 0x800;
-        if (size < max_stream_size) {
+        if (use_fast_cbuf || size < max_stream_size) {
             if (!is_written && !IsRegionWritten(cache_addr, cache_addr + size - 1)) {
-                return StreamBufferUpload(host_ptr, size, alignment);
+                if (use_fast_cbuf) {
+                    return ConstBufferUpload(host_ptr, size);
+                } else {
+                    return StreamBufferUpload(host_ptr, size, alignment);
+                }
             }
         }
 
@@ -152,6 +156,10 @@ protected:
     virtual void CopyBlock(const TBuffer& src, const TBuffer& dst, std::size_t src_offset,
                            std::size_t dst_offset, std::size_t size) = 0;
 
+    virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) {
+        return {};
+    }
+
     /// Register an object into the cache
     void Register(const MapInterval& new_map, bool inherit_written = false) {
         const CacheAddr cache_ptr = new_map->GetStart();

+ 27 - 4
src/video_core/renderer_opengl/gl_buffer_cache.cpp

@@ -8,13 +8,17 @@
 
 #include "common/assert.h"
 #include "common/microprofile.h"
+#include "video_core/engines/maxwell_3d.h"
 #include "video_core/rasterizer_interface.h"
 #include "video_core/renderer_opengl/gl_buffer_cache.h"
+#include "video_core/renderer_opengl/gl_device.h"
 #include "video_core/renderer_opengl/gl_rasterizer.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 
 namespace OpenGL {
 
+using Maxwell = Tegra::Engines::Maxwell3D::Regs;
+
 MICROPROFILE_DEFINE(OpenGL_Buffer_Download, "OpenGL", "Buffer Download", MP_RGB(192, 192, 128));
 
 CachedBufferBlock::CachedBufferBlock(CacheAddr cache_addr, const std::size_t size)
@@ -26,11 +30,22 @@ CachedBufferBlock::CachedBufferBlock(CacheAddr cache_addr, const std::size_t siz
 CachedBufferBlock::~CachedBufferBlock() = default;
 
 OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
-                               std::size_t stream_size)
-    : VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>{
-          rasterizer, system, std::make_unique<OGLStreamBuffer>(stream_size, true)} {}
+                               const Device& device, std::size_t stream_size)
+    : GenericBufferCache{rasterizer, system, std::make_unique<OGLStreamBuffer>(stream_size, true)} {
+    if (!device.HasFastBufferSubData()) {
+        return;
+    }
+
+    static constexpr auto size = static_cast<GLsizeiptr>(Maxwell::MaxConstBufferSize);
+    glCreateBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
+    for (const GLuint cbuf : cbufs) {
+        glNamedBufferData(cbuf, size, nullptr, GL_STREAM_DRAW);
+    }
+}
 
-OGLBufferCache::~OGLBufferCache() = default;
+OGLBufferCache::~OGLBufferCache() {
+    glDeleteBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
+}
 
 Buffer OGLBufferCache::CreateBlock(CacheAddr cache_addr, std::size_t size) {
     return std::make_shared<CachedBufferBlock>(cache_addr, size);
@@ -69,4 +84,12 @@ void OGLBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t
                              static_cast<GLsizeiptr>(size));
 }
 
+OGLBufferCache::BufferInfo OGLBufferCache::ConstBufferUpload(const void* raw_pointer,
+                                                             std::size_t size) {
+    DEBUG_ASSERT(cbuf_cursor < std::size(cbufs));
+    const GLuint& cbuf = cbufs[cbuf_cursor++];
+    glNamedBufferSubData(cbuf, 0, static_cast<GLsizeiptr>(size), raw_pointer);
+    return {&cbuf, 0};
+}
+
 } // namespace OpenGL

+ 18 - 2
src/video_core/renderer_opengl/gl_buffer_cache.h

@@ -4,10 +4,12 @@
 
 #pragma once
 
+#include <array>
 #include <memory>
 
 #include "common/common_types.h"
 #include "video_core/buffer_cache/buffer_cache.h"
+#include "video_core/engines/maxwell_3d.h"
 #include "video_core/rasterizer_cache.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 #include "video_core/renderer_opengl/gl_stream_buffer.h"
@@ -18,12 +20,14 @@ class System;
 
 namespace OpenGL {
 
+class Device;
 class OGLStreamBuffer;
 class RasterizerOpenGL;
 
 class CachedBufferBlock;
 
 using Buffer = std::shared_ptr<CachedBufferBlock>;
+using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
 
 class CachedBufferBlock : public VideoCommon::BufferBlock {
 public:
@@ -38,14 +42,18 @@ private:
     OGLBuffer gl_buffer{};
 };
 
-class OGLBufferCache final : public VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer> {
+class OGLBufferCache final : public GenericBufferCache {
 public:
     explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
-                            std::size_t stream_size);
+                            const Device& device, std::size_t stream_size);
     ~OGLBufferCache();
 
     const GLuint* GetEmptyBuffer(std::size_t) override;
 
+    void Acquire() noexcept {
+        cbuf_cursor = 0;
+    }
+
 protected:
     Buffer CreateBlock(CacheAddr cache_addr, std::size_t size) override;
 
@@ -61,6 +69,14 @@ protected:
 
     void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
                    std::size_t dst_offset, std::size_t size) override;
+
+    BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) override;
+
+private:
+    std::size_t cbuf_cursor = 0;
+    std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers *
+                           Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram>
+        cbufs;
 };
 
 } // namespace OpenGL

+ 4 - 0
src/video_core/renderer_opengl/gl_device.cpp

@@ -51,8 +51,11 @@ bool HasExtension(const std::vector<std::string_view>& images, std::string_view
 } // Anonymous namespace
 
 Device::Device() {
+    const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
     const std::vector extensions = GetExtensions();
 
+    const bool is_nvidia = vendor == "NVIDIA Corporation";
+
     uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
     shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
     max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
@@ -64,6 +67,7 @@ Device::Device() {
     has_variable_aoffi = TestVariableAoffi();
     has_component_indexing_bug = TestComponentIndexingBug();
     has_precise_bug = TestPreciseBug();
+    has_fast_buffer_sub_data = is_nvidia;
 
     LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
     LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);

+ 5 - 0
src/video_core/renderer_opengl/gl_device.h

@@ -54,6 +54,10 @@ public:
         return has_precise_bug;
     }
 
+    bool HasFastBufferSubData() const {
+        return has_fast_buffer_sub_data;
+    }
+
 private:
     static bool TestVariableAoffi();
     static bool TestComponentIndexingBug();
@@ -69,6 +73,7 @@ private:
     bool has_variable_aoffi{};
     bool has_component_indexing_bug{};
     bool has_precise_bug{};
+    bool has_fast_buffer_sub_data{};
 };
 
 } // namespace OpenGL

+ 5 - 2
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -67,7 +67,7 @@ static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buf
 RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
                                    ScreenInfo& info)
     : texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device},
-      system{system}, screen_info{info}, buffer_cache{*this, system, STREAM_BUFFER_SIZE} {
+      system{system}, screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
     shader_program_manager = std::make_unique<GLShader::ProgramManager>();
     state.draw.shader_program = 0;
     state.Apply();
@@ -558,6 +558,8 @@ void RasterizerOpenGL::DrawPrelude() {
     SyncPolygonOffset();
     SyncAlphaTest();
 
+    buffer_cache.Acquire();
+
     // Draw the vertex batch
     const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
 
@@ -879,7 +881,8 @@ void RasterizerOpenGL::SetupConstBuffer(const Tegra::Engines::ConstBufferInfo& b
     const std::size_t size = Common::AlignUp(GetConstBufferSize(buffer, entry), sizeof(GLvec4));
 
     const auto alignment = device.GetUniformBufferAlignment();
-    const auto [cbuf, offset] = buffer_cache.UploadMemory(buffer.address, size, alignment);
+    const auto [cbuf, offset] = buffer_cache.UploadMemory(buffer.address, size, alignment, false,
+                                                          device.HasFastBufferSubData());
     bind_ubo_pushbuffer.Push(cbuf, offset, size);
 }