diff --git a/src/core/core.cpp b/src/core/core.cpp index 9824769cfa..29222babaa 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -18,6 +18,7 @@ #include "core/loader/loader.h" #include "core/settings.h" #include "file_sys/vfs_real.h" +#include "video_core/renderer_base.h" #include "video_core/video_core.h" namespace Core { @@ -174,7 +175,6 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { cpu_cores[index] = std::make_shared(cpu_exclusive_monitor, cpu_barrier, index); } - gpu_core = std::make_unique(); telemetry_session = std::make_unique(); service_manager = std::make_shared(); @@ -182,10 +182,13 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { Service::Init(service_manager); GDBStub::Init(); - if (!VideoCore::Init(emu_window)) { + renderer = VideoCore::CreateRenderer(emu_window); + if (!renderer->Init()) { return ResultStatus::ErrorVideoCore; } + gpu_core = std::make_unique(*renderer->Rasterizer()); + // Create threads for CPU cores 1-3, and build thread_to_cpu map // CPU core 0 is run on the main thread thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; @@ -217,7 +220,7 @@ void System::Shutdown() { perf_results.frametime * 1000.0); // Shutdown emulation session - VideoCore::Shutdown(); + renderer.reset(); GDBStub::Shutdown(); Service::Shutdown(); Kernel::Shutdown(); diff --git a/src/core/core.h b/src/core/core.h index ed475ac4ef..059db4262c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -27,6 +27,10 @@ namespace Service::SM { class ServiceManager; } +namespace VideoCore { +class RendererBase; +} + namespace Core { class System { @@ -127,11 +131,26 @@ public: /// Gets a CPU interface to the CPU core with the specified index Cpu& CpuCore(size_t core_index); - /// Gets the GPU interface + /// Gets a mutable reference to the GPU interface Tegra::GPU& GPU() { return *gpu_core; } + /// Gets an immutable reference to the GPU interface. + const Tegra::GPU& GPU() const { + return *gpu_core; + } + + /// Gets a mutable reference to the renderer. + VideoCore::RendererBase& Renderer() { + return *renderer; + } + + /// Gets an immutable reference to the renderer. + const VideoCore::RendererBase& Renderer() const { + return *renderer; + } + /// Gets the scheduler for the CPU core that is currently running Kernel::Scheduler& CurrentScheduler() { return *CurrentCpuCore().Scheduler(); @@ -195,6 +214,7 @@ private: /// AppLoader used to load the current executing application std::unique_ptr app_loader; + std::unique_ptr renderer; std::unique_ptr gpu_core; std::shared_ptr debug_context; Kernel::SharedPtr current_process; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index ed69a4325d..2b74e6a339 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -30,9 +30,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 addr, offset, width, height, stride, static_cast(format), transform, crop_rect}; - Core::System::GetInstance().perf_stats.EndGameFrame(); - - VideoCore::g_renderer->SwapBuffers(framebuffer); + auto& instance = Core::System::GetInstance(); + instance.perf_stats.EndGameFrame(); + instance.Renderer().SwapBuffers(framebuffer); } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 57b128b40a..06151a1ea1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -150,15 +150,16 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vector& ou LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); - auto& gpu = Core::System::GetInstance().GPU(); - - auto itr = buffer_mappings.find(params.offset); - + const auto itr = buffer_mappings.find(params.offset); ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping"); - // Remove this memory region from the rasterizer cache. - VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(params.offset, itr->second.size); + auto& system_instance = Core::System::GetInstance(); + // Remove this memory region from the rasterizer cache. + system_instance.Renderer().Rasterizer()->FlushAndInvalidateRegion(params.offset, + itr->second.size); + + auto& gpu = system_instance.GPU(); params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size); buffer_mappings.erase(itr->second.offset); diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 5344441e1d..0bf51062cb 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -127,9 +127,11 @@ void NVFlinger::Compose() { MicroProfileFlip(); if (buffer == boost::none) { + auto& system_instance = Core::System::GetInstance(); + // There was no queued buffer to draw, render previous frame - Core::System::GetInstance().perf_stats.EndGameFrame(); - VideoCore::g_renderer->SwapBuffers({}); + system_instance.perf_stats.EndGameFrame(); + system_instance.Renderer().SwapBuffers({}); continue; } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 4b3bb7b31a..a8f08e1da5 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -326,34 +326,36 @@ void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) } void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { + auto& system_instance = Core::System::GetInstance(); + // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be // null here - if (VideoCore::g_renderer == nullptr) { + if (!system_instance.IsPoweredOn()) { return; } VAddr end = start + size; - auto CheckRegion = [&](VAddr region_start, VAddr region_end) { + const auto CheckRegion = [&](VAddr region_start, VAddr region_end) { if (start >= region_end || end <= region_start) { // No overlap with region return; } - VAddr overlap_start = std::max(start, region_start); - VAddr overlap_end = std::min(end, region_end); + const VAddr overlap_start = std::max(start, region_start); + const VAddr overlap_end = std::min(end, region_end); - std::vector gpu_addresses = - Core::System::GetInstance().GPU().memory_manager->CpuToGpuAddress(overlap_start); + const std::vector gpu_addresses = + system_instance.GPU().memory_manager->CpuToGpuAddress(overlap_start); if (gpu_addresses.empty()) { return; } - u64 overlap_size = overlap_end - overlap_start; + const u64 overlap_size = overlap_end - overlap_start; for (const auto& gpu_address : gpu_addresses) { - auto* rasterizer = VideoCore::g_renderer->Rasterizer(); + auto* rasterizer = system_instance.Renderer().Rasterizer(); switch (mode) { case FlushMode::Flush: rasterizer->FlushRegion(gpu_address, overlap_size); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 79e0b347b8..a4623223d1 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/core.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/service/hid/hid.h" #include "core/settings.h" @@ -19,8 +20,9 @@ void Apply() { VideoCore::g_toggle_framelimit_enabled = values.toggle_framelimit; - if (VideoCore::g_renderer) { - VideoCore::g_renderer->UpdateCurrentFramebufferLayout(); + auto& system_instance = Core::System::GetInstance(); + if (system_instance.IsPoweredOn()) { + system_instance.Renderer().UpdateCurrentFramebufferLayout(); } Service::HID::ReloadInputDevices(); diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 0e205ed72e..a235b543e5 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -19,8 +19,8 @@ namespace Engines { /// First register id that is actually a Macro call. constexpr u32 MacroRegistersStart = 0xE00; -Maxwell3D::Maxwell3D(MemoryManager& memory_manager) - : memory_manager(memory_manager), macro_interpreter(*this) {} +Maxwell3D::Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) + : memory_manager(memory_manager), rasterizer{rasterizer}, macro_interpreter(*this) {} void Maxwell3D::CallMacroMethod(u32 method, std::vector parameters) { auto macro_code = uploaded_macros.find(method); @@ -130,7 +130,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { break; } - VideoCore::g_renderer->Rasterizer()->NotifyMaxwellRegisterChanged(method); + rasterizer.NotifyMaxwellRegisterChanged(method); if (debug_context) { debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr); @@ -218,7 +218,7 @@ void Maxwell3D::DrawArrays() { } const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count}; - VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed); + rasterizer.AccelerateDrawBatch(is_indexed); // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - @@ -393,7 +393,7 @@ void Maxwell3D::ProcessClearBuffers() { regs.clear_buffers.R == regs.clear_buffers.B && regs.clear_buffers.R == regs.clear_buffers.A); - VideoCore::g_renderer->Rasterizer()->Clear(); + rasterizer.Clear(); } } // namespace Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 3c32f10671..4d0ff96a57 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -17,6 +17,10 @@ #include "video_core/memory_manager.h" #include "video_core/textures/texture.h" +namespace VideoCore { +class RasterizerInterface; +} + namespace Tegra::Engines { #define MAXWELL3D_REG_INDEX(field_name) \ @@ -24,7 +28,7 @@ namespace Tegra::Engines { class Maxwell3D final { public: - explicit Maxwell3D(MemoryManager& memory_manager); + explicit Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager); ~Maxwell3D() = default; /// Register structure of the Maxwell3D engine. @@ -818,6 +822,8 @@ public: Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const; private: + VideoCore::RasterizerInterface& rasterizer; + std::unordered_map> uploaded_macros; /// Macro method that is currently being executed / being fed parameters. diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 141e20444f..b2a83ce0b0 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -7,12 +7,13 @@ #include "video_core/engines/maxwell_compute.h" #include "video_core/engines/maxwell_dma.h" #include "video_core/gpu.h" +#include "video_core/rasterizer_interface.h" namespace Tegra { -GPU::GPU() { +GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { memory_manager = std::make_unique(); - maxwell_3d = std::make_unique(*memory_manager); + maxwell_3d = std::make_unique(rasterizer, *memory_manager); fermi_2d = std::make_unique(*memory_manager); maxwell_compute = std::make_unique(); maxwell_dma = std::make_unique(*memory_manager); diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 08aa75503b..440505c9d1 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -11,6 +11,10 @@ #include "core/hle/service/nvflinger/buffer_queue.h" #include "video_core/memory_manager.h" +namespace VideoCore { +class RasterizerInterface; +} + namespace Tegra { enum class RenderTargetFormat : u32 { @@ -98,7 +102,7 @@ enum class EngineID { class GPU final { public: - GPU(); + explicit GPU(VideoCore::RasterizerInterface& rasterizer); ~GPU(); /// Processes a command list stored at the specified address in GPU memory. diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index dbe3edf09a..3ca3502433 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -7,6 +7,8 @@ #include "video_core/renderer_base.h" #include "video_core/renderer_opengl/gl_rasterizer.h" +namespace VideoCore { + RendererBase::RendererBase(EmuWindow& window) : render_window{window} {} RendererBase::~RendererBase() = default; @@ -21,3 +23,5 @@ void RendererBase::RefreshRasterizerSetting() { rasterizer = std::make_unique(render_window); } } + +} // namespace VideoCore diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 1cb161b7f9..effb9aed3b 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -13,6 +13,8 @@ class EmuWindow; +namespace VideoCore { + class RendererBase : NonCopyable { public: /// Used to reference a framebuffer @@ -44,7 +46,7 @@ public: return m_current_frame; } - VideoCore::RasterizerInterface* Rasterizer() const { + RasterizerInterface* Rasterizer() const { return rasterizer.get(); } @@ -52,7 +54,9 @@ public: protected: EmuWindow& render_window; ///< Reference to the render window handle. - std::unique_ptr rasterizer; + std::unique_ptr rasterizer; f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer int m_current_frame = 0; ///< Current frame, should be set by the renderer }; + +} // namespace VideoCore diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 74383c7cfc..50846975f0 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -103,7 +103,7 @@ ScopeAcquireGLContext::~ScopeAcquireGLContext() { } } -RendererOpenGL::RendererOpenGL(EmuWindow& window) : RendererBase{window} {} +RendererOpenGL::RendererOpenGL(EmuWindow& window) : VideoCore::RendererBase{window} {} RendererOpenGL::~RendererOpenGL() = default; /// Swap buffers (render frame) diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index ab7de41c8b..428afa3b71 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -41,7 +41,7 @@ private: EmuWindow& emu_window; }; -class RendererOpenGL : public RendererBase { +class RendererOpenGL : public VideoCore::RendererBase { public: explicit RendererOpenGL(EmuWindow& window); ~RendererOpenGL() override; diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 06b13e6817..5085ef96bd 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -3,37 +3,16 @@ // Refer to the license.txt file included. #include -#include "common/logging/log.h" #include "video_core/renderer_base.h" #include "video_core/renderer_opengl/renderer_opengl.h" #include "video_core/video_core.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Video Core namespace - namespace VideoCore { -std::unique_ptr g_renderer; ///< Renderer plugin - std::atomic g_toggle_framelimit_enabled; -/// Initialize the video core -bool Init(EmuWindow& emu_window) { - g_renderer = std::make_unique(emu_window); - if (g_renderer->Init()) { - LOG_DEBUG(Render, "initialized OK"); - } else { - LOG_CRITICAL(Render, "initialization failed !"); - return false; - } - return true; -} - -/// Shutdown the video core -void Shutdown() { - g_renderer.reset(); - - LOG_DEBUG(Render, "shutdown OK"); +std::unique_ptr CreateRenderer(EmuWindow& emu_window) { + return std::make_unique(emu_window); } } // namespace VideoCore diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 519b757f50..7c01c0b8da 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -8,25 +8,23 @@ #include class EmuWindow; -class RendererBase; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Video Core namespace namespace VideoCore { -enum class Renderer { Software, OpenGL }; +class RendererBase; -extern std::unique_ptr g_renderer; ///< Renderer plugin +enum class Renderer { Software, OpenGL }; // TODO: Wrap these in a user settings struct along with any other graphics settings (often set from // qt ui) extern std::atomic g_toggle_framelimit_enabled; -/// Initialize the video core -bool Init(EmuWindow& emu_window); - -/// Shutdown the video core -void Shutdown(); +/** + * Creates a renderer instance. + * + * @note The returned renderer instance is simply allocated. Its Init() + * function still needs to be called to fully complete its setup. + */ +std::unique_ptr CreateRenderer(EmuWindow& emu_window); } // namespace VideoCore diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 341867f7b3..955353a2c6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -445,7 +445,7 @@ bool GMainWindow::LoadROM(const QString& filename) { case Core::System::ResultStatus::ErrorVideoCore: QMessageBox::critical( - this, tr("An error occured in the video core."), + this, tr("An error occurred initializing the video core."), tr("yuzu has encountered an error while running the video core, please see the " "log for more details." "For more information on accessing the log, please see the following page: " @@ -459,7 +459,7 @@ bool GMainWindow::LoadROM(const QString& filename) { default: QMessageBox::critical( this, tr("Error while loading ROM!"), - tr("An unknown error occured. Please see the log for more details.")); + tr("An unknown error occurred. Please see the log for more details.")); break; } return false; diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 5ff6266bff..5911ec1778 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -187,7 +187,7 @@ int main(int argc, char** argv) { LOG_CRITICAL(Frontend, "Failed to determine system mode!"); return -1; case Core::System::ResultStatus::ErrorVideoCore: - LOG_CRITICAL(Frontend, "VideoCore not initialized"); + LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!"); return -1; case Core::System::ResultStatus::Success: break; // Expected case