diff options
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 44 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 50 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 27 |
5 files changed, 98 insertions, 28 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 98ed11ec5..0e1d6d785 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -165,6 +165,7 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 165 | void Maxwell3D::DrawArrays() { | 165 | void Maxwell3D::DrawArrays() { |
| 166 | LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(), | 166 | LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(), |
| 167 | regs.vertex_buffer.count); | 167 | regs.vertex_buffer.count); |
| 168 | ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 168 | 169 | ||
| 169 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); | 170 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); |
| 170 | 171 | ||
| @@ -176,7 +177,8 @@ void Maxwell3D::DrawArrays() { | |||
| 176 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); | 177 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/); | 180 | const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count}; |
| 181 | VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed); | ||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { | 184 | void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 1fae41cb2..2b45ffed7 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -248,6 +248,12 @@ public: | |||
| 248 | Patches = 0xe, | 248 | Patches = 0xe, |
| 249 | }; | 249 | }; |
| 250 | 250 | ||
| 251 | enum class IndexFormat : u32 { | ||
| 252 | UnsignedByte = 0x0, | ||
| 253 | UnsignedShort = 0x1, | ||
| 254 | UnsignedInt = 0x2, | ||
| 255 | }; | ||
| 256 | |||
| 251 | union { | 257 | union { |
| 252 | struct { | 258 | struct { |
| 253 | INSERT_PADDING_WORDS(0x200); | 259 | INSERT_PADDING_WORDS(0x200); |
| @@ -375,7 +381,42 @@ public: | |||
| 375 | }; | 381 | }; |
| 376 | } draw; | 382 | } draw; |
| 377 | 383 | ||
| 378 | INSERT_PADDING_WORDS(0x139); | 384 | INSERT_PADDING_WORDS(0x6B); |
| 385 | |||
| 386 | struct { | ||
| 387 | u32 start_addr_high; | ||
| 388 | u32 start_addr_low; | ||
| 389 | u32 end_addr_high; | ||
| 390 | u32 end_addr_low; | ||
| 391 | IndexFormat format; | ||
| 392 | u32 first; | ||
| 393 | u32 count; | ||
| 394 | |||
| 395 | unsigned FormatSizeInBytes() const { | ||
| 396 | switch (format) { | ||
| 397 | case IndexFormat::UnsignedByte: | ||
| 398 | return 1; | ||
| 399 | case IndexFormat::UnsignedShort: | ||
| 400 | return 2; | ||
| 401 | case IndexFormat::UnsignedInt: | ||
| 402 | return 4; | ||
| 403 | } | ||
| 404 | UNREACHABLE(); | ||
| 405 | } | ||
| 406 | |||
| 407 | GPUVAddr StartAddress() const { | ||
| 408 | return static_cast<GPUVAddr>( | ||
| 409 | (static_cast<GPUVAddr>(start_addr_high) << 32) | start_addr_low); | ||
| 410 | } | ||
| 411 | |||
| 412 | GPUVAddr EndAddress() const { | ||
| 413 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(end_addr_high) << 32) | | ||
| 414 | end_addr_low); | ||
| 415 | } | ||
| 416 | } index_array; | ||
| 417 | |||
| 418 | INSERT_PADDING_WORDS(0xC7); | ||
| 419 | |||
| 379 | struct { | 420 | struct { |
| 380 | u32 query_address_high; | 421 | u32 query_address_high; |
| 381 | u32 query_address_low; | 422 | u32 query_address_low; |
| @@ -572,6 +613,7 @@ ASSERT_REG_POSITION(tsc, 0x557); | |||
| 572 | ASSERT_REG_POSITION(tic, 0x55D); | 613 | ASSERT_REG_POSITION(tic, 0x55D); |
| 573 | ASSERT_REG_POSITION(code_address, 0x582); | 614 | ASSERT_REG_POSITION(code_address, 0x582); |
| 574 | ASSERT_REG_POSITION(draw, 0x585); | 615 | ASSERT_REG_POSITION(draw, 0x585); |
| 616 | ASSERT_REG_POSITION(index_array, 0x5F2); | ||
| 575 | ASSERT_REG_POSITION(query, 0x6C0); | 617 | ASSERT_REG_POSITION(query, 0x6C0); |
| 576 | ASSERT_REG_POSITION(vertex_array[0], 0x700); | 618 | ASSERT_REG_POSITION(vertex_array[0], 0x700); |
| 577 | ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); | 619 | ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 28abc563a..75b4031a7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -97,7 +97,6 @@ RasterizerOpenGL::RasterizerOpenGL() { | |||
| 97 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | 97 | state.draw.vertex_buffer = stream_buffer->GetHandle(); |
| 98 | 98 | ||
| 99 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); | 99 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
| 100 | |||
| 101 | state.draw.shader_program = 0; | 100 | state.draw.shader_program = 0; |
| 102 | state.draw.vertex_array = hw_vao.handle; | 101 | state.draw.vertex_array = hw_vao.handle; |
| 103 | state.Apply(); | 102 | state.Apply(); |
| @@ -128,17 +127,6 @@ RasterizerOpenGL::~RasterizerOpenGL() { | |||
| 128 | } | 127 | } |
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) { | ||
| 132 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | ||
| 133 | |||
| 134 | if (is_indexed) { | ||
| 135 | UNREACHABLE(); | ||
| 136 | } | ||
| 137 | |||
| 138 | // TODO(bunnei): Add support for 1+ vertex arrays | ||
| 139 | vs_input_size = regs.vertex_buffer.count * regs.vertex_array[0].stride; | ||
| 140 | } | ||
| 141 | |||
| 142 | void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { | 130 | void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { |
| 143 | MICROPROFILE_SCOPE(OpenGL_VAO); | 131 | MICROPROFILE_SCOPE(OpenGL_VAO); |
| 144 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 132 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| @@ -150,6 +138,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { | |||
| 150 | 138 | ||
| 151 | // TODO(bunnei): Add support for 1+ vertex arrays | 139 | // TODO(bunnei): Add support for 1+ vertex arrays |
| 152 | const auto& vertex_array{regs.vertex_array[0]}; | 140 | const auto& vertex_array{regs.vertex_array[0]}; |
| 141 | const auto& vertex_array_limit{regs.vertex_array_limit[0]}; | ||
| 153 | ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?"); | 142 | ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?"); |
| 154 | ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!"); | 143 | ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!"); |
| 155 | for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) { | 144 | for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) { |
| @@ -162,6 +151,10 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { | |||
| 162 | // to avoid OpenGL errors. | 151 | // to avoid OpenGL errors. |
| 163 | for (unsigned index = 0; index < 16; ++index) { | 152 | for (unsigned index = 0; index < 16; ++index) { |
| 164 | auto& attrib = regs.vertex_attrib_format[index]; | 153 | auto& attrib = regs.vertex_attrib_format[index]; |
| 154 | NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", | ||
| 155 | index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), | ||
| 156 | attrib.offset.Value(), attrib.IsNormalized()); | ||
| 157 | |||
| 165 | glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), | 158 | glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), |
| 166 | attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride, | 159 | attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride, |
| 167 | reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset)); | 160 | reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset)); |
| @@ -170,7 +163,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { | |||
| 170 | } | 163 | } |
| 171 | 164 | ||
| 172 | // Copy vertex array data | 165 | // Copy vertex array data |
| 173 | const u32 data_size{vertex_array.stride * regs.vertex_buffer.count}; | 166 | const u64 data_size{vertex_array_limit.LimitAddress() - vertex_array.StartAddress() + 1}; |
| 174 | const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())}; | 167 | const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())}; |
| 175 | res_cache.FlushRegion(data_addr, data_size, nullptr); | 168 | res_cache.FlushRegion(data_addr, data_size, nullptr); |
| 176 | Memory::ReadBlock(data_addr, array_ptr, data_size); | 169 | Memory::ReadBlock(data_addr, array_ptr, data_size); |
| @@ -333,13 +326,18 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 333 | 326 | ||
| 334 | // Draw the vertex batch | 327 | // Draw the vertex batch |
| 335 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | 328 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; |
| 336 | AnalyzeVertexArray(is_indexed); | 329 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; |
| 330 | const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count}; | ||
| 331 | |||
| 332 | // TODO(bunnei): Add support for 1+ vertex arrays | ||
| 333 | vs_input_size = vertex_num * regs.vertex_array[0].stride; | ||
| 334 | |||
| 337 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | 335 | state.draw.vertex_buffer = stream_buffer->GetHandle(); |
| 338 | state.Apply(); | 336 | state.Apply(); |
| 339 | 337 | ||
| 340 | size_t buffer_size = static_cast<size_t>(vs_input_size); | 338 | size_t buffer_size = static_cast<size_t>(vs_input_size); |
| 341 | if (is_indexed) { | 339 | if (is_indexed) { |
| 342 | UNREACHABLE(); | 340 | buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size; |
| 343 | } | 341 | } |
| 344 | 342 | ||
| 345 | // Uniform space for the 5 shader stages | 343 | // Uniform space for the 5 shader stages |
| @@ -354,9 +352,18 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 354 | SetupVertexArray(buffer_ptr, buffer_offset); | 352 | SetupVertexArray(buffer_ptr, buffer_offset); |
| 355 | ptr_pos += vs_input_size; | 353 | ptr_pos += vs_input_size; |
| 356 | 354 | ||
| 355 | // If indexed mode, copy the index buffer | ||
| 357 | GLintptr index_buffer_offset = 0; | 356 | GLintptr index_buffer_offset = 0; |
| 358 | if (is_indexed) { | 357 | if (is_indexed) { |
| 359 | UNREACHABLE(); | 358 | ptr_pos = Common::AlignUp(ptr_pos, 4); |
| 359 | |||
| 360 | const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; | ||
| 361 | const VAddr index_data_addr{ | ||
| 362 | memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())}; | ||
| 363 | Memory::ReadBlock(index_data_addr, &buffer_ptr[ptr_pos], index_buffer_size); | ||
| 364 | |||
| 365 | index_buffer_offset = buffer_offset + static_cast<GLintptr>(ptr_pos); | ||
| 366 | ptr_pos += index_buffer_size; | ||
| 360 | } | 367 | } |
| 361 | 368 | ||
| 362 | SetupShaders(buffer_ptr, buffer_offset, ptr_pos); | 369 | SetupShaders(buffer_ptr, buffer_offset, ptr_pos); |
| @@ -366,11 +373,16 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 366 | shader_program_manager->ApplyTo(state); | 373 | shader_program_manager->ApplyTo(state); |
| 367 | state.Apply(); | 374 | state.Apply(); |
| 368 | 375 | ||
| 376 | const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)}; | ||
| 369 | if (is_indexed) { | 377 | if (is_indexed) { |
| 370 | UNREACHABLE(); | 378 | const GLint index_min{static_cast<GLint>(regs.index_array.first)}; |
| 379 | const GLint index_max{static_cast<GLint>(regs.index_array.first + regs.index_array.count)}; | ||
| 380 | glDrawRangeElementsBaseVertex(primitive_mode, index_min, index_max, regs.index_array.count, | ||
| 381 | MaxwellToGL::IndexFormat(regs.index_array.format), | ||
| 382 | reinterpret_cast<const void*>(index_buffer_offset), | ||
| 383 | -index_min); | ||
| 371 | } else { | 384 | } else { |
| 372 | glDrawArrays(MaxwellToGL::PrimitiveTopology(regs.draw.topology), 0, | 385 | glDrawArrays(primitive_mode, 0, regs.vertex_buffer.count); |
| 373 | regs.vertex_buffer.count); | ||
| 374 | } | 386 | } |
| 375 | 387 | ||
| 376 | // Disable scissor test | 388 | // Disable scissor test |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 548ce0453..fb5d99ba2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -155,7 +155,6 @@ private: | |||
| 155 | 155 | ||
| 156 | GLsizeiptr vs_input_size; | 156 | GLsizeiptr vs_input_size; |
| 157 | 157 | ||
| 158 | void AnalyzeVertexArray(bool is_indexed); | ||
| 159 | void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset); | 158 | void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset); |
| 160 | 159 | ||
| 161 | std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers; | 160 | std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers; |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 7909dcfc3..632d14b78 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -31,7 +31,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 31 | return GL_UNSIGNED_BYTE; | 31 | return GL_UNSIGNED_BYTE; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size=%s", attrib.SizeString().c_str()); | 34 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); |
| 35 | UNREACHABLE(); | 35 | UNREACHABLE(); |
| 36 | return {}; | 36 | return {}; |
| 37 | } | 37 | } |
| @@ -40,7 +40,21 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 40 | return GL_FLOAT; | 40 | return GL_FLOAT; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type=%s", attrib.TypeString().c_str()); | 43 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); |
| 44 | UNREACHABLE(); | ||
| 45 | return {}; | ||
| 46 | } | ||
| 47 | |||
| 48 | inline GLenum IndexFormat(Maxwell::IndexFormat index_format) { | ||
| 49 | switch (index_format) { | ||
| 50 | case Maxwell::IndexFormat::UnsignedByte: | ||
| 51 | return GL_UNSIGNED_BYTE; | ||
| 52 | case Maxwell::IndexFormat::UnsignedShort: | ||
| 53 | return GL_UNSIGNED_SHORT; | ||
| 54 | case Maxwell::IndexFormat::UnsignedInt: | ||
| 55 | return GL_UNSIGNED_INT; | ||
| 56 | } | ||
| 57 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented index_format={}", static_cast<u32>(index_format)); | ||
| 44 | UNREACHABLE(); | 58 | UNREACHABLE(); |
| 45 | return {}; | 59 | return {}; |
| 46 | } | 60 | } |
| @@ -52,7 +66,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | |||
| 52 | case Maxwell::PrimitiveTopology::TriangleStrip: | 66 | case Maxwell::PrimitiveTopology::TriangleStrip: |
| 53 | return GL_TRIANGLE_STRIP; | 67 | return GL_TRIANGLE_STRIP; |
| 54 | } | 68 | } |
| 55 | LOG_CRITICAL(Render_OpenGL, "Unimplemented primitive topology=%d", topology); | 69 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology)); |
| 56 | UNREACHABLE(); | 70 | UNREACHABLE(); |
| 57 | return {}; | 71 | return {}; |
| 58 | } | 72 | } |
| @@ -64,8 +78,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { | |||
| 64 | case Tegra::Texture::TextureFilter::Nearest: | 78 | case Tegra::Texture::TextureFilter::Nearest: |
| 65 | return GL_NEAREST; | 79 | return GL_NEAREST; |
| 66 | } | 80 | } |
| 67 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u", | 81 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", |
| 68 | static_cast<u32>(filter_mode)); | 82 | static_cast<u32>(filter_mode)); |
| 69 | UNREACHABLE(); | 83 | UNREACHABLE(); |
| 70 | return {}; | 84 | return {}; |
| 71 | } | 85 | } |
| @@ -75,7 +89,8 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | |||
| 75 | case Tegra::Texture::WrapMode::ClampToEdge: | 89 | case Tegra::Texture::WrapMode::ClampToEdge: |
| 76 | return GL_CLAMP_TO_EDGE; | 90 | return GL_CLAMP_TO_EDGE; |
| 77 | } | 91 | } |
| 78 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode)); | 92 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", |
| 93 | static_cast<u32>(wrap_mode)); | ||
| 79 | UNREACHABLE(); | 94 | UNREACHABLE(); |
| 80 | return {}; | 95 | return {}; |
| 81 | } | 96 | } |