From 195fedccf07b909c95e5905c7154c595bb260fc7 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 6 Dec 2015 19:06:12 -0800 Subject: [PATCH] VideoCore: Unify interface to OpenGL and SW rasterizers This removes explicit checks sprinkled all over the codebase to instead just have the SW rasterizer expose an implementation with no-ops for most operations. --- src/core/hle/service/gsp_gpu.cpp | 8 +++--- src/core/hle/service/y2r_u.cpp | 2 +- src/core/hw/gpu.cpp | 12 ++++---- src/video_core/CMakeLists.txt | 5 +++- src/video_core/clipper.cpp | 2 +- src/video_core/clipper.h | 2 +- src/video_core/command_processor.cpp | 25 ++++++----------- src/video_core/debug_utils/debug_utils.cpp | 6 ++-- ...sterizer_base.h => rasterizer_interface.h} | 9 ++++-- src/video_core/renderer_base.cpp | 28 +++++++++++++++++++ src/video_core/renderer_base.h | 8 ++++-- .../renderer_opengl/gl_rasterizer.cpp | 9 ------ .../renderer_opengl/gl_rasterizer.h | 19 ++----------- .../renderer_opengl/renderer_opengl.cpp | 15 ++-------- src/video_core/swrasterizer.cpp | 16 +++++++++++ src/video_core/swrasterizer.h | 26 +++++++++++++++++ 16 files changed, 115 insertions(+), 77 deletions(-) rename src/video_core/{hwrasterizer_base.h => rasterizer_interface.h} (93%) create mode 100644 src/video_core/renderer_base.cpp create mode 100644 src/video_core/swrasterizer.cpp create mode 100644 src/video_core/swrasterizer.h diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 3e4c70e184..98b11c7989 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -275,7 +275,7 @@ static void FlushDataCache(Service::Interface* self) { u32 size = cmd_buff[2]; u32 process = cmd_buff[4]; - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(address), size); + VideoCore::g_renderer->rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(address), size); // TODO(purpasmart96): Verify return header on HW @@ -365,7 +365,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { // GX request DMA - typically used for copying memory from GSP heap to VRAM case CommandId::REQUEST_DMA: - VideoCore::g_renderer->hw_rasterizer->FlushRegion(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), + VideoCore::g_renderer->rasterizer->FlushRegion(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), command.dma_request.size); memcpy(Memory::GetPointer(command.dma_request.dest_address), @@ -373,7 +373,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { command.dma_request.size); SignalInterrupt(InterruptId::DMA); - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), + VideoCore::g_renderer->rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), command.dma_request.size); break; @@ -467,7 +467,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { if (region.size == 0) break; - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion( + VideoCore::g_renderer->rasterizer->InvalidateRegion( Memory::VirtualToPhysicalAddress(region.address), region.size); } break; diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index face1d7b02..0429927f29 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -267,7 +267,7 @@ static void StartConversion(Service::Interface* self) { // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( u32 total_output_size = conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion( + VideoCore::g_renderer->rasterizer->InvalidateRegion( Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); LOG_DEBUG(Service_Y2R, "called"); diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 55e215600d..4bd3a632da 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -26,7 +26,7 @@ #include "core/tracer/recorder.h" #include "video_core/command_processor.h" -#include "video_core/hwrasterizer_base.h" +#include "video_core/rasterizer_interface.h" #include "video_core/renderer_base.h" #include "video_core/utils.h" #include "video_core/video_core.h" @@ -141,7 +141,7 @@ inline void Write(u32 addr, const T data) { GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); } - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); + VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); } // Reset "trigger" flag and set the "finish" flag @@ -172,7 +172,7 @@ inline void Write(u32 addr, const T data) { u32 output_gap = config.texture_copy.output_gap * 16; size_t contiguous_input_size = config.texture_copy.size / input_width * (input_width + input_gap); - VideoCore::g_renderer->hw_rasterizer->FlushRegion(config.GetPhysicalInputAddress(), contiguous_input_size); + VideoCore::g_renderer->rasterizer->FlushRegion(config.GetPhysicalInputAddress(), contiguous_input_size); u32 remaining_size = config.texture_copy.size; u32 remaining_input = input_width; @@ -205,7 +205,7 @@ inline void Write(u32 addr, const T data) { config.flags); size_t contiguous_output_size = config.texture_copy.size / output_width * (output_width + output_gap); - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), contiguous_output_size); + VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), contiguous_output_size); GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); break; @@ -232,7 +232,7 @@ inline void Write(u32 addr, const T data) { u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); - VideoCore::g_renderer->hw_rasterizer->FlushRegion(config.GetPhysicalInputAddress(), input_size); + VideoCore::g_renderer->rasterizer->FlushRegion(config.GetPhysicalInputAddress(), input_size); for (u32 y = 0; y < output_height; ++y) { for (u32 x = 0; x < output_width; ++x) { @@ -339,7 +339,7 @@ inline void Write(u32 addr, const T data) { g_regs.display_transfer_config.trigger = 0; GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); - VideoCore::g_renderer->hw_rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), output_size); + VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), output_size); } break; } diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 2a924f4ad0..c3d7294d58 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -11,8 +11,10 @@ set(SRCS pica.cpp primitive_assembly.cpp rasterizer.cpp + renderer_base.cpp shader/shader.cpp shader/shader_interpreter.cpp + swrasterizer.cpp utils.cpp video_core.cpp ) @@ -30,13 +32,14 @@ set(HEADERS clipper.h command_processor.h gpu_debugger.h - hwrasterizer_base.h pica.h primitive_assembly.h rasterizer.h + rasterizer_interface.h renderer_base.h shader/shader.h shader/shader_interpreter.h + swrasterizer.h utils.h video_core.h ) diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp index ed99c4f134..5d609da065 100644 --- a/src/video_core/clipper.cpp +++ b/src/video_core/clipper.cpp @@ -78,7 +78,7 @@ static void InitScreenCoordinates(OutputVertex& vtx) vtx.screenpos[2] = viewport.offset_z + vtx.pos.z * inv_w * viewport.zscale; } -void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { +void ProcessTriangle(const OutputVertex &v0, const OutputVertex &v1, const OutputVertex &v2) { using boost::container::static_vector; // Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at diff --git a/src/video_core/clipper.h b/src/video_core/clipper.h index 6ed01e8772..f85d8d4c90 100644 --- a/src/video_core/clipper.h +++ b/src/video_core/clipper.h @@ -14,7 +14,7 @@ namespace Clipper { using Shader::OutputVertex; -void ProcessTriangle(OutputVertex& v0, OutputVertex& v1, OutputVertex& v2); +void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2); } // namespace diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index bd1b09a4b8..35b976c604 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -336,19 +336,14 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { } } - if (Settings::values.use_hw_renderer) { - // Send to hardware renderer - static auto AddHWTriangle = [](const Pica::Shader::OutputVertex& v0, - const Pica::Shader::OutputVertex& v1, - const Pica::Shader::OutputVertex& v2) { - VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); - }; + // Send to renderer + using Pica::Shader::OutputVertex; + auto AddTriangle = []( + const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { + VideoCore::g_renderer->rasterizer->AddTriangle(v0, v1, v2); + }; - primitive_assembler.SubmitVertex(output, AddHWTriangle); - } else { - // Send to triangle clipper - primitive_assembler.SubmitVertex(output, Clipper::ProcessTriangle); - } + primitive_assembler.SubmitVertex(output, AddTriangle); } for (auto& range : memory_accesses.ranges) { @@ -356,9 +351,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { range.second, range.first); } - if (Settings::values.use_hw_renderer) { - VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); - } + VideoCore::g_renderer->rasterizer->DrawTriangles(); #if PICA_DUMP_GEOMETRY geometry_dumper.Dump(); @@ -475,7 +468,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { break; } - VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); + VideoCore::g_renderer->rasterizer->NotifyPicaRegisterChanged(id); if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast(&id)); diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 0e29661c71..4f66dbd658 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -46,10 +46,8 @@ void DebugContext::OnEvent(Event event, void* data) { { std::unique_lock lock(breakpoint_mutex); - if (Settings::values.use_hw_renderer) { - // Commit the hardware renderer's framebuffer so it will show on debug widgets - VideoCore::g_renderer->hw_rasterizer->FlushFramebuffer(); - } + // Commit the hardware renderer's framebuffer so it will show on debug widgets + VideoCore::g_renderer->rasterizer->FlushFramebuffer(); // TODO: Should stop the CPU thread here once we multithread emulation. diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/rasterizer_interface.h similarity index 93% rename from src/video_core/hwrasterizer_base.h rename to src/video_core/rasterizer_interface.h index b6390950a4..008c5827be 100644 --- a/src/video_core/hwrasterizer_base.h +++ b/src/video_core/rasterizer_interface.h @@ -12,10 +12,11 @@ struct OutputVertex; } } -class HWRasterizer { +namespace VideoCore { + +class RasterizerInterface { public: - virtual ~HWRasterizer() { - } + virtual ~RasterizerInterface() {} /// Initialize API-specific GPU objects virtual void InitObjects() = 0; @@ -43,3 +44,5 @@ public: /// Notify rasterizer that any caches of the specified region should be discraded and reloaded from 3DS memory. virtual void InvalidateRegion(PAddr addr, u32 size) = 0; }; + +} diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp new file mode 100644 index 0000000000..93e980216a --- /dev/null +++ b/src/video_core/renderer_base.cpp @@ -0,0 +1,28 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/make_unique.h" + +#include "core/settings.h" + +#include "video_core/renderer_base.h" +#include "video_core/video_core.h" +#include "video_core/swrasterizer.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" + +void RendererBase::RefreshRasterizerSetting() { + bool hw_renderer_enabled = VideoCore::g_hw_renderer_enabled; + if (rasterizer == nullptr || opengl_rasterizer_active != hw_renderer_enabled) { + opengl_rasterizer_active = hw_renderer_enabled; + + if (hw_renderer_enabled) { + rasterizer = Common::make_unique(); + } else { + rasterizer = Common::make_unique(); + } + rasterizer->InitObjects(); + } +} diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 6587bcf271..506bff8151 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -8,7 +8,7 @@ #include "common/common_types.h" -#include "video_core/hwrasterizer_base.h" +#include "video_core/rasterizer_interface.h" class EmuWindow; @@ -54,10 +54,14 @@ public: return m_current_frame; } - std::unique_ptr hw_rasterizer; + void RefreshRasterizerSetting(); + + std::unique_ptr rasterizer; protected: f32 m_current_fps; ///< Current framerate, should be set by the renderer int m_current_frame; ///< Current frame, should be set by the renderer +private: + bool opengl_rasterizer_active = false; }; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index cc7830688e..681fdca8d1 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -188,9 +188,6 @@ void RasterizerOpenGL::FlushFramebuffer() { void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { const auto& regs = Pica::g_state.regs; - if (!Settings::values.use_hw_renderer) - return; - switch(id) { // Culling case PICA_REG_INDEX(cull_mode): @@ -287,9 +284,6 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { const auto& regs = Pica::g_state.regs; - if (!Settings::values.use_hw_renderer) - return; - PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); @@ -309,9 +303,6 @@ void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { const auto& regs = Pica::g_state.regs; - if (!Settings::values.use_hw_renderer) - return; - PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 378cdb65c3..92b1f812e8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -14,7 +14,7 @@ #include "common/hash.h" #include "video_core/pica.h" -#include "video_core/hwrasterizer_base.h" +#include "video_core/rasterizer_interface.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_state.h" #include "video_core/shader/shader_interpreter.h" @@ -102,36 +102,21 @@ struct hash { } // namespace std -class RasterizerOpenGL : public HWRasterizer { +class RasterizerOpenGL : public VideoCore::RasterizerInterface { public: RasterizerOpenGL(); ~RasterizerOpenGL() override; - /// Initialize API-specific GPU objects void InitObjects() override; - - /// Reset the rasterizer, such as flushing all caches and updating all state void Reset() override; - - /// Queues the primitive formed by the given vertices for rendering void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1, const Pica::Shader::OutputVertex& v2) override; - - /// Draw the current batch of triangles void DrawTriangles() override; - - /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer void FlushFramebuffer() override; - - /// Notify rasterizer that the specified PICA register has been changed void NotifyPicaRegisterChanged(u32 id) override; - - /// Notify rasterizer that the specified 3DS memory region will be read from after this notification void FlushRegion(PAddr addr, u32 size) override; - - /// Notify rasterizer that a 3DS memory region has been changed void InvalidateRegion(PAddr addr, u32 size) override; /// OpenGL shader generated for a given Pica register state diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 1420229ccd..c14bdb8ab9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -93,7 +93,6 @@ static std::array MakeOrthographicMatrix(const float width, const /// RendererOpenGL constructor RendererOpenGL::RendererOpenGL() { - hw_rasterizer.reset(new RasterizerOpenGL()); resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; } @@ -157,15 +156,7 @@ void RendererOpenGL::SwapBuffers() { profiler.BeginFrame(); - bool hw_renderer_enabled = VideoCore::g_hw_renderer_enabled; - if (Settings::values.use_hw_renderer != hw_renderer_enabled) { - // TODO: Save new setting value to config file for next startup - Settings::values.use_hw_renderer = hw_renderer_enabled; - - if (Settings::values.use_hw_renderer) { - hw_rasterizer->Reset(); - } - } + RefreshRasterizerSetting(); if (Pica::g_debug_context && Pica::g_debug_context->recorder) { Pica::g_debug_context->recorder->FrameFinished(); @@ -286,8 +277,6 @@ void RendererOpenGL::InitOpenGLObjects() { state.texture_units[0].texture_2d = 0; state.Apply(); - - hw_rasterizer->InitObjects(); } void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, @@ -419,6 +408,8 @@ void RendererOpenGL::Init() { LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR)); LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER)); InitOpenGLObjects(); + + RefreshRasterizerSetting(); } /// Shutdown the renderer diff --git a/src/video_core/swrasterizer.cpp b/src/video_core/swrasterizer.cpp new file mode 100644 index 0000000000..03df15b013 --- /dev/null +++ b/src/video_core/swrasterizer.cpp @@ -0,0 +1,16 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/clipper.h" +#include "video_core/swrasterizer.h" + +namespace VideoCore { + +void SWRasterizer::AddTriangle(const Pica::Shader::OutputVertex& v0, + const Pica::Shader::OutputVertex& v1, + const Pica::Shader::OutputVertex& v2) { + Pica::Clipper::ProcessTriangle(v0, v1, v2); +} + +} diff --git a/src/video_core/swrasterizer.h b/src/video_core/swrasterizer.h new file mode 100644 index 0000000000..e9a4e39c6e --- /dev/null +++ b/src/video_core/swrasterizer.h @@ -0,0 +1,26 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "video_core/rasterizer_interface.h" + +namespace VideoCore { + +class SWRasterizer : public RasterizerInterface { + void InitObjects() override {} + void Reset() override {} + void AddTriangle(const Pica::Shader::OutputVertex& v0, + const Pica::Shader::OutputVertex& v1, + const Pica::Shader::OutputVertex& v2); + void DrawTriangles() override {} + void FlushFramebuffer() override {} + void NotifyPicaRegisterChanged(u32 id) override {} + void FlushRegion(PAddr addr, u32 size) override {} + void InvalidateRegion(PAddr addr, u32 size) override {} +}; + +}