From 010227e1490c01484903d4e9cf9038e74906ec7c Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 10:50:28 -0500 Subject: GPU: Implement the RGB10_A2 RenderTarget format, it will use the same format as the A2BGR10 texture format. --- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index e4cb3390f..bf0fabb29 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -106,6 +106,8 @@ struct SurfaceParams { switch (format) { case Tegra::RenderTargetFormat::RGBA8_UNORM: return PixelFormat::ABGR8; + case Tegra::RenderTargetFormat::RGB10_A2_UNORM: + return PixelFormat::A2B10G10R10; default: NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); -- cgit v1.2.3 From f823c1d5991657a3d91f97c345e1f01a1162fca7 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 10:57:12 -0500 Subject: GPU: Make the GPU virtual memory manager use 16 page bits and 10 page table bits. Also removed some dead code and added memory map consistency asserts. --- src/video_core/memory_manager.cpp | 53 +++++++++++++++------------------------ src/video_core/memory_manager.h | 6 ++++- 2 files changed, 25 insertions(+), 34 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 2789a4ca1..2e1edee03 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/alignment.h" #include "common/assert.h" #include "video_core/memory_manager.h" @@ -11,7 +12,8 @@ PAddr MemoryManager::AllocateSpace(u64 size, u64 align) { boost::optional paddr = FindFreeBlock(size, align); ASSERT(paddr); - for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) { + for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { + ASSERT(PageSlot(*paddr + offset) == static_cast(PageStatus::Unmapped)); PageSlot(*paddr + offset) = static_cast(PageStatus::Allocated); } @@ -19,13 +21,8 @@ PAddr MemoryManager::AllocateSpace(u64 size, u64 align) { } PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) { - for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) { - if (IsPageMapped(paddr + offset)) { - return AllocateSpace(size, align); - } - } - - for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) { + for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { + ASSERT(PageSlot(paddr + offset) == static_cast(PageStatus::Unmapped)); PageSlot(paddr + offset) = static_cast(PageStatus::Allocated); } @@ -33,12 +30,11 @@ PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) { } PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) { - vaddr &= ~Memory::PAGE_MASK; - - boost::optional paddr = FindFreeBlock(size); + boost::optional paddr = FindFreeBlock(size, PAGE_SIZE); ASSERT(paddr); - for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) { + for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { + ASSERT(PageSlot(*paddr + offset) == static_cast(PageStatus::Unmapped)); PageSlot(*paddr + offset) = vaddr + offset; } @@ -46,16 +42,10 @@ PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) { } PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) { - vaddr &= ~Memory::PAGE_MASK; - paddr &= ~Memory::PAGE_MASK; + ASSERT((paddr & PAGE_MASK) == 0); - for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) { - if (PageSlot(paddr + offset) != static_cast(PageStatus::Allocated)) { - return MapBufferEx(vaddr, size); - } - } - - for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) { + for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { + ASSERT(PageSlot(paddr + offset) == static_cast(PageStatus::Allocated)); PageSlot(paddr + offset) = vaddr + offset; } @@ -63,23 +53,20 @@ PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) { } boost::optional MemoryManager::FindFreeBlock(u64 size, u64 align) { - PAddr paddr{}; - u64 free_space{}; - align = (align + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; + PAddr paddr = 0; + u64 free_space = 0; + align = (align + PAGE_MASK) & ~PAGE_MASK; while (paddr + free_space < MAX_ADDRESS) { if (!IsPageMapped(paddr + free_space)) { - free_space += Memory::PAGE_SIZE; + free_space += PAGE_SIZE; if (free_space >= size) { return paddr; } } else { - paddr += free_space + Memory::PAGE_SIZE; + paddr += free_space + PAGE_SIZE; free_space = 0; - const u64 remainder{paddr % align}; - if (!remainder) { - paddr = (paddr - remainder) + align; - } + paddr = Common::AlignUp(paddr, align); } } @@ -89,7 +76,7 @@ boost::optional MemoryManager::FindFreeBlock(u64 size, u64 align) { VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) { VAddr base_addr = PageSlot(paddr); ASSERT(base_addr != static_cast(PageStatus::Unmapped)); - return base_addr + (paddr & Memory::PAGE_MASK); + return base_addr + (paddr & PAGE_MASK); } bool MemoryManager::IsPageMapped(PAddr paddr) { @@ -97,14 +84,14 @@ bool MemoryManager::IsPageMapped(PAddr paddr) { } VAddr& MemoryManager::PageSlot(PAddr paddr) { - auto& block = page_table[(paddr >> (Memory::PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; + auto& block = page_table[(paddr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; if (!block) { block = std::make_unique(); for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) { (*block)[index] = static_cast(PageStatus::Unmapped); } } - return (*block)[(paddr >> Memory::PAGE_BITS) & PAGE_BLOCK_MASK]; + return (*block)[(paddr >> PAGE_BITS) & PAGE_BLOCK_MASK]; } } // namespace Tegra diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 47da7acd6..b73e283f8 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -24,6 +24,10 @@ public: PAddr MapBufferEx(VAddr vaddr, PAddr paddr, u64 size); VAddr PhysicalToVirtualAddress(PAddr paddr); + static constexpr u64 PAGE_BITS = 16; + static constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; + static constexpr u64 PAGE_MASK = PAGE_SIZE - 1; + private: boost::optional FindFreeBlock(u64 size, u64 align = 1); bool IsPageMapped(PAddr paddr); @@ -35,7 +39,7 @@ private: }; static constexpr u64 MAX_ADDRESS{0x10000000000ULL}; - static constexpr u64 PAGE_TABLE_BITS{14}; + static constexpr u64 PAGE_TABLE_BITS{10}; static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS}; static constexpr u64 PAGE_TABLE_MASK{PAGE_TABLE_SIZE - 1}; static constexpr u64 PAGE_BLOCK_BITS{14}; -- cgit v1.2.3 From 9531a2928369bcc094c28b77408811d47c46c7f2 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 21 Apr 2018 19:19:33 -0500 Subject: GPU: Support multiple enabled vertex arrays. The vertex arrays will be copied to the stream buffer one after the other, and the attributes will be set using the ARB_vertex_attrib_binding extension. yuzu now thus requires OpenGL 4.3 or the ARB_vertex_attrib_binding extension. --- src/video_core/engines/maxwell_3d.h | 5 + src/video_core/renderer_opengl/gl_rasterizer.cpp | 121 +++++++++++++++-------- src/video_core/renderer_opengl/gl_rasterizer.h | 6 +- 3 files changed, 89 insertions(+), 43 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index d4fcedace..609504795 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -500,6 +500,11 @@ public: return static_cast((static_cast(start_high) << 32) | start_low); } + + bool IsEnabled() const { + return enable != 0 && StartAddress() != 0; + } + } vertex_array[NumVertexArrays]; Blend blend; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 2d4a0d6db..82001e7b4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -127,7 +127,8 @@ RasterizerOpenGL::~RasterizerOpenGL() { } } -void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { +std::pair RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, + GLintptr buffer_offset) { MICROPROFILE_SCOPE(OpenGL_VAO); const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; @@ -136,43 +137,59 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { state.draw.vertex_buffer = stream_buffer->GetHandle(); state.Apply(); - // TODO(bunnei): Add support for 1+ vertex arrays - const auto& vertex_array{regs.vertex_array[0]}; - const auto& vertex_array_limit{regs.vertex_array_limit[0]}; - ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?"); - ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!"); - for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) { - ASSERT_MSG(!regs.vertex_array[index].enable, "vertex array %d is unimplemented!", index); + // Upload all guest vertex arrays sequentially to our buffer + for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { + const auto& vertex_array = regs.vertex_array[index]; + if (!vertex_array.IsEnabled()) + continue; + + const Tegra::GPUVAddr start = vertex_array.StartAddress(); + const Tegra::GPUVAddr end = regs.vertex_array_limit[index].LimitAddress(); + + ASSERT(end > start); + u64 size = end - start + 1; + + // Copy vertex array data + const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(start)}; + res_cache.FlushRegion(data_addr, size, nullptr); + Memory::ReadBlock(data_addr, array_ptr, size); + + // Bind the vertex array to the buffer at the current offset. + glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride); + + ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented"); + + array_ptr += size; + buffer_offset += size; } // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. // Enables the first 16 vertex attributes always, as we don't know which ones are actually used - // until shader time. Note, Tegra technically supports 32, but we're cappinig this to 16 for now + // until shader time. Note, Tegra technically supports 32, but we're capping this to 16 for now // to avoid OpenGL errors. + // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't + // assume every shader uses them all. for (unsigned index = 0; index < 16; ++index) { auto& attrib = regs.vertex_attrib_format[index]; NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), attrib.offset.Value(), attrib.IsNormalized()); - glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), - attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride, - reinterpret_cast(buffer_offset + attrib.offset)); + auto& buffer = regs.vertex_array[attrib.buffer]; + ASSERT(buffer.IsEnabled()); + glEnableVertexAttribArray(index); + glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), + attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); + glVertexAttribBinding(index, attrib.buffer); + hw_vao_enabled_attributes[index] = true; } - // Copy vertex array data - const u64 data_size{vertex_array_limit.LimitAddress() - vertex_array.StartAddress() + 1}; - const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())}; - res_cache.FlushRegion(data_addr, data_size, nullptr); - Memory::ReadBlock(data_addr, array_ptr, data_size); - - array_ptr += data_size; - buffer_offset += data_size; + return {array_ptr, buffer_offset}; } -void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size_t ptr_pos) { +void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { // Helper function for uploading uniform data const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { if (has_ARB_direct_state_access) { @@ -190,8 +207,6 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size u32 current_constbuffer_bindpoint = 0; for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { - ptr_pos += sizeof(GLShader::MaxwellUniformData); - auto& shader_config = gpu.regs.shader_config[index]; const Maxwell::ShaderProgram program{static_cast(index)}; @@ -205,13 +220,16 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size } // Upload uniform data as one UBO per stage - const GLintptr ubo_offset = buffer_offset + static_cast(ptr_pos); + const GLintptr ubo_offset = buffer_offset; copy_buffer(uniform_buffers[stage].handle, ubo_offset, sizeof(GLShader::MaxwellUniformData)); GLShader::MaxwellUniformData* ub_ptr = - reinterpret_cast(&buffer_ptr[ptr_pos]); + reinterpret_cast(buffer_ptr); ub_ptr->SetFromRegs(gpu.state.shader_stages[stage]); + buffer_ptr += sizeof(GLShader::MaxwellUniformData); + buffer_offset += sizeof(GLShader::MaxwellUniformData); + // Fetch program code from memory GLShader::ProgramCode program_code; const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset}; @@ -252,6 +270,24 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size shader_program_manager->UseTrivialGeometryShader(); } +size_t RasterizerOpenGL::CalculateVertexArraysSize() const { + const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; + + size_t size = 0; + for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { + if (!regs.vertex_array[index].IsEnabled()) + continue; + + const Tegra::GPUVAddr start = regs.vertex_array[index].StartAddress(); + const Tegra::GPUVAddr end = regs.vertex_array_limit[index].LimitAddress(); + + ASSERT(end > start); + size += end - start + 1; + } + + return size; +} + bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; DrawArrays(); @@ -329,44 +365,49 @@ void RasterizerOpenGL::DrawArrays() { const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count}; - // TODO(bunnei): Add support for 1+ vertex arrays - vs_input_size = vertex_num * regs.vertex_array[0].stride; - state.draw.vertex_buffer = stream_buffer->GetHandle(); state.Apply(); - size_t buffer_size = static_cast(vs_input_size); + size_t buffer_size = CalculateVertexArraysSize(); + if (is_indexed) { - buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size; + buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size; } // Uniform space for the 5 shader stages - buffer_size += sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage; + buffer_size = Common::AlignUp(buffer_size, 4) + + sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage; - size_t ptr_pos = 0; u8* buffer_ptr; GLintptr buffer_offset; std::tie(buffer_ptr, buffer_offset) = stream_buffer->Map(static_cast(buffer_size), 4); - SetupVertexArray(buffer_ptr, buffer_offset); - ptr_pos += vs_input_size; + u8* offseted_buffer; + std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset); + + offseted_buffer = + reinterpret_cast(Common::AlignUp(reinterpret_cast(offseted_buffer), 4)); + buffer_offset = Common::AlignUp(buffer_offset, 4); // If indexed mode, copy the index buffer GLintptr index_buffer_offset = 0; if (is_indexed) { - ptr_pos = Common::AlignUp(ptr_pos, 4); - const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; const VAddr index_data_addr{ memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())}; - Memory::ReadBlock(index_data_addr, &buffer_ptr[ptr_pos], index_buffer_size); + Memory::ReadBlock(index_data_addr, offseted_buffer, index_buffer_size); - index_buffer_offset = buffer_offset + static_cast(ptr_pos); - ptr_pos += index_buffer_size; + index_buffer_offset = buffer_offset; + offseted_buffer += index_buffer_size; + buffer_offset += index_buffer_size; } - SetupShaders(buffer_ptr, buffer_offset, ptr_pos); + offseted_buffer = + reinterpret_cast(Common::AlignUp(reinterpret_cast(offseted_buffer), 4)); + buffer_offset = Common::AlignUp(buffer_offset, 4); + + SetupShaders(offseted_buffer, buffer_offset); stream_buffer->Unmap(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 03e02b52a..544714b95 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -148,13 +148,13 @@ private: static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024; std::unique_ptr stream_buffer; - GLsizeiptr vs_input_size; + size_t CalculateVertexArraysSize() const; - void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset); + std::pair SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset); std::array uniform_buffers; - void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size_t ptr_pos); + void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset); enum class AccelDraw { Disabled, Arrays, Indexed }; AccelDraw accelerate_draw; -- cgit v1.2.3 From f20895358525f3a8abaefe3a5c2ebe7d30eadc78 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 17:06:57 -0500 Subject: GPU: Added asserts to our code for handling the QUERY_GET GPU command. This is based on research from nouveau. Many things are currently unknown and will require hwtests in the future. This commit also stubs QueryMode::Write2 to do the same as Write. Nouveau code treats them interchangeably, it is currently unknown what the difference is. --- src/video_core/engines/maxwell_3d.cpp | 27 ++++++++++++++++++++++++++- src/video_core/engines/maxwell_3d.h | 28 +++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 2a3ff234a..35773a695 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -147,11 +147,36 @@ void Maxwell3D::ProcessQueryGet() { // VAddr before writing. VAddr address = memory_manager.PhysicalToVirtualAddress(sequence_address); + // TODO(Subv): Support the other query units. + ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, + "Units other than CROP are unimplemented"); + ASSERT_MSG(regs.query.query_get.short_query, + "Writing the entire query result structure is unimplemented"); + + u32 value = Memory::Read32(address); + u32 result = 0; + + // TODO(Subv): Support the other query variables + switch (regs.query.query_get.select) { + case Regs::QuerySelect::Zero: + result = 0; + break; + default: + UNIMPLEMENTED_MSG("Unimplemented query select type %u", + static_cast(regs.query.query_get.select.Value())); + } + + // TODO(Subv): Research and implement how query sync conditions work. + switch (regs.query.query_get.mode) { - case Regs::QueryMode::Write: { + case Regs::QueryMode::Write: + case Regs::QueryMode::Write2: { // Write the current query sequence to the sequence address. u32 sequence = regs.query.query_sequence; Memory::Write32(address, sequence); + + // TODO(Subv): Write the proper query response structure to the address when not using short + // mode. break; } default: diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index d4fcedace..5ee581acf 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -46,6 +46,29 @@ public: enum class QueryMode : u32 { Write = 0, Sync = 1, + // TODO(Subv): It is currently unknown what the difference between method 2 and method 0 + // is. + Write2 = 2, + }; + + enum class QueryUnit : u32 { + VFetch = 1, + VP = 2, + Rast = 4, + StrmOut = 5, + GP = 6, + ZCull = 7, + Prop = 10, + Crop = 15, + }; + + enum class QuerySelect : u32 { + Zero = 0, + }; + + enum class QuerySyncCondition : u32 { + NotEqual = 0, + GreaterThan = 1, }; enum class ShaderProgram : u32 { @@ -476,7 +499,10 @@ public: u32 raw; BitField<0, 2, QueryMode> mode; BitField<4, 1, u32> fence; - BitField<12, 4, u32> unit; + BitField<12, 4, QueryUnit> unit; + BitField<16, 1, QuerySyncCondition> sync_cond; + BitField<23, 5, QuerySelect> select; + BitField<28, 1, u32> short_query; } query_get; GPUVAddr QueryAddress() const { -- cgit v1.2.3 From d1b23b2b51bcfd0d006e1e6a62065074e3eed2ea Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Apr 2018 11:12:11 -0400 Subject: renderer_opengl: Silence a -Wdangling-else warning in DrawScreenTriangles() --- src/video_core/renderer_opengl/renderer_opengl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index ab0acb20a..baff2c7af 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -295,7 +295,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, const auto& texcoords = screen_info.display_texcoords; auto left = texcoords.left; auto right = texcoords.right; - if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) + if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) { if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) { // Flip the framebuffer vertically left = texcoords.right; @@ -306,6 +306,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, framebuffer_transform_flags); UNIMPLEMENTED(); } + } std::array vertices = {{ ScreenRectVertex(x, y, texcoords.top, left), -- cgit v1.2.3 From 9e11a76e926a7190880063d8fc8c3d97003b9938 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 21 Apr 2018 11:16:21 -0400 Subject: memory_manager: Use GPUVAdddr, not PAddr, for GPU addresses. --- src/video_core/command_processor.cpp | 4 +- src/video_core/engines/maxwell_3d.cpp | 11 ++-- src/video_core/memory_manager.cpp | 72 +++++++++++----------- src/video_core/memory_manager.h | 16 ++--- src/video_core/renderer_opengl/gl_rasterizer.cpp | 6 +- .../renderer_opengl/gl_rasterizer_cache.cpp | 4 +- 6 files changed, 55 insertions(+), 58 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index d4cdb4ab2..7850ae103 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -90,9 +90,7 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) } void GPU::ProcessCommandList(GPUVAddr address, u32 size) { - // TODO(Subv): PhysicalToVirtualAddress is a misnomer, it converts a GPU VAddr into an - // application VAddr. - const VAddr head_address = memory_manager->PhysicalToVirtualAddress(address); + const VAddr head_address = memory_manager->GpuToCpuAddress(address); VAddr current_addr = head_address; while (current_addr < head_address + size * sizeof(CommandHeader)) { const CommandHeader header = {Memory::Read32(current_addr)}; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 35773a695..8d7d627b8 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -145,7 +145,7 @@ void Maxwell3D::ProcessQueryGet() { GPUVAddr sequence_address = regs.query.QueryAddress(); // Since the sequence address is given as a GPU VAddr, we have to convert it to an application // VAddr before writing. - VAddr address = memory_manager.PhysicalToVirtualAddress(sequence_address); + VAddr address = memory_manager.GpuToCpuAddress(sequence_address); // TODO(Subv): Support the other query units. ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, @@ -225,8 +225,7 @@ void Maxwell3D::ProcessCBData(u32 value) { // Don't allow writing past the end of the buffer. ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size); - VAddr address = - memory_manager.PhysicalToVirtualAddress(buffer_address + regs.const_buffer.cb_pos); + VAddr address = memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); Memory::Write32(address, value); @@ -238,7 +237,7 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { GPUVAddr tic_base_address = regs.tic.TICAddress(); GPUVAddr tic_address_gpu = tic_base_address + tic_index * sizeof(Texture::TICEntry); - VAddr tic_address_cpu = memory_manager.PhysicalToVirtualAddress(tic_address_gpu); + VAddr tic_address_cpu = memory_manager.GpuToCpuAddress(tic_address_gpu); Texture::TICEntry tic_entry; Memory::ReadBlock(tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry)); @@ -268,7 +267,7 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { GPUVAddr tsc_base_address = regs.tsc.TSCAddress(); GPUVAddr tsc_address_gpu = tsc_base_address + tsc_index * sizeof(Texture::TSCEntry); - VAddr tsc_address_cpu = memory_manager.PhysicalToVirtualAddress(tsc_address_gpu); + VAddr tsc_address_cpu = memory_manager.GpuToCpuAddress(tsc_address_gpu); Texture::TSCEntry tsc_entry; Memory::ReadBlock(tsc_address_cpu, &tsc_entry, sizeof(Texture::TSCEntry)); @@ -293,7 +292,7 @@ std::vector Maxwell3D::GetStageTextures(Regs::ShaderSt current_texture < tex_info_buffer_end; current_texture += sizeof(Texture::TextureHandle)) { Texture::TextureHandle tex_handle{ - Memory::Read32(memory_manager.PhysicalToVirtualAddress(current_texture))}; + Memory::Read32(memory_manager.GpuToCpuAddress(current_texture))}; Texture::FullTextureInfo tex_info{}; // TODO(Subv): Use the shader to determine which textures are actually accessed. diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 2e1edee03..3f21071c0 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -8,90 +8,90 @@ namespace Tegra { -PAddr MemoryManager::AllocateSpace(u64 size, u64 align) { - boost::optional paddr = FindFreeBlock(size, align); - ASSERT(paddr); +GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { + boost::optional gpu_addr = FindFreeBlock(size, align); + ASSERT(gpu_addr); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(*paddr + offset) == static_cast(PageStatus::Unmapped)); - PageSlot(*paddr + offset) = static_cast(PageStatus::Allocated); + ASSERT(PageSlot(*gpu_addr + offset) == static_cast(PageStatus::Unmapped)); + PageSlot(*gpu_addr + offset) = static_cast(PageStatus::Allocated); } - return *paddr; + return *gpu_addr; } -PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) { +GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) { for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(paddr + offset) == static_cast(PageStatus::Unmapped)); - PageSlot(paddr + offset) = static_cast(PageStatus::Allocated); + ASSERT(PageSlot(gpu_addr + offset) == static_cast(PageStatus::Unmapped)); + PageSlot(gpu_addr + offset) = static_cast(PageStatus::Allocated); } - return paddr; + return gpu_addr; } -PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) { - boost::optional paddr = FindFreeBlock(size, PAGE_SIZE); - ASSERT(paddr); +GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { + boost::optional gpu_addr = FindFreeBlock(size, PAGE_SIZE); + ASSERT(gpu_addr); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(*paddr + offset) == static_cast(PageStatus::Unmapped)); - PageSlot(*paddr + offset) = vaddr + offset; + ASSERT(PageSlot(*gpu_addr + offset) == static_cast(PageStatus::Unmapped)); + PageSlot(*gpu_addr + offset) = cpu_addr + offset; } - return *paddr; + return *gpu_addr; } -PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) { - ASSERT((paddr & PAGE_MASK) == 0); +GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) { + ASSERT((gpu_addr & PAGE_MASK) == 0); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(paddr + offset) == static_cast(PageStatus::Allocated)); - PageSlot(paddr + offset) = vaddr + offset; + ASSERT(PageSlot(gpu_addr + offset) == static_cast(PageStatus::Allocated)); + PageSlot(gpu_addr + offset) = cpu_addr + offset; } - return paddr; + return gpu_addr; } -boost::optional MemoryManager::FindFreeBlock(u64 size, u64 align) { - PAddr paddr = 0; +boost::optional MemoryManager::FindFreeBlock(u64 size, u64 align) { + GPUVAddr gpu_addr = 0; u64 free_space = 0; align = (align + PAGE_MASK) & ~PAGE_MASK; - while (paddr + free_space < MAX_ADDRESS) { - if (!IsPageMapped(paddr + free_space)) { + while (gpu_addr + free_space < MAX_ADDRESS) { + if (!IsPageMapped(gpu_addr + free_space)) { free_space += PAGE_SIZE; if (free_space >= size) { - return paddr; + return gpu_addr; } } else { - paddr += free_space + PAGE_SIZE; + gpu_addr += free_space + PAGE_SIZE; free_space = 0; - paddr = Common::AlignUp(paddr, align); + gpu_addr = Common::AlignUp(gpu_addr, align); } } return {}; } -VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) { - VAddr base_addr = PageSlot(paddr); +VAddr MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { + VAddr base_addr = PageSlot(gpu_addr); ASSERT(base_addr != static_cast(PageStatus::Unmapped)); - return base_addr + (paddr & PAGE_MASK); + return base_addr + (gpu_addr & PAGE_MASK); } -bool MemoryManager::IsPageMapped(PAddr paddr) { - return PageSlot(paddr) != static_cast(PageStatus::Unmapped); +bool MemoryManager::IsPageMapped(GPUVAddr gpu_addr) { + return PageSlot(gpu_addr) != static_cast(PageStatus::Unmapped); } -VAddr& MemoryManager::PageSlot(PAddr paddr) { - auto& block = page_table[(paddr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; +VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) { + auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; if (!block) { block = std::make_unique(); for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) { (*block)[index] = static_cast(PageStatus::Unmapped); } } - return (*block)[(paddr >> PAGE_BITS) & PAGE_BLOCK_MASK]; + return (*block)[(gpu_addr >> PAGE_BITS) & PAGE_BLOCK_MASK]; } } // namespace Tegra diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index b73e283f8..4710cb21f 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -18,20 +18,20 @@ class MemoryManager final { public: MemoryManager() = default; - PAddr AllocateSpace(u64 size, u64 align); - PAddr AllocateSpace(PAddr paddr, u64 size, u64 align); - PAddr MapBufferEx(VAddr vaddr, u64 size); - PAddr MapBufferEx(VAddr vaddr, PAddr paddr, u64 size); - VAddr PhysicalToVirtualAddress(PAddr paddr); + GPUVAddr AllocateSpace(u64 size, u64 align); + GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align); + GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); + GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size); + VAddr GpuToCpuAddress(GPUVAddr gpu_addr); static constexpr u64 PAGE_BITS = 16; static constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; static constexpr u64 PAGE_MASK = PAGE_SIZE - 1; private: - boost::optional FindFreeBlock(u64 size, u64 align = 1); - bool IsPageMapped(PAddr paddr); - VAddr& PageSlot(PAddr paddr); + boost::optional FindFreeBlock(u64 size, u64 align = 1); + bool IsPageMapped(GPUVAddr gpu_addr); + VAddr& PageSlot(GPUVAddr gpu_addr); enum class PageStatus : u64 { Unmapped = 0xFFFFFFFFFFFFFFFFULL, diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 82001e7b4..8568d6762 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -233,7 +233,7 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { // Fetch program code from memory GLShader::ProgramCode program_code; const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset}; - const VAddr cpu_address{gpu.memory_manager.PhysicalToVirtualAddress(gpu_address)}; + const VAddr cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)}; Memory::ReadBlock(cpu_address, program_code.data(), program_code.size() * sizeof(u64)); GLShader::ShaderSetup setup{std::move(program_code)}; @@ -395,7 +395,7 @@ void RasterizerOpenGL::DrawArrays() { if (is_indexed) { const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; const VAddr index_data_addr{ - memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())}; + memory_manager->GpuToCpuAddress(regs.index_array.StartAddress())}; Memory::ReadBlock(index_data_addr, offseted_buffer, index_buffer_size); index_buffer_offset = buffer_offset; @@ -659,7 +659,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr buffer_draw_state.enabled = true; buffer_draw_state.bindpoint = current_bindpoint + bindpoint; - VAddr addr = gpu.memory_manager->PhysicalToVirtualAddress(buffer.address); + VAddr addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); std::vector data(used_buffer.GetSize() * sizeof(float)); Memory::ReadBlock(addr, data.data(), data.size()); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 7410471cc..46f0f25aa 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1028,7 +1028,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu auto& gpu = Core::System::GetInstance().GPU(); SurfaceParams params; - params.addr = gpu.memory_manager->PhysicalToVirtualAddress(config.tic.Address()); + params.addr = gpu.memory_manager->GpuToCpuAddress(config.tic.Address()); params.width = config.tic.Width(); params.height = config.tic.Height(); params.is_tiled = config.tic.IsTiled(); @@ -1106,7 +1106,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; SurfaceParams depth_params = color_params; - color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address()); + color_params.addr = memory_manager->GpuToCpuAddress(config.Address()); color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format); color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format); color_params.UpdateParams(); -- cgit v1.2.3 From 239ac8abe228b9080741ba7d50d9e13cc4a1ceae Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 21 Apr 2018 12:31:30 -0400 Subject: memory_manager: Make GpuToCpuAddress return an optional. --- src/video_core/command_processor.cpp | 6 +++--- src/video_core/engines/maxwell_3d.cpp | 21 +++++++++++---------- src/video_core/memory_manager.cpp | 7 ++++++- src/video_core/memory_manager.h | 5 ++++- src/video_core/renderer_opengl/gl_rasterizer.cpp | 14 +++++++------- .../renderer_opengl/gl_rasterizer_cache.cpp | 4 ++-- 6 files changed, 33 insertions(+), 24 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 7850ae103..2c04daba3 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -90,9 +90,9 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) } void GPU::ProcessCommandList(GPUVAddr address, u32 size) { - const VAddr head_address = memory_manager->GpuToCpuAddress(address); - VAddr current_addr = head_address; - while (current_addr < head_address + size * sizeof(CommandHeader)) { + const boost::optional head_address = memory_manager->GpuToCpuAddress(address); + VAddr current_addr = *head_address; + while (current_addr < *head_address + size * sizeof(CommandHeader)) { const CommandHeader header = {Memory::Read32(current_addr)}; current_addr += sizeof(u32); diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 8d7d627b8..4e9aed380 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -145,7 +145,7 @@ void Maxwell3D::ProcessQueryGet() { GPUVAddr sequence_address = regs.query.QueryAddress(); // Since the sequence address is given as a GPU VAddr, we have to convert it to an application // VAddr before writing. - VAddr address = memory_manager.GpuToCpuAddress(sequence_address); + boost::optional address = memory_manager.GpuToCpuAddress(sequence_address); // TODO(Subv): Support the other query units. ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, @@ -153,7 +153,7 @@ void Maxwell3D::ProcessQueryGet() { ASSERT_MSG(regs.query.query_get.short_query, "Writing the entire query result structure is unimplemented"); - u32 value = Memory::Read32(address); + u32 value = Memory::Read32(*address); u32 result = 0; // TODO(Subv): Support the other query variables @@ -173,7 +173,7 @@ void Maxwell3D::ProcessQueryGet() { case Regs::QueryMode::Write2: { // Write the current query sequence to the sequence address. u32 sequence = regs.query.query_sequence; - Memory::Write32(address, sequence); + Memory::Write32(*address, sequence); // TODO(Subv): Write the proper query response structure to the address when not using short // mode. @@ -225,9 +225,10 @@ void Maxwell3D::ProcessCBData(u32 value) { // Don't allow writing past the end of the buffer. ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size); - VAddr address = memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); + boost::optional address = + memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); - Memory::Write32(address, value); + Memory::Write32(*address, value); // Increment the current buffer position. regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; @@ -237,10 +238,10 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { GPUVAddr tic_base_address = regs.tic.TICAddress(); GPUVAddr tic_address_gpu = tic_base_address + tic_index * sizeof(Texture::TICEntry); - VAddr tic_address_cpu = memory_manager.GpuToCpuAddress(tic_address_gpu); + boost::optional tic_address_cpu = memory_manager.GpuToCpuAddress(tic_address_gpu); Texture::TICEntry tic_entry; - Memory::ReadBlock(tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry)); + Memory::ReadBlock(*tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry)); ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear || tic_entry.header_version == Texture::TICHeaderVersion::Pitch, @@ -267,10 +268,10 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { GPUVAddr tsc_base_address = regs.tsc.TSCAddress(); GPUVAddr tsc_address_gpu = tsc_base_address + tsc_index * sizeof(Texture::TSCEntry); - VAddr tsc_address_cpu = memory_manager.GpuToCpuAddress(tsc_address_gpu); + boost::optional tsc_address_cpu = memory_manager.GpuToCpuAddress(tsc_address_gpu); Texture::TSCEntry tsc_entry; - Memory::ReadBlock(tsc_address_cpu, &tsc_entry, sizeof(Texture::TSCEntry)); + Memory::ReadBlock(*tsc_address_cpu, &tsc_entry, sizeof(Texture::TSCEntry)); return tsc_entry; } @@ -292,7 +293,7 @@ std::vector Maxwell3D::GetStageTextures(Regs::ShaderSt current_texture < tex_info_buffer_end; current_texture += sizeof(Texture::TextureHandle)) { Texture::TextureHandle tex_handle{ - Memory::Read32(memory_manager.GpuToCpuAddress(current_texture))}; + Memory::Read32(*memory_manager.GpuToCpuAddress(current_texture))}; Texture::FullTextureInfo tex_info{}; // TODO(Subv): Use the shader to determine which textures are actually accessed. diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 3f21071c0..9bbbb7e65 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -73,9 +73,14 @@ boost::optional MemoryManager::FindFreeBlock(u64 size, u64 align) { return {}; } -VAddr MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { +boost::optional MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { VAddr base_addr = PageSlot(gpu_addr); ASSERT(base_addr != static_cast(PageStatus::Unmapped)); + + if (base_addr == static_cast(PageStatus::Allocated)) { + return {}; + } + return base_addr + (gpu_addr & PAGE_MASK); } diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 4710cb21f..246c8fb7e 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -6,6 +6,9 @@ #include #include + +#include + #include "common/common_types.h" #include "core/memory.h" @@ -22,7 +25,7 @@ public: GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align); GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size); - VAddr GpuToCpuAddress(GPUVAddr gpu_addr); + boost::optional GpuToCpuAddress(GPUVAddr gpu_addr); static constexpr u64 PAGE_BITS = 16; static constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 8568d6762..71612790b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -150,7 +150,7 @@ std::pair RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, u64 size = end - start + 1; // Copy vertex array data - const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(start)}; + const VAddr data_addr{*memory_manager->GpuToCpuAddress(start)}; res_cache.FlushRegion(data_addr, size, nullptr); Memory::ReadBlock(data_addr, array_ptr, size); @@ -233,8 +233,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { // Fetch program code from memory GLShader::ProgramCode program_code; const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset}; - const VAddr cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)}; - Memory::ReadBlock(cpu_address, program_code.data(), program_code.size() * sizeof(u64)); + const boost::optional cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)}; + Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64)); GLShader::ShaderSetup setup{std::move(program_code)}; GLShader::ShaderEntries shader_resources; @@ -394,9 +394,9 @@ void RasterizerOpenGL::DrawArrays() { GLintptr index_buffer_offset = 0; if (is_indexed) { const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; - const VAddr index_data_addr{ + const boost::optional index_data_addr{ memory_manager->GpuToCpuAddress(regs.index_array.StartAddress())}; - Memory::ReadBlock(index_data_addr, offseted_buffer, index_buffer_size); + Memory::ReadBlock(*index_data_addr, offseted_buffer, index_buffer_size); index_buffer_offset = buffer_offset; offseted_buffer += index_buffer_size; @@ -659,9 +659,9 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr buffer_draw_state.enabled = true; buffer_draw_state.bindpoint = current_bindpoint + bindpoint; - VAddr addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); + boost::optional addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); std::vector data(used_buffer.GetSize() * sizeof(float)); - Memory::ReadBlock(addr, data.data(), data.size()); + Memory::ReadBlock(*addr, data.data(), data.size()); glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo); glBufferData(GL_SHADER_STORAGE_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 46f0f25aa..ced648c12 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1028,7 +1028,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu auto& gpu = Core::System::GetInstance().GPU(); SurfaceParams params; - params.addr = gpu.memory_manager->GpuToCpuAddress(config.tic.Address()); + params.addr = *gpu.memory_manager->GpuToCpuAddress(config.tic.Address()); params.width = config.tic.Width(); params.height = config.tic.Height(); params.is_tiled = config.tic.IsTiled(); @@ -1106,7 +1106,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; SurfaceParams depth_params = color_params; - color_params.addr = memory_manager->GpuToCpuAddress(config.Address()); + color_params.addr = *memory_manager->GpuToCpuAddress(config.Address()); color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format); color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format); color_params.UpdateParams(); -- cgit v1.2.3 From 10c6d891190e407cf4fbcf6eb8ce2506ddf388ec Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 21 Apr 2018 14:40:51 -0400 Subject: memory_manager: Add implement CpuToGpuAddress. --- src/video_core/memory_manager.cpp | 17 +++++++++++++++++ src/video_core/memory_manager.h | 10 ++++++++++ 2 files changed, 27 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 9bbbb7e65..25984439d 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -38,6 +38,9 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { PageSlot(*gpu_addr + offset) = cpu_addr + offset; } + MappedRegion region{cpu_addr, *gpu_addr, size}; + mapped_regions.push_back(region); + return *gpu_addr; } @@ -49,6 +52,9 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) PageSlot(gpu_addr + offset) = cpu_addr + offset; } + MappedRegion region{cpu_addr, gpu_addr, size}; + mapped_regions.push_back(region); + return gpu_addr; } @@ -84,6 +90,17 @@ boost::optional MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { return base_addr + (gpu_addr & PAGE_MASK); } +std::vector MemoryManager::CpuToGpuAddress(VAddr cpu_addr) const { + std::vector results; + for (const auto& region : mapped_regions) { + if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) { + u64 offset = cpu_addr - region.cpu_addr; + results.push_back(region.gpu_addr + offset); + } + } + return results; +} + bool MemoryManager::IsPageMapped(GPUVAddr gpu_addr) { return PageSlot(gpu_addr) != static_cast(PageStatus::Unmapped); } diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 246c8fb7e..7d745101f 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -6,6 +6,7 @@ #include #include +#include #include @@ -26,6 +27,7 @@ public: GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size); boost::optional GpuToCpuAddress(GPUVAddr gpu_addr); + std::vector CpuToGpuAddress(VAddr cpu_addr) const; static constexpr u64 PAGE_BITS = 16; static constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; @@ -51,6 +53,14 @@ private: using PageBlock = std::array; std::array, PAGE_TABLE_SIZE> page_table{}; + + struct MappedRegion { + VAddr cpu_addr; + GPUVAddr gpu_addr; + u64 size; + }; + + std::vector mapped_regions; }; } // namespace Tegra -- cgit v1.2.3 From 4415e00181f71b35eea779157976773d9bccf638 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 24 Apr 2018 00:19:36 -0400 Subject: gl_rasterizer_cache: Update to be based on GPU addresses, not CPU addresses. --- src/video_core/memory_manager.h | 1 - src/video_core/rasterizer_interface.h | 7 +-- src/video_core/renderer_opengl/gl_rasterizer.cpp | 13 +++-- src/video_core/renderer_opengl/gl_rasterizer.h | 7 +-- .../renderer_opengl/gl_rasterizer_cache.cpp | 63 +++++++++++++--------- .../renderer_opengl/gl_rasterizer_cache.h | 27 ++++++---- src/video_core/renderer_opengl/renderer_opengl.cpp | 3 +- src/video_core/textures/decoders.cpp | 1 + 8 files changed, 72 insertions(+), 50 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 7d745101f..08140c83a 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -11,7 +11,6 @@ #include #include "common/common_types.h" -#include "core/memory.h" namespace Tegra { diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 36629dd11..f0e48a802 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -6,6 +6,7 @@ #include "common/common_types.h" #include "video_core/gpu.h" +#include "video_core/memory_manager.h" struct ScreenInfo; @@ -25,14 +26,14 @@ public: virtual void FlushAll() = 0; /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory - virtual void FlushRegion(VAddr addr, u64 size) = 0; + virtual void FlushRegion(Tegra::GPUVAddr addr, u64 size) = 0; /// Notify rasterizer that any caches of the specified region should be invalidated - virtual void InvalidateRegion(VAddr addr, u64 size) = 0; + virtual void InvalidateRegion(Tegra::GPUVAddr addr, u64 size) = 0; /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory /// and invalidated - virtual void FlushAndInvalidateRegion(VAddr addr, u64 size) = 0; + virtual void FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) = 0; /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0 virtual bool AccelerateDisplayTransfer(const void* config) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 71612790b..bc9368877 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -150,9 +150,8 @@ std::pair RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, u64 size = end - start + 1; // Copy vertex array data - const VAddr data_addr{*memory_manager->GpuToCpuAddress(start)}; - res_cache.FlushRegion(data_addr, size, nullptr); - Memory::ReadBlock(data_addr, array_ptr, size); + res_cache.FlushRegion(start, size, nullptr); + Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size); // Bind the vertex array to the buffer at the current offset. glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride); @@ -519,17 +518,17 @@ void RasterizerOpenGL::FlushAll() { res_cache.FlushAll(); } -void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) { +void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) { MICROPROFILE_SCOPE(OpenGL_CacheManagement); res_cache.FlushRegion(addr, size); } -void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) { +void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) { MICROPROFILE_SCOPE(OpenGL_CacheManagement); res_cache.InvalidateRegion(addr, size, nullptr); } -void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) { +void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) { MICROPROFILE_SCOPE(OpenGL_CacheManagement); res_cache.FlushRegion(addr, size); res_cache.InvalidateRegion(addr, size, nullptr); @@ -560,7 +559,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu MICROPROFILE_SCOPE(OpenGL_CacheManagement); SurfaceParams src_params; - src_params.addr = framebuffer_addr; + src_params.cpu_addr = framebuffer_addr; src_params.width = std::min(framebuffer.width, pixel_stride); src_params.height = framebuffer.height; src_params.stride = pixel_stride; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 544714b95..9709e595e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -11,6 +11,7 @@ #include #include "common/common_types.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" @@ -29,9 +30,9 @@ public: void DrawArrays() override; void NotifyMaxwellRegisterChanged(u32 method) override; void FlushAll() override; - void FlushRegion(VAddr addr, u64 size) override; - void InvalidateRegion(VAddr addr, u64 size) override; - void FlushAndInvalidateRegion(VAddr addr, u64 size) override; + void FlushRegion(Tegra::GPUVAddr addr, u64 size) override; + void InvalidateRegion(Tegra::GPUVAddr addr, u64 size) override; + void FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) override; bool AccelerateDisplayTransfer(const void* config) override; bool AccelerateTextureCopy(const void* config) override; bool AccelerateFill(const void* config) override; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index ced648c12..d139d51e9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -83,26 +83,30 @@ static u16 GetResolutionScaleFactor() { } template -void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, VAddr base, VAddr start, - VAddr end) { +void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr base, + Tegra::GPUVAddr start, Tegra::GPUVAddr end) { constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); + const auto& gpu = Core::System::GetInstance().GPU(); if (morton_to_gl) { auto data = Tegra::Texture::UnswizzleTexture( - base, SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, - block_height); + *gpu.memory_manager->GpuToCpuAddress(base), + SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height); std::memcpy(gl_buffer, data.data(), data.size()); } else { // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check // the configuration for this and perform more generic un/swizzle LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); - VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel, - Memory::GetPointer(base), gl_buffer, morton_to_gl); + VideoCore::MortonCopyPixels128( + stride, height, bytes_per_pixel, gl_bytes_per_pixel, + Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(base)), gl_buffer, + morton_to_gl); } } -static constexpr std::array morton_to_gl_fns = { MortonCopy, MortonCopy, @@ -110,7 +114,8 @@ static constexpr std::array, MortonCopy, }; -static constexpr std::array gl_to_morton_fns = { MortonCopy, @@ -219,9 +224,9 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { SurfaceParams params = *this; const u32 tiled_size = is_tiled ? 8 : 1; const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size); - VAddr aligned_start = + Tegra::GPUVAddr aligned_start = addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); - VAddr aligned_end = + Tegra::GPUVAddr aligned_end = addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); if (aligned_end - aligned_start > stride_tiled_bytes) { @@ -342,6 +347,13 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const { return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval(); } +VAddr SurfaceParams::GetCpuAddr() const { + // When this function is used, only cpu_addr or (GPU) addr should be set, not both + ASSERT(!(cpu_addr && addr)); + const auto& gpu = Core::System::GetInstance().GPU(); + return cpu_addr.get_value_or(*gpu.memory_manager->GpuToCpuAddress(addr)); +} + bool CachedSurface::CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const { if (type == SurfaceType::Fill && IsRegionValid(fill_interval) && @@ -456,10 +468,10 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac } MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); -void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { +void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr load_end) { ASSERT(type != SurfaceType::Fill); - u8* const texture_src_data = Memory::GetPointer(addr); + u8* const texture_src_data = Memory::GetPointer(GetCpuAddr()); if (texture_src_data == nullptr) return; @@ -485,8 +497,8 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { } MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); -void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) { - u8* const dst_buffer = Memory::GetPointer(addr); +void CachedSurface::FlushGLBuffer(Tegra::GPUVAddr flush_start, Tegra::GPUVAddr flush_end) { + u8* const dst_buffer = Memory::GetPointer(GetCpuAddr()); if (dst_buffer == nullptr) return; @@ -1028,7 +1040,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu auto& gpu = Core::System::GetInstance().GPU(); SurfaceParams params; - params.addr = *gpu.memory_manager->GpuToCpuAddress(config.tic.Address()); + params.addr = config.tic.Address(); params.width = config.tic.Width(); params.height = config.tic.Height(); params.is_tiled = config.tic.IsTiled(); @@ -1045,7 +1057,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu params.block_height = config.tic.BlockHeight(); } else { // Use the texture-provided stride value if the texture isn't tiled. - params.stride = params.PixelsInBytes(config.tic.Pitch()); + params.stride = static_cast(params.PixelsInBytes(config.tic.Pitch())); } params.UpdateParams(); @@ -1073,7 +1085,6 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle& viewport) { const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; - const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; const auto& config = regs.rt[0]; // TODO(bunnei): This is hard corded to use just the first render buffer @@ -1106,7 +1117,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; SurfaceParams depth_params = color_params; - color_params.addr = *memory_manager->GpuToCpuAddress(config.Address()); + color_params.addr = config.Address(); color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format); color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format); color_params.UpdateParams(); @@ -1222,7 +1233,8 @@ void RasterizerCacheOpenGL::DuplicateSurface(const Surface& src_surface, } } -void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, u64 size) { +void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, Tegra::GPUVAddr addr, + u64 size) { if (size == 0) return; @@ -1261,7 +1273,7 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, } } -void RasterizerCacheOpenGL::FlushRegion(VAddr addr, u64 size, Surface flush_surface) { +void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size, Surface flush_surface) { if (size == 0) return; @@ -1297,7 +1309,8 @@ void RasterizerCacheOpenGL::FlushAll() { FlushRegion(0, Kernel::VMManager::MAX_ADDRESS); } -void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner) { +void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size, + const Surface& region_owner) { if (size == 0) return; @@ -1390,7 +1403,7 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}}); } -void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { +void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) { const u64 num_pages = ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1; const u64 page_start = addr >> Memory::PAGE_BITS; @@ -1406,8 +1419,10 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int del const auto interval = pair.first & pages_interval; const int count = pair.second; - const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; - const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; + const Tegra::GPUVAddr interval_start_addr = boost::icl::first(interval) + << Memory::PAGE_BITS; + const Tegra::GPUVAddr interval_end_addr = boost::icl::last_next(interval) + << Memory::PAGE_BITS; const u64 interval_size = interval_end_addr - interval_start_addr; if (delta > 0 && count == delta) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index bf0fabb29..5f77f4e61 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -17,12 +17,14 @@ #ifdef __GNUC__ #pragma GCC diagnostic pop #endif +#include #include #include "common/assert.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "common/math_util.h" #include "video_core/gpu.h" +#include "video_core/memory_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/textures/texture.h" @@ -30,9 +32,9 @@ struct CachedSurface; using Surface = std::shared_ptr; using SurfaceSet = std::set; -using SurfaceRegions = boost::icl::interval_set; -using SurfaceMap = boost::icl::interval_map; -using SurfaceCache = boost::icl::interval_map; +using SurfaceRegions = boost::icl::interval_set; +using SurfaceMap = boost::icl::interval_map; +using SurfaceCache = boost::icl::interval_map; using SurfaceInterval = SurfaceCache::interval_type; static_assert(std::is_same() && @@ -277,6 +279,8 @@ struct SurfaceParams { return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; } + VAddr GetCpuAddr() const; + bool ExactMatch(const SurfaceParams& other_surface) const; bool CanSubRect(const SurfaceParams& sub_surface) const; bool CanExpand(const SurfaceParams& expanded_surface) const; @@ -285,8 +289,9 @@ struct SurfaceParams { MathUtil::Rectangle GetSubRect(const SurfaceParams& sub_surface) const; MathUtil::Rectangle GetScaledSubRect(const SurfaceParams& sub_surface) const; - VAddr addr = 0; - VAddr end = 0; + Tegra::GPUVAddr addr = 0; + Tegra::GPUVAddr end = 0; + boost::optional cpu_addr; u64 size = 0; u32 width = 0; @@ -332,8 +337,8 @@ struct CachedSurface : SurfaceParams { size_t gl_buffer_size = 0; // Read/Write data in Switch memory to/from gl_buffer - void LoadGLBuffer(VAddr load_start, VAddr load_end); - void FlushGLBuffer(VAddr flush_start, VAddr flush_end); + void LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr load_end); + void FlushGLBuffer(Tegra::GPUVAddr flush_start, Tegra::GPUVAddr flush_end); // Upload/Download data in gl_buffer in/to this surface's texture void UploadGLTexture(const MathUtil::Rectangle& rect, GLuint read_fb_handle, @@ -381,10 +386,10 @@ public: SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params); /// Write any cached resources overlapping the region back to memory (if dirty) - void FlushRegion(VAddr addr, u64 size, Surface flush_surface = nullptr); + void FlushRegion(Tegra::GPUVAddr addr, u64 size, Surface flush_surface = nullptr); /// Mark region as being invalidated by region_owner (nullptr if Switch memory) - void InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner); + void InvalidateRegion(Tegra::GPUVAddr addr, u64 size, const Surface& region_owner); /// Flush all cached resources tracked by this cache manager void FlushAll(); @@ -393,7 +398,7 @@ private: void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface); /// Update surface's texture for given region when necessary - void ValidateSurface(const Surface& surface, VAddr addr, u64 size); + void ValidateSurface(const Surface& surface, Tegra::GPUVAddr addr, u64 size); /// Create a new surface Surface CreateSurface(const SurfaceParams& params); @@ -405,7 +410,7 @@ private: void UnregisterSurface(const Surface& surface); /// Increase/decrease the number of surface in pages touching the specified region - void UpdatePagesCachedCount(VAddr addr, u64 size, int delta); + void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta); SurfaceCache surface_cache; PageMap cached_pages; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index baff2c7af..a266e21cf 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -152,7 +152,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf screen_info.display_texture = screen_info.texture.resource.handle; screen_info.display_texcoords = MathUtil::Rectangle(0.f, 0.f, 1.f, 1.f); - Rasterizer()->FlushRegion(framebuffer_addr, size_in_bytes); + Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes, + Memory::FlushMode::Flush); VideoCore::MortonCopyPixels128(framebuffer.width, framebuffer.height, bytes_per_pixel, 4, Memory::GetPointer(framebuffer_addr), diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index e0509f0ce..9c3ae875c 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -4,6 +4,7 @@ #include #include "common/assert.h" +#include "core/memory.h" #include "video_core/textures/decoders.h" #include "video_core/textures/texture.h" -- cgit v1.2.3 From bc0f1896fc1092bdc66fb66f977163de08672f01 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Apr 2018 23:45:47 -0400 Subject: gl_rasterizer_cache: Handle compressed texture sizes. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 37 +++++++-------- .../renderer_opengl/gl_rasterizer_cache.h | 52 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 24 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index d139d51e9..e1ad00feb 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -41,18 +41,15 @@ struct FormatTuple { GLenum format; GLenum type; bool compressed; - // How many pixels in the original texture are equivalent to one pixel in the compressed - // texture. - u32 compression_factor; }; static constexpr std::array tex_format_tuples = {{ - {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8 - {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5 - {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, 1}, // A2B10G10R10 - {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1 - {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23 - {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45 + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8 + {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5 + {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10 + {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1 + {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23 + {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45 }}; static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { @@ -476,7 +473,7 @@ void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr loa return; if (gl_buffer == nullptr) { - gl_buffer_size = width * height * GetGLBytesPerPixel(pixel_format); + gl_buffer_size = GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format); gl_buffer.reset(new u8[gl_buffer_size]); } @@ -491,8 +488,9 @@ void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr loa std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset, bytes_per_pixel * width * height); } else { - morton_to_gl_fns[static_cast(pixel_format)]( - stride, block_height, height, &gl_buffer[0], addr, load_start, load_end); + morton_to_gl_fns[static_cast(pixel_format)](GetActualWidth(), block_height, + GetActualHeight(), &gl_buffer[0], addr, + load_start, load_end); } } @@ -548,7 +546,8 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle& rect, GLuint MICROPROFILE_SCOPE(OpenGL_TextureUL); - ASSERT(gl_buffer_size == width * height * GetGLBytesPerPixel(pixel_format)); + ASSERT(gl_buffer_size == + GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format)); // Load data from memory to the surface GLint x0 = static_cast(rect.left); @@ -583,11 +582,9 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle& rect, GLuint glActiveTexture(GL_TEXTURE0); if (tuple.compressed) { glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, - static_cast(rect.GetWidth()), - static_cast(rect.GetHeight()), 0, - rect.GetWidth() * rect.GetHeight() * - GetGLBytesPerPixel(pixel_format) / tuple.compression_factor, - &gl_buffer[buffer_offset]); + static_cast(rect.GetWidth() * GetCompresssionFactor()), + static_cast(rect.GetHeight() * GetCompresssionFactor()), 0, + size, &gl_buffer[buffer_offset]); } else { glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast(rect.GetWidth()), static_cast(rect.GetHeight()), tuple.format, tuple.type, @@ -1041,10 +1038,10 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu SurfaceParams params; params.addr = config.tic.Address(); - params.width = config.tic.Width(); - params.height = config.tic.Height(); params.is_tiled = config.tic.IsTiled(); params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format); + params.width = config.tic.Width() / params.GetCompresssionFactor(); + params.height = config.tic.Height() / params.GetCompresssionFactor(); // TODO(Subv): Different types per component are not supported. ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() && diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 5f77f4e61..08858bab4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -84,23 +84,49 @@ struct SurfaceParams { Invalid = 4, }; - static constexpr unsigned int GetFormatBpp(PixelFormat format) { + /** + * Gets the compression factor for the specified PixelFormat. This applies to just the + * "compressed width" and "compressed height", not the overall compression factor of a + * compressed image. This is used for maintaining proper surface sizes for compressed texture + * formats. + */ + static constexpr u32 GetCompresssionFactor(PixelFormat format) { if (format == PixelFormat::Invalid) return 0; - constexpr std::array bpp_table = { + constexpr std::array compression_factor_table = {{ + 1, // ABGR8 + 1, // B5G6R5 + 1, // A2B10G10R10 + 4, // DXT1 + 4, // DXT23 + 4, // DXT45 + }}; + + ASSERT(static_cast(format) < compression_factor_table.size()); + return compression_factor_table[static_cast(format)]; + } + u32 GetCompresssionFactor() const { + return GetCompresssionFactor(pixel_format); + } + + static constexpr u32 GetFormatBpp(PixelFormat format) { + if (format == PixelFormat::Invalid) + return 0; + + constexpr std::array bpp_table = {{ 32, // ABGR8 16, // B5G6R5 32, // A2B10G10R10 64, // DXT1 128, // DXT23 128, // DXT45 - }; + }}; ASSERT(static_cast(format) < bpp_table.size()); return bpp_table[static_cast(format)]; } - unsigned int GetFormatBpp() const { + u32 GetFormatBpp() const { return GetFormatBpp(pixel_format); } @@ -255,6 +281,24 @@ struct SurfaceParams { // Returns the region of the biggest valid rectange within interval SurfaceInterval GetCopyableInterval(const Surface& src_surface) const; + /** + * Gets the actual width (in pixels) of the surface. This is provided because `width` is used + * for tracking the surface region in memory, which may be compressed for certain formats. In + * this scenario, `width` is actually the compressed width. + */ + u32 GetActualWidth() const { + return width * GetCompresssionFactor(); + } + + /** + * Gets the actual height (in pixels) of the surface. This is provided because `height` is used + * for tracking the surface region in memory, which may be compressed for certain formats. In + * this scenario, `height` is actually the compressed height. + */ + u32 GetActualHeight() const { + return height * GetCompresssionFactor(); + } + u32 GetScaledWidth() const { return width * res_scale; } -- cgit v1.2.3 From fbb3cd110c598003bf58a2aca5be489b5f3fb772 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 24 Apr 2018 00:46:51 -0400 Subject: gl_rasterizer_cache: Add a function for finding framebuffer GPU address. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 1 + .../renderer_opengl/gl_rasterizer_cache.cpp | 27 ++++++++++++++++++++++ .../renderer_opengl/gl_rasterizer_cache.h | 3 +++ 3 files changed, 31 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index bc9368877..b457b1fbe 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -560,6 +560,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu SurfaceParams src_params; src_params.cpu_addr = framebuffer_addr; + src_params.addr = res_cache.TryFindFramebufferGpuAddress(framebuffer_addr).get_value_or(0); src_params.width = std::min(framebuffer.width, pixel_stride); src_params.height = framebuffer.height; src_params.stride = pixel_stride; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index e1ad00feb..b924f1b8e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -954,6 +954,33 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc return surface; } +boost::optional RasterizerCacheOpenGL::TryFindFramebufferGpuAddress( + VAddr cpu_addr) const { + // Tries to find the GPU address of a framebuffer based on the CPU address. This is because + // final output framebuffers are specified by CPU address, but internally our GPU cache uses GPU + // addresses. We iterate through all cached framebuffers, and compare their starting CPU address + // to the one provided. This is obviously not great, and won't work if the framebuffer overlaps + // surfaces. + + std::vector gpu_addresses; + for (const auto& pair : surface_cache) { + for (const auto& surface : pair.second) { + const VAddr surface_cpu_addr = surface->GetCpuAddr(); + if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + surface->size)) { + ASSERT_MSG(cpu_addr == surface_cpu_addr, "overlapping surfaces are unsupported"); + gpu_addresses.push_back(surface->addr); + } + } + } + + if (gpu_addresses.empty()) { + return {}; + } + + ASSERT_MSG(gpu_addresses.size() == 1, ">1 surface is unsupported"); + return gpu_addresses[0]; +} + SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale, bool load_if_create) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 08858bab4..dfddcce90 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -411,6 +411,9 @@ public: Surface GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale, bool load_if_create); + /// Tries to find a framebuffer GPU address based on the provided CPU address + boost::optional TryFindFramebufferGpuAddress(VAddr cpu_addr) const; + /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from /// Switch memory to OpenGL and caches it (if not already cached) SurfaceRect_Tuple GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale, -- cgit v1.2.3 From 9022d926eb8553f382e215c8b005b7a45358e87c Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 24 Apr 2018 14:45:15 -0400 Subject: gl_rasterizer_cache: Use new logger. --- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index b924f1b8e..9348b0297 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -94,7 +94,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra:: } else { // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check // the configuration for this and perform more generic un/swizzle - LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); + NGLOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); VideoCore::MortonCopyPixels128( stride, height, bytes_per_pixel, gl_bytes_per_pixel, Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(base)), gl_buffer, @@ -1112,7 +1112,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( const auto& config = regs.rt[0]; // TODO(bunnei): This is hard corded to use just the first render buffer - LOG_WARNING(Render_OpenGL, "hard-coded for render target 0!"); + NGLOG_WARNING(Render_OpenGL, "hard-coded for render target 0!"); // update resolution_scale_factor and reset cache if changed // TODO (bunnei): This code was ported as-is from Citra, and is technically not thread-safe. We @@ -1157,8 +1157,8 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( // Make sure that framebuffers don't overlap if both color and depth are being used if (using_color_fb && using_depth_fb && boost::icl::length(color_vp_interval & depth_vp_interval)) { - LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " - "overlapping framebuffers not supported!"); + NGLOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " + "overlapping framebuffers not supported!"); using_depth_fb = false; } -- cgit v1.2.3 From 0a023cfb4ff5631520ad8d4409dcf8e2a103fd98 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 24 Apr 2018 15:30:22 -0400 Subject: gl_rasterizer_cache: Use GPU PAGE_BITS/SIZE, not CPU. --- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 9348b0297..aef1c5979 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1428,9 +1428,9 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { } void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) { - const u64 num_pages = - ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1; - const u64 page_start = addr >> Memory::PAGE_BITS; + const u64 num_pages = ((addr + size - 1) >> Tegra::MemoryManager::PAGE_BITS) - + (addr >> Tegra::MemoryManager::PAGE_BITS) + 1; + const u64 page_start = addr >> Tegra::MemoryManager::PAGE_BITS; const u64 page_end = page_start + num_pages; // Interval maps will erase segments if count reaches 0, so if delta is negative we have to @@ -1444,9 +1444,9 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 siz const int count = pair.second; const Tegra::GPUVAddr interval_start_addr = boost::icl::first(interval) - << Memory::PAGE_BITS; + << Tegra::MemoryManager::PAGE_BITS; const Tegra::GPUVAddr interval_end_addr = boost::icl::last_next(interval) - << Memory::PAGE_BITS; + << Tegra::MemoryManager::PAGE_BITS; const u64 interval_size = interval_end_addr - interval_start_addr; if (delta > 0 && count == delta) -- cgit v1.2.3 From f1a4a004fb8423091b48ceffdbd1e696372d4dc4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 24 Apr 2018 18:01:06 -0400 Subject: gl_rasterizer_cache: Use CHAR_BIT for bpp conversions instead of 8. --- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 6 +++--- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index aef1c5979..501d15e98 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -82,7 +82,7 @@ static u16 GetResolutionScaleFactor() { template void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr base, Tegra::GPUVAddr start, Tegra::GPUVAddr end) { - constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; + constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); const auto& gpu = Core::System::GetInstance().GPU(); @@ -358,9 +358,9 @@ bool CachedSurface::CanFill(const SurfaceParams& dest_surface, boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range dest_surface.FromInterval(fill_interval).GetInterval() == fill_interval) { // make sure interval is a rectangle in dest surface - if (fill_size * 8 != dest_surface.GetFormatBpp()) { + if (fill_size * CHAR_BIT != dest_surface.GetFormatBpp()) { // Check if bits repeat for our fill_size - const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / 8, 1u); + const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / CHAR_BIT, 1u); std::vector fill_test(fill_size * dest_bytes_per_pixel); for (u32 i = 0; i < dest_bytes_per_pixel; ++i) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index dfddcce90..55f1bdee8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -374,7 +374,7 @@ struct CachedSurface : SurfaceParams { if (format == PixelFormat::Invalid) return 0; - return SurfaceParams::GetFormatBpp(format) / 8; + return SurfaceParams::GetFormatBpp(format) / CHAR_BIT; } std::unique_ptr gl_buffer; -- cgit v1.2.3 From c30cd898fc122d1277583c5165d622e323faad07 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 24 Apr 2018 19:44:09 -0400 Subject: renderer_opengl: Use correct byte order for framebuffer pixel format ABGR8. --- src/video_core/renderer_opengl/renderer_opengl.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index a266e21cf..5ca9821b7 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -270,10 +270,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, GLint internal_format; switch (framebuffer.pixel_format) { case Tegra::FramebufferConfig::PixelFormat::ABGR8: - // Use RGBA8 and swap in the fragment shader internal_format = GL_RGBA; texture.gl_format = GL_RGBA; - texture.gl_type = GL_UNSIGNED_INT_8_8_8_8; + texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; gl_framebuffer_data.resize(texture.width * texture.height * 4); break; default: -- cgit v1.2.3 From 0369ee72484c42983185d8d50fe6db13607fb599 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Apr 2018 22:42:54 -0500 Subject: Shaders: Added decodings for the FSET instructions. --- src/video_core/engines/shader_bytecode.h | 37 +++++++++++++++++----- .../renderer_opengl/gl_shader_decompiler.cpp | 2 +- 2 files changed, 30 insertions(+), 9 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 5a006aee5..6cae6ff45 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -214,6 +214,20 @@ union Instruction { BitField<56, 1, u64> neg_b; } fsetp; + union { + BitField<39, 3, u64> pred39; + BitField<42, 1, u64> neg_pred; + BitField<43, 1, u64> neg_a; + BitField<44, 1, u64> abs_b; + BitField<45, 2, PredOperation> op; + BitField<48, 4, PredCondition> cond; + BitField<53, 1, u64> neg_b; + BitField<54, 1, u64> abs_a; + BitField<52, 1, u64> bf; + BitField<55, 1, u64> ftz; + BitField<56, 1, u64> neg_imm; + } fset; + BitField<61, 1, u64> is_b_imm; BitField<60, 1, u64> is_b_gpr; BitField<59, 1, u64> is_c_gpr; @@ -272,6 +286,9 @@ public: FSETP_C, // Set Predicate FSETP_R, FSETP_IMM, + FSET_C, + FSET_R, + FSET_IMM, ISETP_C, ISETP_IMM, ISETP_R, @@ -283,8 +300,9 @@ public: Ffma, Flow, Memory, - FloatPredicate, - IntegerPredicate, + FloatSet, + FloatSetPredicate, + IntegerSetPredicate, Unknown, }; @@ -417,12 +435,15 @@ private: INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"), INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"), INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"), - INST("010010111011----", Id::FSETP_C, Type::FloatPredicate, "FSETP_C"), - INST("010110111011----", Id::FSETP_R, Type::FloatPredicate, "FSETP_R"), - INST("0011011-1011----", Id::FSETP_IMM, Type::FloatPredicate, "FSETP_IMM"), - INST("010010110110----", Id::ISETP_C, Type::IntegerPredicate, "ISETP_C"), - INST("010110110110----", Id::ISETP_R, Type::IntegerPredicate, "ISETP_R"), - INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerPredicate, "ISETP_IMM"), + INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"), + INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"), + INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"), + INST("010010111011----", Id::FSETP_C, Type::FloatSetPredicate, "FSETP_C"), + INST("010110111011----", Id::FSETP_R, Type::FloatSetPredicate, "FSETP_R"), + INST("0011011-1011----", Id::FSETP_IMM, Type::FloatSetPredicate, "FSETP_IMM"), + INST("010010110110----", Id::ISETP_C, Type::IntegerSetPredicate, "ISETP_C"), + INST("010110110110----", Id::ISETP_R, Type::IntegerSetPredicate, "ISETP_R"), + INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerSetPredicate, "ISETP_IMM"), }; #undef INST std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) { diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 086424395..896b6cd2c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -519,7 +519,7 @@ private: } break; } - case OpCode::Type::FloatPredicate: { + case OpCode::Type::FloatSetPredicate: { std::string op_a = instr.fsetp.neg_a ? "-" : ""; op_a += GetRegister(instr.gpr8); -- cgit v1.2.3 From b7551e457bacf972789136cfdc1e90c5a2e0dae6 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 25 Apr 2018 08:13:44 -0400 Subject: video-core: Move logging macros over to new fmt-capable ones --- src/video_core/command_processor.cpp | 12 +++++++----- src/video_core/engines/maxwell_3d.cpp | 4 ++-- src/video_core/renderer_opengl/gl_rasterizer.cpp | 6 +++--- src/video_core/renderer_opengl/renderer_opengl.cpp | 10 +++++----- src/video_core/video_core.cpp | 6 +++--- 5 files changed, 20 insertions(+), 18 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 2c04daba3..f6a88f031 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -31,12 +31,14 @@ enum class BufferMethods { }; void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { - LOG_WARNING(HW_GPU, "Processing method %08X on subchannel %u value %08X remaining params %u", - method, subchannel, value, remaining_params); + NGLOG_WARNING(HW_GPU, + "Processing method {:08X} on subchannel {} value " + "{:08X} remaining params {}", + method, subchannel, value, remaining_params); if (method == static_cast(BufferMethods::SetGraphMacroEntry)) { // Prepare to upload a new macro, reset the upload counter. - LOG_DEBUG(HW_GPU, "Uploading GPU macro %08X", value); + NGLOG_DEBUG(HW_GPU, "Uploading GPU macro {:08X}", value); current_macro_entry = value; current_macro_code.clear(); return; @@ -58,7 +60,7 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) if (method == static_cast(BufferMethods::BindObject)) { // Bind the current subchannel to the desired engine id. - LOG_DEBUG(HW_GPU, "Binding subchannel %u to engine %u", subchannel, value); + NGLOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); ASSERT(bound_engines.find(subchannel) == bound_engines.end()); bound_engines[subchannel] = static_cast(value); return; @@ -66,7 +68,7 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) if (method < static_cast(BufferMethods::CountBufferMethods)) { // TODO(Subv): Research and implement these methods. - LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); + NGLOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); return; } diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 4e9aed380..2acbb9cd6 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -186,8 +186,8 @@ void Maxwell3D::ProcessQueryGet() { } void Maxwell3D::DrawArrays() { - LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(), - regs.vertex_buffer.count); + NGLOG_DEBUG(HW_GPU, "called, topology={}, count={}", + static_cast(regs.draw.topology.Value()), regs.vertex_buffer.count); ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b457b1fbe..9b3542e10 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -116,7 +116,7 @@ RasterizerOpenGL::RasterizerOpenGL() { glEnable(GL_BLEND); - LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); + NGLOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); } RasterizerOpenGL::~RasterizerOpenGL() { @@ -252,8 +252,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { break; } default: - LOG_CRITICAL(HW_GPU, "Unimplemented shader index=%d, enable=%d, offset=0x%08X", index, - shader_config.enable.Value(), shader_config.offset); + NGLOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset={:#010X}", + index, shader_config.enable.Value(), shader_config.offset); UNREACHABLE(); } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 5ca9821b7..77d1692f4 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -302,8 +302,8 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, right = texcoords.left; } else { // Other transformations are unsupported - LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags=%d", - framebuffer_transform_flags); + NGLOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags={}", + static_cast(framebuffer_transform_flags)); UNIMPLEMENTED(); } } @@ -428,9 +428,9 @@ bool RendererOpenGL::Init() { const char* gpu_vendor{reinterpret_cast(glGetString(GL_VENDOR))}; const char* gpu_model{reinterpret_cast(glGetString(GL_RENDERER))}; - LOG_INFO(Render_OpenGL, "GL_VERSION: %s", gl_version); - LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", gpu_vendor); - LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", gpu_model); + NGLOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version); + NGLOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor); + NGLOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor); Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 289140f31..89dc8ed1e 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -24,9 +24,9 @@ bool Init(EmuWindow* emu_window) { g_renderer = std::make_unique(); g_renderer->SetWindow(g_emu_window); if (g_renderer->Init()) { - LOG_DEBUG(Render, "initialized OK"); + NGLOG_DEBUG(Render, "initialized OK"); } else { - LOG_CRITICAL(Render, "initialization failed !"); + NGLOG_CRITICAL(Render, "initialization failed !"); return false; } return true; @@ -36,7 +36,7 @@ bool Init(EmuWindow* emu_window) { void Shutdown() { g_renderer.reset(); - LOG_DEBUG(Render, "shutdown OK"); + NGLOG_DEBUG(Render, "shutdown OK"); } } // namespace VideoCore -- cgit v1.2.3 From e2f2a49d2d0fd51ef83ef94fa2e93a2829d974e5 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 19:45:14 -0500 Subject: GPU: Corrected the upper bound of the PFIFO method ids in the command processor. --- src/video_core/command_processor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index f6a88f031..26792a2bf 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -27,7 +27,7 @@ enum class BufferMethods { SetGraphMacroCode = 0x45, SetGraphMacroCodeArg = 0x46, SetGraphMacroEntry = 0x47, - CountBufferMethods = 0x100, + CountBufferMethods = 0x40, }; void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { -- cgit v1.2.3 From a994446b6ec776c9383e8b13c45eeb461405adff Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 20:01:29 -0500 Subject: GPU: Move the Maxwell3D macro uploading code to the inside of the Maxwell3D processor. It doesn't belong in the PFIFO handler. --- src/video_core/command_processor.cpp | 25 ------------------------- src/video_core/engines/maxwell_3d.cpp | 14 ++++++++++---- src/video_core/engines/maxwell_3d.h | 17 +++++++++++++---- src/video_core/gpu.h | 7 ------- 4 files changed, 23 insertions(+), 40 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 26792a2bf..2eaece298 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -24,9 +24,6 @@ namespace Tegra { enum class BufferMethods { BindObject = 0, - SetGraphMacroCode = 0x45, - SetGraphMacroCodeArg = 0x46, - SetGraphMacroEntry = 0x47, CountBufferMethods = 0x40, }; @@ -36,28 +33,6 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) "{:08X} remaining params {}", method, subchannel, value, remaining_params); - if (method == static_cast(BufferMethods::SetGraphMacroEntry)) { - // Prepare to upload a new macro, reset the upload counter. - NGLOG_DEBUG(HW_GPU, "Uploading GPU macro {:08X}", value); - current_macro_entry = value; - current_macro_code.clear(); - return; - } - - if (method == static_cast(BufferMethods::SetGraphMacroCodeArg)) { - // Append a new code word to the current macro. - current_macro_code.push_back(value); - - // There are no more params remaining, submit the code to the 3D engine. - if (remaining_params == 0) { - maxwell_3d->SubmitMacroCode(current_macro_entry, std::move(current_macro_code)); - current_macro_entry = InvalidGraphMacroEntry; - current_macro_code.clear(); - } - - return; - } - if (method == static_cast(BufferMethods::BindObject)) { // Bind the current subchannel to the desired engine id. NGLOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 2acbb9cd6..bc40f8d98 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -22,10 +22,6 @@ constexpr u32 MacroRegistersStart = 0xE00; Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager), macro_interpreter(*this) {} -void Maxwell3D::SubmitMacroCode(u32 entry, std::vector code) { - uploaded_macros[entry * 2 + MacroRegistersStart] = std::move(code); -} - void Maxwell3D::CallMacroMethod(u32 method, std::vector parameters) { auto macro_code = uploaded_macros.find(method); // The requested macro must have been uploaded already. @@ -75,6 +71,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { regs.reg_array[method] = value; switch (method) { + case MAXWELL3D_REG_INDEX(macros.data): { + ProcessMacroUpload(value); + break; + } case MAXWELL3D_REG_INDEX(code_address.code_address_high): case MAXWELL3D_REG_INDEX(code_address.code_address_low): { // Note: For some reason games (like Puyo Puyo Tetris) seem to write 0 to the CODE_ADDRESS @@ -141,6 +141,12 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { } } +void Maxwell3D::ProcessMacroUpload(u32 data) { + // Store the uploaded macro code to interpret them when they're called. + auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart]; + macro.push_back(data); +} + void Maxwell3D::ProcessQueryGet() { GPUVAddr sequence_address = regs.query.QueryAddress(); // Since the sequence address is given as a GPU VAddr, we have to convert it to an application diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index a022665eb..8edc3cd38 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -322,7 +322,15 @@ public: union { struct { - INSERT_PADDING_WORDS(0x200); + INSERT_PADDING_WORDS(0x45); + + struct { + INSERT_PADDING_WORDS(1); + u32 data; + u32 entry; + } macros; + + INSERT_PADDING_WORDS(0x1B8); struct { u32 address_high; @@ -637,9 +645,6 @@ public: /// Write the value to the register identified by method. void WriteReg(u32 method, u32 value, u32 remaining_params); - /// Uploads the code for a GPU macro program associated with the specified entry. - void SubmitMacroCode(u32 entry, std::vector code); - /// Returns a list of enabled textures for the specified shader stage. std::vector GetStageTextures(Regs::ShaderStage stage) const; @@ -670,6 +675,9 @@ private: */ void CallMacroMethod(u32 method, std::vector parameters); + /// Handles writes to the macro uploading registers. + void ProcessMacroUpload(u32 data); + /// Handles a write to the QUERY_GET register. void ProcessQueryGet(); @@ -687,6 +695,7 @@ private: static_assert(offsetof(Maxwell3D::Regs, field_name) == position * 4, \ "Field " #field_name " has invalid position") +ASSERT_REG_POSITION(macros, 0x45); ASSERT_REG_POSITION(rt, 0x200); ASSERT_REG_POSITION(viewport_transform[0], 0x280); ASSERT_REG_POSITION(viewport, 0x300); diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 2888daedc..7afa6aaef 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -86,8 +86,6 @@ public: } private: - static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF; - /// Writes a single register in the engine bound to the specified subchannel void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params); @@ -100,11 +98,6 @@ private: std::unique_ptr fermi_2d; /// Compute engine std::unique_ptr maxwell_compute; - - /// Entry of the macro that is currently being uploaded - u32 current_macro_entry = InvalidGraphMacroEntry; - /// Code being uploaded for the current macro - std::vector current_macro_code; }; } // namespace Tegra -- cgit v1.2.3 From c16cfbbc6c062491d84a6bc9976027b7a7587fdb Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 20:03:50 -0500 Subject: GPU: Reduce the number of registers of Maxwell3D to 0xE00. The rest are just macro shim registers. --- src/video_core/engines/maxwell_3d.cpp | 6 +++--- src/video_core/engines/maxwell_3d.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index bc40f8d98..4306b894f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -33,9 +33,6 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector parameters) { } void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { - ASSERT_MSG(method < Regs::NUM_REGS, - "Invalid Maxwell3D register, increase the size of the Regs structure"); - auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); // It is an error to write to a register other than the current macro's ARG register before it @@ -64,6 +61,9 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { return; } + ASSERT_MSG(method < Regs::NUM_REGS, + "Invalid Maxwell3D register, increase the size of the Regs structure"); + if (debug_context) { debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); } diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 8edc3cd38..5cf62fb01 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -31,7 +31,7 @@ public: /// Register structure of the Maxwell3D engine. /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. struct Regs { - static constexpr size_t NUM_REGS = 0xE36; + static constexpr size_t NUM_REGS = 0xE00; static constexpr size_t NumRenderTargets = 8; static constexpr size_t NumViewports = 16; @@ -613,7 +613,7 @@ public: u32 size[MaxShaderStage]; } tex_info_buffers; - INSERT_PADDING_WORDS(0x102); + INSERT_PADDING_WORDS(0xCC); }; std::array reg_array; }; -- cgit v1.2.3 From b1109931b9a92ce89635cb7c0c0c1c0c7e6866ed Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 20:12:40 -0500 Subject: GPU: Added boilerplate code for the Fermi2D engine --- src/video_core/engines/fermi_2d.cpp | 7 ++++++- src/video_core/engines/fermi_2d.h | 28 +++++++++++++++++++++++++++- src/video_core/gpu.cpp | 2 +- 3 files changed, 34 insertions(+), 3 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 7aab163dc..87634da21 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -7,7 +7,12 @@ namespace Tegra { namespace Engines { -void Fermi2D::WriteReg(u32 method, u32 value) {} +Fermi2D::Fermi2D(MemoryManager& memory_manager) : memory_manager(memory_manager) {} + +void Fermi2D::WriteReg(u32 method, u32 value) { + ASSERT_MSG(method < Regs::NUM_REGS, + "Invalid Fermi2D register, increase the size of the Regs structure"); +} } // namespace Engines } // namespace Tegra diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 8967ddede..a97f5bb28 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -4,19 +4,45 @@ #pragma once +#include +#include "common/assert.h" +#include "common/common_funcs.h" #include "common/common_types.h" +#include "video_core/memory_manager.h" namespace Tegra { namespace Engines { +#define FERMI2D_REG_INDEX(field_name) \ + (offsetof(Tegra::Engines::Fermi2D::Regs, field_name) / sizeof(u32)) + class Fermi2D final { public: - Fermi2D() = default; + explicit Fermi2D(MemoryManager& memory_manager); ~Fermi2D() = default; /// Write the value to the register identified by method. void WriteReg(u32 method, u32 value); + + struct Regs { + static constexpr size_t NUM_REGS = 0x258; + + union { + struct { + INSERT_PADDING_WORDS(0x258); + }; + std::array reg_array; + }; + } regs{}; + + MemoryManager& memory_manager; }; +#define ASSERT_REG_POSITION(field_name, position) \ + static_assert(offsetof(Fermi2D::Regs, field_name) == position * 4, \ + "Field " #field_name " has invalid position") + +#undef ASSERT_REG_POSITION + } // namespace Engines } // namespace Tegra diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 9463cd5d6..351d21711 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -12,7 +12,7 @@ namespace Tegra { GPU::GPU() { memory_manager = std::make_unique(); maxwell_3d = std::make_unique(*memory_manager); - fermi_2d = std::make_unique(); + fermi_2d = std::make_unique(*memory_manager); maxwell_compute = std::make_unique(); } -- cgit v1.2.3 From 378c881427d34962461099ef3d55de871710b897 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Apr 2018 22:14:08 -0500 Subject: GPU: Added surface copy registers to Fermi2D --- src/video_core/engines/fermi_2d.h | 58 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'src/video_core') diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index a97f5bb28..78d06218f 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -6,8 +6,10 @@ #include #include "common/assert.h" +#include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "video_core/gpu.h" #include "video_core/memory_manager.h" namespace Tegra { @@ -27,9 +29,59 @@ public: struct Regs { static constexpr size_t NUM_REGS = 0x258; + struct Surface { + RenderTargetFormat format; + BitField<0, 1, u32> linear; + union { + BitField<0, 4, u32> block_depth; + BitField<4, 4, u32> block_height; + BitField<8, 4, u32> block_width; + }; + u32 depth; + u32 layer; + u32 pitch; + u32 width; + u32 height; + u32 address_high; + u32 address_low; + + GPUVAddr Address() const { + return static_cast((static_cast(address_high) << 32) | + address_low); + } + }; + static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size"); + + enum class Operation : u32 { + SrcCopyAnd = 0, + ROPAnd = 1, + Blend = 2, + SrcCopy = 3, + ROP = 4, + SrcCopyPremult = 5, + BlendPremult = 6, + }; + union { struct { - INSERT_PADDING_WORDS(0x258); + INSERT_PADDING_WORDS(0x80); + + Surface dst; + + INSERT_PADDING_WORDS(2); + + Surface src; + + INSERT_PADDING_WORDS(0x15); + + Operation operation; + + INSERT_PADDING_WORDS(0x9); + + // TODO(Subv): This is only a guess. + u32 trigger; + + INSERT_PADDING_WORDS(0x1A3); }; std::array reg_array; }; @@ -42,6 +94,10 @@ public: static_assert(offsetof(Fermi2D::Regs, field_name) == position * 4, \ "Field " #field_name " has invalid position") +ASSERT_REG_POSITION(dst, 0x80); +ASSERT_REG_POSITION(src, 0x8C); +ASSERT_REG_POSITION(operation, 0xAB); +ASSERT_REG_POSITION(trigger, 0xB5); #undef ASSERT_REG_POSITION } // namespace Engines -- cgit v1.2.3 From a6da2b93c16fd09ef491606d9a0dc99b51f4186f Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Apr 2018 21:57:10 -0500 Subject: GPU: Added a function to retrieve the bytes per pixel of the render target formats. --- src/video_core/gpu.cpp | 12 ++++++++++++ src/video_core/gpu.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 351d21711..9eb143918 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -22,4 +22,16 @@ const Tegra::Engines::Maxwell3D& GPU::Get3DEngine() const { return *maxwell_3d; } +u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { + ASSERT(format != RenderTargetFormat::NONE); + + switch (format) { + case RenderTargetFormat::RGBA8_UNORM: + case RenderTargetFormat::RGB10_A2_UNORM: + return 4; + default: + UNIMPLEMENTED_MSG("Unimplemented render target format %u", static_cast(format)); + } +} + } // namespace Tegra diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 7afa6aaef..f168a5171 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -21,6 +21,9 @@ enum class RenderTargetFormat : u32 { RGBA8_SRGB = 0xD6, }; +/// Returns the number of bytes per pixel of each rendertarget format. +u32 RenderTargetBytesPerPixel(RenderTargetFormat format); + class DebugContext; /** -- cgit v1.2.3 From 1dd4861d38b862724052a5db66067d77ede468d4 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Apr 2018 21:58:45 -0500 Subject: GPU: Make the Textures::CopySwizzledData function accessible from the outside of the file. --- src/video_core/textures/decoders.cpp | 5 ++--- src/video_core/textures/decoders.h | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 9c3ae875c..8b39b2bdf 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -27,9 +27,8 @@ static u32 GetSwizzleOffset(u32 x, u32 y, u32 image_width, u32 bytes_per_pixel, return address; } -static void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, - u8* swizzled_data, u8* unswizzled_data, bool unswizzle, - u32 block_height) { +void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, + u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) { u8* data_ptrs[2]; for (unsigned y = 0; y < height; ++y) { for (unsigned x = 0; x < width; ++x) { diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index a700911cf..2562c4b06 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -17,6 +17,10 @@ namespace Texture { std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, u32 block_height = TICEntry::DefaultBlockHeight); +/// Copies texture data from a buffer and performs swizzling/unswizzling as necessary. +void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, + u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height); + /** * Decodes an unswizzled texture into a A8R8G8B8 texture. */ -- cgit v1.2.3 From 1740aa544408d32a5c904f40d92c6e06ace6d00a Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 25 Apr 2018 11:17:38 -0500 Subject: Shaders: Implemented the FSET instruction. This instruction is similar to the FSETP instruction, but it doesn't set a predicate, it sets the destination register to 1.0 if the condition holds, and 0 otherwise. --- .../renderer_opengl/gl_shader_decompiler.cpp | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 896b6cd2c..3dffb205d 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -570,6 +570,59 @@ private: } break; } + case OpCode::Type::FloatSet: { + std::string dest = GetRegister(instr.gpr0); + std::string op_a = instr.fset.neg_a ? "-" : ""; + op_a += GetRegister(instr.gpr8); + + if (instr.fset.abs_a) { + op_a = "abs(" + op_a + ')'; + } + + std::string op_b = instr.fset.neg_b ? "-" : ""; + + if (instr.is_b_imm) { + std::string imm = GetImmediate19(instr); + if (instr.fset.neg_imm) + op_b += "(-" + imm + ')'; + else + op_b += imm; + } else { + if (instr.is_b_gpr) { + op_b += GetRegister(instr.gpr20); + } else { + op_b += GetUniform(instr.uniform); + } + } + + if (instr.fset.abs_b) { + op_b = "abs(" + op_b + ")"; + } + + using Tegra::Shader::Pred; + ASSERT_MSG(instr.fset.pred39 == static_cast(Pred::UnusedIndex), + "Compound predicates are not implemented"); + + // The fset instruction sets a register to 1.0 if the condition is true, and to 0 + // otherwise. + using Tegra::Shader::PredCondition; + switch (instr.fset.cond) { + case PredCondition::LessThan: + SetDest(0, dest, "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1); + break; + case PredCondition::Equal: + SetDest(0, dest, "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1); + break; + case PredCondition::GreaterThan: + SetDest(0, dest, "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1); + break; + default: + NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})", + static_cast(instr.fset.cond.Value()), op_a, op_b); + UNREACHABLE(); + } + break; + } default: { switch (opcode->GetId()) { case OpCode::Id::EXIT: { -- cgit v1.2.3 From e9ad8e9185a4ab7f29728dbaf131de328eefc4fc Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 25 Apr 2018 12:52:55 -0500 Subject: Shaders: Added bit decodings for the I2I instruction. --- src/video_core/engines/shader_bytecode.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 6cae6ff45..f4d11fa5d 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -275,6 +275,9 @@ public: I2F_C, I2F_R, I2F_IMM, + I2I_C, + I2I_R, + I2I_IMM, LOP32I, MOV_C, MOV_R, @@ -427,6 +430,9 @@ private: INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"), INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"), INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"), + INST("0100110011100---", Id::I2I_C, Type::Arithmetic, "I2I_C"), + INST("0101110011100---", Id::I2I_R, Type::Arithmetic, "I2I_R"), + INST("01110001-1000---", Id::I2I_IMM, Type::Arithmetic, "I2I_IMM"), INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"), INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), -- cgit v1.2.3 From 20d86d8a36dca4bf1b465193745a365c3ab9abcd Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Apr 2018 22:00:40 -0500 Subject: GPU: Partially implemented the Fermi2D surface copy operation. The hardware allows for some rather complicated operations to be performed on the data during the copy, this is not implemented. Only same-format same-size raw copies are implemented for now. --- src/video_core/engines/fermi_2d.cpp | 54 +++++++++++++++++++++++++++++++++++++ src/video_core/engines/fermi_2d.h | 5 ++++ 2 files changed, 59 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 87634da21..9019f2504 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -2,7 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/memory.h" #include "video_core/engines/fermi_2d.h" +#include "video_core/textures/decoders.h" namespace Tegra { namespace Engines { @@ -12,6 +14,58 @@ Fermi2D::Fermi2D(MemoryManager& memory_manager) : memory_manager(memory_manager) void Fermi2D::WriteReg(u32 method, u32 value) { ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Fermi2D register, increase the size of the Regs structure"); + + regs.reg_array[method] = value; + + switch (method) { + case FERMI2D_REG_INDEX(trigger): { + HandleSurfaceCopy(); + break; + } + } +} + +void Fermi2D::HandleSurfaceCopy() { + NGLOG_WARNING(HW_GPU, "Requested a surface copy with operation {}", + static_cast(regs.operation)); + + const GPUVAddr source = regs.src.Address(); + const GPUVAddr dest = regs.dst.Address(); + + // TODO(Subv): Only same-format and same-size copies are allowed for now. + ASSERT(regs.src.format == regs.dst.format); + ASSERT(regs.src.width * regs.src.height == regs.dst.width * regs.dst.height); + + // TODO(Subv): Only raw copies are implemented. + ASSERT(regs.operation == Regs::Operation::SrcCopy); + + const VAddr source_cpu = *memory_manager.GpuToCpuAddress(source); + const VAddr dest_cpu = *memory_manager.GpuToCpuAddress(dest); + + u32 src_bytes_per_pixel = RenderTargetBytesPerPixel(regs.src.format); + u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); + + if (regs.src.linear == regs.dst.linear) { + // If the input layout and the output layout are the same, just perform a raw copy. + Memory::CopyBlock(dest_cpu, source_cpu, + src_bytes_per_pixel * regs.dst.width * regs.dst.height); + return; + } + + u8* src_buffer = Memory::GetPointer(source_cpu); + u8* dst_buffer = Memory::GetPointer(dest_cpu); + + if (!regs.src.linear && regs.dst.linear) { + // If the input is tiled and the output is linear, deswizzle the input and copy it over. + Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel, + dst_bytes_per_pixel, src_buffer, dst_buffer, true, + regs.src.block_height); + } else { + // If the input is linear and the output is tiled, swizzle the input and copy it over. + Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel, + dst_bytes_per_pixel, dst_buffer, src_buffer, false, + regs.dst.block_height); + } } } // namespace Engines diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 78d06218f..0c5b413cc 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -88,6 +88,11 @@ public: } regs{}; MemoryManager& memory_manager; + +private: + /// Performs the copy from the source surface to the destination surface as configured in the + /// registers. + void HandleSurfaceCopy(); }; #define ASSERT_REG_POSITION(field_name, position) \ -- cgit v1.2.3