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.
master
Yuri Kunde Schlesner 2015-12-06 19:06:12 +07:00
parent 03835d04f4
commit 195fedccf0
16 changed files with 115 additions and 77 deletions

@ -275,7 +275,7 @@ static void FlushDataCache(Service::Interface* self) {
u32 size = cmd_buff[2]; u32 size = cmd_buff[2];
u32 process = cmd_buff[4]; 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 // 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 // GX request DMA - typically used for copying memory from GSP heap to VRAM
case CommandId::REQUEST_DMA: 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); command.dma_request.size);
memcpy(Memory::GetPointer(command.dma_request.dest_address), 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); command.dma_request.size);
SignalInterrupt(InterruptId::DMA); 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); command.dma_request.size);
break; break;
@ -467,7 +467,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
if (region.size == 0) if (region.size == 0)
break; break;
VideoCore::g_renderer->hw_rasterizer->InvalidateRegion( VideoCore::g_renderer->rasterizer->InvalidateRegion(
Memory::VirtualToPhysicalAddress(region.address), region.size); Memory::VirtualToPhysicalAddress(region.address), region.size);
} }
break; break;

@ -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 :( // dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
u32 total_output_size = conversion.input_lines * u32 total_output_size = conversion.input_lines *
(conversion.dst.transfer_unit + conversion.dst.gap); (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); Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size);
LOG_DEBUG(Service_Y2R, "called"); LOG_DEBUG(Service_Y2R, "called");

@ -26,7 +26,7 @@
#include "core/tracer/recorder.h" #include "core/tracer/recorder.h"
#include "video_core/command_processor.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/renderer_base.h"
#include "video_core/utils.h" #include "video_core/utils.h"
#include "video_core/video_core.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); 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 // 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; u32 output_gap = config.texture_copy.output_gap * 16;
size_t contiguous_input_size = config.texture_copy.size / input_width * (input_width + input_gap); 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_size = config.texture_copy.size;
u32 remaining_input = input_width; u32 remaining_input = input_width;
@ -205,7 +205,7 @@ inline void Write(u32 addr, const T data) {
config.flags); config.flags);
size_t contiguous_output_size = config.texture_copy.size / output_width * (output_width + output_gap); 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); GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
break; 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 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); 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 y = 0; y < output_height; ++y) {
for (u32 x = 0; x < output_width; ++x) { 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; g_regs.display_transfer_config.trigger = 0;
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); 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; break;
} }

@ -11,8 +11,10 @@ set(SRCS
pica.cpp pica.cpp
primitive_assembly.cpp primitive_assembly.cpp
rasterizer.cpp rasterizer.cpp
renderer_base.cpp
shader/shader.cpp shader/shader.cpp
shader/shader_interpreter.cpp shader/shader_interpreter.cpp
swrasterizer.cpp
utils.cpp utils.cpp
video_core.cpp video_core.cpp
) )
@ -30,13 +32,14 @@ set(HEADERS
clipper.h clipper.h
command_processor.h command_processor.h
gpu_debugger.h gpu_debugger.h
hwrasterizer_base.h
pica.h pica.h
primitive_assembly.h primitive_assembly.h
rasterizer.h rasterizer.h
rasterizer_interface.h
renderer_base.h renderer_base.h
shader/shader.h shader/shader.h
shader/shader_interpreter.h shader/shader_interpreter.h
swrasterizer.h
utils.h utils.h
video_core.h video_core.h
) )

@ -78,7 +78,7 @@ static void InitScreenCoordinates(OutputVertex& vtx)
vtx.screenpos[2] = viewport.offset_z + vtx.pos.z * inv_w * viewport.zscale; 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; using boost::container::static_vector;
// Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at // Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at

@ -14,7 +14,7 @@ namespace Clipper {
using Shader::OutputVertex; using Shader::OutputVertex;
void ProcessTriangle(OutputVertex& v0, OutputVertex& v1, OutputVertex& v2); void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2);
} // namespace } // namespace

@ -336,19 +336,14 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
} }
} }
if (Settings::values.use_hw_renderer) { // Send to renderer
// Send to hardware renderer using Pica::Shader::OutputVertex;
static auto AddHWTriangle = [](const Pica::Shader::OutputVertex& v0, auto AddTriangle = [](
const Pica::Shader::OutputVertex& v1, const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) {
const Pica::Shader::OutputVertex& v2) { VideoCore::g_renderer->rasterizer->AddTriangle(v0, v1, v2);
VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); };
};
primitive_assembler.SubmitVertex(output, AddHWTriangle); primitive_assembler.SubmitVertex(output, AddTriangle);
} else {
// Send to triangle clipper
primitive_assembler.SubmitVertex(output, Clipper::ProcessTriangle);
}
} }
for (auto& range : memory_accesses.ranges) { for (auto& range : memory_accesses.ranges) {
@ -356,9 +351,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
range.second, range.first); range.second, range.first);
} }
if (Settings::values.use_hw_renderer) { VideoCore::g_renderer->rasterizer->DrawTriangles();
VideoCore::g_renderer->hw_rasterizer->DrawTriangles();
}
#if PICA_DUMP_GEOMETRY #if PICA_DUMP_GEOMETRY
geometry_dumper.Dump(); geometry_dumper.Dump();
@ -475,7 +468,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
break; break;
} }
VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); VideoCore::g_renderer->rasterizer->NotifyPicaRegisterChanged(id);
if (g_debug_context) if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id)); g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id));

@ -46,10 +46,8 @@ void DebugContext::OnEvent(Event event, void* data) {
{ {
std::unique_lock<std::mutex> lock(breakpoint_mutex); std::unique_lock<std::mutex> lock(breakpoint_mutex);
if (Settings::values.use_hw_renderer) { // Commit the hardware renderer's framebuffer so it will show on debug widgets
// Commit the hardware renderer's framebuffer so it will show on debug widgets VideoCore::g_renderer->rasterizer->FlushFramebuffer();
VideoCore::g_renderer->hw_rasterizer->FlushFramebuffer();
}
// TODO: Should stop the CPU thread here once we multithread emulation. // TODO: Should stop the CPU thread here once we multithread emulation.

@ -12,10 +12,11 @@ struct OutputVertex;
} }
} }
class HWRasterizer { namespace VideoCore {
class RasterizerInterface {
public: public:
virtual ~HWRasterizer() { virtual ~RasterizerInterface() {}
}
/// Initialize API-specific GPU objects /// Initialize API-specific GPU objects
virtual void InitObjects() = 0; 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. /// 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; virtual void InvalidateRegion(PAddr addr, u32 size) = 0;
}; };
}

@ -0,0 +1,28 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#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<RasterizerOpenGL>();
} else {
rasterizer = Common::make_unique<VideoCore::SWRasterizer>();
}
rasterizer->InitObjects();
}
}

@ -8,7 +8,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/hwrasterizer_base.h" #include "video_core/rasterizer_interface.h"
class EmuWindow; class EmuWindow;
@ -54,10 +54,14 @@ public:
return m_current_frame; return m_current_frame;
} }
std::unique_ptr<HWRasterizer> hw_rasterizer; void RefreshRasterizerSetting();
std::unique_ptr<VideoCore::RasterizerInterface> rasterizer;
protected: protected:
f32 m_current_fps; ///< Current framerate, should be set by the renderer f32 m_current_fps; ///< Current framerate, should be set by the renderer
int m_current_frame; ///< Current frame, should be set by the renderer int m_current_frame; ///< Current frame, should be set by the renderer
private:
bool opengl_rasterizer_active = false;
}; };

@ -188,9 +188,6 @@ void RasterizerOpenGL::FlushFramebuffer() {
void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
if (!Settings::values.use_hw_renderer)
return;
switch(id) { switch(id) {
// Culling // Culling
case PICA_REG_INDEX(cull_mode): case PICA_REG_INDEX(cull_mode):
@ -287,9 +284,6 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
if (!Settings::values.use_hw_renderer)
return;
PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
* regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
@ -309,9 +303,6 @@ void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
if (!Settings::values.use_hw_renderer)
return;
PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
* regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();

@ -14,7 +14,7 @@
#include "common/hash.h" #include "common/hash.h"
#include "video_core/pica.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_rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"
#include "video_core/shader/shader_interpreter.h" #include "video_core/shader/shader_interpreter.h"
@ -102,36 +102,21 @@ struct hash<PicaShaderConfig> {
} // namespace std } // namespace std
class RasterizerOpenGL : public HWRasterizer { class RasterizerOpenGL : public VideoCore::RasterizerInterface {
public: public:
RasterizerOpenGL(); RasterizerOpenGL();
~RasterizerOpenGL() override; ~RasterizerOpenGL() override;
/// Initialize API-specific GPU objects
void InitObjects() override; void InitObjects() override;
/// Reset the rasterizer, such as flushing all caches and updating all state
void Reset() override; void Reset() override;
/// Queues the primitive formed by the given vertices for rendering
void AddTriangle(const Pica::Shader::OutputVertex& v0, void AddTriangle(const Pica::Shader::OutputVertex& v0,
const Pica::Shader::OutputVertex& v1, const Pica::Shader::OutputVertex& v1,
const Pica::Shader::OutputVertex& v2) override; const Pica::Shader::OutputVertex& v2) override;
/// Draw the current batch of triangles
void DrawTriangles() override; void DrawTriangles() override;
/// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer
void FlushFramebuffer() override; void FlushFramebuffer() override;
/// Notify rasterizer that the specified PICA register has been changed
void NotifyPicaRegisterChanged(u32 id) override; 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; void FlushRegion(PAddr addr, u32 size) override;
/// Notify rasterizer that a 3DS memory region has been changed
void InvalidateRegion(PAddr addr, u32 size) override; void InvalidateRegion(PAddr addr, u32 size) override;
/// OpenGL shader generated for a given Pica register state /// OpenGL shader generated for a given Pica register state

@ -93,7 +93,6 @@ static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const
/// RendererOpenGL constructor /// RendererOpenGL constructor
RendererOpenGL::RendererOpenGL() { RendererOpenGL::RendererOpenGL() {
hw_rasterizer.reset(new RasterizerOpenGL());
resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
} }
@ -157,15 +156,7 @@ void RendererOpenGL::SwapBuffers() {
profiler.BeginFrame(); profiler.BeginFrame();
bool hw_renderer_enabled = VideoCore::g_hw_renderer_enabled; RefreshRasterizerSetting();
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();
}
}
if (Pica::g_debug_context && Pica::g_debug_context->recorder) { if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
Pica::g_debug_context->recorder->FrameFinished(); Pica::g_debug_context->recorder->FrameFinished();
@ -286,8 +277,6 @@ void RendererOpenGL::InitOpenGLObjects() {
state.texture_units[0].texture_2d = 0; state.texture_units[0].texture_2d = 0;
state.Apply(); state.Apply();
hw_rasterizer->InitObjects();
} }
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, 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_VENDOR: %s", glGetString(GL_VENDOR));
LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER)); LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER));
InitOpenGLObjects(); InitOpenGLObjects();
RefreshRasterizerSetting();
} }
/// Shutdown the renderer /// Shutdown the renderer

@ -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);
}
}

@ -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 {}
};
}