diff options
| author | 2022-11-27 20:37:37 -0500 | |
|---|---|---|
| committer | 2022-11-28 19:49:09 -0500 | |
| commit | 89dd7dc1802cc53e828cb71c1f3e2bc0879459ce (patch) | |
| tree | 718f8fec3534b4fdb77405e347f86bcf37980363 | |
| parent | Merge pull request #8829 from Docteh/qt6_0002 (diff) | |
| download | yuzu-89dd7dc1802cc53e828cb71c1f3e2bc0879459ce.tar.gz yuzu-89dd7dc1802cc53e828cb71c1f3e2bc0879459ce.tar.xz yuzu-89dd7dc1802cc53e828cb71c1f3e2bc0879459ce.zip | |
video_core: add null backend
| -rw-r--r-- | src/common/settings.h | 3 | ||||
| -rw-r--r-- | src/core/telemetry_session.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_null/null_rasterizer.cpp | 90 | ||||
| -rw-r--r-- | src/video_core/renderer_null/null_rasterizer.h | 78 | ||||
| -rw-r--r-- | src/video_core/renderer_null/renderer_null.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_null/renderer_null.h | 36 | ||||
| -rw-r--r-- | src/video_core/video_core.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 18 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 1 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.cpp | 5 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.ui | 5 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 52 | ||||
| -rw-r--r-- | src/yuzu/main.h | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.h | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp | 51 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_null.h | 26 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 4 |
20 files changed, 383 insertions, 28 deletions
diff --git a/src/common/settings.h b/src/common/settings.h index 00e4421f7..c0620066c 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -19,6 +19,7 @@ namespace Settings { | |||
| 19 | enum class RendererBackend : u32 { | 19 | enum class RendererBackend : u32 { |
| 20 | OpenGL = 0, | 20 | OpenGL = 0, |
| 21 | Vulkan = 1, | 21 | Vulkan = 1, |
| 22 | Null = 2, | ||
| 22 | }; | 23 | }; |
| 23 | 24 | ||
| 24 | enum class ShaderBackend : u32 { | 25 | enum class ShaderBackend : u32 { |
| @@ -411,7 +412,7 @@ struct Values { | |||
| 411 | 412 | ||
| 412 | // Renderer | 413 | // Renderer |
| 413 | SwitchableSetting<RendererBackend, true> renderer_backend{ | 414 | SwitchableSetting<RendererBackend, true> renderer_backend{ |
| 414 | RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; | 415 | RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"}; |
| 415 | Setting<bool> renderer_debug{false, "debug"}; | 416 | Setting<bool> renderer_debug{false, "debug"}; |
| 416 | Setting<bool> renderer_shader_feedback{false, "shader_feedback"}; | 417 | Setting<bool> renderer_shader_feedback{false, "shader_feedback"}; |
| 417 | Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; | 418 | Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; |
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index abcf6eb11..8d5f2be2f 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp | |||
| @@ -55,6 +55,8 @@ static const char* TranslateRenderer(Settings::RendererBackend backend) { | |||
| 55 | return "OpenGL"; | 55 | return "OpenGL"; |
| 56 | case Settings::RendererBackend::Vulkan: | 56 | case Settings::RendererBackend::Vulkan: |
| 57 | return "Vulkan"; | 57 | return "Vulkan"; |
| 58 | case Settings::RendererBackend::Null: | ||
| 59 | return "Null"; | ||
| 58 | } | 60 | } |
| 59 | return "Unknown"; | 61 | return "Unknown"; |
| 60 | } | 62 | } |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index b03a30992..0d6bf1f0d 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -91,6 +91,10 @@ add_library(video_core STATIC | |||
| 91 | rasterizer_interface.h | 91 | rasterizer_interface.h |
| 92 | renderer_base.cpp | 92 | renderer_base.cpp |
| 93 | renderer_base.h | 93 | renderer_base.h |
| 94 | renderer_null/null_rasterizer.cpp | ||
| 95 | renderer_null/null_rasterizer.h | ||
| 96 | renderer_null/renderer_null.cpp | ||
| 97 | renderer_null/renderer_null.h | ||
| 94 | renderer_opengl/gl_buffer_cache.cpp | 98 | renderer_opengl/gl_buffer_cache.cpp |
| 95 | renderer_opengl/gl_buffer_cache.h | 99 | renderer_opengl/gl_buffer_cache.h |
| 96 | renderer_opengl/gl_compute_pipeline.cpp | 100 | renderer_opengl/gl_compute_pipeline.cpp |
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp new file mode 100644 index 000000000..9734d84bc --- /dev/null +++ b/src/video_core/renderer_null/null_rasterizer.cpp | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/host1x/host1x.h" | ||
| 5 | #include "video_core/memory_manager.h" | ||
| 6 | #include "video_core/renderer_null/null_rasterizer.h" | ||
| 7 | |||
| 8 | namespace Null { | ||
| 9 | |||
| 10 | AccelerateDMA::AccelerateDMA() = default; | ||
| 11 | |||
| 12 | bool AccelerateDMA::BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) { | ||
| 13 | return true; | ||
| 14 | } | ||
| 15 | bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) { | ||
| 16 | return true; | ||
| 17 | } | ||
| 18 | |||
| 19 | RasterizerNull::RasterizerNull(Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu) | ||
| 20 | : RasterizerAccelerated(cpu_memory_), m_gpu{gpu} {} | ||
| 21 | RasterizerNull::~RasterizerNull() = default; | ||
| 22 | |||
| 23 | void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {} | ||
| 24 | void RasterizerNull::Clear(u32 layer_count) {} | ||
| 25 | void RasterizerNull::DispatchCompute() {} | ||
| 26 | void RasterizerNull::ResetCounter(VideoCore::QueryType type) {} | ||
| 27 | void RasterizerNull::Query(GPUVAddr gpu_addr, VideoCore::QueryType type, | ||
| 28 | std::optional<u64> timestamp) { | ||
| 29 | if (!gpu_memory) { | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | gpu_memory->Write(gpu_addr, u64{0}); | ||
| 34 | if (timestamp) { | ||
| 35 | gpu_memory->Write(gpu_addr + 8, *timestamp); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | void RasterizerNull::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, | ||
| 39 | u32 size) {} | ||
| 40 | void RasterizerNull::DisableGraphicsUniformBuffer(size_t stage, u32 index) {} | ||
| 41 | void RasterizerNull::FlushAll() {} | ||
| 42 | void RasterizerNull::FlushRegion(VAddr addr, u64 size) {} | ||
| 43 | bool RasterizerNull::MustFlushRegion(VAddr addr, u64 size) { | ||
| 44 | return false; | ||
| 45 | } | ||
| 46 | void RasterizerNull::InvalidateRegion(VAddr addr, u64 size) {} | ||
| 47 | void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {} | ||
| 48 | void RasterizerNull::InvalidateGPUCache() {} | ||
| 49 | void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {} | ||
| 50 | void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} | ||
| 51 | void RasterizerNull::SignalFence(std::function<void()>&& func) { | ||
| 52 | func(); | ||
| 53 | } | ||
| 54 | void RasterizerNull::SyncOperation(std::function<void()>&& func) { | ||
| 55 | func(); | ||
| 56 | } | ||
| 57 | void RasterizerNull::SignalSyncPoint(u32 value) { | ||
| 58 | auto& syncpoint_manager = m_gpu.Host1x().GetSyncpointManager(); | ||
| 59 | syncpoint_manager.IncrementGuest(value); | ||
| 60 | syncpoint_manager.IncrementHost(value); | ||
| 61 | } | ||
| 62 | void RasterizerNull::SignalReference() {} | ||
| 63 | void RasterizerNull::ReleaseFences() {} | ||
| 64 | void RasterizerNull::FlushAndInvalidateRegion(VAddr addr, u64 size) {} | ||
| 65 | void RasterizerNull::WaitForIdle() {} | ||
| 66 | void RasterizerNull::FragmentBarrier() {} | ||
| 67 | void RasterizerNull::TiledCacheBarrier() {} | ||
| 68 | void RasterizerNull::FlushCommands() {} | ||
| 69 | void RasterizerNull::TickFrame() {} | ||
| 70 | Tegra::Engines::AccelerateDMAInterface& RasterizerNull::AccessAccelerateDMA() { | ||
| 71 | return m_accelerate_dma; | ||
| 72 | } | ||
| 73 | bool RasterizerNull::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, | ||
| 74 | const Tegra::Engines::Fermi2D::Surface& dst, | ||
| 75 | const Tegra::Engines::Fermi2D::Config& copy_config) { | ||
| 76 | return true; | ||
| 77 | } | ||
| 78 | void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||
| 79 | std::span<const u8> memory) {} | ||
| 80 | bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||
| 81 | VAddr framebuffer_addr, u32 pixel_stride) { | ||
| 82 | return true; | ||
| 83 | } | ||
| 84 | void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||
| 85 | const VideoCore::DiskResourceLoadCallback& callback) {} | ||
| 86 | void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) {} | ||
| 87 | void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) {} | ||
| 88 | void RasterizerNull::ReleaseChannel(s32 channel_id) {} | ||
| 89 | |||
| 90 | } // namespace Null | ||
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h new file mode 100644 index 000000000..ecf77ba42 --- /dev/null +++ b/src/video_core/renderer_null/null_rasterizer.h | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "video_core/control/channel_state_cache.h" | ||
| 8 | #include "video_core/engines/maxwell_dma.h" | ||
| 9 | #include "video_core/rasterizer_accelerated.h" | ||
| 10 | #include "video_core/rasterizer_interface.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Null { | ||
| 17 | |||
| 18 | class RasterizerNull; | ||
| 19 | |||
| 20 | class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface { | ||
| 21 | public: | ||
| 22 | explicit AccelerateDMA(); | ||
| 23 | bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override; | ||
| 24 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; | ||
| 25 | }; | ||
| 26 | |||
| 27 | class RasterizerNull final : public VideoCore::RasterizerAccelerated, | ||
| 28 | protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { | ||
| 29 | public: | ||
| 30 | explicit RasterizerNull(Core::Memory::Memory& cpu_memory, Tegra::GPU& gpu); | ||
| 31 | ~RasterizerNull() override; | ||
| 32 | |||
| 33 | void Draw(bool is_indexed, u32 instance_count) override; | ||
| 34 | void Clear(u32 layer_count) override; | ||
| 35 | void DispatchCompute() override; | ||
| 36 | void ResetCounter(VideoCore::QueryType type) override; | ||
| 37 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; | ||
| 38 | void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; | ||
| 39 | void DisableGraphicsUniformBuffer(size_t stage, u32 index) override; | ||
| 40 | void FlushAll() override; | ||
| 41 | void FlushRegion(VAddr addr, u64 size) override; | ||
| 42 | bool MustFlushRegion(VAddr addr, u64 size) override; | ||
| 43 | void InvalidateRegion(VAddr addr, u64 size) override; | ||
| 44 | void OnCPUWrite(VAddr addr, u64 size) override; | ||
| 45 | void InvalidateGPUCache() override; | ||
| 46 | void UnmapMemory(VAddr addr, u64 size) override; | ||
| 47 | void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; | ||
| 48 | void SignalFence(std::function<void()>&& func) override; | ||
| 49 | void SyncOperation(std::function<void()>&& func) override; | ||
| 50 | void SignalSyncPoint(u32 value) override; | ||
| 51 | void SignalReference() override; | ||
| 52 | void ReleaseFences() override; | ||
| 53 | void FlushAndInvalidateRegion(VAddr addr, u64 size) override; | ||
| 54 | void WaitForIdle() override; | ||
| 55 | void FragmentBarrier() override; | ||
| 56 | void TiledCacheBarrier() override; | ||
| 57 | void FlushCommands() override; | ||
| 58 | void TickFrame() override; | ||
| 59 | bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, | ||
| 60 | const Tegra::Engines::Fermi2D::Surface& dst, | ||
| 61 | const Tegra::Engines::Fermi2D::Config& copy_config) override; | ||
| 62 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | ||
| 63 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | ||
| 64 | std::span<const u8> memory) override; | ||
| 65 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, | ||
| 66 | u32 pixel_stride) override; | ||
| 67 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||
| 68 | const VideoCore::DiskResourceLoadCallback& callback) override; | ||
| 69 | void InitializeChannel(Tegra::Control::ChannelState& channel) override; | ||
| 70 | void BindChannel(Tegra::Control::ChannelState& channel) override; | ||
| 71 | void ReleaseChannel(s32 channel_id) override; | ||
| 72 | |||
| 73 | private: | ||
| 74 | Tegra::GPU& m_gpu; | ||
| 75 | AccelerateDMA m_accelerate_dma; | ||
| 76 | }; | ||
| 77 | |||
| 78 | } // namespace Null | ||
diff --git a/src/video_core/renderer_null/renderer_null.cpp b/src/video_core/renderer_null/renderer_null.cpp new file mode 100644 index 000000000..e2a189b63 --- /dev/null +++ b/src/video_core/renderer_null/renderer_null.cpp | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/renderer_null/renderer_null.h" | ||
| 5 | |||
| 6 | namespace Null { | ||
| 7 | |||
| 8 | RendererNull::RendererNull(Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, | ||
| 9 | Tegra::GPU& gpu, | ||
| 10 | std::unique_ptr<Core::Frontend::GraphicsContext> context_) | ||
| 11 | : RendererBase(emu_window, std::move(context_)), m_gpu(gpu), m_rasterizer(cpu_memory, gpu) {} | ||
| 12 | |||
| 13 | RendererNull::~RendererNull() = default; | ||
| 14 | |||
| 15 | void RendererNull::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||
| 16 | if (!framebuffer) { | ||
| 17 | return; | ||
| 18 | } | ||
| 19 | |||
| 20 | m_gpu.RendererFrameEndNotify(); | ||
| 21 | render_window.OnFrameDisplayed(); | ||
| 22 | } | ||
| 23 | |||
| 24 | } // namespace Null | ||
diff --git a/src/video_core/renderer_null/renderer_null.h b/src/video_core/renderer_null/renderer_null.h new file mode 100644 index 000000000..967ff5645 --- /dev/null +++ b/src/video_core/renderer_null/renderer_null.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "video_core/renderer_base.h" | ||
| 10 | #include "video_core/renderer_null/null_rasterizer.h" | ||
| 11 | |||
| 12 | namespace Null { | ||
| 13 | |||
| 14 | class RendererNull final : public VideoCore::RendererBase { | ||
| 15 | public: | ||
| 16 | explicit RendererNull(Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, | ||
| 17 | Tegra::GPU& gpu, | ||
| 18 | std::unique_ptr<Core::Frontend::GraphicsContext> context); | ||
| 19 | ~RendererNull() override; | ||
| 20 | |||
| 21 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | ||
| 22 | |||
| 23 | VideoCore::RasterizerInterface* ReadRasterizer() override { | ||
| 24 | return &m_rasterizer; | ||
| 25 | } | ||
| 26 | |||
| 27 | [[nodiscard]] std::string GetDeviceVendor() const override { | ||
| 28 | return "NULL"; | ||
| 29 | } | ||
| 30 | |||
| 31 | private: | ||
| 32 | Tegra::GPU& m_gpu; | ||
| 33 | RasterizerNull m_rasterizer; | ||
| 34 | }; | ||
| 35 | |||
| 36 | } // namespace Null | ||
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 04ac4af11..fedb4a7bb 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "video_core/renderer_base.h" | 9 | #include "video_core/renderer_base.h" |
| 10 | #include "video_core/renderer_null/renderer_null.h" | ||
| 10 | #include "video_core/renderer_opengl/renderer_opengl.h" | 11 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 11 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 12 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 12 | #include "video_core/video_core.h" | 13 | #include "video_core/video_core.h" |
| @@ -26,6 +27,9 @@ std::unique_ptr<VideoCore::RendererBase> CreateRenderer( | |||
| 26 | case Settings::RendererBackend::Vulkan: | 27 | case Settings::RendererBackend::Vulkan: |
| 27 | return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window, cpu_memory, | 28 | return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window, cpu_memory, |
| 28 | gpu, std::move(context)); | 29 | gpu, std::move(context)); |
| 30 | case Settings::RendererBackend::Null: | ||
| 31 | return std::make_unique<Null::RendererNull>(emu_window, cpu_memory, gpu, | ||
| 32 | std::move(context)); | ||
| 29 | default: | 33 | default: |
| 30 | return nullptr; | 34 | return nullptr; |
| 31 | } | 35 | } |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index c934069dd..f140e951f 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -237,8 +237,7 @@ private: | |||
| 237 | GRenderWindow* render_window; | 237 | GRenderWindow* render_window; |
| 238 | }; | 238 | }; |
| 239 | 239 | ||
| 240 | class OpenGLRenderWidget : public RenderWidget { | 240 | struct OpenGLRenderWidget : public RenderWidget { |
| 241 | public: | ||
| 242 | explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) { | 241 | explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) { |
| 243 | windowHandle()->setSurfaceType(QWindow::OpenGLSurface); | 242 | windowHandle()->setSurfaceType(QWindow::OpenGLSurface); |
| 244 | } | 243 | } |
| @@ -251,13 +250,16 @@ private: | |||
| 251 | std::unique_ptr<Core::Frontend::GraphicsContext> context; | 250 | std::unique_ptr<Core::Frontend::GraphicsContext> context; |
| 252 | }; | 251 | }; |
| 253 | 252 | ||
| 254 | class VulkanRenderWidget : public RenderWidget { | 253 | struct VulkanRenderWidget : public RenderWidget { |
| 255 | public: | ||
| 256 | explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) { | 254 | explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) { |
| 257 | windowHandle()->setSurfaceType(QWindow::VulkanSurface); | 255 | windowHandle()->setSurfaceType(QWindow::VulkanSurface); |
| 258 | } | 256 | } |
| 259 | }; | 257 | }; |
| 260 | 258 | ||
| 259 | struct NullRenderWidget : public RenderWidget { | ||
| 260 | explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {} | ||
| 261 | }; | ||
| 262 | |||
| 261 | static Core::Frontend::WindowSystemType GetWindowSystemType() { | 263 | static Core::Frontend::WindowSystemType GetWindowSystemType() { |
| 262 | // Determine WSI type based on Qt platform. | 264 | // Determine WSI type based on Qt platform. |
| 263 | QString platform_name = QGuiApplication::platformName(); | 265 | QString platform_name = QGuiApplication::platformName(); |
| @@ -874,6 +876,9 @@ bool GRenderWindow::InitRenderTarget() { | |||
| 874 | return false; | 876 | return false; |
| 875 | } | 877 | } |
| 876 | break; | 878 | break; |
| 879 | case Settings::RendererBackend::Null: | ||
| 880 | InitializeNull(); | ||
| 881 | break; | ||
| 877 | } | 882 | } |
| 878 | 883 | ||
| 879 | // Update the Window System information with the new render target | 884 | // Update the Window System information with the new render target |
| @@ -970,6 +975,11 @@ bool GRenderWindow::InitializeVulkan() { | |||
| 970 | return true; | 975 | return true; |
| 971 | } | 976 | } |
| 972 | 977 | ||
| 978 | void GRenderWindow::InitializeNull() { | ||
| 979 | child_widget = new NullRenderWidget(this); | ||
| 980 | main_context = std::make_unique<DummyContext>(); | ||
| 981 | } | ||
| 982 | |||
| 973 | bool GRenderWindow::LoadOpenGL() { | 983 | bool GRenderWindow::LoadOpenGL() { |
| 974 | auto context = CreateSharedContext(); | 984 | auto context = CreateSharedContext(); |
| 975 | auto scope = context->Acquire(); | 985 | auto scope = context->Acquire(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 4a01481cd..2e19a879e 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -218,6 +218,7 @@ private: | |||
| 218 | 218 | ||
| 219 | bool InitializeOpenGL(); | 219 | bool InitializeOpenGL(); |
| 220 | bool InitializeVulkan(); | 220 | bool InitializeVulkan(); |
| 221 | void InitializeNull(); | ||
| 221 | bool LoadOpenGL(); | 222 | bool LoadOpenGL(); |
| 222 | QStringList GetUnsupportedGLExtensions() const; | 223 | QStringList GetUnsupportedGLExtensions() const; |
| 223 | 224 | ||
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index f1385e972..4a875f86a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -260,6 +260,7 @@ void ConfigureGraphics::ApplyConfiguration() { | |||
| 260 | Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend()); | 260 | Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend()); |
| 261 | switch (GetCurrentGraphicsBackend()) { | 261 | switch (GetCurrentGraphicsBackend()) { |
| 262 | case Settings::RendererBackend::OpenGL: | 262 | case Settings::RendererBackend::OpenGL: |
| 263 | case Settings::RendererBackend::Null: | ||
| 263 | Settings::values.shader_backend.SetGlobal(false); | 264 | Settings::values.shader_backend.SetGlobal(false); |
| 264 | Settings::values.vulkan_device.SetGlobal(true); | 265 | Settings::values.vulkan_device.SetGlobal(true); |
| 265 | Settings::values.shader_backend.SetValue(shader_backend); | 266 | Settings::values.shader_backend.SetValue(shader_backend); |
| @@ -348,6 +349,10 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 348 | ui->device_widget->setVisible(true); | 349 | ui->device_widget->setVisible(true); |
| 349 | ui->backend_widget->setVisible(false); | 350 | ui->backend_widget->setVisible(false); |
| 350 | break; | 351 | break; |
| 352 | case Settings::RendererBackend::Null: | ||
| 353 | ui->device_widget->setVisible(false); | ||
| 354 | ui->backend_widget->setVisible(false); | ||
| 355 | break; | ||
| 351 | } | 356 | } |
| 352 | } | 357 | } |
| 353 | 358 | ||
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 37271f956..f78396690 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -139,6 +139,11 @@ | |||
| 139 | <string notr="true">Vulkan</string> | 139 | <string notr="true">Vulkan</string> |
| 140 | </property> | 140 | </property> |
| 141 | </item> | 141 | </item> |
| 142 | <item> | ||
| 143 | <property name="text"> | ||
| 144 | <string>None</string> | ||
| 145 | </property> | ||
| 146 | </item> | ||
| 142 | </widget> | 147 | </widget> |
| 143 | </item> | 148 | </item> |
| 144 | </layout> | 149 | </layout> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2aae746f0..be13024c6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1007,29 +1007,11 @@ void GMainWindow::InitializeWidgets() { | |||
| 1007 | renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton")); | 1007 | renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton")); |
| 1008 | renderer_status_button->setCheckable(true); | 1008 | renderer_status_button->setCheckable(true); |
| 1009 | renderer_status_button->setFocusPolicy(Qt::NoFocus); | 1009 | renderer_status_button->setFocusPolicy(Qt::NoFocus); |
| 1010 | connect(renderer_status_button, &QPushButton::toggled, [this](bool checked) { | 1010 | connect(renderer_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleGraphicsAPI); |
| 1011 | renderer_status_button->setText(checked ? tr("VULKAN") : tr("OPENGL")); | 1011 | UpdateAPIText(); |
| 1012 | }); | 1012 | renderer_status_button->setCheckable(true); |
| 1013 | renderer_status_button->toggle(); | ||
| 1014 | |||
| 1015 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == | 1013 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == |
| 1016 | Settings::RendererBackend::Vulkan); | 1014 | Settings::RendererBackend::Vulkan); |
| 1017 | connect(renderer_status_button, &QPushButton::clicked, [this] { | ||
| 1018 | if (emulation_running) { | ||
| 1019 | return; | ||
| 1020 | } | ||
| 1021 | if (renderer_status_button->isChecked()) { | ||
| 1022 | Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan); | ||
| 1023 | } else { | ||
| 1024 | Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); | ||
| 1025 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 1026 | Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor); | ||
| 1027 | UpdateFilterText(); | ||
| 1028 | } | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | system->ApplySettings(); | ||
| 1032 | }); | ||
| 1033 | statusBar()->insertPermanentWidget(0, renderer_status_button); | 1015 | statusBar()->insertPermanentWidget(0, renderer_status_button); |
| 1034 | 1016 | ||
| 1035 | statusBar()->setVisible(true); | 1017 | statusBar()->setVisible(true); |
| @@ -3248,6 +3230,18 @@ void GMainWindow::OnToggleAdaptingFilter() { | |||
| 3248 | UpdateFilterText(); | 3230 | UpdateFilterText(); |
| 3249 | } | 3231 | } |
| 3250 | 3232 | ||
| 3233 | void GMainWindow::OnToggleGraphicsAPI() { | ||
| 3234 | auto api = Settings::values.renderer_backend.GetValue(); | ||
| 3235 | if (api == Settings::RendererBackend::OpenGL) { | ||
| 3236 | api = Settings::RendererBackend::Vulkan; | ||
| 3237 | } else { | ||
| 3238 | api = Settings::RendererBackend::OpenGL; | ||
| 3239 | } | ||
| 3240 | Settings::values.renderer_backend.SetValue(api); | ||
| 3241 | renderer_status_button->setChecked(api == Settings::RendererBackend::Vulkan); | ||
| 3242 | UpdateAPIText(); | ||
| 3243 | } | ||
| 3244 | |||
| 3251 | void GMainWindow::OnConfigurePerGame() { | 3245 | void GMainWindow::OnConfigurePerGame() { |
| 3252 | const u64 title_id = system->GetCurrentProcessProgramID(); | 3246 | const u64 title_id = system->GetCurrentProcessProgramID(); |
| 3253 | OpenPerGameConfiguration(title_id, current_game_path.toStdString()); | 3247 | OpenPerGameConfiguration(title_id, current_game_path.toStdString()); |
| @@ -3568,6 +3562,21 @@ void GMainWindow::UpdateDockedButton() { | |||
| 3568 | dock_status_button->setText(is_docked ? tr("DOCKED") : tr("HANDHELD")); | 3562 | dock_status_button->setText(is_docked ? tr("DOCKED") : tr("HANDHELD")); |
| 3569 | } | 3563 | } |
| 3570 | 3564 | ||
| 3565 | void GMainWindow::UpdateAPIText() { | ||
| 3566 | const auto api = Settings::values.renderer_backend.GetValue(); | ||
| 3567 | switch (api) { | ||
| 3568 | case Settings::RendererBackend::OpenGL: | ||
| 3569 | renderer_status_button->setText(tr("OPENGL")); | ||
| 3570 | break; | ||
| 3571 | case Settings::RendererBackend::Vulkan: | ||
| 3572 | renderer_status_button->setText(tr("VULKAN")); | ||
| 3573 | break; | ||
| 3574 | case Settings::RendererBackend::Null: | ||
| 3575 | renderer_status_button->setText(tr("NULL")); | ||
| 3576 | break; | ||
| 3577 | } | ||
| 3578 | } | ||
| 3579 | |||
| 3571 | void GMainWindow::UpdateFilterText() { | 3580 | void GMainWindow::UpdateFilterText() { |
| 3572 | const auto filter = Settings::values.scaling_filter.GetValue(); | 3581 | const auto filter = Settings::values.scaling_filter.GetValue(); |
| 3573 | switch (filter) { | 3582 | switch (filter) { |
| @@ -3613,6 +3622,7 @@ void GMainWindow::UpdateAAText() { | |||
| 3613 | void GMainWindow::UpdateStatusButtons() { | 3622 | void GMainWindow::UpdateStatusButtons() { |
| 3614 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == | 3623 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == |
| 3615 | Settings::RendererBackend::Vulkan); | 3624 | Settings::RendererBackend::Vulkan); |
| 3625 | UpdateAPIText(); | ||
| 3616 | UpdateGPUAccuracyButton(); | 3626 | UpdateGPUAccuracyButton(); |
| 3617 | UpdateDockedButton(); | 3627 | UpdateDockedButton(); |
| 3618 | UpdateFilterText(); | 3628 | UpdateFilterText(); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6a9992d05..af6fcec3c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -307,6 +307,7 @@ private slots: | |||
| 307 | void OnTasStartStop(); | 307 | void OnTasStartStop(); |
| 308 | void OnTasRecord(); | 308 | void OnTasRecord(); |
| 309 | void OnTasReset(); | 309 | void OnTasReset(); |
| 310 | void OnToggleGraphicsAPI(); | ||
| 310 | void OnToggleDockedMode(); | 311 | void OnToggleDockedMode(); |
| 311 | void OnToggleGpuAccuracy(); | 312 | void OnToggleGpuAccuracy(); |
| 312 | void OnToggleAdaptingFilter(); | 313 | void OnToggleAdaptingFilter(); |
| @@ -347,6 +348,7 @@ private: | |||
| 347 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, | 348 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, |
| 348 | std::string_view gpu_vendor = {}); | 349 | std::string_view gpu_vendor = {}); |
| 349 | void UpdateDockedButton(); | 350 | void UpdateDockedButton(); |
| 351 | void UpdateAPIText(); | ||
| 350 | void UpdateFilterText(); | 352 | void UpdateFilterText(); |
| 351 | void UpdateAAText(); | 353 | void UpdateAAText(); |
| 352 | void UpdateStatusBar(); | 354 | void UpdateStatusBar(); |
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 7d8ca3d8a..774d026aa 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt | |||
| @@ -22,6 +22,8 @@ add_executable(yuzu-cmd | |||
| 22 | emu_window/emu_window_sdl2.h | 22 | emu_window/emu_window_sdl2.h |
| 23 | emu_window/emu_window_sdl2_gl.cpp | 23 | emu_window/emu_window_sdl2_gl.cpp |
| 24 | emu_window/emu_window_sdl2_gl.h | 24 | emu_window/emu_window_sdl2_gl.h |
| 25 | emu_window/emu_window_sdl2_null.cpp | ||
| 26 | emu_window/emu_window_sdl2_null.h | ||
| 25 | emu_window/emu_window_sdl2_vk.cpp | 27 | emu_window/emu_window_sdl2_vk.cpp |
| 26 | emu_window/emu_window_sdl2_vk.h | 28 | emu_window/emu_window_sdl2_vk.h |
| 27 | yuzu.cpp | 29 | yuzu.cpp |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 90bb0b415..25c23e2a5 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -89,3 +89,5 @@ protected: | |||
| 89 | /// yuzu core instance | 89 | /// yuzu core instance |
| 90 | Core::System& system; | 90 | Core::System& system; |
| 91 | }; | 91 | }; |
| 92 | |||
| 93 | class DummyContext : public Core::Frontend::GraphicsContext {}; | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp new file mode 100644 index 000000000..259192f3c --- /dev/null +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <cstdlib> | ||
| 5 | #include <memory> | ||
| 6 | #include <string> | ||
| 7 | |||
| 8 | #include <fmt/format.h> | ||
| 9 | |||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "common/scm_rev.h" | ||
| 12 | #include "video_core/renderer_null/renderer_null.h" | ||
| 13 | #include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" | ||
| 14 | |||
| 15 | #ifdef YUZU_USE_EXTERNAL_SDL2 | ||
| 16 | // Include this before SDL.h to prevent the external from including a dummy | ||
| 17 | #define USING_GENERATED_CONFIG_H | ||
| 18 | #include <SDL_config.h> | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #include <SDL.h> | ||
| 22 | |||
| 23 | EmuWindow_SDL2_Null::EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_, | ||
| 24 | Core::System& system_, bool fullscreen) | ||
| 25 | : EmuWindow_SDL2{input_subsystem_, system_} { | ||
| 26 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, | ||
| 27 | Common::g_scm_branch, Common::g_scm_desc); | ||
| 28 | render_window = | ||
| 29 | SDL_CreateWindow(window_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, | ||
| 30 | Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, | ||
| 31 | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||
| 32 | |||
| 33 | SetWindowIcon(); | ||
| 34 | |||
| 35 | if (fullscreen) { | ||
| 36 | Fullscreen(); | ||
| 37 | ShowCursor(false); | ||
| 38 | } | ||
| 39 | |||
| 40 | OnResize(); | ||
| 41 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); | ||
| 42 | SDL_PumpEvents(); | ||
| 43 | LOG_INFO(Frontend, "yuzu Version: {} | {}-{} (Null)", Common::g_build_name, | ||
| 44 | Common::g_scm_branch, Common::g_scm_desc); | ||
| 45 | } | ||
| 46 | |||
| 47 | EmuWindow_SDL2_Null::~EmuWindow_SDL2_Null() = default; | ||
| 48 | |||
| 49 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_Null::CreateSharedContext() const { | ||
| 50 | return std::make_unique<DummyContext>(); | ||
| 51 | } | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_null.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.h new file mode 100644 index 000000000..35aee286d --- /dev/null +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "core/frontend/emu_window.h" | ||
| 9 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace InputCommon { | ||
| 16 | class InputSubsystem; | ||
| 17 | } | ||
| 18 | |||
| 19 | class EmuWindow_SDL2_Null final : public EmuWindow_SDL2 { | ||
| 20 | public: | ||
| 21 | explicit EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_, | ||
| 22 | Core::System& system, bool fullscreen); | ||
| 23 | ~EmuWindow_SDL2_Null() override; | ||
| 24 | |||
| 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | ||
| 26 | }; | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h index e39ad754d..9467d164a 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h | |||
| @@ -24,5 +24,3 @@ public: | |||
| 24 | 24 | ||
| 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
| 26 | }; | 26 | }; |
| 27 | |||
| 28 | class DummyContext : public Core::Frontend::GraphicsContext {}; | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index dfe5a30ea..a80649703 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include "yuzu_cmd/config.h" | 34 | #include "yuzu_cmd/config.h" |
| 35 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 35 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 36 | #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" | 36 | #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" |
| 37 | #include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" | ||
| 37 | #include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h" | 38 | #include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h" |
| 38 | 39 | ||
| 39 | #ifdef _WIN32 | 40 | #ifdef _WIN32 |
| @@ -317,6 +318,9 @@ int main(int argc, char** argv) { | |||
| 317 | case Settings::RendererBackend::Vulkan: | 318 | case Settings::RendererBackend::Vulkan: |
| 318 | emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen); | 319 | emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen); |
| 319 | break; | 320 | break; |
| 321 | case Settings::RendererBackend::Null: | ||
| 322 | emu_window = std::make_unique<EmuWindow_SDL2_Null>(&input_subsystem, system, fullscreen); | ||
| 323 | break; | ||
| 320 | } | 324 | } |
| 321 | 325 | ||
| 322 | system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | 326 | system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); |