diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_buffer_cache.cpp | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_buffer_cache.h | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_primitive_assembler.cpp | 64 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_primitive_assembler.h | 33 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 146 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 7 |
8 files changed, 236 insertions, 46 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f5ae57039..09ecc5bad 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -27,6 +27,8 @@ add_library(video_core STATIC | |||
| 27 | renderer_base.h | 27 | renderer_base.h |
| 28 | renderer_opengl/gl_buffer_cache.cpp | 28 | renderer_opengl/gl_buffer_cache.cpp |
| 29 | renderer_opengl/gl_buffer_cache.h | 29 | renderer_opengl/gl_buffer_cache.h |
| 30 | renderer_opengl/gl_primitive_assembler.cpp | ||
| 31 | renderer_opengl/gl_primitive_assembler.h | ||
| 30 | renderer_opengl/gl_rasterizer.cpp | 32 | renderer_opengl/gl_rasterizer.cpp |
| 31 | renderer_opengl/gl_rasterizer.h | 33 | renderer_opengl/gl_rasterizer.h |
| 32 | renderer_opengl/gl_rasterizer_cache.cpp | 34 | renderer_opengl/gl_rasterizer_cache.cpp |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 9f5581045..4290da33f 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -744,6 +744,12 @@ public: | |||
| 744 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(end_addr_high) << 32) | | 744 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(end_addr_high) << 32) | |
| 745 | end_addr_low); | 745 | end_addr_low); |
| 746 | } | 746 | } |
| 747 | |||
| 748 | /// Adjust the index buffer offset so it points to the first desired index. | ||
| 749 | GPUVAddr IndexStart() const { | ||
| 750 | return StartAddress() + static_cast<size_t>(first) * | ||
| 751 | static_cast<size_t>(FormatSizeInBytes()); | ||
| 752 | } | ||
| 747 | } index_array; | 753 | } index_array; |
| 748 | 754 | ||
| 749 | INSERT_PADDING_WORDS(0x7); | 755 | INSERT_PADDING_WORDS(0x7); |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 578aca789..c142095c5 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -34,7 +34,7 @@ GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size | |||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | AlignBuffer(alignment); | 36 | AlignBuffer(alignment); |
| 37 | GLintptr uploaded_offset = buffer_offset; | 37 | const GLintptr uploaded_offset = buffer_offset; |
| 38 | 38 | ||
| 39 | Memory::ReadBlock(*cpu_addr, buffer_ptr, size); | 39 | Memory::ReadBlock(*cpu_addr, buffer_ptr, size); |
| 40 | 40 | ||
| @@ -57,13 +57,23 @@ GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, std::size_t s | |||
| 57 | std::size_t alignment) { | 57 | std::size_t alignment) { |
| 58 | AlignBuffer(alignment); | 58 | AlignBuffer(alignment); |
| 59 | std::memcpy(buffer_ptr, raw_pointer, size); | 59 | std::memcpy(buffer_ptr, raw_pointer, size); |
| 60 | GLintptr uploaded_offset = buffer_offset; | 60 | const GLintptr uploaded_offset = buffer_offset; |
| 61 | 61 | ||
| 62 | buffer_ptr += size; | 62 | buffer_ptr += size; |
| 63 | buffer_offset += size; | 63 | buffer_offset += size; |
| 64 | return uploaded_offset; | 64 | return uploaded_offset; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::size_t alignment) { | ||
| 68 | AlignBuffer(alignment); | ||
| 69 | u8* const uploaded_ptr = buffer_ptr; | ||
| 70 | const GLintptr uploaded_offset = buffer_offset; | ||
| 71 | |||
| 72 | buffer_ptr += size; | ||
| 73 | buffer_offset += size; | ||
| 74 | return std::make_tuple(uploaded_ptr, uploaded_offset); | ||
| 75 | } | ||
| 76 | |||
| 67 | void OGLBufferCache::Map(std::size_t max_size) { | 77 | void OGLBufferCache::Map(std::size_t max_size) { |
| 68 | bool invalidate; | 78 | bool invalidate; |
| 69 | std::tie(buffer_ptr, buffer_offset_base, invalidate) = | 79 | std::tie(buffer_ptr, buffer_offset_base, invalidate) = |
| @@ -74,6 +84,7 @@ void OGLBufferCache::Map(std::size_t max_size) { | |||
| 74 | InvalidateAll(); | 84 | InvalidateAll(); |
| 75 | } | 85 | } |
| 76 | } | 86 | } |
| 87 | |||
| 77 | void OGLBufferCache::Unmap() { | 88 | void OGLBufferCache::Unmap() { |
| 78 | stream_buffer.Unmap(buffer_offset - buffer_offset_base); | 89 | stream_buffer.Unmap(buffer_offset - buffer_offset_base); |
| 79 | } | 90 | } |
| @@ -84,7 +95,7 @@ GLuint OGLBufferCache::GetHandle() const { | |||
| 84 | 95 | ||
| 85 | void OGLBufferCache::AlignBuffer(std::size_t alignment) { | 96 | void OGLBufferCache::AlignBuffer(std::size_t alignment) { |
| 86 | // Align the offset, not the mapped pointer | 97 | // Align the offset, not the mapped pointer |
| 87 | GLintptr offset_aligned = | 98 | const GLintptr offset_aligned = |
| 88 | static_cast<GLintptr>(Common::AlignUp(static_cast<std::size_t>(buffer_offset), alignment)); | 99 | static_cast<GLintptr>(Common::AlignUp(static_cast<std::size_t>(buffer_offset), alignment)); |
| 89 | buffer_ptr += offset_aligned - buffer_offset; | 100 | buffer_ptr += offset_aligned - buffer_offset; |
| 90 | buffer_offset = offset_aligned; | 101 | buffer_offset = offset_aligned; |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 6c18461f4..965976334 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <tuple> | ||
| 9 | 10 | ||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | #include "video_core/rasterizer_cache.h" | 12 | #include "video_core/rasterizer_cache.h" |
| @@ -33,11 +34,17 @@ class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBuffer | |||
| 33 | public: | 34 | public: |
| 34 | explicit OGLBufferCache(std::size_t size); | 35 | explicit OGLBufferCache(std::size_t size); |
| 35 | 36 | ||
| 37 | /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been | ||
| 38 | /// allocated. | ||
| 36 | GLintptr UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4, | 39 | GLintptr UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4, |
| 37 | bool cache = true); | 40 | bool cache = true); |
| 38 | 41 | ||
| 42 | /// Uploads from a host memory. Returns host's buffer offset where it's been allocated. | ||
| 39 | GLintptr UploadHostMemory(const void* raw_pointer, std::size_t size, std::size_t alignment = 4); | 43 | GLintptr UploadHostMemory(const void* raw_pointer, std::size_t size, std::size_t alignment = 4); |
| 40 | 44 | ||
| 45 | /// Reserves memory to be used by host's CPU. Returns mapped address and offset. | ||
| 46 | std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); | ||
| 47 | |||
| 41 | void Map(std::size_t max_size); | 48 | void Map(std::size_t max_size); |
| 42 | void Unmap(); | 49 | void Unmap(); |
| 43 | 50 | ||
diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp new file mode 100644 index 000000000..ee1d9601b --- /dev/null +++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <array> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/memory.h" | ||
| 10 | #include "video_core/renderer_opengl/gl_buffer_cache.h" | ||
| 11 | #include "video_core/renderer_opengl/gl_primitive_assembler.h" | ||
| 12 | |||
| 13 | namespace OpenGL { | ||
| 14 | |||
| 15 | constexpr u32 TRIANGLES_PER_QUAD = 6; | ||
| 16 | constexpr std::array<u32, TRIANGLES_PER_QUAD> QUAD_MAP = {0, 1, 2, 0, 2, 3}; | ||
| 17 | |||
| 18 | PrimitiveAssembler::PrimitiveAssembler(OGLBufferCache& buffer_cache) : buffer_cache(buffer_cache) {} | ||
| 19 | |||
| 20 | PrimitiveAssembler::~PrimitiveAssembler() = default; | ||
| 21 | |||
| 22 | std::size_t PrimitiveAssembler::CalculateQuadSize(u32 count) const { | ||
| 23 | ASSERT_MSG(count % 4 == 0, "Quad count is expected to be a multiple of 4"); | ||
| 24 | return (count / 4) * TRIANGLES_PER_QUAD * sizeof(GLuint); | ||
| 25 | } | ||
| 26 | |||
| 27 | GLintptr PrimitiveAssembler::MakeQuadArray(u32 first, u32 count) { | ||
| 28 | const std::size_t size{CalculateQuadSize(count)}; | ||
| 29 | auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(size); | ||
| 30 | |||
| 31 | for (u32 primitive = 0; primitive < count / 4; ++primitive) { | ||
| 32 | for (u32 i = 0; i < TRIANGLES_PER_QUAD; ++i) { | ||
| 33 | const u32 index = first + primitive * 4 + QUAD_MAP[i]; | ||
| 34 | std::memcpy(dst_pointer, &index, sizeof(index)); | ||
| 35 | dst_pointer += sizeof(index); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | return index_offset; | ||
| 40 | } | ||
| 41 | |||
| 42 | GLintptr PrimitiveAssembler::MakeQuadIndexed(Tegra::GPUVAddr gpu_addr, std::size_t index_size, | ||
| 43 | u32 count) { | ||
| 44 | const std::size_t map_size{CalculateQuadSize(count)}; | ||
| 45 | auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(map_size); | ||
| 46 | |||
| 47 | auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); | ||
| 48 | const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; | ||
| 49 | const u8* source{Memory::GetPointer(*cpu_addr)}; | ||
| 50 | |||
| 51 | for (u32 primitive = 0; primitive < count / 4; ++primitive) { | ||
| 52 | for (std::size_t i = 0; i < TRIANGLES_PER_QUAD; ++i) { | ||
| 53 | const u32 index = primitive * 4 + QUAD_MAP[i]; | ||
| 54 | const u8* src_offset = source + (index * index_size); | ||
| 55 | |||
| 56 | std::memcpy(dst_pointer, src_offset, index_size); | ||
| 57 | dst_pointer += index_size; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | return index_offset; | ||
| 62 | } | ||
| 63 | |||
| 64 | } // namespace OpenGL \ No newline at end of file | ||
diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.h b/src/video_core/renderer_opengl/gl_primitive_assembler.h new file mode 100644 index 000000000..a8cb88eb5 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_primitive_assembler.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include <glad/glad.h> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/memory_manager.h" | ||
| 12 | |||
| 13 | namespace OpenGL { | ||
| 14 | |||
| 15 | class OGLBufferCache; | ||
| 16 | |||
| 17 | class PrimitiveAssembler { | ||
| 18 | public: | ||
| 19 | explicit PrimitiveAssembler(OGLBufferCache& buffer_cache); | ||
| 20 | ~PrimitiveAssembler(); | ||
| 21 | |||
| 22 | /// Calculates the size required by MakeQuadArray and MakeQuadIndexed. | ||
| 23 | std::size_t CalculateQuadSize(u32 count) const; | ||
| 24 | |||
| 25 | GLintptr MakeQuadArray(u32 first, u32 count); | ||
| 26 | |||
| 27 | GLintptr MakeQuadIndexed(Tegra::GPUVAddr gpu_addr, std::size_t index_size, u32 count); | ||
| 28 | |||
| 29 | private: | ||
| 30 | OGLBufferCache& buffer_cache; | ||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace OpenGL \ No newline at end of file | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 587d9dffb..60dcdc184 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -42,6 +42,41 @@ MICROPROFILE_DEFINE(OpenGL_Framebuffer, "OpenGL", "Framebuffer Setup", MP_RGB(12 | |||
| 42 | MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); | 42 | MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); |
| 43 | MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192)); | 43 | MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192)); |
| 44 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); | 44 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); |
| 45 | MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100)); | ||
| 46 | |||
| 47 | struct DrawParameters { | ||
| 48 | GLenum primitive_mode; | ||
| 49 | GLsizei count; | ||
| 50 | GLint current_instance; | ||
| 51 | bool use_indexed; | ||
| 52 | |||
| 53 | GLint vertex_first; | ||
| 54 | |||
| 55 | GLenum index_format; | ||
| 56 | GLint base_vertex; | ||
| 57 | GLintptr index_buffer_offset; | ||
| 58 | |||
| 59 | void DispatchDraw() const { | ||
| 60 | if (use_indexed) { | ||
| 61 | const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset); | ||
| 62 | if (current_instance > 0) { | ||
| 63 | glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format, | ||
| 64 | index_buffer_ptr, 1, base_vertex, | ||
| 65 | current_instance); | ||
| 66 | } else { | ||
| 67 | glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr, | ||
| 68 | base_vertex); | ||
| 69 | } | ||
| 70 | } else { | ||
| 71 | if (current_instance > 0) { | ||
| 72 | glDrawArraysInstancedBaseInstance(primitive_mode, vertex_first, count, 1, | ||
| 73 | current_instance); | ||
| 74 | } else { | ||
| 75 | glDrawArrays(primitive_mode, vertex_first, count); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | }; | ||
| 45 | 80 | ||
| 46 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) | 81 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) |
| 47 | : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) { | 82 | : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) { |
| @@ -172,6 +207,53 @@ void RasterizerOpenGL::SetupVertexArrays() { | |||
| 172 | } | 207 | } |
| 173 | } | 208 | } |
| 174 | 209 | ||
| 210 | DrawParameters RasterizerOpenGL::SetupDraw() { | ||
| 211 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | ||
| 212 | const auto& regs = gpu.regs; | ||
| 213 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | ||
| 214 | |||
| 215 | DrawParameters params{}; | ||
| 216 | params.current_instance = gpu.state.current_instance; | ||
| 217 | |||
| 218 | if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) { | ||
| 219 | MICROPROFILE_SCOPE(OpenGL_PrimitiveAssembly); | ||
| 220 | |||
| 221 | params.use_indexed = true; | ||
| 222 | params.primitive_mode = GL_TRIANGLES; | ||
| 223 | |||
| 224 | if (is_indexed) { | ||
| 225 | params.index_format = MaxwellToGL::IndexFormat(regs.index_array.format); | ||
| 226 | params.count = (regs.index_array.count / 4) * 6; | ||
| 227 | params.index_buffer_offset = primitive_assembler.MakeQuadIndexed( | ||
| 228 | regs.index_array.IndexStart(), regs.index_array.FormatSizeInBytes(), | ||
| 229 | regs.index_array.count); | ||
| 230 | params.base_vertex = static_cast<GLint>(regs.vb_element_base); | ||
| 231 | } else { | ||
| 232 | // MakeQuadArray always generates u32 indexes | ||
| 233 | params.index_format = GL_UNSIGNED_INT; | ||
| 234 | params.count = (regs.vertex_buffer.count / 4) * 6; | ||
| 235 | params.index_buffer_offset = | ||
| 236 | primitive_assembler.MakeQuadArray(regs.vertex_buffer.first, params.count); | ||
| 237 | } | ||
| 238 | return params; | ||
| 239 | } | ||
| 240 | |||
| 241 | params.use_indexed = is_indexed; | ||
| 242 | params.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology); | ||
| 243 | |||
| 244 | if (is_indexed) { | ||
| 245 | MICROPROFILE_SCOPE(OpenGL_Index); | ||
| 246 | params.index_format = MaxwellToGL::IndexFormat(regs.index_array.format); | ||
| 247 | params.count = regs.index_array.count; | ||
| 248 | params.index_buffer_offset = | ||
| 249 | buffer_cache.UploadMemory(regs.index_array.IndexStart(), CalculateIndexBufferSize()); | ||
| 250 | params.base_vertex = static_cast<GLint>(regs.vb_element_base); | ||
| 251 | } else { | ||
| 252 | params.count = regs.vertex_buffer.count; | ||
| 253 | params.vertex_first = regs.vertex_buffer.first; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 175 | void RasterizerOpenGL::SetupShaders() { | 257 | void RasterizerOpenGL::SetupShaders() { |
| 176 | MICROPROFILE_SCOPE(OpenGL_Shader); | 258 | MICROPROFILE_SCOPE(OpenGL_Shader); |
| 177 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 259 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| @@ -256,6 +338,13 @@ std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | |||
| 256 | return size; | 338 | return size; |
| 257 | } | 339 | } |
| 258 | 340 | ||
| 341 | std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const { | ||
| 342 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 343 | |||
| 344 | return static_cast<std::size_t>(regs.index_array.count) * | ||
| 345 | static_cast<std::size_t>(regs.index_array.FormatSizeInBytes()); | ||
| 346 | } | ||
| 347 | |||
| 259 | bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { | 348 | bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { |
| 260 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; | 349 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; |
| 261 | DrawArrays(); | 350 | DrawArrays(); |
| @@ -459,16 +548,23 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 459 | 548 | ||
| 460 | // Draw the vertex batch | 549 | // Draw the vertex batch |
| 461 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | 550 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; |
| 462 | const u64 index_buffer_size{static_cast<u64>(regs.index_array.count) * | ||
| 463 | static_cast<u64>(regs.index_array.FormatSizeInBytes())}; | ||
| 464 | 551 | ||
| 465 | state.draw.vertex_buffer = buffer_cache.GetHandle(); | 552 | state.draw.vertex_buffer = buffer_cache.GetHandle(); |
| 466 | state.Apply(); | 553 | state.Apply(); |
| 467 | 554 | ||
| 468 | std::size_t buffer_size = CalculateVertexArraysSize(); | 555 | std::size_t buffer_size = CalculateVertexArraysSize(); |
| 469 | 556 | ||
| 470 | if (is_indexed) { | 557 | // Add space for index buffer (keeping in mind non-core primitives) |
| 471 | buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + index_buffer_size; | 558 | switch (regs.draw.topology) { |
| 559 | case Maxwell::PrimitiveTopology::Quads: | ||
| 560 | buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + | ||
| 561 | primitive_assembler.CalculateQuadSize(regs.vertex_buffer.count); | ||
| 562 | break; | ||
| 563 | default: | ||
| 564 | if (is_indexed) { | ||
| 565 | buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + CalculateIndexBufferSize(); | ||
| 566 | } | ||
| 567 | break; | ||
| 472 | } | 568 | } |
| 473 | 569 | ||
| 474 | // Uniform space for the 5 shader stages | 570 | // Uniform space for the 5 shader stages |
| @@ -482,20 +578,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 482 | buffer_cache.Map(buffer_size); | 578 | buffer_cache.Map(buffer_size); |
| 483 | 579 | ||
| 484 | SetupVertexArrays(); | 580 | SetupVertexArrays(); |
| 485 | 581 | DrawParameters params = SetupDraw(); | |
| 486 | // If indexed mode, copy the index buffer | ||
| 487 | GLintptr index_buffer_offset = 0; | ||
| 488 | if (is_indexed) { | ||
| 489 | MICROPROFILE_SCOPE(OpenGL_Index); | ||
| 490 | |||
| 491 | // Adjust the index buffer offset so it points to the first desired index. | ||
| 492 | auto index_start = regs.index_array.StartAddress(); | ||
| 493 | index_start += static_cast<size_t>(regs.index_array.first) * | ||
| 494 | static_cast<size_t>(regs.index_array.FormatSizeInBytes()); | ||
| 495 | |||
| 496 | index_buffer_offset = buffer_cache.UploadMemory(index_start, index_buffer_size); | ||
| 497 | } | ||
| 498 | |||
| 499 | SetupShaders(); | 582 | SetupShaders(); |
| 500 | 583 | ||
| 501 | buffer_cache.Unmap(); | 584 | buffer_cache.Unmap(); |
| @@ -503,31 +586,8 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 503 | shader_program_manager->ApplyTo(state); | 586 | shader_program_manager->ApplyTo(state); |
| 504 | state.Apply(); | 587 | state.Apply(); |
| 505 | 588 | ||
| 506 | const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)}; | 589 | // Execute draw call |
| 507 | if (is_indexed) { | 590 | params.DispatchDraw(); |
| 508 | const GLint base_vertex{static_cast<GLint>(regs.vb_element_base)}; | ||
| 509 | |||
| 510 | if (gpu.state.current_instance > 0) { | ||
| 511 | glDrawElementsInstancedBaseVertexBaseInstance( | ||
| 512 | primitive_mode, regs.index_array.count, | ||
| 513 | MaxwellToGL::IndexFormat(regs.index_array.format), | ||
| 514 | reinterpret_cast<const void*>(index_buffer_offset), 1, base_vertex, | ||
| 515 | gpu.state.current_instance); | ||
| 516 | } else { | ||
| 517 | glDrawElementsBaseVertex(primitive_mode, regs.index_array.count, | ||
| 518 | MaxwellToGL::IndexFormat(regs.index_array.format), | ||
| 519 | reinterpret_cast<const void*>(index_buffer_offset), | ||
| 520 | base_vertex); | ||
| 521 | } | ||
| 522 | } else { | ||
| 523 | if (gpu.state.current_instance > 0) { | ||
| 524 | glDrawArraysInstancedBaseInstance(primitive_mode, regs.vertex_buffer.first, | ||
| 525 | regs.vertex_buffer.count, 1, | ||
| 526 | gpu.state.current_instance); | ||
| 527 | } else { | ||
| 528 | glDrawArrays(primitive_mode, regs.vertex_buffer.first, regs.vertex_buffer.count); | ||
| 529 | } | ||
| 530 | } | ||
| 531 | 591 | ||
| 532 | // Disable scissor test | 592 | // Disable scissor test |
| 533 | state.scissor.enabled = false; | 593 | state.scissor.enabled = false; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 4c8ecbd1c..bf954bb5d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "video_core/rasterizer_cache.h" | 23 | #include "video_core/rasterizer_cache.h" |
| 24 | #include "video_core/rasterizer_interface.h" | 24 | #include "video_core/rasterizer_interface.h" |
| 25 | #include "video_core/renderer_opengl/gl_buffer_cache.h" | 25 | #include "video_core/renderer_opengl/gl_buffer_cache.h" |
| 26 | #include "video_core/renderer_opengl/gl_primitive_assembler.h" | ||
| 26 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 27 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 27 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 28 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 28 | #include "video_core/renderer_opengl/gl_shader_cache.h" | 29 | #include "video_core/renderer_opengl/gl_shader_cache.h" |
| @@ -38,6 +39,7 @@ class EmuWindow; | |||
| 38 | namespace OpenGL { | 39 | namespace OpenGL { |
| 39 | 40 | ||
| 40 | struct ScreenInfo; | 41 | struct ScreenInfo; |
| 42 | struct DrawParameters; | ||
| 41 | 43 | ||
| 42 | class RasterizerOpenGL : public VideoCore::RasterizerInterface { | 44 | class RasterizerOpenGL : public VideoCore::RasterizerInterface { |
| 43 | public: | 45 | public: |
| @@ -192,12 +194,17 @@ private: | |||
| 192 | static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | 194 | static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |
| 193 | OGLBufferCache buffer_cache; | 195 | OGLBufferCache buffer_cache; |
| 194 | OGLFramebuffer framebuffer; | 196 | OGLFramebuffer framebuffer; |
| 197 | PrimitiveAssembler primitive_assembler{buffer_cache}; | ||
| 195 | GLint uniform_buffer_alignment; | 198 | GLint uniform_buffer_alignment; |
| 196 | 199 | ||
| 197 | std::size_t CalculateVertexArraysSize() const; | 200 | std::size_t CalculateVertexArraysSize() const; |
| 198 | 201 | ||
| 202 | std::size_t CalculateIndexBufferSize() const; | ||
| 203 | |||
| 199 | void SetupVertexArrays(); | 204 | void SetupVertexArrays(); |
| 200 | 205 | ||
| 206 | DrawParameters SetupDraw(); | ||
| 207 | |||
| 201 | void SetupShaders(); | 208 | void SetupShaders(); |
| 202 | 209 | ||
| 203 | enum class AccelDraw { Disabled, Arrays, Indexed }; | 210 | enum class AccelDraw { Disabled, Arrays, Indexed }; |