Merge pull request #11522 from phire/KillRendererWithFire

Kill Renderer (with phire)
This commit is contained in:
Scott Mansell 2023-02-09 19:59:16 +13:00 committed by GitHub
commit ccf92a3e56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
144 changed files with 5584 additions and 4840 deletions

View File

@ -59,7 +59,7 @@
#include "UICommon/UICommon.h" #include "UICommon/UICommon.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "jni/AndroidCommon/AndroidCommon.h" #include "jni/AndroidCommon/AndroidCommon.h"
@ -456,8 +456,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
if (s_surf == nullptr) if (s_surf == nullptr)
__android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null."); __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
if (g_renderer) if (g_presenter)
g_renderer->ChangeSurface(s_surf); g_presenter->ChangeSurface(s_surf);
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv*, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv*,
@ -483,8 +483,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestr
std::lock_guard surface_guard(s_surface_lock); std::lock_guard surface_guard(s_surface_lock);
if (g_renderer) if (g_presenter)
g_renderer->ChangeSurface(nullptr); g_presenter->ChangeSurface(nullptr);
if (s_surf) if (s_surf)
{ {
@ -503,7 +503,7 @@ JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_HasSurfa
JNIEXPORT jfloat JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv*, JNIEXPORT jfloat JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv*,
jclass) jclass)
{ {
return g_renderer->CalculateDrawAspectRatio(); return g_presenter->CalculateDrawAspectRatio();
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv*, jclass) JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv*, jclass)

View File

@ -62,6 +62,7 @@ add_library(common
GekkoDisassembler.h GekkoDisassembler.h
Hash.cpp Hash.cpp
Hash.h Hash.h
HookableEvent.h
HttpRequest.cpp HttpRequest.cpp
HttpRequest.h HttpRequest.h
Image.cpp Image.cpp
@ -115,6 +116,7 @@ add_library(common
SocketContext.cpp SocketContext.cpp
SocketContext.h SocketContext.h
SPSCQueue.h SPSCQueue.h
StringLiteral.h
StringUtil.cpp StringUtil.cpp
StringUtil.h StringUtil.h
SymbolDB.cpp SymbolDB.cpp

View File

@ -0,0 +1,102 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "Common/Logging/Log.h"
#include "Common/StringLiteral.h"
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <vector>
namespace Common
{
struct HookBase
{
virtual ~HookBase() = default;
protected:
HookBase() = default;
// This shouldn't be copied. And since we always wrap it in unique_ptr, no need to move it either
HookBase(const HookBase&) = delete;
HookBase(HookBase&&) = delete;
HookBase& operator=(const HookBase&) = delete;
HookBase& operator=(HookBase&&) = delete;
};
// EventHook is a handle a registered listener holds.
// When the handle is destroyed, the HookableEvent will automatically remove the listener.
using EventHook = std::unique_ptr<HookBase>;
// A hookable event system.
//
// Define Events in a header as:
//
// using MyLoveyEvent = HookableEvent<"My lovely event", std::string, u32>;
//
// Register listeners anywhere you need them as:
// EventHook myHook = MyLoveyEvent::Register([](std::string foo, u32 bar) {
// fmt::print("I've been triggered with {} and {}", foo, bar)
// }, "NameOfHook");
//
// The hook will be automatically unregistered when the EventHook object goes out of scope.
// Trigger events by calling Trigger as:
//
// MyLoveyEvent::Trigger("Hello world", 42);
//
template <StringLiteral EventName, typename... CallbackArgs>
class HookableEvent
{
public:
using CallbackType = std::function<void(CallbackArgs...)>;
private:
struct HookImpl final : public HookBase
{
~HookImpl() override { HookableEvent::Remove(this); }
HookImpl(CallbackType callback, std::string name)
: m_fn(std::move(callback)), m_name(std::move(name))
{
}
CallbackType m_fn;
std::string m_name;
};
public:
// Returns a handle that will unregister the listener when destroyed.
static EventHook Register(CallbackType callback, std::string name)
{
std::lock_guard lock(m_mutex);
DEBUG_LOG_FMT(COMMON, "Registering {} handler at {} event hook", name, EventName.value);
auto handle = std::make_unique<HookImpl>(callback, std::move(name));
m_listeners.push_back(handle.get());
return handle;
}
static void Trigger(const CallbackArgs&... args)
{
std::lock_guard lock(m_mutex);
for (const auto& handle : m_listeners)
handle->m_fn(args...);
}
private:
static void Remove(HookImpl* handle)
{
std::lock_guard lock(m_mutex);
std::erase(m_listeners, handle);
}
inline static std::vector<HookImpl*> m_listeners = {};
inline static std::mutex m_mutex;
};
} // namespace Common

View File

@ -0,0 +1,20 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <algorithm>
namespace Common
{
// A useful template for passing string literals as arguments to templates
// from: https://ctrpeach.io/posts/cpp20-string-literal-template-parameters/
template <size_t N>
struct StringLiteral
{
consteval StringLiteral(const char (&str)[N]) { std::copy_n(str, N, value); }
char value[N];
};
} // namespace Common

View File

@ -84,11 +84,13 @@
#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/AsyncRequests.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
#include "VideoCommon/FrameDumper.h"
#include "VideoCommon/HiresTextures.h" #include "VideoCommon/HiresTextures.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PerformanceMetrics.h" #include "VideoCommon/PerformanceMetrics.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoEvents.h"
#ifdef ANDROID #ifdef ANDROID
#include "jni/AndroidCommon/IDCache.h" #include "jni/AndroidCommon/IDCache.h"
@ -130,6 +132,15 @@ static thread_local bool tls_is_gpu_thread = false;
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi); static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi);
static Common::EventHook s_frame_presented = AfterPresentEvent::Register(
[](auto& present_info) {
const double last_speed_denominator = g_perf_metrics.GetLastSpeedDenominator();
// The denominator should always be > 0 but if it's not, just return 1
const double last_speed = last_speed_denominator > 0.0 ? (1.0 / last_speed_denominator) : 1.0;
Core::Callback_FramePresented(last_speed);
},
"Core Frame Presented");
bool GetIsThrottlerTempDisabled() bool GetIsThrottlerTempDisabled()
{ {
return s_is_throttler_temp_disabled; return s_is_throttler_temp_disabled;
@ -538,11 +549,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
} }
Common::ScopeGuard video_guard{[] { g_video_backend->Shutdown(); }}; Common::ScopeGuard video_guard{[] { g_video_backend->Shutdown(); }};
// Render a single frame without anything on it to clear the screen.
// This avoids the game list being displayed while the core is finishing initializing.
g_renderer->BeginUIFrame();
g_renderer->EndUIFrame();
if (cpu_info.HTT) if (cpu_info.HTT)
Config::SetBaseOrCurrent(Config::MAIN_DSP_THREAD, cpu_info.num_cores > 4); Config::SetBaseOrCurrent(Config::MAIN_DSP_THREAD, cpu_info.num_cores > 4);
else else
@ -731,13 +737,13 @@ static std::string GenerateScreenshotName()
void SaveScreenShot() void SaveScreenShot()
{ {
Core::RunAsCPUThread([] { g_renderer->SaveScreenshot(GenerateScreenshotName()); }); Core::RunAsCPUThread([] { g_frame_dumper->SaveScreenshot(GenerateScreenshotName()); });
} }
void SaveScreenShot(std::string_view name) void SaveScreenShot(std::string_view name)
{ {
Core::RunAsCPUThread([&name] { Core::RunAsCPUThread([&name] {
g_renderer->SaveScreenshot(fmt::format("{}{}.png", GenerateScreenshotFolderPath(), name)); g_frame_dumper->SaveScreenshot(fmt::format("{}{}.png", GenerateScreenshotFolderPath(), name));
}); });
} }

View File

@ -14,7 +14,12 @@
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/System.h" #include "Core/System.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoEvents.h"
#include "VideoCommon/XFMemory.h"
#include "VideoCommon/XFStructs.h" #include "VideoCommon/XFStructs.h"
class FifoRecorder::FifoRecordAnalyzer : public OpcodeDecoder::Callback class FifoRecorder::FifoRecordAnalyzer : public OpcodeDecoder::Callback
@ -249,6 +254,42 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
m_RequestedRecordingEnd = false; m_RequestedRecordingEnd = false;
m_FinishedCb = finishedCb; m_FinishedCb = finishedCb;
m_end_of_frame_event = AfterFrameEvent::Register(
[this] {
const bool was_recording = OpcodeDecoder::g_record_fifo_data;
OpcodeDecoder::g_record_fifo_data = IsRecording();
if (!OpcodeDecoder::g_record_fifo_data)
return;
if (!was_recording)
{
RecordInitialVideoMemory();
}
auto& system = Core::System::GetInstance();
auto& command_processor = system.GetCommandProcessor();
const auto& fifo = command_processor.GetFifo();
EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
fifo.CPEnd.load(std::memory_order_relaxed));
},
"FifoRecorder::EndFrame");
}
void FifoRecorder::RecordInitialVideoMemory()
{
const u32* bpmem_ptr = reinterpret_cast<const u32*>(&bpmem);
u32 cpmem[256] = {};
// The FIFO recording format splits XF memory into xfmem and xfregs; follow
// that split here.
const u32* xfmem_ptr = reinterpret_cast<const u32*>(&xfmem);
const u32* xfregs_ptr = reinterpret_cast<const u32*>(&xfmem) + FifoDataFile::XF_MEM_SIZE;
u32 xfregs_size = sizeof(XFMemory) / 4 - FifoDataFile::XF_MEM_SIZE;
g_main_cp_state.FillCPMemoryArray(cpmem);
SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size, texMem);
} }
void FifoRecorder::StopRecording() void FifoRecorder::StopRecording()
@ -391,11 +432,14 @@ void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd)
m_SkipFutureData = true; m_SkipFutureData = true;
// Signal video backend that it should not call this function when the next frame ends // Signal video backend that it should not call this function when the next frame ends
m_IsRecording = false; m_IsRecording = false;
// Remove our frame end callback
m_end_of_frame_event.reset();
} }
} }
void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32* xfMem, void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32* xfMem,
const u32* xfRegs, u32 xfRegsSize, const u8* texMem) const u32* xfRegs, u32 xfRegsSize, const u8* texMem_ptr)
{ {
std::lock_guard lk(m_mutex); std::lock_guard lk(m_mutex);
@ -408,7 +452,7 @@ void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32*
u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize); u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize);
memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4); memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4);
memcpy(m_File->GetTexMem(), texMem, FifoDataFile::TEX_MEM_SIZE); memcpy(m_File->GetTexMem(), texMem_ptr, FifoDataFile::TEX_MEM_SIZE);
} }
m_record_analyzer = std::make_unique<FifoRecordAnalyzer>(this, cpMem); m_record_analyzer = std::make_unique<FifoRecordAnalyzer>(this, cpMem);

View File

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/HookableEvent.h"
#include "Core/FifoPlayer/FifoDataFile.h" #include "Core/FifoPlayer/FifoDataFile.h"
class FifoRecorder class FifoRecorder
@ -50,6 +51,8 @@ public:
private: private:
class FifoRecordAnalyzer; class FifoRecordAnalyzer;
void RecordInitialVideoMemory();
// Accessed from both GUI and video threads // Accessed from both GUI and video threads
std::recursive_mutex m_mutex; std::recursive_mutex m_mutex;
@ -72,4 +75,6 @@ private:
std::vector<u8> m_FifoData; std::vector<u8> m_FifoData;
std::vector<u8> m_Ram; std::vector<u8> m_Ram;
std::vector<u8> m_ExRam; std::vector<u8> m_ExRam;
Common::EventHook m_end_of_frame_event;
}; };

View File

@ -42,7 +42,7 @@
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h" #include "Core/System.h"
#include "VideoCommon/FrameDump.h" #include "VideoCommon/FrameDumpFFMpeg.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
@ -96,7 +96,7 @@ static size_t s_state_writes_in_queue;
static std::condition_variable s_state_write_queue_is_empty; static std::condition_variable s_state_write_queue_is_empty;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 157; // Last changed in PR 11183 constexpr u32 STATE_VERSION = 158; // Last changed in PR 11522
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,

View File

@ -109,6 +109,7 @@
<ClInclude Include="Common\GL\GLUtil.h" /> <ClInclude Include="Common\GL\GLUtil.h" />
<ClInclude Include="Common\GL\GLX11Window.h" /> <ClInclude Include="Common\GL\GLX11Window.h" />
<ClInclude Include="Common\Hash.h" /> <ClInclude Include="Common\Hash.h" />
<ClInclude Include="Common\HookableEvent.h" />
<ClInclude Include="Common\HRWrap.h" /> <ClInclude Include="Common\HRWrap.h" />
<ClInclude Include="Common\HttpRequest.h" /> <ClInclude Include="Common\HttpRequest.h" />
<ClInclude Include="Common\Image.h" /> <ClInclude Include="Common\Image.h" />
@ -145,6 +146,7 @@
<ClInclude Include="Common\SFMLHelper.h" /> <ClInclude Include="Common\SFMLHelper.h" />
<ClInclude Include="Common\SocketContext.h" /> <ClInclude Include="Common\SocketContext.h" />
<ClInclude Include="Common\SPSCQueue.h" /> <ClInclude Include="Common\SPSCQueue.h" />
<ClInclude Include="Common\StringLiteral.h" />
<ClInclude Include="Common\StringUtil.h" /> <ClInclude Include="Common\StringUtil.h" />
<ClInclude Include="Common\Swap.h" /> <ClInclude Include="Common\Swap.h" />
<ClInclude Include="Common\SymbolDB.h" /> <ClInclude Include="Common\SymbolDB.h" />
@ -534,7 +536,7 @@
<ClInclude Include="VideoBackends\D3D\D3DBase.h" /> <ClInclude Include="VideoBackends\D3D\D3DBase.h" />
<ClInclude Include="VideoBackends\D3D\D3DBoundingBox.h" /> <ClInclude Include="VideoBackends\D3D\D3DBoundingBox.h" />
<ClInclude Include="VideoBackends\D3D\D3DPerfQuery.h" /> <ClInclude Include="VideoBackends\D3D\D3DPerfQuery.h" />
<ClInclude Include="VideoBackends\D3D\D3DRender.h" /> <ClInclude Include="VideoBackends\D3D\D3DGfx.h" />
<ClInclude Include="VideoBackends\D3D\D3DState.h" /> <ClInclude Include="VideoBackends\D3D\D3DState.h" />
<ClInclude Include="VideoBackends\D3D\D3DSwapChain.h" /> <ClInclude Include="VideoBackends\D3D\D3DSwapChain.h" />
<ClInclude Include="VideoBackends\D3D\D3DVertexManager.h" /> <ClInclude Include="VideoBackends\D3D\D3DVertexManager.h" />
@ -545,7 +547,7 @@
<ClInclude Include="VideoBackends\D3D12\Common.h" /> <ClInclude Include="VideoBackends\D3D12\Common.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12BoundingBox.h" /> <ClInclude Include="VideoBackends\D3D12\D3D12BoundingBox.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12PerfQuery.h" /> <ClInclude Include="VideoBackends\D3D12\D3D12PerfQuery.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12Renderer.h" /> <ClInclude Include="VideoBackends\D3D12\D3D12Gfx.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12StreamBuffer.h" /> <ClInclude Include="VideoBackends\D3D12\D3D12StreamBuffer.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12SwapChain.h" /> <ClInclude Include="VideoBackends\D3D12\D3D12SwapChain.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12VertexManager.h" /> <ClInclude Include="VideoBackends\D3D12\D3D12VertexManager.h" />
@ -561,7 +563,7 @@
<ClInclude Include="VideoBackends\D3DCommon\Shader.h" /> <ClInclude Include="VideoBackends\D3DCommon\Shader.h" />
<ClInclude Include="VideoBackends\D3DCommon\SwapChain.h" /> <ClInclude Include="VideoBackends\D3DCommon\SwapChain.h" />
<ClInclude Include="VideoBackends\Null\NullBoundingBox.h" /> <ClInclude Include="VideoBackends\Null\NullBoundingBox.h" />
<ClInclude Include="VideoBackends\Null\NullRender.h" /> <ClInclude Include="VideoBackends\Null\NullGfx.h" />
<ClInclude Include="VideoBackends\Null\NullTexture.h" /> <ClInclude Include="VideoBackends\Null\NullTexture.h" />
<ClInclude Include="VideoBackends\Null\NullVertexManager.h" /> <ClInclude Include="VideoBackends\Null\NullVertexManager.h" />
<ClInclude Include="VideoBackends\Null\PerfQuery.h" /> <ClInclude Include="VideoBackends\Null\PerfQuery.h" />
@ -569,9 +571,10 @@
<ClInclude Include="VideoBackends\Null\VideoBackend.h" /> <ClInclude Include="VideoBackends\Null\VideoBackend.h" />
<ClInclude Include="VideoBackends\OGL\GPUTimer.h" /> <ClInclude Include="VideoBackends\OGL\GPUTimer.h" />
<ClInclude Include="VideoBackends\OGL\OGLBoundingBox.h" /> <ClInclude Include="VideoBackends\OGL\OGLBoundingBox.h" />
<ClInclude Include="VideoBackends\OGL\OGLConfig.h" />
<ClInclude Include="VideoBackends\OGL\OGLGfx.h" />
<ClInclude Include="VideoBackends\OGL\OGLPerfQuery.h" /> <ClInclude Include="VideoBackends\OGL\OGLPerfQuery.h" />
<ClInclude Include="VideoBackends\OGL\OGLPipeline.h" /> <ClInclude Include="VideoBackends\OGL\OGLPipeline.h" />
<ClInclude Include="VideoBackends\OGL\OGLRender.h" />
<ClInclude Include="VideoBackends\OGL\OGLShader.h" /> <ClInclude Include="VideoBackends\OGL\OGLShader.h" />
<ClInclude Include="VideoBackends\OGL\OGLStreamBuffer.h" /> <ClInclude Include="VideoBackends\OGL\OGLStreamBuffer.h" />
<ClInclude Include="VideoBackends\OGL\OGLTexture.h" /> <ClInclude Include="VideoBackends\OGL\OGLTexture.h" />
@ -587,6 +590,7 @@
<ClInclude Include="VideoBackends\Software\Rasterizer.h" /> <ClInclude Include="VideoBackends\Software\Rasterizer.h" />
<ClInclude Include="VideoBackends\Software\SetupUnit.h" /> <ClInclude Include="VideoBackends\Software\SetupUnit.h" />
<ClInclude Include="VideoBackends\Software\SWBoundingBox.h" /> <ClInclude Include="VideoBackends\Software\SWBoundingBox.h" />
<ClInclude Include="VideoBackends\Software\SWGfx.h" />
<ClInclude Include="VideoBackends\Software\SWOGLWindow.h" /> <ClInclude Include="VideoBackends\Software\SWOGLWindow.h" />
<ClInclude Include="VideoBackends\Software\SWRenderer.h" /> <ClInclude Include="VideoBackends\Software\SWRenderer.h" />
<ClInclude Include="VideoBackends\Software\SWTexture.h" /> <ClInclude Include="VideoBackends\Software\SWTexture.h" />
@ -608,7 +612,7 @@
<ClInclude Include="VideoBackends\Vulkan\VKBoundingBox.h" /> <ClInclude Include="VideoBackends\Vulkan\VKBoundingBox.h" />
<ClInclude Include="VideoBackends\Vulkan\VKPerfQuery.h" /> <ClInclude Include="VideoBackends\Vulkan\VKPerfQuery.h" />
<ClInclude Include="VideoBackends\Vulkan\VKPipeline.h" /> <ClInclude Include="VideoBackends\Vulkan\VKPipeline.h" />
<ClInclude Include="VideoBackends\Vulkan\VKRenderer.h" /> <ClInclude Include="VideoBackends\Vulkan\VKGfx.h" />
<ClInclude Include="VideoBackends\Vulkan\VKShader.h" /> <ClInclude Include="VideoBackends\Vulkan\VKShader.h" />
<ClInclude Include="VideoBackends\Vulkan\VKStreamBuffer.h" /> <ClInclude Include="VideoBackends\Vulkan\VKStreamBuffer.h" />
<ClInclude Include="VideoBackends\Vulkan\VKSwapChain.h" /> <ClInclude Include="VideoBackends\Vulkan\VKSwapChain.h" />
@ -618,6 +622,7 @@
<ClInclude Include="VideoBackends\Vulkan\VulkanContext.h" /> <ClInclude Include="VideoBackends\Vulkan\VulkanContext.h" />
<ClInclude Include="VideoBackends\Vulkan\VulkanLoader.h" /> <ClInclude Include="VideoBackends\Vulkan\VulkanLoader.h" />
<ClInclude Include="VideoCommon\AbstractFramebuffer.h" /> <ClInclude Include="VideoCommon\AbstractFramebuffer.h" />
<ClInclude Include="VideoCommon\AbstractGfx.h" />
<ClInclude Include="VideoCommon\AbstractPipeline.h" /> <ClInclude Include="VideoCommon\AbstractPipeline.h" />
<ClInclude Include="VideoCommon\AbstractShader.h" /> <ClInclude Include="VideoCommon\AbstractShader.h" />
<ClInclude Include="VideoCommon\AbstractStagingTexture.h" /> <ClInclude Include="VideoCommon\AbstractStagingTexture.h" />
@ -638,7 +643,8 @@
<ClInclude Include="VideoCommon\Fifo.h" /> <ClInclude Include="VideoCommon\Fifo.h" />
<ClInclude Include="VideoCommon\FramebufferManager.h" /> <ClInclude Include="VideoCommon\FramebufferManager.h" />
<ClInclude Include="VideoCommon\FramebufferShaderGen.h" /> <ClInclude Include="VideoCommon\FramebufferShaderGen.h" />
<ClInclude Include="VideoCommon\FrameDump.h" /> <ClInclude Include="VideoCommon\FrameDumpFFMpeg.h" />
<ClInclude Include="VideoCommon\FrameDumper.h" />
<ClInclude Include="VideoCommon\FreeLookCamera.h" /> <ClInclude Include="VideoCommon\FreeLookCamera.h" />
<ClInclude Include="VideoCommon\GeometryShaderGen.h" /> <ClInclude Include="VideoCommon\GeometryShaderGen.h" />
<ClInclude Include="VideoCommon\GeometryShaderManager.h" /> <ClInclude Include="VideoCommon\GeometryShaderManager.h" />
@ -668,6 +674,8 @@
<ClInclude Include="VideoCommon\NetPlayChatUI.h" /> <ClInclude Include="VideoCommon\NetPlayChatUI.h" />
<ClInclude Include="VideoCommon\NetPlayGolfUI.h" /> <ClInclude Include="VideoCommon\NetPlayGolfUI.h" />
<ClInclude Include="VideoCommon\OnScreenDisplay.h" /> <ClInclude Include="VideoCommon\OnScreenDisplay.h" />
<ClInclude Include="VideoCommon\OnScreenUI.h" />
<ClInclude Include="VideoCommon\OnScreenUIKeyMap.h" />
<ClInclude Include="VideoCommon\OpcodeDecoding.h" /> <ClInclude Include="VideoCommon\OpcodeDecoding.h" />
<ClInclude Include="VideoCommon\PerfQueryBase.h" /> <ClInclude Include="VideoCommon\PerfQueryBase.h" />
<ClInclude Include="VideoCommon\PerformanceMetrics.h" /> <ClInclude Include="VideoCommon\PerformanceMetrics.h" />
@ -676,6 +684,7 @@
<ClInclude Include="VideoCommon\PixelShaderGen.h" /> <ClInclude Include="VideoCommon\PixelShaderGen.h" />
<ClInclude Include="VideoCommon\PixelShaderManager.h" /> <ClInclude Include="VideoCommon\PixelShaderManager.h" />
<ClInclude Include="VideoCommon\PostProcessing.h" /> <ClInclude Include="VideoCommon\PostProcessing.h" />
<ClInclude Include="VideoCommon\Present.h" />
<ClInclude Include="VideoCommon\RenderBase.h" /> <ClInclude Include="VideoCommon\RenderBase.h" />
<ClInclude Include="VideoCommon\RenderState.h" /> <ClInclude Include="VideoCommon\RenderState.h" />
<ClInclude Include="VideoCommon\ShaderCache.h" /> <ClInclude Include="VideoCommon\ShaderCache.h" />
@ -707,7 +716,9 @@
<ClInclude Include="VideoCommon\VideoBackendBase.h" /> <ClInclude Include="VideoCommon\VideoBackendBase.h" />
<ClInclude Include="VideoCommon\VideoCommon.h" /> <ClInclude Include="VideoCommon\VideoCommon.h" />
<ClInclude Include="VideoCommon\VideoConfig.h" /> <ClInclude Include="VideoCommon\VideoConfig.h" />
<ClInclude Include="VideoCommon\VideoEvents.h" />
<ClInclude Include="VideoCommon\VideoState.h" /> <ClInclude Include="VideoCommon\VideoState.h" />
<ClInclude Include="VideoCommon\Widescreen.h" />
<ClInclude Include="VideoCommon\XFMemory.h" /> <ClInclude Include="VideoCommon\XFMemory.h" />
<ClInclude Include="VideoCommon\XFStructs.h" /> <ClInclude Include="VideoCommon\XFStructs.h" />
</ItemGroup> </ItemGroup>
@ -1142,7 +1153,7 @@
<ClCompile Include="VideoBackends\D3D\D3DMain.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DMain.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DNativeVertexFormat.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DNativeVertexFormat.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DPerfQuery.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DPerfQuery.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DRender.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DGfx.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DState.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DState.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DSwapChain.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DSwapChain.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DVertexManager.cpp" /> <ClCompile Include="VideoBackends\D3D\D3DVertexManager.cpp" />
@ -1151,7 +1162,7 @@
<ClCompile Include="VideoBackends\D3D\DXTexture.cpp" /> <ClCompile Include="VideoBackends\D3D\DXTexture.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12BoundingBox.cpp" /> <ClCompile Include="VideoBackends\D3D12\D3D12BoundingBox.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12PerfQuery.cpp" /> <ClCompile Include="VideoBackends\D3D12\D3D12PerfQuery.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12Renderer.cpp" /> <ClCompile Include="VideoBackends\D3D12\D3D12Gfx.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12StreamBuffer.cpp" /> <ClCompile Include="VideoBackends\D3D12\D3D12StreamBuffer.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12SwapChain.cpp" /> <ClCompile Include="VideoBackends\D3D12\D3D12SwapChain.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12VertexManager.cpp" /> <ClCompile Include="VideoBackends\D3D12\D3D12VertexManager.cpp" />
@ -1167,15 +1178,16 @@
<ClCompile Include="VideoBackends\D3DCommon\Shader.cpp" /> <ClCompile Include="VideoBackends\D3DCommon\Shader.cpp" />
<ClCompile Include="VideoBackends\D3DCommon\SwapChain.cpp" /> <ClCompile Include="VideoBackends\D3DCommon\SwapChain.cpp" />
<ClCompile Include="VideoBackends\Null\NullBackend.cpp" /> <ClCompile Include="VideoBackends\Null\NullBackend.cpp" />
<ClCompile Include="VideoBackends\Null\NullRender.cpp" /> <ClCompile Include="VideoBackends\Null\NullGfx.cpp" />
<ClCompile Include="VideoBackends\Null\NullTexture.cpp" /> <ClCompile Include="VideoBackends\Null\NullTexture.cpp" />
<ClCompile Include="VideoBackends\Null\NullVertexManager.cpp" /> <ClCompile Include="VideoBackends\Null\NullVertexManager.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLBoundingBox.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLBoundingBox.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLConfig.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLGfx.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLMain.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLMain.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLNativeVertexFormat.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLNativeVertexFormat.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLPerfQuery.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLPerfQuery.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLPipeline.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLPipeline.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLRender.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLShader.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLShader.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLStreamBuffer.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLStreamBuffer.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLTexture.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLTexture.cpp" />
@ -1189,6 +1201,7 @@
<ClCompile Include="VideoBackends\Software\SetupUnit.cpp" /> <ClCompile Include="VideoBackends\Software\SetupUnit.cpp" />
<ClCompile Include="VideoBackends\Software\SWmain.cpp" /> <ClCompile Include="VideoBackends\Software\SWmain.cpp" />
<ClCompile Include="VideoBackends\Software\SWBoundingBox.cpp" /> <ClCompile Include="VideoBackends\Software\SWBoundingBox.cpp" />
<ClCompile Include="VideoBackends\Software\SWGfx.cpp" />
<ClCompile Include="VideoBackends\Software\SWOGLWindow.cpp" /> <ClCompile Include="VideoBackends\Software\SWOGLWindow.cpp" />
<ClCompile Include="VideoBackends\Software\SWRenderer.cpp" /> <ClCompile Include="VideoBackends\Software\SWRenderer.cpp" />
<ClCompile Include="VideoBackends\Software\SWTexture.cpp" /> <ClCompile Include="VideoBackends\Software\SWTexture.cpp" />
@ -1206,7 +1219,7 @@
<ClCompile Include="VideoBackends\Vulkan\VKMain.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKMain.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKPerfQuery.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKPerfQuery.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKPipeline.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKPipeline.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKRenderer.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKGfx.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKShader.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKShader.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKStreamBuffer.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKStreamBuffer.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKSwapChain.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VKSwapChain.cpp" />
@ -1216,6 +1229,7 @@
<ClCompile Include="VideoBackends\Vulkan\VulkanContext.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VulkanContext.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VulkanLoader.cpp" /> <ClCompile Include="VideoBackends\Vulkan\VulkanLoader.cpp" />
<ClCompile Include="VideoCommon\AbstractFramebuffer.cpp" /> <ClCompile Include="VideoCommon\AbstractFramebuffer.cpp" />
<ClCompile Include="VideoCommon\AbstractGfx.cpp" />
<ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" /> <ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" />
<ClCompile Include="VideoCommon\AbstractTexture.cpp" /> <ClCompile Include="VideoCommon\AbstractTexture.cpp" />
<ClCompile Include="VideoCommon\AsyncRequests.cpp" /> <ClCompile Include="VideoCommon\AsyncRequests.cpp" />
@ -1231,7 +1245,8 @@
<ClCompile Include="VideoCommon\Fifo.cpp" /> <ClCompile Include="VideoCommon\Fifo.cpp" />
<ClCompile Include="VideoCommon\FramebufferManager.cpp" /> <ClCompile Include="VideoCommon\FramebufferManager.cpp" />
<ClCompile Include="VideoCommon\FramebufferShaderGen.cpp" /> <ClCompile Include="VideoCommon\FramebufferShaderGen.cpp" />
<ClCompile Include="VideoCommon\FrameDump.cpp" /> <ClCompile Include="VideoCommon\FrameDumpFFMpeg.cpp" />
<ClCompile Include="VideoCommon\FrameDumper.cpp" />
<ClCompile Include="VideoCommon\FreeLookCamera.cpp" /> <ClCompile Include="VideoCommon\FreeLookCamera.cpp" />
<ClCompile Include="VideoCommon\GeometryShaderGen.cpp" /> <ClCompile Include="VideoCommon\GeometryShaderGen.cpp" />
<ClCompile Include="VideoCommon\GeometryShaderManager.cpp" /> <ClCompile Include="VideoCommon\GeometryShaderManager.cpp" />
@ -1254,6 +1269,7 @@
<ClCompile Include="VideoCommon\NetPlayChatUI.cpp" /> <ClCompile Include="VideoCommon\NetPlayChatUI.cpp" />
<ClCompile Include="VideoCommon\NetPlayGolfUI.cpp" /> <ClCompile Include="VideoCommon\NetPlayGolfUI.cpp" />
<ClCompile Include="VideoCommon\OnScreenDisplay.cpp" /> <ClCompile Include="VideoCommon\OnScreenDisplay.cpp" />
<ClCompile Include="VideoCommon\OnScreenUI.cpp" />
<ClCompile Include="VideoCommon\OpcodeDecoding.cpp" /> <ClCompile Include="VideoCommon\OpcodeDecoding.cpp" />
<ClCompile Include="VideoCommon\PerfQueryBase.cpp" /> <ClCompile Include="VideoCommon\PerfQueryBase.cpp" />
<ClCompile Include="VideoCommon\PerformanceMetrics.cpp" /> <ClCompile Include="VideoCommon\PerformanceMetrics.cpp" />
@ -1262,6 +1278,7 @@
<ClCompile Include="VideoCommon\PixelShaderGen.cpp" /> <ClCompile Include="VideoCommon\PixelShaderGen.cpp" />
<ClCompile Include="VideoCommon\PixelShaderManager.cpp" /> <ClCompile Include="VideoCommon\PixelShaderManager.cpp" />
<ClCompile Include="VideoCommon\PostProcessing.cpp" /> <ClCompile Include="VideoCommon\PostProcessing.cpp" />
<ClCompile Include="VideoCommon\Present.cpp" />
<ClCompile Include="VideoCommon\RenderBase.cpp" /> <ClCompile Include="VideoCommon\RenderBase.cpp" />
<ClCompile Include="VideoCommon\RenderState.cpp" /> <ClCompile Include="VideoCommon\RenderState.cpp" />
<ClCompile Include="VideoCommon\ShaderCache.cpp" /> <ClCompile Include="VideoCommon\ShaderCache.cpp" />
@ -1291,6 +1308,7 @@
<ClCompile Include="VideoCommon\VideoBackendBase.cpp" /> <ClCompile Include="VideoCommon\VideoBackendBase.cpp" />
<ClCompile Include="VideoCommon\VideoConfig.cpp" /> <ClCompile Include="VideoCommon\VideoConfig.cpp" />
<ClCompile Include="VideoCommon\VideoState.cpp" /> <ClCompile Include="VideoCommon\VideoState.cpp" />
<ClCompile Include="VideoCommon\Widescreen.cpp" />
<ClCompile Include="VideoCommon\XFMemory.cpp" /> <ClCompile Include="VideoCommon\XFMemory.cpp" />
<ClCompile Include="VideoCommon\XFStructs.cpp" /> <ClCompile Include="VideoCommon\XFStructs.cpp" />
</ItemGroup> </ItemGroup>

View File

@ -33,7 +33,6 @@
#include "InputCommon/GCAdapter.h" #include "InputCommon/GCAdapter.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
static std::unique_ptr<Platform> s_platform; static std::unique_ptr<Platform> s_platform;

View File

@ -12,6 +12,7 @@
#include <climits> #include <climits>
#include <cstdio> #include <cstdio>
#include <thread>
#include <fcntl.h> #include <fcntl.h>
#include <linux/fb.h> #include <linux/fb.h>
@ -21,7 +22,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include "VideoCommon/RenderBase.h"
namespace namespace
{ {

View File

@ -13,7 +13,7 @@
#include <climits> #include <climits>
#include <cstdio> #include <cstdio>
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#include "resource.h" #include "resource.h"
namespace namespace
@ -181,8 +181,8 @@ LRESULT PlatformWin32::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
case WM_SIZE: case WM_SIZE:
{ {
if (g_renderer) if (g_presenter)
g_renderer->ResizeSurface(); g_presenter->ResizeSurface();
} }
break; break;

View File

@ -19,13 +19,14 @@ static constexpr auto X_None = None;
#include <climits> #include <climits>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <thread>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include "UICommon/X11Utils.h" #include "UICommon/X11Utils.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#ifndef HOST_NAME_MAX #ifndef HOST_NAME_MAX
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
@ -263,8 +264,8 @@ void PlatformX11::ProcessEvents()
break; break;
case ConfigureNotify: case ConfigureNotify:
{ {
if (g_renderer) if (g_presenter)
g_renderer->ResizeSurface(); g_presenter->ResizeSurface();
} }
break; break;
} }

View File

@ -21,7 +21,7 @@
#include "DolphinQt/Config/Graphics/EnhancementsWidget.h" #include "DolphinQt/Config/Graphics/EnhancementsWidget.h"
#include "VideoCommon/PostProcessing.h" #include "VideoCommon/PostProcessing.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
using ConfigurationOption = VideoCommon::PostProcessingConfiguration::ConfigurationOption; using ConfigurationOption = VideoCommon::PostProcessingConfiguration::ConfigurationOption;
@ -31,9 +31,9 @@ PostProcessingConfigWindow::PostProcessingConfigWindow(EnhancementsWidget* paren
const std::string& shader) const std::string& shader)
: QDialog(parent), m_shader(shader) : QDialog(parent), m_shader(shader)
{ {
if (g_renderer && g_renderer->GetPostProcessor()) if (g_presenter && g_presenter->GetPostProcessor())
{ {
m_post_processor = g_renderer->GetPostProcessor()->GetConfig(); m_post_processor = g_presenter->GetPostProcessor()->GetConfig();
} }
else else
{ {
@ -52,7 +52,7 @@ PostProcessingConfigWindow::PostProcessingConfigWindow(EnhancementsWidget* paren
PostProcessingConfigWindow::~PostProcessingConfigWindow() PostProcessingConfigWindow::~PostProcessingConfigWindow()
{ {
m_post_processor->SaveOptionsConfiguration(); m_post_processor->SaveOptionsConfiguration();
if (!(g_renderer && g_renderer->GetPostProcessor())) if (!(g_presenter && g_presenter->GetPostProcessor()))
{ {
delete m_post_processor; delete m_post_processor;
} }

View File

@ -36,8 +36,9 @@
#include "UICommon/DiscordPresence.h" #include "UICommon/DiscordPresence.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/Fifo.cpp" #include "VideoCommon/Fifo.cpp"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
static thread_local bool tls_is_host_thread = false; static thread_local bool tls_is_host_thread = false;
@ -76,9 +77,9 @@ void Host::SetRenderHandle(void* handle)
return; return;
m_render_handle = handle; m_render_handle = handle;
if (g_renderer) if (g_presenter)
{ {
g_renderer->ChangeSurface(handle); g_presenter->ChangeSurface(handle);
g_controller_interface.ChangeWindow(handle); g_controller_interface.ChangeWindow(handle);
} }
} }
@ -149,11 +150,11 @@ bool Host::GetRenderFullFocus()
void Host::SetRenderFocus(bool focus) void Host::SetRenderFocus(bool focus)
{ {
m_render_focus = focus; m_render_focus = focus;
if (g_renderer && m_render_fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled()) if (g_gfx && m_render_fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
{ {
RunWithGPUThreadInactive([focus] { RunWithGPUThreadInactive([focus] {
if (!Config::Get(Config::MAIN_RENDER_TO_MAIN)) if (!Config::Get(Config::MAIN_RENDER_TO_MAIN))
g_renderer->SetFullscreen(focus); g_gfx->SetFullscreen(focus);
}); });
} }
} }
@ -181,17 +182,16 @@ void Host::SetRenderFullscreen(bool fullscreen)
{ {
m_render_fullscreen = fullscreen; m_render_fullscreen = fullscreen;
if (g_renderer && g_renderer->IsFullscreen() != fullscreen && if (g_gfx && g_gfx->IsFullscreen() != fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
g_ActiveConfig.ExclusiveFullscreenEnabled())
{ {
RunWithGPUThreadInactive([fullscreen] { g_renderer->SetFullscreen(fullscreen); }); RunWithGPUThreadInactive([fullscreen] { g_gfx->SetFullscreen(fullscreen); });
} }
} }
void Host::ResizeSurface(int new_width, int new_height) void Host::ResizeSurface(int new_width, int new_height)
{ {
if (g_renderer) if (g_presenter)
g_renderer->ResizeSurface(); g_presenter->ResizeSurface();
} }
std::vector<std::string> Host_GetPreferredLocales() std::vector<std::string> Host_GetPreferredLocales()

View File

@ -43,7 +43,6 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"

View File

@ -1383,7 +1383,7 @@ void MainWindow::SetStateSlot(int slot)
void MainWindow::IncrementSelectedStateSlot() void MainWindow::IncrementSelectedStateSlot()
{ {
int state_slot = m_state_slot + 1; u32 state_slot = m_state_slot + 1;
if (state_slot > State::NUM_STATES) if (state_slot > State::NUM_STATES)
state_slot = 1; state_slot = 1;
m_menu_bar->SetStateSlot(state_slot); m_menu_bar->SetStateSlot(state_slot);
@ -1391,7 +1391,7 @@ void MainWindow::IncrementSelectedStateSlot()
void MainWindow::DecrementSelectedStateSlot() void MainWindow::DecrementSelectedStateSlot()
{ {
int state_slot = m_state_slot - 1; u32 state_slot = m_state_slot - 1;
if (state_slot < 1) if (state_slot < 1)
state_slot = State::NUM_STATES; state_slot = State::NUM_STATES;
m_menu_bar->SetStateSlot(state_slot); m_menu_bar->SetStateSlot(state_slot);

View File

@ -217,7 +217,7 @@ private:
bool m_exit_requested = false; bool m_exit_requested = false;
bool m_fullscreen_requested = false; bool m_fullscreen_requested = false;
bool m_is_screensaver_inhibited = false; bool m_is_screensaver_inhibited = false;
int m_state_slot = 1; u32 m_state_slot = 1;
std::unique_ptr<BootParameters> m_pending_boot; std::unique_ptr<BootParameters> m_pending_boot;
ControllersWindow* m_controllers_window = nullptr; ControllersWindow* m_controllers_window = nullptr;

View File

@ -61,7 +61,6 @@
#include "VideoCommon/NetPlayChatUI.h" #include "VideoCommon/NetPlayChatUI.h"
#include "VideoCommon/NetPlayGolfUI.h" #include "VideoCommon/NetPlayGolfUI.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
namespace namespace

View File

@ -19,8 +19,6 @@
#include <QTimer> #include <QTimer>
#include <QWindow> #include <QWindow>
#include <imgui.h>
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/State.h" #include "Core/State.h"
@ -32,7 +30,8 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/OnScreenUI.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#ifdef _WIN32 #ifdef _WIN32
@ -62,7 +61,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
if (state == Core::State::Running) if (state == Core::State::Running)
SetImGuiKeyMap(); SetPresenterKeyMap();
}); });
// We have to use Qt::DirectConnection here because we don't want those signals to get queued // We have to use Qt::DirectConnection here because we don't want those signals to get queued
@ -338,7 +337,7 @@ void RenderWidget::SetWaitingForMessageBox(bool waiting_for_message_box)
bool RenderWidget::event(QEvent* event) bool RenderWidget::event(QEvent* event)
{ {
PassEventToImGui(event); PassEventToPresenter(event);
switch (event->type()) switch (event->type())
{ {
@ -470,7 +469,7 @@ bool RenderWidget::event(QEvent* event)
return QWidget::event(event); return QWidget::event(event);
} }
void RenderWidget::PassEventToImGui(const QEvent* event) void RenderWidget::PassEventToPresenter(const QEvent* event)
{ {
if (!Core::IsRunningAndStarted()) if (!Core::IsRunningAndStarted())
return; return;
@ -487,38 +486,40 @@ void RenderWidget::PassEventToImGui(const QEvent* event)
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event); const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
const bool is_down = event->type() == QEvent::KeyPress; const bool is_down = event->type() == QEvent::KeyPress;
const u32 key = static_cast<u32>(key_event->key() & 0x1FF); const u32 key = static_cast<u32>(key_event->key() & 0x1FF);
auto lock = g_renderer->GetImGuiLock();
if (key < std::size(ImGui::GetIO().KeysDown)) const char* chars = nullptr;
ImGui::GetIO().KeysDown[key] = is_down;
if (is_down) if (is_down)
{ {
auto utf8 = key_event->text().toUtf8(); auto utf8 = key_event->text().toUtf8();
ImGui::GetIO().AddInputCharactersUTF8(utf8.constData());
if (utf8.size())
chars = utf8.constData();
} }
// Pass the key onto Presenter (for the imgui UI)
g_presenter->SetKey(key, is_down, chars);
} }
break; break;
case QEvent::MouseMove: case QEvent::MouseMove:
{ {
auto lock = g_renderer->GetImGuiLock();
// Qt multiplies all coordinates by the scaling factor in highdpi mode, giving us "scaled" mouse // Qt multiplies all coordinates by the scaling factor in highdpi mode, giving us "scaled" mouse
// coordinates (as if the screen was standard dpi). We need to update the mouse position in // coordinates (as if the screen was standard dpi). We need to update the mouse position in
// native coordinates, as the UI (and game) is rendered at native resolution. // native coordinates, as the UI (and game) is rendered at native resolution.
const float scale = devicePixelRatio(); const float scale = devicePixelRatio();
ImGui::GetIO().MousePos.x = static_cast<const QMouseEvent*>(event)->pos().x() * scale; float x = static_cast<const QMouseEvent*>(event)->pos().x() * scale;
ImGui::GetIO().MousePos.y = static_cast<const QMouseEvent*>(event)->pos().y() * scale; float y = static_cast<const QMouseEvent*>(event)->pos().y() * scale;
g_presenter->SetMousePos(x, y);
} }
break; break;
case QEvent::MouseButtonPress: case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease: case QEvent::MouseButtonRelease:
{ {
auto lock = g_renderer->GetImGuiLock();
const u32 button_mask = static_cast<u32>(static_cast<const QMouseEvent*>(event)->buttons()); const u32 button_mask = static_cast<u32>(static_cast<const QMouseEvent*>(event)->buttons());
for (size_t i = 0; i < std::size(ImGui::GetIO().MouseDown); i++) g_presenter->SetMousePress(button_mask);
ImGui::GetIO().MouseDown[i] = (button_mask & (1u << i)) != 0;
} }
break; break;
@ -527,36 +528,16 @@ void RenderWidget::PassEventToImGui(const QEvent* event)
} }
} }
void RenderWidget::SetImGuiKeyMap() void RenderWidget::SetPresenterKeyMap()
{ {
static constexpr std::array<std::array<int, 2>, 21> key_map{{ static constexpr DolphinKeyMap key_map = {
{ImGuiKey_Tab, Qt::Key_Tab}, Qt::Key_Tab, Qt::Key_Left, Qt::Key_Right, Qt::Key_Up, Qt::Key_Down,
{ImGuiKey_LeftArrow, Qt::Key_Left}, Qt::Key_PageUp, Qt::Key_PageDown, Qt::Key_Home, Qt::Key_End, Qt::Key_Insert,
{ImGuiKey_RightArrow, Qt::Key_Right}, Qt::Key_Delete, Qt::Key_Backspace, Qt::Key_Space, Qt::Key_Return, Qt::Key_Escape,
{ImGuiKey_UpArrow, Qt::Key_Up}, Qt::Key_Enter, // Keypad enter
{ImGuiKey_DownArrow, Qt::Key_Down}, Qt::Key_A, Qt::Key_C, Qt::Key_V, Qt::Key_X, Qt::Key_Y,
{ImGuiKey_PageUp, Qt::Key_PageUp}, Qt::Key_Z,
{ImGuiKey_PageDown, Qt::Key_PageDown}, };
{ImGuiKey_Home, Qt::Key_Home},
{ImGuiKey_End, Qt::Key_End},
{ImGuiKey_Insert, Qt::Key_Insert},
{ImGuiKey_Delete, Qt::Key_Delete},
{ImGuiKey_Backspace, Qt::Key_Backspace},
{ImGuiKey_Space, Qt::Key_Space},
{ImGuiKey_Enter, Qt::Key_Return},
{ImGuiKey_Escape, Qt::Key_Escape},
{ImGuiKey_A, Qt::Key_A},
{ImGuiKey_C, Qt::Key_C},
{ImGuiKey_V, Qt::Key_V},
{ImGuiKey_X, Qt::Key_X},
{ImGuiKey_Y, Qt::Key_Y},
{ImGuiKey_Z, Qt::Key_Z},
}};
auto lock = g_renderer->GetImGuiLock();
if (!ImGui::GetCurrentContext()) g_presenter->SetKeyMap(key_map);
return;
for (auto [imgui_key, qt_key] : key_map)
ImGui::GetIO().KeyMap[imgui_key] = (qt_key & 0x1FF);
} }

View File

@ -39,8 +39,8 @@ private:
void OnLockCursorChanged(); void OnLockCursorChanged();
void OnKeepOnTopChanged(bool top); void OnKeepOnTopChanged(bool top);
void UpdateCursor(); void UpdateCursor();
void PassEventToImGui(const QEvent* event); void PassEventToPresenter(const QEvent* event);
void SetImGuiKeyMap(); void SetPresenterKeyMap();
void dragEnterEvent(QDragEnterEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override; void dropEvent(QDropEvent* event) override;

View File

@ -46,7 +46,6 @@
#include "VideoCommon/NetPlayChatUI.h" #include "VideoCommon/NetPlayChatUI.h"
#include "VideoCommon/NetPlayGolfUI.h" #include "VideoCommon/NetPlayGolfUI.h"
#include "VideoCommon/RenderBase.h"
Settings::Settings() Settings::Settings()
{ {

View File

@ -15,7 +15,6 @@
#include "Core/Host.h" #include "Core/Host.h"
// Begin stubs needed to satisfy Core dependencies // Begin stubs needed to satisfy Core dependencies
#include "VideoCommon/RenderBase.h"
std::vector<std::string> Host_GetPreferredLocales() std::vector<std::string> Host_GetPreferredLocales()
{ {

View File

@ -13,7 +13,7 @@
#include "InputCommon/DynamicInputTextures/DITConfiguration.h" #include "InputCommon/DynamicInputTextures/DITConfiguration.h"
#include "VideoCommon/HiresTextures.h" #include "VideoCommon/HiresTextures.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/TextureCacheBase.h"
namespace InputCommon namespace InputCommon
{ {
@ -48,7 +48,7 @@ void DynamicInputTextureManager::GenerateTextures(const IniFile& file,
any_dirty |= configuration.GenerateTextures(file, controller_names); any_dirty |= configuration.GenerateTextures(file, controller_names);
} }
if (any_dirty && g_renderer && Core::GetState() != Core::State::Starting) if (any_dirty && g_texture_cache && Core::GetState() != Core::State::Starting)
g_renderer->ForceReloadTextures(); g_texture_cache->ForceReloadTextures();
} }
} // namespace InputCommon } // namespace InputCommon

View File

@ -7,8 +7,8 @@ add_library(videod3d
D3DNativeVertexFormat.cpp D3DNativeVertexFormat.cpp
D3DPerfQuery.cpp D3DPerfQuery.cpp
D3DPerfQuery.h D3DPerfQuery.h
D3DRender.cpp D3DGfx.cpp
D3DRender.h D3DGfx.h
D3DState.cpp D3DState.cpp
D3DState.h D3DState.h
D3DSwapChain.cpp D3DSwapChain.cpp

View File

@ -1,7 +1,7 @@
// Copyright 2010 Dolphin Emulator Project // Copyright 2010 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -30,48 +30,46 @@
#include "VideoCommon/BPFunctions.h" #include "VideoCommon/BPFunctions.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/PostProcessing.h" #include "VideoCommon/PostProcessing.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderState.h" #include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h" #include "VideoCommon/XFMemory.h"
namespace DX11 namespace DX11
{ {
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale) Gfx::Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0, : m_backbuffer_scale(backbuffer_scale), m_swap_chain(std::move(swap_chain))
backbuffer_scale,
swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
{ {
} }
Renderer::~Renderer() = default; Gfx::~Gfx() = default;
bool Renderer::IsHeadless() const bool Gfx::IsHeadless() const
{ {
return !m_swap_chain; return !m_swap_chain;
} }
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> Gfx::CreateTexture(const TextureConfig& config,
std::string_view name) std::string_view name)
{ {
return DXTexture::Create(config, name); return DXTexture::Create(config, name);
} }
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type, std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config) const TextureConfig& config)
{ {
return DXStagingTexture::Create(type, config); return DXStagingTexture::Create(type, config);
} }
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment, std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment) AbstractTexture* depth_attachment)
{ {
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment), return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment)); static_cast<DXTexture*>(depth_attachment));
} }
std::unique_ptr<AbstractShader> std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name) Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{ {
auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source); auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source);
if (!bytecode) if (!bytecode)
@ -80,21 +78,20 @@ Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std
return DXShader::CreateFromBytecode(stage, std::move(*bytecode), name); return DXShader::CreateFromBytecode(stage, std::move(*bytecode), name);
} }
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage, std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
const void* data, size_t length, size_t length, std::string_view name)
std::string_view name)
{ {
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name); return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name);
} }
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config, std::unique_ptr<AbstractPipeline> Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data, const void* cache_data,
size_t cache_data_length) size_t cache_data_length)
{ {
return DXPipeline::Create(config); return DXPipeline::Create(config);
} }
void Renderer::SetPipeline(const AbstractPipeline* pipeline) void Gfx::SetPipeline(const AbstractPipeline* pipeline)
{ {
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline); const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
if (m_current_pipeline == dx_pipeline) if (m_current_pipeline == dx_pipeline)
@ -122,7 +119,7 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline)
} }
} }
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) void Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{ {
// TODO: Move to stateman // TODO: Move to stateman
const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1), const CD3D11_RECT rect(rc.left, rc.top, std::max(rc.right, rc.left + 1),
@ -130,75 +127,75 @@ void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
D3D::context->RSSetScissorRects(1, &rect); D3D::context->RSSetScissorRects(1, &rect);
} }
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth, void Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) float far_depth)
{ {
// TODO: Move to stateman // TODO: Move to stateman
const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth); const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth);
D3D::context->RSSetViewports(1, &vp); D3D::context->RSSetViewports(1, &vp);
} }
void Renderer::Draw(u32 base_vertex, u32 num_vertices) void Gfx::Draw(u32 base_vertex, u32 num_vertices)
{ {
D3D::stateman->Apply(); D3D::stateman->Apply();
D3D::context->Draw(num_vertices, base_vertex); D3D::context->Draw(num_vertices, base_vertex);
} }
void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) void Gfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{ {
D3D::stateman->Apply(); D3D::stateman->Apply();
D3D::context->DrawIndexed(num_indices, base_index, base_vertex); D3D::context->DrawIndexed(num_indices, base_index, base_vertex);
} }
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y, void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{ {
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader()); D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
D3D::stateman->SyncComputeBindings(); D3D::stateman->SyncComputeBindings();
D3D::context->Dispatch(groups_x, groups_y, groups_z); D3D::context->Dispatch(groups_x, groups_y, groups_z);
} }
void Renderer::BindBackbuffer(const ClearColor& clear_color) void Gfx::BindBackbuffer(const ClearColor& clear_color)
{ {
CheckForSwapChainChanges(); CheckForSwapChainChanges();
SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color); SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
} }
void Renderer::PresentBackbuffer() void Gfx::PresentBackbuffer()
{ {
m_swap_chain->Present(); m_swap_chain->Present();
} }
void Renderer::OnConfigChanged(u32 bits) void Gfx::OnConfigChanged(u32 bits)
{ {
AbstractGfx::OnConfigChanged(bits);
// Quad-buffer changes require swap chain recreation. // Quad-buffer changes require swap chain recreation.
if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain) if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain)
m_swap_chain->SetStereo(SwapChain::WantsStereo()); m_swap_chain->SetStereo(SwapChain::WantsStereo());
} }
void Renderer::CheckForSwapChainChanges() void Gfx::CheckForSwapChainChanges()
{ {
const bool surface_changed = m_surface_changed.TestAndClear(); const bool surface_changed = g_presenter->SurfaceChangedTestAndClear();
const bool surface_resized = const bool surface_resized =
m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange(); g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
if (!surface_changed && !surface_resized) if (!surface_changed && !surface_resized)
return; return;
if (surface_changed) if (surface_changed)
{ {
m_swap_chain->ChangeSurface(m_new_surface_handle); m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
m_new_surface_handle = nullptr;
} }
else else
{ {
m_swap_chain->ResizeSwapChain(); m_swap_chain->ResizeSwapChain();
} }
m_backbuffer_width = m_swap_chain->GetWidth(); g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
m_backbuffer_height = m_swap_chain->GetHeight();
} }
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{ {
if (m_current_framebuffer == framebuffer) if (m_current_framebuffer == framebuffer)
return; return;
@ -219,13 +216,13 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
m_current_framebuffer = fb; m_current_framebuffer = fb;
} }
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{ {
SetFramebuffer(framebuffer); SetFramebuffer(framebuffer);
} }
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
const ClearColor& color_value, float depth_value) float depth_value)
{ {
SetFramebuffer(framebuffer); SetFramebuffer(framebuffer);
D3D::stateman->Apply(); D3D::stateman->Apply();
@ -242,53 +239,55 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
} }
} }
void Renderer::SetTexture(u32 index, const AbstractTexture* texture) void Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{ {
D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() : D3D::stateman->SetTexture(index, texture ? static_cast<const DXTexture*>(texture)->GetD3DSRV() :
nullptr); nullptr);
} }
void Renderer::SetSamplerState(u32 index, const SamplerState& state) void Gfx::SetSamplerState(u32 index, const SamplerState& state)
{ {
D3D::stateman->SetSampler(index, m_state_cache.Get(state)); D3D::stateman->SetSampler(index, m_state_cache.Get(state));
} }
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) void Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{ {
D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr); D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
} }
void Renderer::UnbindTexture(const AbstractTexture* texture) void Gfx::UnbindTexture(const AbstractTexture* texture)
{ {
if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0) if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
D3D::stateman->ApplyTextures(); D3D::stateman->ApplyTextures();
} }
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const void Gfx::Flush()
{
return std::make_unique<D3DBoundingBox>();
}
void Renderer::Flush()
{ {
D3D::context->Flush(); D3D::context->Flush();
} }
void Renderer::WaitForGPUIdle() void Gfx::WaitForGPUIdle()
{ {
// There is no glFinish() equivalent in D3D. // There is no glFinish() equivalent in D3D.
D3D::context->Flush(); D3D::context->Flush();
} }
void Renderer::SetFullscreen(bool enable_fullscreen) void Gfx::SetFullscreen(bool enable_fullscreen)
{ {
if (m_swap_chain) if (m_swap_chain)
m_swap_chain->SetFullscreen(enable_fullscreen); m_swap_chain->SetFullscreen(enable_fullscreen);
} }
bool Renderer::IsFullscreen() const bool Gfx::IsFullscreen() const
{ {
return m_swap_chain && m_swap_chain->GetFullscreen(); return m_swap_chain && m_swap_chain->GetFullscreen();
} }
SurfaceInfo Gfx::GetSurfaceInfo() const
{
return {m_swap_chain ? static_cast<u32>(m_swap_chain->GetWidth()) : 0,
m_swap_chain ? static_cast<u32>(m_swap_chain->GetHeight()) : 0, m_backbuffer_scale,
m_swap_chain ? m_swap_chain->GetFormat() : AbstractTextureFormat::Undefined};
}
} // namespace DX11 } // namespace DX11

View File

@ -6,7 +6,7 @@
#include <d3d11.h> #include <d3d11.h>
#include <string_view> #include <string_view>
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/AbstractGfx.h"
class BoundingBox; class BoundingBox;
@ -16,11 +16,11 @@ class SwapChain;
class DXTexture; class DXTexture;
class DXFramebuffer; class DXFramebuffer;
class Renderer : public ::Renderer class Gfx final : public ::AbstractGfx
{ {
public: public:
Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale); Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~Renderer() override; ~Gfx() override;
StateCache& GetStateCache() { return m_state_cache; } StateCache& GetStateCache() { return m_state_cache; }
@ -69,14 +69,14 @@ public:
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
protected: SurfaceInfo GetSurfaceInfo() const override;
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private: private:
void CheckForSwapChainChanges(); void CheckForSwapChainChanges();
StateCache m_state_cache; StateCache m_state_cache;
float m_backbuffer_scale;
std::unique_ptr<SwapChain> m_swap_chain; std::unique_ptr<SwapChain> m_swap_chain;
}; };
} // namespace DX11 } // namespace DX11

View File

@ -13,12 +13,13 @@
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBoundingBox.h" #include "VideoBackends/D3D/D3DBoundingBox.h"
#include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DPerfQuery.h" #include "VideoBackends/D3D/D3DPerfQuery.h"
#include "VideoBackends/D3D/D3DRender.h"
#include "VideoBackends/D3D/D3DSwapChain.h" #include "VideoBackends/D3D/D3DSwapChain.h"
#include "VideoBackends/D3D/D3DVertexManager.h" #include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3DCommon/D3DCommon.h" #include "VideoBackends/D3DCommon/D3DCommon.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/ShaderCache.h" #include "VideoCommon/ShaderCache.h"
#include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureCacheBase.h"
@ -143,7 +144,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
return false; return false;
FillBackendInfo(); FillBackendInfo();
InitializeShared(); UpdateActiveConfig();
std::unique_ptr<SwapChain> swap_chain; std::unique_ptr<SwapChain> swap_chain;
if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi))) if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi)))
@ -154,36 +155,17 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
return false; return false;
} }
g_renderer = std::make_unique<Renderer>(std::move(swap_chain), wsi.render_surface_scale); auto gfx = std::make_unique<DX11::Gfx>(std::move(swap_chain), wsi.render_surface_scale);
g_vertex_manager = std::make_unique<VertexManager>(); auto vertex_manager = std::make_unique<VertexManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>(); auto perf_query = std::make_unique<PerfQuery>();
g_framebuffer_manager = std::make_unique<FramebufferManager>(); auto bounding_box = std::make_unique<D3DBoundingBox>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_perf_query = std::make_unique<PerfQuery>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache(); return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query),
return true; std::move(bounding_box));
} }
void VideoBackend::Shutdown() void VideoBackend::Shutdown()
{ {
g_shader_cache->Shutdown();
g_renderer->Shutdown();
g_perf_query.reset();
g_texture_cache.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
g_vertex_manager.reset();
g_renderer.reset();
ShutdownShared(); ShutdownShared();
D3D::Destroy(); D3D::Destroy();
} }

View File

@ -7,7 +7,7 @@
#include "Common/EnumMap.h" #include "Common/EnumMap.h"
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DVertexManager.h" #include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3D/DXShader.h" #include "VideoBackends/D3D/DXShader.h"
@ -18,7 +18,7 @@ namespace DX11
std::mutex s_input_layout_lock; std::mutex s_input_layout_lock;
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
return std::make_unique<D3DVertexFormat>(vtx_decl); return std::make_unique<D3DVertexFormat>(vtx_decl);
} }

View File

@ -6,7 +6,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
namespace DX11 namespace DX11
@ -114,8 +114,8 @@ void PerfQuery::FlushOne()
// NOTE: Reported pixel metrics should be referenced to native resolution // NOTE: Reported pixel metrics should be referenced to native resolution
// TODO: Dropping the lower 2 bits from this count should be closer to actual // TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles. // hardware behavior when drawing triangles.
const u64 native_res_result = result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / const u64 native_res_result = result * EFB_WIDTH / g_framebuffer_manager->GetEFBWidth() *
g_renderer->GetTargetHeight(); EFB_HEIGHT / g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result), m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed); std::memory_order_relaxed);
@ -143,8 +143,8 @@ void PerfQuery::WeakFlush()
if (hr == S_OK) if (hr == S_OK)
{ {
// NOTE: Reported pixel metrics should be referenced to native resolution // NOTE: Reported pixel metrics should be referenced to native resolution
const u64 native_res_result = result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / const u64 native_res_result = result * EFB_WIDTH / g_framebuffer_manager->GetEFBWidth() *
g_renderer->GetTargetHeight(); EFB_HEIGHT / g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].store(static_cast<u32>(native_res_result), m_results[entry.query_group].store(static_cast<u32>(native_res_result),
std::memory_order_relaxed); std::memory_order_relaxed);

View File

@ -13,7 +13,7 @@
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBoundingBox.h" #include "VideoBackends/D3D/D3DBoundingBox.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3DCommon/D3DCommon.h" #include "VideoBackends/D3DCommon/D3DCommon.h"

View File

@ -7,7 +7,7 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DRender.h" #include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DVertexManager.h" #include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3D/DXShader.h" #include "VideoBackends/D3D/DXShader.h"
@ -32,7 +32,7 @@ DXPipeline::~DXPipeline() = default;
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config) std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config)
{ {
StateCache& state_cache = static_cast<Renderer*>(g_renderer.get())->GetStateCache(); StateCache& state_cache = static_cast<Gfx*>(g_gfx.get())->GetStateCache();
ID3D11RasterizerState* rasterizer_state = state_cache.Get(config.rasterization_state); ID3D11RasterizerState* rasterizer_state = state_cache.Get(config.rasterization_state);
ID3D11DepthStencilState* depth_state = state_cache.Get(config.depth_state); ID3D11DepthStencilState* depth_state = state_cache.Get(config.depth_state);
ID3D11BlendState* blend_state = state_cache.Get(config.blending_state); ID3D11BlendState* blend_state = state_cache.Get(config.blending_state);

View File

@ -3,8 +3,8 @@ add_library(videod3d12
D3D12BoundingBox.h D3D12BoundingBox.h
D3D12PerfQuery.cpp D3D12PerfQuery.cpp
D3D12PerfQuery.h D3D12PerfQuery.h
D3D12Renderer.cpp D3D12Gfx.cpp
D3D12Renderer.h D3D12Gfx.h
D3D12StreamBuffer.cpp D3D12StreamBuffer.cpp
D3D12StreamBuffer.h D3D12StreamBuffer.h
D3D12SwapChain.cpp D3D12SwapChain.cpp

View File

@ -6,7 +6,7 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoBackends/D3D12/D3D12Renderer.h" #include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/DX12Context.h" #include "VideoBackends/D3D12/DX12Context.h"
namespace DX12 namespace DX12
@ -22,7 +22,7 @@ bool D3D12BoundingBox::Initialize()
if (!CreateBuffers()) if (!CreateBuffers())
return false; return false;
Renderer::GetInstance()->SetPixelShaderUAV(m_gpu_descriptor.cpu_handle); Gfx::GetInstance()->SetPixelShaderUAV(m_gpu_descriptor.cpu_handle);
return true; return true;
} }
@ -35,7 +35,7 @@ std::vector<BBoxType> D3D12BoundingBox::Read(u32 index, u32 length)
0, BUFFER_SIZE); 0, BUFFER_SIZE);
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(), ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(),
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
Renderer::GetInstance()->ExecuteCommandList(true); Gfx::GetInstance()->ExecuteCommandList(true);
// Read back to cached values. // Read back to cached values.
std::vector<BBoxType> values(length); std::vector<BBoxType> values(length);
@ -62,7 +62,7 @@ void D3D12BoundingBox::Write(u32 index, const std::vector<BBoxType>& values)
if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(BBoxType))) if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(BBoxType)))
{ {
WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in bbox stream buffer"); WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in bbox stream buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(BBoxType))) if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(BBoxType)))
{ {
PanicAlertFmt("Failed to allocate bbox stream buffer space"); PanicAlertFmt("Failed to allocate bbox stream buffer space");

View File

@ -1,7 +1,7 @@
// Copyright 2019 Dolphin Emulator Project // Copyright 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/D3D12/D3D12Renderer.h" #include "VideoBackends/D3D12/D3D12Gfx.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -15,6 +15,7 @@
#include "VideoBackends/D3D12/DX12Texture.h" #include "VideoBackends/D3D12/DX12Texture.h"
#include "VideoBackends/D3D12/DX12VertexFormat.h" #include "VideoBackends/D3D12/DX12VertexFormat.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h" #include "VideoBackends/D3D12/DescriptorHeapManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
namespace DX12 namespace DX12
@ -27,11 +28,8 @@ static bool UsesDynamicVertexLoader(const AbstractPipeline* pipeline)
(g_ActiveConfig.UseVSForLinePointExpand() && usage != AbstractPipelineUsage::Utility); (g_ActiveConfig.UseVSForLinePointExpand() && usage != AbstractPipelineUsage::Utility);
} }
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale) Gfx::Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0, : m_backbuffer_scale(backbuffer_scale), m_swap_chain(std::move(swap_chain))
backbuffer_scale,
swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
{ {
m_state.root_signature = g_dx_context->GetGXRootSignature(); m_state.root_signature = g_dx_context->GetGXRootSignature();
@ -43,98 +41,75 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale
} }
} }
Renderer::~Renderer() = default; Gfx::~Gfx() = default;
bool Renderer::IsHeadless() const bool Gfx::IsHeadless() const
{ {
return !m_swap_chain; return !m_swap_chain;
} }
bool Renderer::Initialize() std::unique_ptr<AbstractTexture> Gfx::CreateTexture(const TextureConfig& config,
{ std::string_view name)
if (!::Renderer::Initialize())
return false;
return true;
}
void Renderer::Shutdown()
{
m_swap_chain.reset();
::Renderer::Shutdown();
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
std::string_view name)
{ {
return DXTexture::Create(config, name); return DXTexture::Create(config, name);
} }
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type, std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config) const TextureConfig& config)
{ {
return DXStagingTexture::Create(type, config); return DXStagingTexture::Create(type, config);
} }
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment, std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment) AbstractTexture* depth_attachment)
{ {
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment), return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment)); static_cast<DXTexture*>(depth_attachment));
} }
std::unique_ptr<AbstractShader> std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name) Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{ {
return DXShader::CreateFromSource(stage, source, name); return DXShader::CreateFromSource(stage, source, name);
} }
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage, std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
const void* data, size_t length, size_t length, std::string_view name)
std::string_view name)
{ {
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name); return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name);
} }
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
return std::make_unique<DXVertexFormat>(vtx_decl); return std::make_unique<DXVertexFormat>(vtx_decl);
} }
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config, std::unique_ptr<AbstractPipeline> Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data, const void* cache_data,
size_t cache_data_length) size_t cache_data_length)
{ {
return DXPipeline::Create(config, cache_data, cache_data_length); return DXPipeline::Create(config, cache_data, cache_data_length);
} }
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const void Gfx::Flush()
{
return std::make_unique<D3D12BoundingBox>();
}
void Renderer::Flush()
{ {
ExecuteCommandList(false); ExecuteCommandList(false);
} }
void Renderer::WaitForGPUIdle() void Gfx::WaitForGPUIdle()
{ {
ExecuteCommandList(true); ExecuteCommandList(true);
} }
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable, void Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable,
bool z_enable, u32 color, u32 z) bool alpha_enable, bool z_enable, u32 color, u32 z)
{ {
// Use a fast path without the shader if both color/alpha are enabled. // Use a fast path without the shader if both color/alpha are enabled.
const bool fast_color_clear = color_enable && (alpha_enable || !EFBHasAlphaChannel()); const bool fast_color_clear = color_enable && alpha_enable;
if (fast_color_clear || z_enable) if (fast_color_clear || z_enable)
{ {
MathUtil::Rectangle<int> native_rc = ConvertEFBRectangle(rc); const D3D12_RECT d3d_clear_rc{target_rc.left, target_rc.top, target_rc.right, target_rc.bottom};
native_rc.ClampUL(0, 0, m_current_framebuffer->GetWidth(), m_current_framebuffer->GetHeight());
const D3D12_RECT d3d_clear_rc{native_rc.left, native_rc.top, native_rc.right, native_rc.bottom};
if (fast_color_clear) if (fast_color_clear)
{ {
@ -169,10 +144,10 @@ void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable
// Anything left over, fall back to clear triangle. // Anything left over, fall back to clear triangle.
if (color_enable || alpha_enable || z_enable) if (color_enable || alpha_enable || z_enable)
::Renderer::ClearScreen(rc, color_enable, alpha_enable, z_enable, color, z); ::AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z);
} }
void Renderer::SetPipeline(const AbstractPipeline* pipeline) void Gfx::SetPipeline(const AbstractPipeline* pipeline)
{ {
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline); const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
if (m_current_pipeline == dx_pipeline) if (m_current_pipeline == dx_pipeline)
@ -204,7 +179,7 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline)
} }
} }
void Renderer::BindFramebuffer(DXFramebuffer* fb) void Gfx::BindFramebuffer(DXFramebuffer* fb)
{ {
if (fb->HasColorBuffer()) if (fb->HasColorBuffer())
{ {
@ -225,7 +200,7 @@ void Renderer::BindFramebuffer(DXFramebuffer* fb)
m_dirty_bits &= ~DirtyState_Framebuffer; m_dirty_bits &= ~DirtyState_Framebuffer;
} }
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{ {
if (m_current_framebuffer == framebuffer) if (m_current_framebuffer == framebuffer)
return; return;
@ -234,7 +209,7 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
m_dirty_bits |= DirtyState_Framebuffer; m_dirty_bits |= DirtyState_Framebuffer;
} }
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{ {
SetFramebuffer(framebuffer); SetFramebuffer(framebuffer);
@ -253,8 +228,8 @@ void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
} }
} }
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
const ClearColor& color_value, float depth_value) float depth_value)
{ {
DXFramebuffer* dxfb = static_cast<DXFramebuffer*>(framebuffer); DXFramebuffer* dxfb = static_cast<DXFramebuffer*>(framebuffer);
BindFramebuffer(dxfb); BindFramebuffer(dxfb);
@ -272,7 +247,7 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
} }
} }
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) void Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{ {
if (m_state.scissor.left == rc.left && m_state.scissor.right == rc.right && if (m_state.scissor.left == rc.left && m_state.scissor.right == rc.right &&
m_state.scissor.top == rc.top && m_state.scissor.bottom == rc.bottom) m_state.scissor.top == rc.top && m_state.scissor.bottom == rc.bottom)
@ -287,7 +262,7 @@ void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
m_dirty_bits |= DirtyState_ScissorRect; m_dirty_bits |= DirtyState_ScissorRect;
} }
void Renderer::SetTexture(u32 index, const AbstractTexture* texture) void Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{ {
const DXTexture* dxtex = static_cast<const DXTexture*>(texture); const DXTexture* dxtex = static_cast<const DXTexture*>(texture);
if (m_state.textures[index].ptr == dxtex->GetSRVDescriptor().cpu_handle.ptr) if (m_state.textures[index].ptr == dxtex->GetSRVDescriptor().cpu_handle.ptr)
@ -300,7 +275,7 @@ void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
m_dirty_bits |= DirtyState_Textures; m_dirty_bits |= DirtyState_Textures;
} }
void Renderer::SetSamplerState(u32 index, const SamplerState& state) void Gfx::SetSamplerState(u32 index, const SamplerState& state)
{ {
if (m_state.samplers.states[index] == state) if (m_state.samplers.states[index] == state)
return; return;
@ -309,7 +284,7 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
m_dirty_bits |= DirtyState_Samplers; m_dirty_bits |= DirtyState_Samplers;
} }
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) void Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{ {
const DXTexture* dxtex = static_cast<const DXTexture*>(texture); const DXTexture* dxtex = static_cast<const DXTexture*>(texture);
if (m_state.compute_image_texture == dxtex) if (m_state.compute_image_texture == dxtex)
@ -322,7 +297,7 @@ void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool
m_dirty_bits |= DirtyState_ComputeImageTexture; m_dirty_bits |= DirtyState_ComputeImageTexture;
} }
void Renderer::UnbindTexture(const AbstractTexture* texture) void Gfx::UnbindTexture(const AbstractTexture* texture)
{ {
const auto srv_shadow_descriptor = const auto srv_shadow_descriptor =
static_cast<const DXTexture*>(texture)->GetSRVDescriptor().cpu_handle; static_cast<const DXTexture*>(texture)->GetSRVDescriptor().cpu_handle;
@ -341,8 +316,8 @@ void Renderer::UnbindTexture(const AbstractTexture* texture)
} }
} }
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth, void Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) float far_depth)
{ {
if (m_state.viewport.TopLeftX == x && m_state.viewport.TopLeftY == y && if (m_state.viewport.TopLeftX == x && m_state.viewport.TopLeftY == y &&
m_state.viewport.Width == width && m_state.viewport.Height == height && m_state.viewport.Width == width && m_state.viewport.Height == height &&
@ -360,7 +335,7 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne
m_dirty_bits |= DirtyState_Viewport; m_dirty_bits |= DirtyState_Viewport;
} }
void Renderer::Draw(u32 base_vertex, u32 num_vertices) void Gfx::Draw(u32 base_vertex, u32 num_vertices)
{ {
if (!ApplyState()) if (!ApplyState())
return; return;
@ -368,7 +343,7 @@ void Renderer::Draw(u32 base_vertex, u32 num_vertices)
g_dx_context->GetCommandList()->DrawInstanced(num_vertices, 1, base_vertex, 0); g_dx_context->GetCommandList()->DrawInstanced(num_vertices, 1, base_vertex, 0);
} }
void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) void Gfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{ {
if (!ApplyState()) if (!ApplyState())
return; return;
@ -380,8 +355,8 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
g_dx_context->GetCommandList()->DrawIndexedInstanced(num_indices, 1, base_index, base_vertex, 0); g_dx_context->GetCommandList()->DrawIndexedInstanced(num_indices, 1, base_index, base_vertex, 0);
} }
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y, void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{ {
SetRootSignatures(); SetRootSignatures();
SetDescriptorHeaps(); SetDescriptorHeaps();
@ -411,17 +386,17 @@ void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize
m_dirty_bits |= DirtyState_Pipeline; m_dirty_bits |= DirtyState_Pipeline;
} }
void Renderer::BindBackbuffer(const ClearColor& clear_color) void Gfx::BindBackbuffer(const ClearColor& clear_color)
{ {
CheckForSwapChainChanges(); CheckForSwapChainChanges();
SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(), clear_color); SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(), clear_color);
} }
void Renderer::CheckForSwapChainChanges() void Gfx::CheckForSwapChainChanges()
{ {
const bool surface_changed = m_surface_changed.TestAndClear(); const bool surface_changed = g_presenter->SurfaceChangedTestAndClear();
const bool surface_resized = const bool surface_resized =
m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange(); g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
if (!surface_changed && !surface_resized) if (!surface_changed && !surface_resized)
return; return;
@ -429,19 +404,17 @@ void Renderer::CheckForSwapChainChanges()
WaitForGPUIdle(); WaitForGPUIdle();
if (surface_changed) if (surface_changed)
{ {
m_swap_chain->ChangeSurface(m_new_surface_handle); m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
m_new_surface_handle = nullptr;
} }
else else
{ {
m_swap_chain->ResizeSwapChain(); m_swap_chain->ResizeSwapChain();
} }
m_backbuffer_width = m_swap_chain->GetWidth(); g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
m_backbuffer_height = m_swap_chain->GetHeight();
} }
void Renderer::PresentBackbuffer() void Gfx::PresentBackbuffer()
{ {
m_current_framebuffer = nullptr; m_current_framebuffer = nullptr;
@ -451,9 +424,16 @@ void Renderer::PresentBackbuffer()
m_swap_chain->Present(); m_swap_chain->Present();
} }
void Renderer::OnConfigChanged(u32 bits) SurfaceInfo Gfx::GetSurfaceInfo() const
{ {
::Renderer::OnConfigChanged(bits); return {m_swap_chain ? static_cast<u32>(m_swap_chain->GetWidth()) : 0,
m_swap_chain ? static_cast<u32>(m_swap_chain->GetHeight()) : 0, m_backbuffer_scale,
m_swap_chain ? m_swap_chain->GetFormat() : AbstractTextureFormat::Undefined};
}
void Gfx::OnConfigChanged(u32 bits)
{
AbstractGfx::OnConfigChanged(bits);
// For quad-buffered stereo we need to change the layer count, so recreate the swap chain. // For quad-buffered stereo we need to change the layer count, so recreate the swap chain.
if (m_swap_chain && bits & CONFIG_CHANGE_BIT_STEREO_MODE) if (m_swap_chain && bits & CONFIG_CHANGE_BIT_STEREO_MODE)
@ -475,14 +455,14 @@ void Renderer::OnConfigChanged(u32 bits)
g_dx_context->RecreateGXRootSignature(); g_dx_context->RecreateGXRootSignature();
} }
void Renderer::ExecuteCommandList(bool wait_for_completion) void Gfx::ExecuteCommandList(bool wait_for_completion)
{ {
PerfQuery::GetInstance()->ResolveQueries(); PerfQuery::GetInstance()->ResolveQueries();
g_dx_context->ExecuteCommandList(wait_for_completion); g_dx_context->ExecuteCommandList(wait_for_completion);
m_dirty_bits = DirtyState_All; m_dirty_bits = DirtyState_All;
} }
void Renderer::SetConstantBuffer(u32 index, D3D12_GPU_VIRTUAL_ADDRESS address) void Gfx::SetConstantBuffer(u32 index, D3D12_GPU_VIRTUAL_ADDRESS address)
{ {
if (m_state.constant_buffers[index] == address) if (m_state.constant_buffers[index] == address)
return; return;
@ -491,7 +471,7 @@ void Renderer::SetConstantBuffer(u32 index, D3D12_GPU_VIRTUAL_ADDRESS address)
m_dirty_bits |= DirtyState_PS_CBV << index; m_dirty_bits |= DirtyState_PS_CBV << index;
} }
void Renderer::SetTextureDescriptor(u32 index, D3D12_CPU_DESCRIPTOR_HANDLE handle) void Gfx::SetTextureDescriptor(u32 index, D3D12_CPU_DESCRIPTOR_HANDLE handle)
{ {
if (m_state.textures[index].ptr == handle.ptr) if (m_state.textures[index].ptr == handle.ptr)
return; return;
@ -500,7 +480,7 @@ void Renderer::SetTextureDescriptor(u32 index, D3D12_CPU_DESCRIPTOR_HANDLE handl
m_dirty_bits |= DirtyState_Textures; m_dirty_bits |= DirtyState_Textures;
} }
void Renderer::SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle) void Gfx::SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
{ {
if (m_state.ps_uav.ptr == handle.ptr) if (m_state.ps_uav.ptr == handle.ptr)
return; return;
@ -509,8 +489,8 @@ void Renderer::SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
m_dirty_bits |= DirtyState_PS_UAV; m_dirty_bits |= DirtyState_PS_UAV;
} }
void Renderer::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESCRIPTOR_HANDLE srv, void Gfx::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESCRIPTOR_HANDLE srv,
u32 stride, u32 size) u32 stride, u32 size)
{ {
if (m_state.vertex_buffer.BufferLocation != address || if (m_state.vertex_buffer.BufferLocation != address ||
m_state.vertex_buffer.StrideInBytes != stride || m_state.vertex_buffer.SizeInBytes != size) m_state.vertex_buffer.StrideInBytes != stride || m_state.vertex_buffer.SizeInBytes != size)
@ -527,7 +507,7 @@ void Renderer::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESC
} }
} }
void Renderer::SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format) void Gfx::SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format)
{ {
if (m_state.index_buffer.BufferLocation == address && m_state.index_buffer.SizeInBytes == size && if (m_state.index_buffer.BufferLocation == address && m_state.index_buffer.SizeInBytes == size &&
m_state.index_buffer.Format == format) m_state.index_buffer.Format == format)
@ -541,7 +521,7 @@ void Renderer::SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_
m_dirty_bits |= DirtyState_IndexBuffer; m_dirty_bits |= DirtyState_IndexBuffer;
} }
bool Renderer::ApplyState() bool Gfx::ApplyState()
{ {
if (!m_current_framebuffer || !m_current_pipeline) if (!m_current_framebuffer || !m_current_pipeline)
return false; return false;
@ -637,7 +617,7 @@ bool Renderer::ApplyState()
return true; return true;
} }
void Renderer::SetRootSignatures() void Gfx::SetRootSignatures()
{ {
const u32 dirty_bits = m_dirty_bits; const u32 dirty_bits = m_dirty_bits;
if (dirty_bits & DirtyState_RootSignature) if (dirty_bits & DirtyState_RootSignature)
@ -650,7 +630,7 @@ void Renderer::SetRootSignatures()
m_dirty_bits &= ~(DirtyState_RootSignature | DirtyState_ComputeRootSignature); m_dirty_bits &= ~(DirtyState_RootSignature | DirtyState_ComputeRootSignature);
} }
void Renderer::SetDescriptorHeaps() void Gfx::SetDescriptorHeaps()
{ {
if (m_dirty_bits & DirtyState_DescriptorHeaps) if (m_dirty_bits & DirtyState_DescriptorHeaps)
{ {
@ -660,7 +640,7 @@ void Renderer::SetDescriptorHeaps()
} }
} }
void Renderer::UpdateDescriptorTables() void Gfx::UpdateDescriptorTables()
{ {
// Samplers force a full sync because any of the samplers could be in use. // Samplers force a full sync because any of the samplers could be in use.
const bool texture_update_failed = const bool texture_update_failed =
@ -684,7 +664,7 @@ void Renderer::UpdateDescriptorTables()
} }
} }
bool Renderer::UpdateSRVDescriptorTable() bool Gfx::UpdateSRVDescriptorTable()
{ {
static constexpr std::array<UINT, MAX_TEXTURES> src_sizes = {1, 1, 1, 1, 1, 1, 1, 1}; static constexpr std::array<UINT, MAX_TEXTURES> src_sizes = {1, 1, 1, 1, 1, 1, 1, 1};
DescriptorHandle dst_base_handle; DescriptorHandle dst_base_handle;
@ -700,7 +680,7 @@ bool Renderer::UpdateSRVDescriptorTable()
return true; return true;
} }
bool Renderer::UpdateSamplerDescriptorTable() bool Gfx::UpdateSamplerDescriptorTable()
{ {
if (!g_dx_context->GetSamplerAllocator()->GetGroupHandle(m_state.samplers, if (!g_dx_context->GetSamplerAllocator()->GetGroupHandle(m_state.samplers,
&m_state.sampler_descriptor_base)) &m_state.sampler_descriptor_base))
@ -713,7 +693,7 @@ bool Renderer::UpdateSamplerDescriptorTable()
return true; return true;
} }
bool Renderer::UpdateUAVDescriptorTable() bool Gfx::UpdateUAVDescriptorTable()
{ {
// We can skip writing the UAV descriptor if bbox isn't enabled, since it's not used otherwise. // We can skip writing the UAV descriptor if bbox isn't enabled, since it's not used otherwise.
if (!g_ActiveConfig.bBBoxEnable) if (!g_ActiveConfig.bBBoxEnable)
@ -730,7 +710,7 @@ bool Renderer::UpdateUAVDescriptorTable()
return true; return true;
} }
bool Renderer::UpdateVSSRVDescriptorTable() bool Gfx::UpdateVSSRVDescriptorTable()
{ {
if (!UsesDynamicVertexLoader(m_current_pipeline)) if (!UsesDynamicVertexLoader(m_current_pipeline))
{ {
@ -748,7 +728,7 @@ bool Renderer::UpdateVSSRVDescriptorTable()
return true; return true;
} }
bool Renderer::UpdateComputeUAVDescriptorTable() bool Gfx::UpdateComputeUAVDescriptorTable()
{ {
DescriptorHandle handle; DescriptorHandle handle;
if (!g_dx_context->GetDescriptorAllocator()->Allocate(1, &handle)) if (!g_dx_context->GetDescriptorAllocator()->Allocate(1, &handle))

View File

@ -6,9 +6,7 @@
#include <d3d12.h> #include <d3d12.h>
#include "VideoBackends/D3D12/DescriptorAllocator.h" #include "VideoBackends/D3D12/DescriptorAllocator.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h" #include "VideoBackends/D3D12/DescriptorHeapManager.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/AbstractGfx.h"
class BoundingBox;
namespace DX12 namespace DX12
{ {
@ -18,19 +16,16 @@ class DXShader;
class DXPipeline; class DXPipeline;
class SwapChain; class SwapChain;
class Renderer final : public ::Renderer class Gfx final : public ::AbstractGfx
{ {
public: public:
Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale); Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~Renderer() override; ~Gfx() override;
static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); } static Gfx* GetInstance() { return static_cast<Gfx*>(g_gfx.get()); }
bool IsHeadless() const override; bool IsHeadless() const override;
bool Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override; std::string_view name) override;
std::unique_ptr<AbstractStagingTexture> std::unique_ptr<AbstractStagingTexture>
@ -52,7 +47,7 @@ public:
void Flush() override; void Flush() override;
void WaitForGPUIdle() override; void WaitForGPUIdle() override;
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable, void ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable, bool alpha_enable,
bool z_enable, u32 color, u32 z) override; bool z_enable, u32 color, u32 z) override;
void SetPipeline(const AbstractPipeline* pipeline) override; void SetPipeline(const AbstractPipeline* pipeline) override;
@ -74,6 +69,8 @@ public:
void BindBackbuffer(const ClearColor& clear_color = {}) override; void BindBackbuffer(const ClearColor& clear_color = {}) override;
void PresentBackbuffer() override; void PresentBackbuffer() override;
SurfaceInfo GetSurfaceInfo() const override;
// Completes the current render pass, executes the command buffer, and restores state ready for // Completes the current render pass, executes the command buffer, and restores state ready for
// next render. Use when you want to kick the current buffer to make room for new data. // next render. Use when you want to kick the current buffer to make room for new data.
void ExecuteCommandList(bool wait_for_completion); void ExecuteCommandList(bool wait_for_completion);
@ -98,8 +95,6 @@ public:
protected: protected:
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private: private:
static const u32 MAX_TEXTURES = 8; static const u32 MAX_TEXTURES = 8;
static const u32 NUM_CONSTANT_BUFFERS = 3; static const u32 NUM_CONSTANT_BUFFERS = 3;
@ -152,6 +147,8 @@ private:
bool UpdateComputeUAVDescriptorTable(); bool UpdateComputeUAVDescriptorTable();
bool UpdateSamplerDescriptorTable(); bool UpdateSamplerDescriptorTable();
float m_backbuffer_scale;
// Owned objects // Owned objects
std::unique_ptr<SwapChain> m_swap_chain; std::unique_ptr<SwapChain> m_swap_chain;

View File

@ -9,8 +9,9 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoBackends/D3D12/Common.h" #include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/D3D12Renderer.h" #include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/DX12Context.h" #include "VideoBackends/D3D12/DX12Context.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
namespace DX12 namespace DX12
@ -64,7 +65,7 @@ void PerfQuery::EnableQuery(PerfQueryGroup group)
// This is because we can't leave a query open when submitting a command list, and the draw // This is because we can't leave a query open when submitting a command list, and the draw
// call itself may need to execute a command list if we run out of descriptors. Note that // call itself may need to execute a command list if we run out of descriptors. Note that
// this assumes that the caller has bound all required state prior to enabling the query. // this assumes that the caller has bound all required state prior to enabling the query.
Renderer::GetInstance()->ApplyState(); Gfx::GetInstance()->ApplyState();
if (group == PQG_ZCOMP_ZCOMPLOC || group == PQG_ZCOMP) if (group == PQG_ZCOMP_ZCOMPLOC || group == PQG_ZCOMP)
{ {
@ -244,8 +245,8 @@ void PerfQuery::AccumulateQueriesFromBuffer(u32 query_count)
// NOTE: Reported pixel metrics should be referenced to native resolution // NOTE: Reported pixel metrics should be referenced to native resolution
const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH / const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH /
g_renderer->GetTargetWidth() * EFB_HEIGHT / g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight(); g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result), m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed); std::memory_order_relaxed);
} }
@ -261,7 +262,7 @@ void PerfQuery::PartialFlush(bool resolve, bool blocking)
{ {
// Submit a command buffer if there are unresolved queries (to write them to the buffer). // Submit a command buffer if there are unresolved queries (to write them to the buffer).
if (resolve && m_unresolved_queries > 0) if (resolve && m_unresolved_queries > 0)
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
ReadbackQueries(blocking); ReadbackQueries(blocking);
} }

View File

@ -17,7 +17,7 @@ public:
static PerfQuery* GetInstance() { return static_cast<PerfQuery*>(g_perf_query.get()); } static PerfQuery* GetInstance() { return static_cast<PerfQuery*>(g_perf_query.get()); }
bool Initialize(); bool Initialize() override;
void ResolveQueries(); void ResolveQueries();
void EnableQuery(PerfQueryGroup group) override; void EnableQuery(PerfQueryGroup group) override;

View File

@ -10,7 +10,7 @@
#include "Core/System.h" #include "Core/System.h"
#include "VideoBackends/D3D12/D3D12Renderer.h" #include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/D3D12StreamBuffer.h" #include "VideoBackends/D3D12/D3D12StreamBuffer.h"
#include "VideoBackends/D3D12/DX12Context.h" #include "VideoBackends/D3D12/DX12Context.h"
@ -92,7 +92,7 @@ void VertexManager::ResetBuffer(u32 vertex_stride)
{ {
// Flush any pending commands first, so that we can wait on the fences // Flush any pending commands first, so that we can wait on the fences
WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in vertex/index buffer"); WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in vertex/index buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
// Attempt to allocate again, this may cause a fence wait // Attempt to allocate again, this may cause a fence wait
if (!has_vbuffer_allocation) if (!has_vbuffer_allocation)
@ -129,11 +129,11 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size)); ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size));
ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size)); ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size));
Renderer::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(), Gfx::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(),
m_vertex_srv.cpu_handle, vertex_stride, m_vertex_srv.cpu_handle, vertex_stride,
m_vertex_stream_buffer.GetSize()); m_vertex_stream_buffer.GetSize());
Renderer::GetInstance()->SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), Gfx::GetInstance()->SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(),
m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT); m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);
} }
void VertexManager::UploadUniforms() void VertexManager::UploadUniforms()
@ -151,7 +151,7 @@ void VertexManager::UpdateVertexShaderConstants()
if (!vertex_shader_manager.dirty || !ReserveConstantStorage()) if (!vertex_shader_manager.dirty || !ReserveConstantStorage())
return; return;
Renderer::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer()); Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &vertex_shader_manager.constants, std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &vertex_shader_manager.constants,
sizeof(VertexShaderConstants)); sizeof(VertexShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(VertexShaderConstants)); m_uniform_stream_buffer.CommitMemory(sizeof(VertexShaderConstants));
@ -167,7 +167,7 @@ void VertexManager::UpdateGeometryShaderConstants()
if (!geometry_shader_manager.dirty || !ReserveConstantStorage()) if (!geometry_shader_manager.dirty || !ReserveConstantStorage())
return; return;
Renderer::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer()); Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &geometry_shader_manager.constants, std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &geometry_shader_manager.constants,
sizeof(GeometryShaderConstants)); sizeof(GeometryShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(GeometryShaderConstants)); m_uniform_stream_buffer.CommitMemory(sizeof(GeometryShaderConstants));
@ -183,7 +183,7 @@ void VertexManager::UpdatePixelShaderConstants()
if (!pixel_shader_manager.dirty || !ReserveConstantStorage()) if (!pixel_shader_manager.dirty || !ReserveConstantStorage())
return; return;
Renderer::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer()); Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &pixel_shader_manager.constants, std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &pixel_shader_manager.constants,
sizeof(PixelShaderConstants)); sizeof(PixelShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(PixelShaderConstants)); m_uniform_stream_buffer.CommitMemory(sizeof(PixelShaderConstants));
@ -204,7 +204,7 @@ bool VertexManager::ReserveConstantStorage()
// The only places that call constant updates are safe to have state restored. // The only places that call constant updates are safe to have state restored.
WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in uniform buffer"); WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in uniform buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
// Since we are on a new command buffer, all constants have been invalidated, and we need // Since we are on a new command buffer, all constants have been invalidated, and we need
// to reupload them. We may as well do this now, since we're issuing a draw anyway. // to reupload them. We may as well do this now, since we're issuing a draw anyway.
@ -234,12 +234,12 @@ void VertexManager::UploadAllConstants()
} }
// Update bindings // Update bindings
Renderer::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer() + Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer() +
pixel_constants_offset); pixel_constants_offset);
Renderer::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer() + Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer() +
vertex_constants_offset); vertex_constants_offset);
Renderer::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer() + Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer() +
geometry_constants_offset); geometry_constants_offset);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager(); auto& pixel_shader_manager = system.GetPixelShaderManager();
@ -271,12 +271,12 @@ void VertexManager::UploadUtilityUniforms(const void* data, u32 data_size)
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)) D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
{ {
WARN_LOG_FMT(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer"); WARN_LOG_FMT(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
} }
Renderer::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer()); Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer());
Renderer::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer()); Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer());
Renderer::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer()); Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), data, data_size); std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), data, data_size);
m_uniform_stream_buffer.CommitMemory(data_size); m_uniform_stream_buffer.CommitMemory(data_size);
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size); ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size);
@ -293,7 +293,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
{ {
// Try submitting cmdbuffer. // Try submitting cmdbuffer.
WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer"); WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
if (!m_texel_stream_buffer.ReserveMemory(data_size, elem_size)) if (!m_texel_stream_buffer.ReserveMemory(data_size, elem_size))
{ {
PanicAlertFmt("Failed to allocate {} bytes from texel buffer", data_size); PanicAlertFmt("Failed to allocate {} bytes from texel buffer", data_size);
@ -305,7 +305,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
*out_offset = static_cast<u32>(m_texel_stream_buffer.GetCurrentOffset()) / elem_size; *out_offset = static_cast<u32>(m_texel_stream_buffer.GetCurrentOffset()) / elem_size;
m_texel_stream_buffer.CommitMemory(data_size); m_texel_stream_buffer.CommitMemory(data_size);
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size); ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size);
Renderer::GetInstance()->SetTextureDescriptor(0, m_texel_buffer_views[format].cpu_handle); Gfx::GetInstance()->SetTextureDescriptor(0, m_texel_buffer_views[format].cpu_handle);
return true; return true;
} }
@ -323,7 +323,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
{ {
// Try submitting cmdbuffer. // Try submitting cmdbuffer.
WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer"); WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
if (!m_texel_stream_buffer.ReserveMemory(reserve_size, elem_size)) if (!m_texel_stream_buffer.ReserveMemory(reserve_size, elem_size))
{ {
PanicAlertFmt("Failed to allocate {} bytes from texel buffer", reserve_size); PanicAlertFmt("Failed to allocate {} bytes from texel buffer", reserve_size);
@ -342,8 +342,8 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
m_texel_stream_buffer.CommitMemory(palette_byte_offset + palette_size); m_texel_stream_buffer.CommitMemory(palette_byte_offset + palette_size);
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, palette_byte_offset + palette_size); ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, palette_byte_offset + palette_size);
Renderer::GetInstance()->SetTextureDescriptor(0, m_texel_buffer_views[format].cpu_handle); Gfx::GetInstance()->SetTextureDescriptor(0, m_texel_buffer_views[format].cpu_handle);
Renderer::GetInstance()->SetTextureDescriptor(1, m_texel_buffer_views[palette_format].cpu_handle); Gfx::GetInstance()->SetTextureDescriptor(1, m_texel_buffer_views[palette_format].cpu_handle);
return true; return true;
} }

View File

@ -8,7 +8,7 @@
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "VideoBackends/D3D12/Common.h" #include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/D3D12Renderer.h" #include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/D3D12StreamBuffer.h" #include "VideoBackends/D3D12/D3D12StreamBuffer.h"
#include "VideoBackends/D3D12/DX12Context.h" #include "VideoBackends/D3D12/DX12Context.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h" #include "VideoBackends/D3D12/DescriptorHeapManager.h"
@ -254,7 +254,7 @@ void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8*
{ {
WARN_LOG_FMT(VIDEO, WARN_LOG_FMT(VIDEO,
"Executing command list while waiting for space in texture upload buffer"); "Executing command list while waiting for space in texture upload buffer");
Renderer::GetInstance()->ExecuteCommandList(false); Gfx::GetInstance()->ExecuteCommandList(false);
if (!g_dx_context->GetTextureUploadBuffer().ReserveMemory( if (!g_dx_context->GetTextureUploadBuffer().ReserveMemory(
upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
{ {
@ -632,7 +632,7 @@ void DXStagingTexture::Flush()
// the current list and wait for it to complete. This is the slowest path. Otherwise, if the // the current list and wait for it to complete. This is the slowest path. Otherwise, if the
// command list with the copy has been submitted, we only need to wait for the fence. // command list with the copy has been submitted, we only need to wait for the fence.
if (m_completed_fence == g_dx_context->GetCurrentFenceValue()) if (m_completed_fence == g_dx_context->GetCurrentFenceValue())
Renderer::GetInstance()->ExecuteCommandList(true); Gfx::GetInstance()->ExecuteCommandList(true);
else else
g_dx_context->WaitForFence(m_completed_fence); g_dx_context->WaitForFence(m_completed_fence);
} }

View File

@ -11,8 +11,9 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "VideoBackends/D3D12/Common.h" #include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/D3D12BoundingBox.h"
#include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/D3D12PerfQuery.h" #include "VideoBackends/D3D12/D3D12PerfQuery.h"
#include "VideoBackends/D3D12/D3D12Renderer.h"
#include "VideoBackends/D3D12/D3D12SwapChain.h" #include "VideoBackends/D3D12/D3D12SwapChain.h"
#include "VideoBackends/D3D12/D3D12VertexManager.h" #include "VideoBackends/D3D12/D3D12VertexManager.h"
#include "VideoBackends/D3D12/DX12Context.h" #include "VideoBackends/D3D12/DX12Context.h"
@ -111,7 +112,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
} }
FillBackendInfo(); FillBackendInfo();
InitializeShared(); UpdateActiveConfig();
if (!g_dx_context->CreateGlobalResources()) if (!g_dx_context->CreateGlobalResources())
{ {
@ -131,45 +132,22 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
} }
// Create main wrapper instances. // Create main wrapper instances.
g_renderer = std::make_unique<Renderer>(std::move(swap_chain), wsi.render_surface_scale); auto gfx = std::make_unique<DX12::Gfx>(std::move(swap_chain), wsi.render_surface_scale);
g_vertex_manager = std::make_unique<VertexManager>(); auto vertex_manager = std::make_unique<DX12::VertexManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>(); auto perf_query = std::make_unique<DX12::PerfQuery>();
g_framebuffer_manager = std::make_unique<FramebufferManager>(); auto bounding_box = std::make_unique<DX12::D3D12BoundingBox>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_perf_query = std::make_unique<PerfQuery>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() || return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query),
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() || std::move(bounding_box));
!g_texture_cache->Initialize() || !PerfQuery::GetInstance()->Initialize())
{
PanicAlertFmtT("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache();
return true;
} }
void VideoBackend::Shutdown() void VideoBackend::Shutdown()
{ {
// Keep the debug runtime happy... // Keep the debug runtime happy...
if (g_renderer) if (g_gfx)
Renderer::GetInstance()->ExecuteCommandList(true); Gfx::GetInstance()->ExecuteCommandList(true);
if (g_shader_cache)
g_shader_cache->Shutdown();
if (g_renderer)
g_renderer->Shutdown();
g_perf_query.reset();
g_texture_cache.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
g_vertex_manager.reset();
g_renderer.reset();
DXContext::Destroy();
ShutdownShared(); ShutdownShared();
DXContext::Destroy();
} }
} // namespace DX12 } // namespace DX12

View File

@ -2,6 +2,8 @@ add_library(videometal
MRCHelpers.h MRCHelpers.h
MTLBoundingBox.mm MTLBoundingBox.mm
MTLBoundingBox.h MTLBoundingBox.h
MTLGfx.mm
MTLGfx.h
MTLMain.mm MTLMain.mm
MTLObjectCache.h MTLObjectCache.h
MTLObjectCache.mm MTLObjectCache.mm
@ -9,8 +11,6 @@ add_library(videometal
MTLPerfQuery.h MTLPerfQuery.h
MTLPipeline.mm MTLPipeline.mm
MTLPipeline.h MTLPipeline.h
MTLRenderer.mm
MTLRenderer.h
MTLShader.mm MTLShader.mm
MTLShader.h MTLShader.h
MTLStateTracker.mm MTLStateTracker.mm

View File

@ -6,7 +6,7 @@
#include <Metal/Metal.h> #include <Metal/Metal.h>
#include <QuartzCore/QuartzCore.h> #include <QuartzCore/QuartzCore.h>
#include "VideoCommon/RenderBase.h" #include "VideoCommon/AbstractGfx.h"
#include "VideoBackends/Metal/MRCHelpers.h" #include "VideoBackends/Metal/MRCHelpers.h"
@ -15,16 +15,14 @@ namespace Metal
class Framebuffer; class Framebuffer;
class Texture; class Texture;
class Renderer final : public ::Renderer class Gfx final : public ::AbstractGfx
{ {
public: public:
Renderer(MRCOwned<CAMetalLayer*> layer, int width, int height, float layer_scale); Gfx(MRCOwned<CAMetalLayer*> layer);
~Renderer() override; ~Gfx() override;
bool IsHeadless() const override; bool IsHeadless() const override;
bool Initialize() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override; std::string_view name) override;
std::unique_ptr<AbstractStagingTexture> std::unique_ptr<AbstractStagingTexture>
@ -49,7 +47,7 @@ public:
void WaitForGPUIdle() override; void WaitForGPUIdle() override;
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable, void ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable, bool alpha_enable,
bool z_enable, u32 color, u32 z) override; bool z_enable, u32 color, u32 z) override;
void SetPipeline(const AbstractPipeline* pipeline) override; void SetPipeline(const AbstractPipeline* pipeline) override;
@ -71,8 +69,7 @@ public:
void BindBackbuffer(const ClearColor& clear_color = {}) override; void BindBackbuffer(const ClearColor& clear_color = {}) override;
void PresentBackbuffer() override; void PresentBackbuffer() override;
protected: SurfaceInfo GetSurfaceInfo() const override;
std::unique_ptr<::BoundingBox> CreateBoundingBox() const override;
private: private:
MRCOwned<CAMetalLayer*> m_layer; MRCOwned<CAMetalLayer*> m_layer;

View File

@ -1,7 +1,7 @@
// Copyright 2022 Dolphin Emulator Project // Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Metal/MTLRenderer.h" #include "VideoBackends/Metal/MTLGfx.h"
#include "VideoBackends/Metal/MTLBoundingBox.h" #include "VideoBackends/Metal/MTLBoundingBox.h"
#include "VideoBackends/Metal/MTLObjectCache.h" #include "VideoBackends/Metal/MTLObjectCache.h"
@ -13,36 +13,31 @@
#include "VideoBackends/Metal/MTLVertexManager.h" #include "VideoBackends/Metal/MTLVertexManager.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
Metal::Renderer::Renderer(MRCOwned<CAMetalLayer*> layer, int width, int height, float layer_scale) #include <fstream>
: ::Renderer(width, height, layer_scale, Util::ToAbstract([layer pixelFormat])),
m_layer(std::move(layer)) Metal::Gfx::Gfx(MRCOwned<CAMetalLayer*> layer) : m_layer(std::move(layer))
{ {
UpdateActiveConfig(); UpdateActiveConfig();
[m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive]; [m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive];
SetupSurface();
g_state_tracker->FlushEncoders();
} }
Metal::Renderer::~Renderer() = default; Metal::Gfx::~Gfx() = default;
bool Metal::Renderer::IsHeadless() const bool Metal::Gfx::IsHeadless() const
{ {
return m_layer == nullptr; return m_layer == nullptr;
} }
bool Metal::Renderer::Initialize()
{
if (!::Renderer::Initialize())
return false;
SetupSurface();
g_state_tracker->FlushEncoders();
return true;
}
// MARK: Texture Creation // MARK: Texture Creation
std::unique_ptr<AbstractTexture> Metal::Renderer::CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> Metal::Gfx::CreateTexture(const TextureConfig& config,
std::string_view name) std::string_view name)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -77,7 +72,7 @@ std::unique_ptr<AbstractTexture> Metal::Renderer::CreateTexture(const TextureCon
} }
std::unique_ptr<AbstractStagingTexture> std::unique_ptr<AbstractStagingTexture>
Metal::Renderer::CreateStagingTexture(StagingTextureType type, const TextureConfig& config) Metal::Gfx::CreateStagingTexture(StagingTextureType type, const TextureConfig& config)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -98,8 +93,7 @@ Metal::Renderer::CreateStagingTexture(StagingTextureType type, const TextureConf
} }
std::unique_ptr<AbstractFramebuffer> std::unique_ptr<AbstractFramebuffer>
Metal::Renderer::CreateFramebuffer(AbstractTexture* color_attachment, Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
AbstractTexture* depth_attachment)
{ {
AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment; AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment;
return std::make_unique<Framebuffer>( return std::make_unique<Framebuffer>(
@ -110,9 +104,9 @@ Metal::Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
// MARK: Pipeline Creation // MARK: Pipeline Creation
std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromSource(ShaderStage stage, std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromSource(ShaderStage stage,
std::string_view source, std::string_view source,
std::string_view name) std::string_view name)
{ {
std::optional<std::string> msl = Util::TranslateShaderToMSL(stage, source); std::optional<std::string> msl = Util::TranslateShaderToMSL(stage, source);
if (!msl.has_value()) if (!msl.has_value())
@ -124,10 +118,9 @@ std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromSource(ShaderSt
return CreateShaderFromMSL(stage, std::move(*msl), source, name); return CreateShaderFromMSL(stage, std::move(*msl), source, name);
} }
std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromBinary(ShaderStage stage, std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromBinary(ShaderStage stage,
const void* data, const void* data, size_t length,
size_t length, std::string_view name)
std::string_view name)
{ {
return CreateShaderFromMSL(stage, std::string(static_cast<const char*>(data), length), {}, name); return CreateShaderFromMSL(stage, std::string(static_cast<const char*>(data), length), {}, name);
} }
@ -158,10 +151,9 @@ static NSString* GenericShaderName(ShaderStage stage)
// clang-format on // clang-format on
std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromMSL(ShaderStage stage, std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromMSL(ShaderStage stage, std::string msl,
std::string msl, std::string_view glsl,
std::string_view glsl, std::string_view name)
std::string_view name)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -243,7 +235,7 @@ std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromMSL(ShaderStage
} }
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Metal::Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) Metal::Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -251,14 +243,14 @@ Metal::Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_d
} }
} }
std::unique_ptr<AbstractPipeline> std::unique_ptr<AbstractPipeline> Metal::Gfx::CreatePipeline(const AbstractPipelineConfig& config,
Metal::Renderer::CreatePipeline(const AbstractPipelineConfig& config, const void* cache_data, const void* cache_data,
size_t cache_data_length) size_t cache_data_length)
{ {
return g_object_cache->CreatePipeline(config); return g_object_cache->CreatePipeline(config);
} }
void Metal::Renderer::Flush() void Metal::Gfx::Flush()
{ {
@autoreleasepool @autoreleasepool
{ {
@ -266,7 +258,7 @@ void Metal::Renderer::Flush()
} }
} }
void Metal::Renderer::WaitForGPUIdle() void Metal::Gfx::WaitForGPUIdle()
{ {
@autoreleasepool @autoreleasepool
{ {
@ -275,8 +267,10 @@ void Metal::Renderer::WaitForGPUIdle()
} }
} }
void Metal::Renderer::OnConfigChanged(u32 bits) void Metal::Gfx::OnConfigChanged(u32 bits)
{ {
AbstractGfx::OnConfigChanged(bits);
if (bits & CONFIG_CHANGE_BIT_VSYNC) if (bits & CONFIG_CHANGE_BIT_VSYNC)
[m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive]; [m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive];
@ -287,14 +281,13 @@ void Metal::Renderer::OnConfigChanged(u32 bits)
} }
} }
void Metal::Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, void Metal::Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable,
bool alpha_enable, bool z_enable, u32 color, u32 z) bool alpha_enable, bool z_enable, u32 color, u32 z)
{ {
MathUtil::Rectangle<int> target_rc = Renderer::ConvertEFBRectangle(rc); u32 framebuffer_width = m_current_framebuffer->GetWidth();
target_rc.ClampUL(0, 0, m_target_width, m_target_height); u32 framebuffer_height = m_current_framebuffer->GetHeight();
// All Metal render passes are fullscreen, so we can only run a fast clear if the target is too // All Metal render passes are fullscreen, so we can only run a fast clear if the target is too
if (target_rc == MathUtil::Rectangle<int>(0, 0, m_target_width, m_target_height)) if (target_rc == MathUtil::Rectangle<int>(0, 0, framebuffer_width, framebuffer_height))
{ {
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha // Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF. This hopefully allows us to use the fast path in most cases. // channel to 0xFF. This hopefully allows us to use the fast path in most cases.
@ -334,16 +327,16 @@ void Metal::Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color
} }
g_state_tracker->EnableEncoderLabel(false); g_state_tracker->EnableEncoderLabel(false);
g_framebuffer_manager->ClearEFB(rc, color_enable, alpha_enable, z_enable, color, z); AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z);
g_state_tracker->EnableEncoderLabel(true); g_state_tracker->EnableEncoderLabel(true);
} }
void Metal::Renderer::SetPipeline(const AbstractPipeline* pipeline) void Metal::Gfx::SetPipeline(const AbstractPipeline* pipeline)
{ {
g_state_tracker->SetPipeline(static_cast<const Pipeline*>(pipeline)); g_state_tracker->SetPipeline(static_cast<const Pipeline*>(pipeline));
} }
void Metal::Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) void Metal::Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{ {
// Shouldn't be bound as a texture. // Shouldn't be bound as a texture.
if (AbstractTexture* color = framebuffer->GetColorAttachment()) if (AbstractTexture* color = framebuffer->GetColorAttachment())
@ -355,7 +348,7 @@ void Metal::Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
g_state_tracker->SetCurrentFramebuffer(static_cast<Framebuffer*>(framebuffer)); g_state_tracker->SetCurrentFramebuffer(static_cast<Framebuffer*>(framebuffer));
} }
void Metal::Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) void Metal::Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -364,8 +357,8 @@ void Metal::Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
} }
} }
void Metal::Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, void Metal::Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value) const ClearColor& color_value, float depth_value)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -376,39 +369,39 @@ void Metal::Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
} }
} }
void Metal::Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) void Metal::Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{ {
g_state_tracker->SetScissor(rc); g_state_tracker->SetScissor(rc);
} }
void Metal::Renderer::SetTexture(u32 index, const AbstractTexture* texture) void Metal::Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{ {
g_state_tracker->SetTexture( g_state_tracker->SetTexture(
index, texture ? static_cast<const Texture*>(texture)->GetMTLTexture() : nullptr); index, texture ? static_cast<const Texture*>(texture)->GetMTLTexture() : nullptr);
} }
void Metal::Renderer::SetSamplerState(u32 index, const SamplerState& state) void Metal::Gfx::SetSamplerState(u32 index, const SamplerState& state)
{ {
g_state_tracker->SetSampler(index, state); g_state_tracker->SetSampler(index, state);
} }
void Metal::Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) void Metal::Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{ {
g_state_tracker->SetComputeTexture(static_cast<const Texture*>(texture)); g_state_tracker->SetComputeTexture(static_cast<const Texture*>(texture));
} }
void Metal::Renderer::UnbindTexture(const AbstractTexture* texture) void Metal::Gfx::UnbindTexture(const AbstractTexture* texture)
{ {
g_state_tracker->UnbindTexture(static_cast<const Texture*>(texture)->GetMTLTexture()); g_state_tracker->UnbindTexture(static_cast<const Texture*>(texture)->GetMTLTexture());
} }
void Metal::Renderer::SetViewport(float x, float y, float width, float height, float near_depth, void Metal::Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) float far_depth)
{ {
g_state_tracker->SetViewport(x, y, width, height, near_depth, far_depth); g_state_tracker->SetViewport(x, y, width, height, near_depth, far_depth);
} }
void Metal::Renderer::Draw(u32 base_vertex, u32 num_vertices) void Metal::Gfx::Draw(u32 base_vertex, u32 num_vertices)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -416,7 +409,7 @@ void Metal::Renderer::Draw(u32 base_vertex, u32 num_vertices)
} }
} }
void Metal::Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) void Metal::Gfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -424,9 +417,9 @@ void Metal::Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vert
} }
} }
void Metal::Renderer::DispatchComputeShader(const AbstractShader* shader, // void Metal::Gfx::DispatchComputeShader(const AbstractShader* shader, //
u32 groupsize_x, u32 groupsize_y, u32 groupsize_z, u32 groupsize_x, u32 groupsize_y, u32 groupsize_z,
u32 groups_x, u32 groups_y, u32 groups_z) u32 groups_x, u32 groups_y, u32 groups_z)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -436,7 +429,7 @@ void Metal::Renderer::DispatchComputeShader(const AbstractShader* shader, //
} }
} }
void Metal::Renderer::BindBackbuffer(const ClearColor& clear_color) void Metal::Gfx::BindBackbuffer(const ClearColor& clear_color)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -448,7 +441,7 @@ void Metal::Renderer::BindBackbuffer(const ClearColor& clear_color)
} }
} }
void Metal::Renderer::PresentBackbuffer() void Metal::Gfx::PresentBackbuffer()
{ {
@autoreleasepool @autoreleasepool
{ {
@ -473,40 +466,45 @@ void Metal::Renderer::PresentBackbuffer()
} }
} }
std::unique_ptr<::BoundingBox> Metal::Renderer::CreateBoundingBox() const void Metal::Gfx::CheckForSurfaceChange()
{ {
return std::make_unique<BoundingBox>(); if (!g_presenter->SurfaceChangedTestAndClear())
}
void Metal::Renderer::CheckForSurfaceChange()
{
if (!m_surface_changed.TestAndClear())
return; return;
m_layer = MRCRetain(static_cast<CAMetalLayer*>(m_new_surface_handle)); m_layer = MRCRetain(static_cast<CAMetalLayer*>(g_presenter->GetNewSurfaceHandle()));
m_new_surface_handle = nullptr;
SetupSurface(); SetupSurface();
} }
void Metal::Renderer::CheckForSurfaceResize() void Metal::Gfx::CheckForSurfaceResize()
{ {
if (!m_surface_resized.TestAndClear()) if (!g_presenter->SurfaceResizedTestAndClear())
return; return;
SetupSurface(); SetupSurface();
} }
void Metal::Renderer::SetupSurface() void Metal::Gfx::SetupSurface()
{ {
CGSize size = [m_layer bounds].size; auto info = GetSurfaceInfo();
// TODO: Update m_backbuffer_scale (need to make doing that not break everything)
const float backbuffer_scale = [m_layer contentsScale]; [m_layer setDrawableSize:{static_cast<double>(info.width), static_cast<double>(info.height)}];
size.width *= backbuffer_scale;
size.height *= backbuffer_scale; TextureConfig cfg(info.width, info.height, 1, 1, 1, info.format,
[m_layer setDrawableSize:size];
m_backbuffer_width = size.width;
m_backbuffer_height = size.height;
TextureConfig cfg(m_backbuffer_width, m_backbuffer_height, 1, 1, 1, m_backbuffer_format,
AbstractTextureFlag_RenderTarget); AbstractTextureFlag_RenderTarget);
m_bb_texture = std::make_unique<Texture>(nullptr, cfg); m_bb_texture = std::make_unique<Texture>(nullptr, cfg);
m_backbuffer = std::make_unique<Framebuffer>(m_bb_texture.get(), nullptr, // m_backbuffer = std::make_unique<Framebuffer>(m_bb_texture.get(), nullptr, //
m_backbuffer_width, m_backbuffer_height, 1, 1); info.width, info.height, 1, 1);
if (g_presenter)
g_presenter->SetBackbuffer(info);
}
SurfaceInfo Metal::Gfx::GetSurfaceInfo() const
{
if (!m_layer) // Headless
return {};
CGSize size = [m_layer bounds].size;
const float scale = [m_layer contentsScale];
return {static_cast<u32>(size.width * scale), static_cast<u32>(size.height * scale), scale,
Util::ToAbstract([m_layer pixelFormat])};
} }

View File

@ -16,13 +16,15 @@
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoBackends/Metal/MTLBoundingBox.h"
#include "VideoBackends/Metal/MTLGfx.h"
#include "VideoBackends/Metal/MTLObjectCache.h" #include "VideoBackends/Metal/MTLObjectCache.h"
#include "VideoBackends/Metal/MTLPerfQuery.h" #include "VideoBackends/Metal/MTLPerfQuery.h"
#include "VideoBackends/Metal/MTLRenderer.h"
#include "VideoBackends/Metal/MTLStateTracker.h" #include "VideoBackends/Metal/MTLStateTracker.h"
#include "VideoBackends/Metal/MTLUtil.h" #include "VideoBackends/Metal/MTLUtil.h"
#include "VideoBackends/Metal/MTLVertexManager.h" #include "VideoBackends/Metal/MTLVertexManager.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -93,57 +95,28 @@ bool Metal::VideoBackend::Initialize(const WindowSystemInfo& wsi)
MRCOwned<id<MTLDevice>> adapter = std::move(devs[selected_adapter_index]); MRCOwned<id<MTLDevice>> adapter = std::move(devs[selected_adapter_index]);
Util::PopulateBackendInfoFeatures(&g_Config, adapter); Util::PopulateBackendInfoFeatures(&g_Config, adapter);
// With the backend information populated, we can now initialize videocommon. UpdateActiveConfig();
InitializeShared();
MRCOwned<CAMetalLayer*> layer = MRCRetain(static_cast<CAMetalLayer*>(wsi.render_surface)); MRCOwned<CAMetalLayer*> layer = MRCRetain(static_cast<CAMetalLayer*>(wsi.render_surface));
[layer setDevice:adapter]; [layer setDevice:adapter];
if (Util::ToAbstract([layer pixelFormat]) == AbstractTextureFormat::Undefined) if (Util::ToAbstract([layer pixelFormat]) == AbstractTextureFormat::Undefined)
[layer setPixelFormat:MTLPixelFormatBGRA8Unorm]; [layer setPixelFormat:MTLPixelFormatBGRA8Unorm];
CGSize size = [layer bounds].size;
float scale = [layer contentsScale];
if (!layer) // headless
scale = 1.0;
ObjectCache::Initialize(std::move(adapter)); ObjectCache::Initialize(std::move(adapter));
g_state_tracker = std::make_unique<StateTracker>(); g_state_tracker = std::make_unique<StateTracker>();
g_renderer = std::make_unique<Renderer>(std::move(layer), size.width * scale,
size.height * scale, scale);
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() || return InitializeShared(
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() || std::make_unique<Metal::Gfx>(std::move(layer)), std::make_unique<Metal::VertexManager>(),
!g_texture_cache->Initialize()) std::make_unique<Metal::PerfQuery>(), std::make_unique<Metal::BoundingBox>());
{
PanicAlertFmt("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache();
return true;
} }
} }
void Metal::VideoBackend::Shutdown() void Metal::VideoBackend::Shutdown()
{ {
g_shader_cache->Shutdown(); ShutdownShared();
g_renderer->Shutdown();
g_shader_cache.reset();
g_texture_cache.reset();
g_framebuffer_manager.reset();
g_perf_query.reset();
g_vertex_manager.reset();
g_renderer.reset();
g_state_tracker.reset(); g_state_tracker.reset();
ObjectCache::Shutdown(); ObjectCache::Shutdown();
ShutdownShared();
} }
void Metal::VideoBackend::InitBackendInfo() void Metal::VideoBackend::InitBackendInfo()

View File

@ -8,6 +8,7 @@
#include "VideoBackends/Metal/MRCHelpers.h" #include "VideoBackends/Metal/MRCHelpers.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/RenderState.h" #include "VideoCommon/RenderState.h"
struct AbstractPipelineConfig; struct AbstractPipelineConfig;

View File

@ -77,8 +77,9 @@ void Metal::PerfQuery::ReturnResults(const u64* data, const PerfQueryGroup* grou
{ {
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
{ {
u64 native_res_result = data[i] * (EFB_WIDTH * EFB_HEIGHT) / u64 native_res_result =
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight()); data[i] * (EFB_WIDTH * EFB_HEIGHT) /
(g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
native_res_result /= g_ActiveConfig.iMultisamples; native_res_result /= g_ActiveConfig.iMultisamples;

View File

@ -17,8 +17,8 @@
#include "VideoBackends/Metal/MTLTexture.h" #include "VideoBackends/Metal/MTLTexture.h"
#include "VideoBackends/Metal/MTLUtil.h" #include "VideoBackends/Metal/MTLUtil.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/PerfQueryBase.h" #include "VideoCommon/PerfQueryBase.h"
#include "VideoCommon/RenderBase.h"
namespace Metal namespace Metal
{ {

View File

@ -6,7 +6,7 @@
#include "Common/Align.h" #include "Common/Align.h"
#include "Common/Assert.h" #include "Common/Assert.h"
#include "VideoBackends/Metal/MTLRenderer.h" #include "VideoBackends/Metal/MTLGfx.h"
#include "VideoBackends/Metal/MTLStateTracker.h" #include "VideoBackends/Metal/MTLStateTracker.h"
Metal::Texture::Texture(MRCOwned<id<MTLTexture>> tex, const TextureConfig& config) Metal::Texture::Texture(MRCOwned<id<MTLTexture>> tex, const TextureConfig& config)

View File

@ -1,8 +1,8 @@
add_library(videonull add_library(videonull
NullBackend.cpp NullBackend.cpp
NullBoundingBox.h NullBoundingBox.h
NullRender.cpp NullGfx.cpp
NullRender.h NullGfx.h
NullTexture.cpp NullTexture.cpp
NullTexture.h NullTexture.h
NullVertexManager.cpp NullVertexManager.cpp

View File

@ -11,12 +11,14 @@
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoBackends/Null/NullRender.h" #include "VideoBackends/Null/NullBoundingBox.h"
#include "VideoBackends/Null/NullGfx.h"
#include "VideoBackends/Null/NullVertexManager.h" #include "VideoBackends/Null/NullVertexManager.h"
#include "VideoBackends/Null/PerfQuery.h" #include "VideoBackends/Null/PerfQuery.h"
#include "VideoBackends/Null/TextureCache.h" #include "VideoBackends/Null/TextureCache.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -69,39 +71,13 @@ void VideoBackend::InitBackendInfo()
bool VideoBackend::Initialize(const WindowSystemInfo& wsi) bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{ {
InitializeShared(); return InitializeShared(std::make_unique<NullGfx>(), std::make_unique<VertexManager>(),
std::make_unique<PerfQuery>(), std::make_unique<NullBoundingBox>(),
g_renderer = std::make_unique<Renderer>(); std::make_unique<NullRenderer>(), std::make_unique<TextureCache>());
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_texture_cache = std::make_unique<TextureCache>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
PanicAlertFmt("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache();
return true;
} }
void VideoBackend::Shutdown() void VideoBackend::Shutdown()
{ {
g_shader_cache->Shutdown();
g_renderer->Shutdown();
g_texture_cache.reset();
g_perf_query.reset();
g_vertex_manager.reset();
g_framebuffer_manager.reset();
g_renderer.reset();
ShutdownShared(); ShutdownShared();
} }

View File

@ -0,0 +1,95 @@
// Copyright 2015 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Null/NullGfx.h"
#include "VideoBackends/Null/NullBoundingBox.h"
#include "VideoBackends/Null/NullTexture.h"
#include "VideoCommon/AbstractPipeline.h"
#include "VideoCommon/AbstractShader.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/VideoConfig.h"
namespace Null
{
// Init functions
NullGfx::NullGfx()
{
UpdateActiveConfig();
}
NullGfx::~NullGfx()
{
UpdateActiveConfig();
}
bool NullGfx::IsHeadless() const
{
return true;
}
bool NullGfx::SupportsUtilityDrawing() const
{
return false;
}
std::unique_ptr<AbstractTexture> NullGfx::CreateTexture(const TextureConfig& config,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<NullTexture>(config);
}
std::unique_ptr<AbstractStagingTexture> NullGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return std::make_unique<NullStagingTexture>(type, config);
}
class NullShader final : public AbstractShader
{
public:
explicit NullShader(ShaderStage stage) : AbstractShader(stage) {}
};
std::unique_ptr<AbstractShader>
NullGfx::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<NullShader>(stage);
}
std::unique_ptr<AbstractShader>
NullGfx::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<NullShader>(stage);
}
class NullPipeline final : public AbstractPipeline
{
};
std::unique_ptr<AbstractPipeline> NullGfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return std::make_unique<NullPipeline>();
}
std::unique_ptr<AbstractFramebuffer> NullGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return NullFramebuffer::Create(static_cast<NullTexture*>(color_attachment),
static_cast<NullTexture*>(depth_attachment));
}
std::unique_ptr<NativeVertexFormat>
NullGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<NativeVertexFormat>(vtx_decl);
}
NullRenderer::~NullRenderer() = default;
} // namespace Null

View File

@ -3,19 +3,19 @@
#pragma once #pragma once
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/RenderBase.h"
class BoundingBox;
namespace Null namespace Null
{ {
class Renderer final : public ::Renderer class NullGfx final : public AbstractGfx
{ {
public: public:
Renderer(); NullGfx();
~Renderer() override; ~NullGfx() override;
bool IsHeadless() const override; bool IsHeadless() const override;
virtual bool SupportsUtilityDrawing() const override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override; std::string_view name) override;
@ -34,18 +34,18 @@ public:
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config, std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data = nullptr, const void* cache_data = nullptr,
size_t cache_data_length = 0) override; size_t cache_data_length = 0) override;
};
class NullRenderer final : public Renderer
{
public:
NullRenderer() {}
~NullRenderer() override;
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; } u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; }
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {} void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z) override
{
}
void ReinterpretPixelData(EFBReinterpretType convtype) override {} void ReinterpretPixelData(EFBReinterpretType convtype) override {}
protected:
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
}; };
} // namespace Null } // namespace Null

View File

@ -1,92 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Null/NullRender.h"
#include "VideoBackends/Null/NullBoundingBox.h"
#include "VideoBackends/Null/NullTexture.h"
#include "VideoCommon/AbstractPipeline.h"
#include "VideoCommon/AbstractShader.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/VideoConfig.h"
namespace Null
{
// Init functions
Renderer::Renderer() : ::Renderer(1, 1, 1.0f, AbstractTextureFormat::RGBA8)
{
UpdateActiveConfig();
}
Renderer::~Renderer()
{
UpdateActiveConfig();
}
bool Renderer::IsHeadless() const
{
return true;
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<NullTexture>(config);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return std::make_unique<NullStagingTexture>(type, config);
}
class NullShader final : public AbstractShader
{
public:
explicit NullShader(ShaderStage stage) : AbstractShader(stage) {}
};
std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<NullShader>(stage);
}
std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<NullShader>(stage);
}
class NullPipeline final : public AbstractPipeline
{
};
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return std::make_unique<NullPipeline>();
}
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return NullFramebuffer::Create(static_cast<NullTexture*>(color_attachment),
static_cast<NullTexture*>(depth_attachment));
}
std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<NativeVertexFormat>(vtx_decl);
}
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const
{
return std::make_unique<NullBoundingBox>();
}
} // namespace Null

View File

@ -18,7 +18,7 @@ protected:
{ {
} }
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, void CopyEFBToCacheEntry(RcTcacheEntry& entry, bool is_depth_copy,
const MathUtil::Rectangle<int>& src_rect, bool scale_by_half, const MathUtil::Rectangle<int>& src_rect, bool scale_by_half,
bool linear_filter, EFBCopyFormat dst_format, bool is_intensity, bool linear_filter, EFBCopyFormat dst_format, bool is_intensity,
float gamma, bool clamp_top, bool clamp_bottom, float gamma, bool clamp_top, bool clamp_bottom,

View File

@ -2,14 +2,16 @@ add_library(videoogl
GPUTimer.h GPUTimer.h
OGLBoundingBox.cpp OGLBoundingBox.cpp
OGLBoundingBox.h OGLBoundingBox.h
OGLConfig.cpp
OGLConfig.h
OGLGfx.cpp
OGLGfx.h
OGLMain.cpp OGLMain.cpp
OGLNativeVertexFormat.cpp OGLNativeVertexFormat.cpp
OGLPerfQuery.cpp OGLPerfQuery.cpp
OGLPerfQuery.h OGLPerfQuery.h
OGLPipeline.cpp OGLPipeline.cpp
OGLPipeline.h OGLPipeline.h
OGLRender.cpp
OGLRender.h
OGLShader.cpp OGLShader.cpp
OGLShader.h OGLShader.h
OGLStreamBuffer.cpp OGLStreamBuffer.cpp

View File

@ -3,7 +3,7 @@
#include "VideoBackends/OGL/OGLBoundingBox.h" #include "VideoBackends/OGL/OGLBoundingBox.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLGfx.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
namespace OGL namespace OGL
@ -35,7 +35,7 @@ std::vector<BBoxType> OGLBoundingBox::Read(u32 index, u32 length)
// on nVidia drivers. This is more noticeable at higher internal resolutions. // on nVidia drivers. This is more noticeable at higher internal resolutions.
// Using glGetBufferSubData instead does not seem to exhibit this slowdown. // Using glGetBufferSubData instead does not seem to exhibit this slowdown.
if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) && if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
!static_cast<Renderer*>(g_renderer.get())->IsGLES()) !static_cast<OGLGfx*>(g_gfx.get())->IsGLES())
{ {
// We also need to ensure the the CPU does not receive stale values which have been updated by // We also need to ensure the the CPU does not receive stale values which have been updated by
// the GPU. Apparently the buffer here is not coherent on NVIDIA drivers. Not sure if this is a // the GPU. Apparently the buffer here is not coherent on NVIDIA drivers. Not sure if this is a

View File

@ -1,135 +1,26 @@
// Copyright 2008 Dolphin Emulator Project // Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <memory>
#include <string>
#include "Common/CommonTypes.h"
#include "Common/GL/GLContext.h" #include "Common/GL/GLContext.h"
#include "Common/GL/GLUtil.h" #include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/Logging/LogManager.h" #include "Common/Logging/LogManager.h"
#include "Common/MathUtil.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/Config/GraphicsSettings.h" #include "Core/Config/GraphicsSettings.h"
#include "VideoBackends/OGL/OGLBoundingBox.h"
#include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLTexture.h"
#include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#include <cstdio>
#include <string>
#include <string_view>
namespace OGL namespace OGL
{ {
VideoConfig g_ogl_config; void InitDriverInfo()
static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const char* message, const void* userParam)
{
const char* s_source;
const char* s_type;
// Performance - DualCore driver performance warning:
// DualCore application thread syncing with server thread
if (id == 0x200b0)
return;
switch (source)
{
case GL_DEBUG_SOURCE_API_ARB:
s_source = "API";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
s_source = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
s_source = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
s_source = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION_ARB:
s_source = "Application";
break;
case GL_DEBUG_SOURCE_OTHER_ARB:
s_source = "Other";
break;
default:
s_source = "Unknown";
break;
}
switch (type)
{
case GL_DEBUG_TYPE_ERROR_ARB:
s_type = "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
s_type = "Deprecated";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
s_type = "Undefined";
break;
case GL_DEBUG_TYPE_PORTABILITY_ARB:
s_type = "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
s_type = "Performance";
break;
case GL_DEBUG_TYPE_OTHER_ARB:
s_type = "Other";
break;
default:
s_type = "Unknown";
break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH_ARB:
ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
WARN_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_LOW_ARB:
DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
default:
ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
}
}
// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
static void APIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
{
glDepthRange(neardepth, fardepth);
}
static void APIENTRY ClearDepthf(GLfloat depthval)
{
glClearDepth(depthval);
}
static void InitDriverInfo()
{ {
const std::string_view svendor(g_ogl_config.gl_vendor); const std::string_view svendor(g_ogl_config.gl_vendor);
const std::string_view srenderer(g_ogl_config.gl_renderer); const std::string_view srenderer(g_ogl_config.gl_renderer);
@ -319,26 +210,8 @@ static void InitDriverInfo()
DriverDetails::Init(DriverDetails::API_OPENGL, vendor, driver, version, family); DriverDetails::Init(DriverDetails::API_OPENGL, vendor, driver, version, family);
} }
// Init functions bool PopulateConfig(GLContext* m_main_gl_context)
Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale)
: ::Renderer(static_cast<int>(std::max(main_gl_context->GetBackBufferWidth(), 1u)),
static_cast<int>(std::max(main_gl_context->GetBackBufferHeight(), 1u)),
backbuffer_scale, AbstractTextureFormat::RGBA8),
m_main_gl_context(std::move(main_gl_context)),
m_current_rasterization_state(RenderState::GetInvalidRasterizationState()),
m_current_depth_state(RenderState::GetInvalidDepthState()),
m_current_blend_state(RenderState::GetInvalidBlendingState())
{ {
// Create the window framebuffer.
if (!m_main_gl_context->IsHeadless())
{
m_system_framebuffer = std::make_unique<OGLFramebuffer>(
nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
m_current_framebuffer = m_system_framebuffer.get();
}
bool bSuccess = true; bool bSuccess = true;
bool supports_glsl_cache = false; bool supports_glsl_cache = false;
@ -346,8 +219,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER); g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER);
g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION); g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION);
InitDriverInfo();
if (!m_main_gl_context->IsGLES()) if (!m_main_gl_context->IsGLES())
{ {
if (!GLExtensions::Supports("GL_ARB_framebuffer_object")) if (!GLExtensions::Supports("GL_ARB_framebuffer_object"))
@ -401,15 +272,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
"GPU: Does your video card support OpenGL 3.3?"); "GPU: Does your video card support OpenGL 3.3?");
bSuccess = false; bSuccess = false;
} }
// OpenGL 3 doesn't provide GLES like float functions for depth.
// They are in core in OpenGL 4.1, so almost every driver should support them.
// But for the oldest ones, we provide fallbacks to the old double functions.
if (!GLExtensions::Supports("GL_ARB_ES2_compatibility"))
{
glDepthRangef = DepthRangef;
glClearDepthf = ClearDepthf;
}
} }
// Copy the GPU name to g_Config, so Analytics can see it. // Copy the GPU name to g_Config, so Analytics can see it.
@ -693,29 +555,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
} }
g_Config.backend_info.bSupportsPipelineCacheData = supports_glsl_cache; g_Config.backend_info.bSupportsPipelineCacheData = supports_glsl_cache;
if (g_ogl_config.bSupportsDebug)
{
if (GLExtensions::Supports("GL_KHR_debug"))
{
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
glDebugMessageCallback(ErrorCallback, nullptr);
}
else
{
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
glDebugMessageCallbackARB(ErrorCallback, nullptr);
}
if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
Common::Log::LogLevel::LERROR))
{
glEnable(GL_DEBUG_OUTPUT);
}
else
{
glDisable(GL_DEBUG_OUTPUT);
}
}
int samples; int samples;
glGetIntegerv(GL_SAMPLES, &samples); glGetIntegerv(GL_SAMPLES, &samples);
if (samples > 1) if (samples > 1)
@ -732,11 +571,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
} }
if (!bSuccess) if (!bSuccess)
{ return false;
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return;
}
g_Config.VerifyValidity(); g_Config.VerifyValidity();
UpdateActiveConfig(); UpdateActiveConfig();
@ -771,565 +606,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ", g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ",
g_ActiveConfig.backend_info.bSupportsDepthClamp ? "" : "DepthClamp "); g_ActiveConfig.backend_info.bSupportsDepthClamp ? "" : "DepthClamp ");
// Handle VSync on/off
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
if (g_ActiveConfig.backend_info.bSupportsClipControl)
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
glEnable(GL_DEPTH_CLAMP);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glGenFramebuffers(1, &m_shared_read_framebuffer);
glGenFramebuffers(1, &m_shared_draw_framebuffer);
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
GLUtil::EnablePrimitiveRestart(m_main_gl_context.get());
UpdateActiveConfig();
}
Renderer::~Renderer() = default;
bool Renderer::IsHeadless() const
{
return m_main_gl_context->IsHeadless();
}
bool Renderer::Initialize()
{
if (!::Renderer::Initialize())
return false;
return true; return true;
} }
void Renderer::Shutdown()
{
::Renderer::Shutdown();
glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
glDeleteFramebuffers(1, &m_shared_read_framebuffer);
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return std::make_unique<OGLTexture>(config, name);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return OGLStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
static_cast<OGLTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{
return OGLShader::CreateFromSource(stage, source, name);
}
std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return nullptr;
}
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return OGLPipeline::Create(config, cache_data, cache_data_length);
}
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
}
std::unique_ptr<::BoundingBox> Renderer::CreateBoundingBox() const
{
return std::make_unique<OGLBoundingBox>();
}
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
if (g_ogl_config.bSupportViewportFloat)
{
glViewportIndexedf(0, x, y, width, height);
}
else
{
auto iceilf = [](float f) { return static_cast<GLint>(std::ceil(f)); };
glViewport(iceilf(x), iceilf(y), iceilf(width), iceilf(height));
}
glDepthRangef(near_depth, far_depth);
}
void Renderer::Draw(u32 base_vertex, u32 num_vertices)
{
glDrawArrays(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(), base_vertex,
num_vertices);
}
void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{
if (g_ogl_config.bSupportsGLBaseVertex)
{
glDrawElementsBaseVertex(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT,
static_cast<u16*>(nullptr) + base_index, base_vertex);
}
else
{
glDrawElements(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT, static_cast<u16*>(nullptr) + base_index);
}
}
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
glUseProgram(static_cast<const OGLShader*>(shader)->GetGLComputeProgramID());
glDispatchCompute(groups_x, groups_y, groups_z);
// We messed up the program binding, so restore it.
ProgramShaderCache::InvalidateLastProgram();
if (m_current_pipeline)
static_cast<const OGLPipeline*>(m_current_pipeline)->GetProgram()->shader.Bind();
// Barrier to texture can be used for reads.
if (m_bound_image_texture)
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z)
{
g_framebuffer_manager->FlushEFBPokes();
g_framebuffer_manager->FlagPeekCacheAsOutOfDate();
u32 clear_mask = 0;
if (colorEnable || alphaEnable)
{
glColorMask(colorEnable, colorEnable, colorEnable, alphaEnable);
glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f,
float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f);
clear_mask = GL_COLOR_BUFFER_BIT;
}
if (zEnable)
{
glDepthMask(zEnable ? GL_TRUE : GL_FALSE);
glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
// Update rect for clearing the picture
// glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
const auto converted_target_rc =
ConvertFramebufferRectangle(ConvertEFBRectangle(rc), m_current_framebuffer);
SetScissorRect(converted_target_rc);
glClear(clear_mask);
// Restore color/depth mask.
if (colorEnable || alphaEnable)
{
glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
if (zEnable)
glDepthMask(m_current_depth_state.updateenable);
// Scissor rect must be restored.
BPFunctions::SetScissorAndViewport();
}
void Renderer::RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc)
{
// Quad-buffered stereo is annoying on GL.
if (g_ActiveConfig.stereo_mode != StereoMode::QuadBuffer)
return ::Renderer::RenderXFBToScreen(target_rc, source_texture, source_rc);
glDrawBuffer(GL_BACK_LEFT);
m_post_processor->BlitFromTexture(target_rc, source_rc, source_texture, 0);
glDrawBuffer(GL_BACK_RIGHT);
m_post_processor->BlitFromTexture(target_rc, source_rc, source_texture, 1);
glDrawBuffer(GL_BACK);
}
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<OGLFramebuffer*>(framebuffer)->GetFBO());
m_current_framebuffer = framebuffer;
}
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
// EXT_discard_framebuffer could be used here to save bandwidth on tilers.
SetFramebuffer(framebuffer);
}
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
SetFramebuffer(framebuffer);
glDisable(GL_SCISSOR_TEST);
GLbitfield clear_mask = 0;
if (framebuffer->HasColorBuffer())
{
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(color_value[0], color_value[1], color_value[2], color_value[3]);
clear_mask |= GL_COLOR_BUFFER_BIT;
}
if (framebuffer->HasDepthBuffer())
{
glDepthMask(GL_TRUE);
glClearDepthf(depth_value);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
glClear(clear_mask);
glEnable(GL_SCISSOR_TEST);
// Restore color/depth mask.
if (framebuffer->HasColorBuffer())
{
glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
if (framebuffer->HasDepthBuffer())
glDepthMask(m_current_depth_state.updateenable);
}
void Renderer::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSurfaceChange();
CheckForSurfaceResize();
SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
}
void Renderer::PresentBackbuffer()
{
if (g_ogl_config.bSupportsDebug)
{
if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
Common::Log::LogLevel::LERROR))
{
glEnable(GL_DEBUG_OUTPUT);
}
else
{
glDisable(GL_DEBUG_OUTPUT);
}
}
// Swap the back and front buffers, presenting the image.
m_main_gl_context->Swap();
}
void Renderer::OnConfigChanged(u32 bits)
{
if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
if (bits & CONFIG_CHANGE_BIT_ANISOTROPY)
g_sampler_cache->Clear();
}
void Renderer::Flush()
{
// ensure all commands are sent to the GPU.
// Otherwise the driver could batch several frames together.
glFlush();
}
void Renderer::WaitForGPUIdle()
{
glFinish();
}
void Renderer::CheckForSurfaceChange()
{
if (!m_surface_changed.TestAndClear())
return;
m_main_gl_context->UpdateSurface(m_new_surface_handle);
m_new_surface_handle = nullptr;
// With a surface change, the window likely has new dimensions.
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
m_system_framebuffer->UpdateDimensions(m_backbuffer_width, m_backbuffer_height);
}
void Renderer::CheckForSurfaceResize()
{
if (!m_surface_resized.TestAndClear())
return;
m_main_gl_context->Update();
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
m_system_framebuffer->UpdateDimensions(m_backbuffer_width, m_backbuffer_height);
}
void Renderer::BeginUtilityDrawing()
{
::Renderer::BeginUtilityDrawing();
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glDisable(GL_CLIP_DISTANCE0);
glDisable(GL_CLIP_DISTANCE1);
}
}
void Renderer::EndUtilityDrawing()
{
::Renderer::EndUtilityDrawing();
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
}
}
void Renderer::ApplyRasterizationState(const RasterizationState state)
{
if (m_current_rasterization_state == state)
return;
// none, ccw, cw, ccw
if (state.cullmode != CullMode::None)
{
// TODO: GX_CULL_ALL not supported, yet!
glEnable(GL_CULL_FACE);
glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
}
else
{
glDisable(GL_CULL_FACE);
}
m_current_rasterization_state = state;
}
void Renderer::ApplyDepthState(const DepthState state)
{
if (m_current_depth_state == state)
return;
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
if (state.testenable)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
}
else
{
// if the test is disabled write is disabled too
// TODO: When PE performance metrics are being emulated via occlusion queries, we should
// (probably?) enable depth test with depth function ALWAYS here
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
m_current_depth_state = state;
}
void Renderer::ApplyBlendingState(const BlendingState state)
{
if (m_current_blend_state == state)
return;
bool useDualSource = state.usedualsrc;
const GLenum src_factors[8] = {GL_ZERO,
GL_ONE,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
(GLenum)GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA};
const GLenum dst_factors[8] = {GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
(GLenum)GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA};
if (state.blendenable)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
// Always call glBlendEquationSeparate and glBlendFuncSeparate, even when
// GL_BLEND is disabled, as a workaround for some bugs (possibly graphics
// driver issues?). See https://bugs.dolphin-emu.org/issues/10120 : "Sonic
// Adventure 2 Battle: graphics crash when loading first Dark level"
GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
glBlendEquationSeparate(equation, equationAlpha);
glBlendFuncSeparate(src_factors[u32(state.srcfactor.Value())],
dst_factors[u32(state.dstfactor.Value())],
src_factors[u32(state.srcfactoralpha.Value())],
dst_factors[u32(state.dstfactoralpha.Value())]);
const GLenum logic_op_codes[16] = {
GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP,
GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};
// Logic ops aren't available in GLES3
if (!IsGLES())
{
if (state.logicopenable)
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(logic_op_codes[u32(state.logicmode.Value())]);
}
else
{
glDisable(GL_COLOR_LOGIC_OP);
}
}
glColorMask(state.colorupdate, state.colorupdate, state.colorupdate, state.alphaupdate);
m_current_blend_state = state;
}
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
{
if (m_current_pipeline == pipeline)
return;
if (pipeline)
{
ApplyRasterizationState(static_cast<const OGLPipeline*>(pipeline)->GetRasterizationState());
ApplyDepthState(static_cast<const OGLPipeline*>(pipeline)->GetDepthState());
ApplyBlendingState(static_cast<const OGLPipeline*>(pipeline)->GetBlendingState());
ProgramShaderCache::BindVertexFormat(
static_cast<const OGLPipeline*>(pipeline)->GetVertexFormat());
static_cast<const OGLPipeline*>(pipeline)->GetProgram()->shader.Bind();
}
else
{
ProgramShaderCache::InvalidateLastProgram();
glUseProgram(0);
}
m_current_pipeline = pipeline;
}
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
{
const OGLTexture* gl_texture = static_cast<const OGLTexture*>(texture);
if (m_bound_textures[index] == gl_texture)
return;
glActiveTexture(GL_TEXTURE0 + index);
if (gl_texture)
glBindTexture(gl_texture->GetGLTarget(), gl_texture->GetGLTextureId());
else
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[index] = gl_texture;
}
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
{
g_sampler_cache->SetSamplerState(index, state);
}
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{
if (m_bound_image_texture == texture)
return;
if (texture)
{
const GLenum access = read ? (write ? GL_READ_WRITE : GL_READ_ONLY) : GL_WRITE_ONLY;
glBindImageTexture(0, static_cast<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
}
else
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}
m_bound_image_texture = texture;
}
void Renderer::UnbindTexture(const AbstractTexture* texture)
{
for (size_t i = 0; i < m_bound_textures.size(); i++)
{
if (m_bound_textures[i] != texture)
continue;
glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + i));
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[i] = nullptr;
}
if (m_bound_image_texture == texture)
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
m_bound_image_texture = nullptr;
}
}
std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCompiler()
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
void Renderer::BindSharedReadFramebuffer()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_shared_read_framebuffer);
}
void Renderer::BindSharedDrawFramebuffer()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared_draw_framebuffer);
}
void Renderer::RestoreFramebufferBinding()
{
glBindFramebuffer(
GL_FRAMEBUFFER,
m_current_framebuffer ? static_cast<OGLFramebuffer*>(m_current_framebuffer)->GetFBO() : 0);
}
} // namespace OGL } // namespace OGL

View File

@ -0,0 +1,78 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "Common/CommonTypes.h"
class GLContext;
namespace OGL
{
enum GlslVersion
{
Glsl130,
Glsl140,
Glsl150,
Glsl330,
Glsl400, // and above
Glsl430,
GlslEs300, // GLES 3.0
GlslEs310, // GLES 3.1
GlslEs320, // GLES 3.2
};
enum class EsTexbufType
{
TexbufNone,
TexbufCore,
TexbufOes,
TexbufExt
};
enum class EsFbFetchType
{
FbFetchNone,
FbFetchExt,
FbFetchArm,
};
// ogl-only config, so not in VideoConfig.h
struct VideoConfig
{
bool bIsES;
bool bSupportsGLPinnedMemory;
bool bSupportsGLSync;
bool bSupportsGLBaseVertex;
bool bSupportsGLBufferStorage;
bool bSupportsMSAA;
GlslVersion eSupportedGLSLVersion;
bool bSupportViewportFloat;
bool bSupportsAEP;
bool bSupportsDebug;
bool bSupportsCopySubImage;
u8 SupportedESPointSize;
EsTexbufType SupportedESTextureBuffer;
bool bSupportsTextureStorage;
bool bSupports2DTextureStorageMultisample;
bool bSupports3DTextureStorageMultisample;
bool bSupportsConservativeDepth;
bool bSupportsImageLoadStore;
bool bSupportsAniso;
bool bSupportsBitfield;
bool bSupportsTextureSubImage;
EsFbFetchType SupportedFramebufferFetch;
bool bSupportsShaderThreadShuffleNV;
const char* gl_vendor;
const char* gl_renderer;
const char* gl_version;
s32 max_samples;
};
void InitDriverInfo();
bool PopulateConfig(GLContext* main_gl_context);
extern VideoConfig g_ogl_config;
} // namespace OGL

View File

@ -0,0 +1,731 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/OGL/OGLGfx.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/Logging/LogManager.h"
#include "Core/Config/GraphicsSettings.h"
#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLTexture.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/AsyncShaderCompiler.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h"
#include <string_view>
namespace OGL
{
VideoConfig g_ogl_config;
static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const char* message, const void* userParam)
{
const char* s_source;
const char* s_type;
// Performance - DualCore driver performance warning:
// DualCore application thread syncing with server thread
if (id == 0x200b0)
return;
switch (source)
{
case GL_DEBUG_SOURCE_API_ARB:
s_source = "API";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
s_source = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
s_source = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
s_source = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION_ARB:
s_source = "Application";
break;
case GL_DEBUG_SOURCE_OTHER_ARB:
s_source = "Other";
break;
default:
s_source = "Unknown";
break;
}
switch (type)
{
case GL_DEBUG_TYPE_ERROR_ARB:
s_type = "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
s_type = "Deprecated";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
s_type = "Undefined";
break;
case GL_DEBUG_TYPE_PORTABILITY_ARB:
s_type = "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
s_type = "Performance";
break;
case GL_DEBUG_TYPE_OTHER_ARB:
s_type = "Other";
break;
default:
s_type = "Unknown";
break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH_ARB:
ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
WARN_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_LOW_ARB:
DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
default:
ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
}
}
// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
static void APIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
{
glDepthRange(neardepth, fardepth);
}
static void APIENTRY ClearDepthf(GLfloat depthval)
{
glClearDepth(depthval);
}
OGLGfx::OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale)
: m_main_gl_context(std::move(main_gl_context)),
m_current_rasterization_state(RenderState::GetInvalidRasterizationState()),
m_current_depth_state(RenderState::GetInvalidDepthState()),
m_current_blend_state(RenderState::GetInvalidBlendingState()),
m_backbuffer_scale(backbuffer_scale)
{
// Create the window framebuffer.
if (!m_main_gl_context->IsHeadless())
{
m_system_framebuffer = std::make_unique<OGLFramebuffer>(
nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
m_current_framebuffer = m_system_framebuffer.get();
}
if (m_main_gl_context->IsGLES())
{
// OpenGL 3 doesn't provide GLES like float functions for depth.
// They are in core in OpenGL 4.1, so almost every driver should support them.
// But for the oldest ones, we provide fallbacks to the old double functions.
if (!GLExtensions::Supports("GL_ARB_ES2_compatibility"))
{
glDepthRangef = DepthRangef;
glClearDepthf = ClearDepthf;
}
}
if (!PopulateConfig(m_main_gl_context.get()))
{
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return;
}
InitDriverInfo();
// Setup Debug logging
if (g_ogl_config.bSupportsDebug)
{
if (GLExtensions::Supports("GL_KHR_debug"))
{
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
glDebugMessageCallback(ErrorCallback, nullptr);
}
else
{
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
glDebugMessageCallbackARB(ErrorCallback, nullptr);
}
if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
Common::Log::LogLevel::LERROR))
{
glEnable(GL_DEBUG_OUTPUT);
}
else
{
glDisable(GL_DEBUG_OUTPUT);
}
}
// Handle VSync on/off
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
if (g_ActiveConfig.backend_info.bSupportsClipControl)
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
glEnable(GL_DEPTH_CLAMP);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glGenFramebuffers(1, &m_shared_read_framebuffer);
glGenFramebuffers(1, &m_shared_draw_framebuffer);
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
GLUtil::EnablePrimitiveRestart(m_main_gl_context.get());
UpdateActiveConfig();
}
OGLGfx::~OGLGfx()
{
glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
glDeleteFramebuffers(1, &m_shared_read_framebuffer);
}
bool OGLGfx::IsHeadless() const
{
return m_main_gl_context->IsHeadless();
}
std::unique_ptr<AbstractTexture> OGLGfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return std::make_unique<OGLTexture>(config, name);
}
std::unique_ptr<AbstractStagingTexture> OGLGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return OGLStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
static_cast<OGLTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader>
OGLGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{
return OGLShader::CreateFromSource(stage, source, name);
}
std::unique_ptr<AbstractShader>
OGLGfx::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return nullptr;
}
std::unique_ptr<AbstractPipeline> OGLGfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return OGLPipeline::Create(config, cache_data, cache_data_length);
}
void OGLGfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
}
void OGLGfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
if (g_ogl_config.bSupportViewportFloat)
{
glViewportIndexedf(0, x, y, width, height);
}
else
{
auto iceilf = [](float f) { return static_cast<GLint>(std::ceil(f)); };
glViewport(iceilf(x), iceilf(y), iceilf(width), iceilf(height));
}
glDepthRangef(near_depth, far_depth);
}
void OGLGfx::Draw(u32 base_vertex, u32 num_vertices)
{
glDrawArrays(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(), base_vertex,
num_vertices);
}
void OGLGfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{
if (g_ogl_config.bSupportsGLBaseVertex)
{
glDrawElementsBaseVertex(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT,
static_cast<u16*>(nullptr) + base_index, base_vertex);
}
else
{
glDrawElements(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT, static_cast<u16*>(nullptr) + base_index);
}
}
void OGLGfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
glUseProgram(static_cast<const OGLShader*>(shader)->GetGLComputeProgramID());
glDispatchCompute(groups_x, groups_y, groups_z);
// We messed up the program binding, so restore it.
ProgramShaderCache::InvalidateLastProgram();
if (m_current_pipeline)
static_cast<const OGLPipeline*>(m_current_pipeline)->GetProgram()->shader.Bind();
// Barrier to texture can be used for reads.
if (m_bound_image_texture)
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
void OGLGfx::SelectLeftBuffer()
{
glDrawBuffer(GL_BACK_LEFT);
}
void OGLGfx::SelectRightBuffer()
{
glDrawBuffer(GL_BACK_RIGHT);
}
void OGLGfx::SelectMainBuffer()
{
glDrawBuffer(GL_BACK);
}
void OGLGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<OGLFramebuffer*>(framebuffer)->GetFBO());
m_current_framebuffer = framebuffer;
}
void OGLGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
// EXT_discard_framebuffer could be used here to save bandwidth on tilers.
SetFramebuffer(framebuffer);
}
void OGLGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
float depth_value)
{
SetFramebuffer(framebuffer);
glDisable(GL_SCISSOR_TEST);
GLbitfield clear_mask = 0;
if (framebuffer->HasColorBuffer())
{
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(color_value[0], color_value[1], color_value[2], color_value[3]);
clear_mask |= GL_COLOR_BUFFER_BIT;
}
if (framebuffer->HasDepthBuffer())
{
glDepthMask(GL_TRUE);
glClearDepthf(depth_value);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
glClear(clear_mask);
glEnable(GL_SCISSOR_TEST);
// Restore color/depth mask.
if (framebuffer->HasColorBuffer())
{
glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
if (framebuffer->HasDepthBuffer())
glDepthMask(m_current_depth_state.updateenable);
}
void OGLGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
bool alphaEnable, bool zEnable, u32 color, u32 z)
{
u32 clear_mask = 0;
if (colorEnable || alphaEnable)
{
glColorMask(colorEnable, colorEnable, colorEnable, alphaEnable);
glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f,
float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f);
clear_mask = GL_COLOR_BUFFER_BIT;
}
if (zEnable)
{
glDepthMask(zEnable ? GL_TRUE : GL_FALSE);
glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
// Update rect for clearing the picture
// glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
g_gfx->SetScissorRect(target_rc);
glClear(clear_mask);
// Restore color/depth mask.
if (colorEnable || alphaEnable)
{
glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
if (zEnable)
glDepthMask(m_current_depth_state.updateenable);
}
void OGLGfx::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSurfaceChange();
CheckForSurfaceResize();
SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
}
void OGLGfx::PresentBackbuffer()
{
if (g_ogl_config.bSupportsDebug)
{
if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
Common::Log::LogLevel::LERROR))
{
glEnable(GL_DEBUG_OUTPUT);
}
else
{
glDisable(GL_DEBUG_OUTPUT);
}
}
// Swap the back and front buffers, presenting the image.
m_main_gl_context->Swap();
}
void OGLGfx::OnConfigChanged(u32 bits)
{
AbstractGfx::OnConfigChanged(bits);
if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
if (bits & CONFIG_CHANGE_BIT_ANISOTROPY)
g_sampler_cache->Clear();
}
void OGLGfx::Flush()
{
// ensure all commands are sent to the GPU.
// Otherwise the driver could batch several frames together.
glFlush();
}
void OGLGfx::WaitForGPUIdle()
{
glFinish();
}
void OGLGfx::CheckForSurfaceChange()
{
if (!g_presenter->SurfaceChangedTestAndClear())
return;
m_main_gl_context->UpdateSurface(g_presenter->GetNewSurfaceHandle());
u32 width = m_main_gl_context->GetBackBufferWidth();
u32 height = m_main_gl_context->GetBackBufferHeight();
// With a surface change, the window likely has new dimensions.
g_presenter->SetBackbuffer(width, height);
m_system_framebuffer->UpdateDimensions(width, height);
}
void OGLGfx::CheckForSurfaceResize()
{
if (!g_presenter->SurfaceResizedTestAndClear())
return;
m_main_gl_context->Update();
u32 width = m_main_gl_context->GetBackBufferWidth();
u32 height = m_main_gl_context->GetBackBufferHeight();
g_presenter->SetBackbuffer(width, height);
m_system_framebuffer->UpdateDimensions(width, height);
}
void OGLGfx::BeginUtilityDrawing()
{
AbstractGfx::BeginUtilityDrawing();
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glDisable(GL_CLIP_DISTANCE0);
glDisable(GL_CLIP_DISTANCE1);
}
}
void OGLGfx::EndUtilityDrawing()
{
AbstractGfx::EndUtilityDrawing();
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
}
}
void OGLGfx::ApplyRasterizationState(const RasterizationState state)
{
if (m_current_rasterization_state == state)
return;
// none, ccw, cw, ccw
if (state.cullmode != CullMode::None)
{
// TODO: GX_CULL_ALL not supported, yet!
glEnable(GL_CULL_FACE);
glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
}
else
{
glDisable(GL_CULL_FACE);
}
m_current_rasterization_state = state;
}
void OGLGfx::ApplyDepthState(const DepthState state)
{
if (m_current_depth_state == state)
return;
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
if (state.testenable)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
}
else
{
// if the test is disabled write is disabled too
// TODO: When PE performance metrics are being emulated via occlusion queries, we should
// (probably?) enable depth test with depth function ALWAYS here
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
m_current_depth_state = state;
}
void OGLGfx::ApplyBlendingState(const BlendingState state)
{
if (m_current_blend_state == state)
return;
bool useDualSource = state.usedualsrc;
const GLenum src_factors[8] = {GL_ZERO,
GL_ONE,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
(GLenum)GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA};
const GLenum dst_factors[8] = {GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
(GLenum)GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA};
if (state.blendenable)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
// Always call glBlendEquationSeparate and glBlendFuncSeparate, even when
// GL_BLEND is disabled, as a workaround for some bugs (possibly graphics
// driver issues?). See https://bugs.dolphin-emu.org/issues/10120 : "Sonic
// Adventure 2 Battle: graphics crash when loading first Dark level"
GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
glBlendEquationSeparate(equation, equationAlpha);
glBlendFuncSeparate(src_factors[u32(state.srcfactor.Value())],
dst_factors[u32(state.dstfactor.Value())],
src_factors[u32(state.srcfactoralpha.Value())],
dst_factors[u32(state.dstfactoralpha.Value())]);
const GLenum logic_op_codes[16] = {
GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP,
GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};
// Logic ops aren't available in GLES3
if (!IsGLES())
{
if (state.logicopenable)
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(logic_op_codes[u32(state.logicmode.Value())]);
}
else
{
glDisable(GL_COLOR_LOGIC_OP);
}
}
glColorMask(state.colorupdate, state.colorupdate, state.colorupdate, state.alphaupdate);
m_current_blend_state = state;
}
void OGLGfx::SetPipeline(const AbstractPipeline* pipeline)
{
if (m_current_pipeline == pipeline)
return;
if (pipeline)
{
ApplyRasterizationState(static_cast<const OGLPipeline*>(pipeline)->GetRasterizationState());
ApplyDepthState(static_cast<const OGLPipeline*>(pipeline)->GetDepthState());
ApplyBlendingState(static_cast<const OGLPipeline*>(pipeline)->GetBlendingState());
ProgramShaderCache::BindVertexFormat(
static_cast<const OGLPipeline*>(pipeline)->GetVertexFormat());
static_cast<const OGLPipeline*>(pipeline)->GetProgram()->shader.Bind();
}
else
{
ProgramShaderCache::InvalidateLastProgram();
glUseProgram(0);
}
m_current_pipeline = pipeline;
}
void OGLGfx::SetTexture(u32 index, const AbstractTexture* texture)
{
const OGLTexture* gl_texture = static_cast<const OGLTexture*>(texture);
if (m_bound_textures[index] == gl_texture)
return;
glActiveTexture(GL_TEXTURE0 + index);
if (gl_texture)
glBindTexture(gl_texture->GetGLTarget(), gl_texture->GetGLTextureId());
else
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[index] = gl_texture;
}
void OGLGfx::SetSamplerState(u32 index, const SamplerState& state)
{
g_sampler_cache->SetSamplerState(index, state);
}
void OGLGfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{
if (m_bound_image_texture == texture)
return;
if (texture)
{
const GLenum access = read ? (write ? GL_READ_WRITE : GL_READ_ONLY) : GL_WRITE_ONLY;
glBindImageTexture(0, static_cast<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
}
else
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}
m_bound_image_texture = texture;
}
void OGLGfx::UnbindTexture(const AbstractTexture* texture)
{
for (size_t i = 0; i < m_bound_textures.size(); i++)
{
if (m_bound_textures[i] != texture)
continue;
glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + i));
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[i] = nullptr;
}
if (m_bound_image_texture == texture)
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
m_bound_image_texture = nullptr;
}
}
std::unique_ptr<VideoCommon::AsyncShaderCompiler> OGLGfx::CreateAsyncShaderCompiler()
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
bool OGLGfx::IsGLES() const
{
return m_main_gl_context->IsGLES();
}
void OGLGfx::BindSharedReadFramebuffer()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_shared_read_framebuffer);
}
void OGLGfx::BindSharedDrawFramebuffer()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared_draw_framebuffer);
}
void OGLGfx::RestoreFramebufferBinding()
{
glBindFramebuffer(
GL_FRAMEBUFFER,
m_current_framebuffer ? static_cast<OGLFramebuffer*>(m_current_framebuffer)->GetFBO() : 0);
}
SurfaceInfo OGLGfx::GetSurfaceInfo() const
{
return {std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), m_backbuffer_scale,
AbstractTextureFormat::RGBA8};
}
} // namespace OGL

View File

@ -1,99 +1,25 @@
// Copyright 2008 Dolphin Emulator Project // Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <array> #include "VideoCommon/AbstractGfx.h"
#include <string>
#include <string_view>
#include "Common/GL/GLContext.h" class GLContext;
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoCommon/RenderBase.h"
class BoundingBox;
namespace OGL namespace OGL
{ {
class OGLFramebuffer; class OGLFramebuffer;
class OGLPipeline;
class OGLTexture; class OGLTexture;
enum GlslVersion class OGLGfx final : public AbstractGfx
{
Glsl130,
Glsl140,
Glsl150,
Glsl330,
Glsl400, // and above
Glsl430,
GlslEs300, // GLES 3.0
GlslEs310, // GLES 3.1
GlslEs320, // GLES 3.2
};
enum class EsTexbufType
{
TexbufNone,
TexbufCore,
TexbufOes,
TexbufExt
};
enum class EsFbFetchType
{
FbFetchNone,
FbFetchExt,
FbFetchArm,
};
// ogl-only config, so not in VideoConfig.h
struct VideoConfig
{
bool bIsES;
bool bSupportsGLPinnedMemory;
bool bSupportsGLSync;
bool bSupportsGLBaseVertex;
bool bSupportsGLBufferStorage;
bool bSupportsMSAA;
GlslVersion eSupportedGLSLVersion;
bool bSupportViewportFloat;
bool bSupportsAEP;
bool bSupportsDebug;
bool bSupportsCopySubImage;
u8 SupportedESPointSize;
EsTexbufType SupportedESTextureBuffer;
bool bSupportsTextureStorage;
bool bSupports2DTextureStorageMultisample;
bool bSupports3DTextureStorageMultisample;
bool bSupportsConservativeDepth;
bool bSupportsImageLoadStore;
bool bSupportsAniso;
bool bSupportsBitfield;
bool bSupportsTextureSubImage;
EsFbFetchType SupportedFramebufferFetch;
bool bSupportsShaderThreadShuffleNV;
const char* gl_vendor;
const char* gl_renderer;
const char* gl_version;
s32 max_samples;
};
extern VideoConfig g_ogl_config;
class Renderer : public ::Renderer
{ {
public: public:
Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale); OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale);
~Renderer() override; ~OGLGfx();
static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); }
bool IsHeadless() const override; bool IsHeadless() const override;
bool Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override; std::string_view name) override;
std::unique_ptr<AbstractStagingTexture> std::unique_ptr<AbstractStagingTexture>
@ -116,6 +42,8 @@ public:
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override; void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {}, void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
float depth_value = 0.0f) override; float depth_value = 0.0f) override;
void ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override; void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override; void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override; void SetSamplerState(u32 index, const SamplerState& state) override;
@ -135,35 +63,32 @@ public:
void Flush() override; void Flush() override;
void WaitForGPUIdle() override; void WaitForGPUIdle() override;
void RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc) override;
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable, virtual void SelectLeftBuffer() override;
bool zEnable, u32 color, u32 z) override; virtual void SelectRightBuffer() override;
virtual void SelectMainBuffer() override;
std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override; std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;
// Only call methods from this on the GPU thread. // Only call methods from this on the GPU thread.
GLContext* GetMainGLContext() const { return m_main_gl_context.get(); } GLContext* GetMainGLContext() const { return m_main_gl_context.get(); }
bool IsGLES() const { return m_main_gl_context->IsGLES(); } bool IsGLES() const;
// Invalidates a cached texture binding. Required for texel buffers when they borrow the units. // Invalidates a cached texture binding. Required for texel buffers when they borrow the units.
void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; } void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; }
// The shared framebuffer exists for copying textures when extensions are not available. It is // The shared framebuffer exists for copying textures when extensions are not available. It is
// slower, but the only way to do these things otherwise. // slower, but the only way to do these things otherwise.
GLuint GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; } u32 GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
GLuint GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; } u32 GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
void BindSharedReadFramebuffer(); void BindSharedReadFramebuffer();
void BindSharedDrawFramebuffer(); void BindSharedDrawFramebuffer();
// Restores FBO binding after it's been changed. // Restores FBO binding after it's been changed.
void RestoreFramebufferBinding(); void RestoreFramebufferBinding();
protected: SurfaceInfo GetSurfaceInfo() const override;
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private: private:
void CheckForSurfaceChange(); void CheckForSurfaceChange();
@ -180,7 +105,14 @@ private:
RasterizationState m_current_rasterization_state; RasterizationState m_current_rasterization_state;
DepthState m_current_depth_state; DepthState m_current_depth_state;
BlendingState m_current_blend_state; BlendingState m_current_blend_state;
GLuint m_shared_read_framebuffer = 0; u32 m_shared_read_framebuffer = 0;
GLuint m_shared_draw_framebuffer = 0; u32 m_shared_draw_framebuffer = 0;
float m_backbuffer_scale;
}; };
inline OGLGfx* GetOGLGfx()
{
return static_cast<OGLGfx*>(g_gfx.get());
}
} // namespace OGL } // namespace OGL

View File

@ -46,8 +46,10 @@ Make AA apply instantly during gameplay if possible
#include "Core/Config/GraphicsSettings.h" #include "Core/Config/GraphicsSettings.h"
#include "VideoBackends/OGL/OGLBoundingBox.h"
#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLPerfQuery.h" #include "VideoBackends/OGL/OGLPerfQuery.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h" #include "VideoBackends/OGL/SamplerCache.h"
@ -115,6 +117,8 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsTextureQueryLevels = false; g_Config.backend_info.bSupportsTextureQueryLevels = false;
g_Config.backend_info.bSupportsSettingObjectNames = false; g_Config.backend_info.bSupportsSettingObjectNames = false;
g_Config.backend_info.bUsesExplictQuadBuffering = true;
g_Config.backend_info.Adapters.clear(); g_Config.backend_info.Adapters.clear();
// aamodes - 1 is to stay consistent with D3D (means no AA) // aamodes - 1 is to stay consistent with D3D (means no AA)
@ -183,41 +187,23 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo()) if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo())
return false; return false;
InitializeShared(); auto gfx = std::make_unique<OGLGfx>(std::move(main_gl_context), wsi.render_surface_scale);
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context), wsi.render_surface_scale);
ProgramShaderCache::Init(); ProgramShaderCache::Init();
g_vertex_manager = std::make_unique<VertexManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_perf_query = GetPerfQuery();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_sampler_cache = std::make_unique<SamplerCache>(); g_sampler_cache = std::make_unique<SamplerCache>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() || auto vertex_manager = std::make_unique<VertexManager>();
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() || auto perf_query = GetPerfQuery(gfx->IsGLES());
!g_texture_cache->Initialize()) auto bounding_box = std::make_unique<OGLBoundingBox>();
{
PanicAlertFmtT("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache(); return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query),
return true; std::move(bounding_box));
} }
void VideoBackend::Shutdown() void VideoBackend::Shutdown()
{ {
g_shader_cache->Shutdown();
g_renderer->Shutdown();
g_sampler_cache.reset();
g_texture_cache.reset();
g_perf_query.reset();
g_vertex_manager.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
ProgramShaderCache::Shutdown();
g_renderer.reset();
ShutdownShared(); ShutdownShared();
ProgramShaderCache::Shutdown();
g_sampler_cache.reset();
} }
} // namespace OGL } // namespace OGL

View File

@ -6,7 +6,7 @@
#include "Common/GL/GLUtil.h" #include "Common/GL/GLUtil.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"
@ -19,7 +19,7 @@
namespace OGL namespace OGL
{ {
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) OGLGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
return std::make_unique<GLVertexFormat>(vtx_decl); return std::make_unique<GLVertexFormat>(vtx_decl);
} }

View File

@ -8,15 +8,15 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLExtensions/GLExtensions.h" #include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLGfx.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
namespace OGL namespace OGL
{ {
std::unique_ptr<PerfQueryBase> GetPerfQuery() std::unique_ptr<PerfQueryBase> GetPerfQuery(bool is_gles)
{ {
const bool is_gles = static_cast<Renderer*>(g_renderer.get())->IsGLES();
if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples")) if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples"))
return std::make_unique<PerfQueryGLESNV>(); return std::make_unique<PerfQueryGLESNV>();
else if (is_gles) else if (is_gles)
@ -165,7 +165,7 @@ void PerfQueryGL::FlushOne()
// TODO: Dropping the lower 2 bits from this count should be closer to actual // TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles. // hardware behavior when drawing triangles.
result = static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT / result = static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT /
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight()); (g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
// Adjust for multisampling // Adjust for multisampling
if (g_ActiveConfig.iMultisamples > 1) if (g_ActiveConfig.iMultisamples > 1)
@ -264,8 +264,9 @@ void PerfQueryGLESNV::FlushOne()
// NOTE: Reported pixel metrics should be referenced to native resolution // NOTE: Reported pixel metrics should be referenced to native resolution
// TODO: Dropping the lower 2 bits from this count should be closer to actual // TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles. // hardware behavior when drawing triangles.
const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT / const u64 native_res_result =
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight()); static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT /
(g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result), m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed); std::memory_order_relaxed);

View File

@ -12,7 +12,7 @@
namespace OGL namespace OGL
{ {
std::unique_ptr<PerfQueryBase> GetPerfQuery(); std::unique_ptr<PerfQueryBase> GetPerfQuery(bool is_gles);
class PerfQuery : public PerfQueryBase class PerfQuery : public PerfQueryBase
{ {

View File

@ -5,7 +5,6 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLShader.h" #include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"

View File

@ -8,7 +8,7 @@
#include "Common/MathUtil.h" #include "Common/MathUtil.h"
#include "Common/MemoryUtil.h" #include "Common/MemoryUtil.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"

View File

@ -7,6 +7,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/SamplerCache.h" #include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -160,7 +162,7 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config, std::string_view name)
OGLTexture::~OGLTexture() OGLTexture::~OGLTexture()
{ {
Renderer::GetInstance()->UnbindTexture(this); GetOGLGfx()->UnbindTexture(this);
glDeleteTextures(1, &m_texId); glDeleteTextures(1, &m_texId);
} }
@ -190,10 +192,10 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer, const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
u32 dst_level) u32 dst_level)
{ {
Renderer::GetInstance()->BindSharedReadFramebuffer(); GetOGLGfx()->BindSharedReadFramebuffer();
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level, glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
src_layer); src_layer);
Renderer::GetInstance()->BindSharedDrawFramebuffer(); GetOGLGfx()->BindSharedDrawFramebuffer();
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level, glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
dst_layer); dst_layer);
@ -206,7 +208,7 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
// The default state for the scissor test is enabled. We don't need to do a full state // The default state for the scissor test is enabled. We don't need to do a full state
// restore, as the framebuffer and scissor test are the only things we changed. // restore, as the framebuffer and scissor test are the only things we changed.
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
Renderer::GetInstance()->RestoreFramebufferBinding(); GetOGLGfx()->RestoreFramebufferBinding();
} }
void OGLTexture::ResolveFromTexture(const AbstractTexture* src, void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
@ -391,7 +393,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
else else
{ {
// Mutate the shared framebuffer. // Mutate the shared framebuffer.
Renderer::GetInstance()->BindSharedReadFramebuffer(); GetOGLGfx()->BindSharedReadFramebuffer();
if (AbstractTexture::IsDepthFormat(gltex->GetFormat())) if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
{ {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0); glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0);
@ -407,7 +409,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(), glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
GetGLFormatForTextureFormat(src->GetFormat()), GetGLFormatForTextureFormat(src->GetFormat()),
GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset)); GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset));
Renderer::GetInstance()->RestoreFramebufferBinding(); GetOGLGfx()->RestoreFramebufferBinding();
} }
glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0);
@ -600,7 +602,7 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
} }
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
Renderer::GetInstance()->RestoreFramebufferBinding(); GetOGLGfx()->RestoreFramebufferBinding();
return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format, return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
depth_format, width, height, layers, samples, fbo); depth_format, width, height, layers, samples, fbo);

View File

@ -12,8 +12,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLExtensions/GLExtensions.h" #include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLPipeline.h" #include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLStreamBuffer.h" #include "VideoBackends/OGL/OGLStreamBuffer.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"
@ -116,7 +116,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
// Bind the correct view to the texel buffer slot. // Bind the correct view to the texel buffer slot.
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]); glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
Renderer::GetInstance()->InvalidateTextureBinding(0); GetOGLGfx()->InvalidateTextureBinding(0);
return true; return true;
} }
@ -141,11 +141,11 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]); glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
Renderer::GetInstance()->InvalidateTextureBinding(0); GetOGLGfx()->InvalidateTextureBinding(0);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]); glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]);
Renderer::GetInstance()->InvalidateTextureBinding(1); GetOGLGfx()->InvalidateTextureBinding(1);
return true; return true;
} }

View File

@ -22,7 +22,8 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/System.h" #include "Core/System.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLShader.h" #include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLStreamBuffer.h" #include "VideoBackends/OGL/OGLStreamBuffer.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
@ -863,8 +864,7 @@ u64 ProgramShaderCache::GenerateShaderID()
bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param) bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
{ {
std::unique_ptr<GLContext> context = std::unique_ptr<GLContext> context = GetOGLGfx()->GetMainGLContext()->CreateSharedContext();
static_cast<Renderer*>(g_renderer.get())->GetMainGLContext()->CreateSharedContext();
if (!context) if (!context)
{ {
PanicAlertFmt("Failed to create shared context for shader compiling."); PanicAlertFmt("Failed to create shared context for shader compiling.");

View File

@ -6,7 +6,7 @@
#include <memory> #include <memory>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
namespace OGL namespace OGL

View File

@ -9,7 +9,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLUtil.h" #include "Common/GL/GLUtil.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoCommon/RenderState.h"
namespace OGL namespace OGL
{ {

View File

@ -14,6 +14,8 @@ add_library(videosoftware
SWmain.cpp SWmain.cpp
SWBoundingBox.cpp SWBoundingBox.cpp
SWBoundingBox.h SWBoundingBox.h
SWGfx.cpp
SWGfx.h
SWOGLWindow.cpp SWOGLWindow.cpp
SWOGLWindow.h SWOGLWindow.h
SWRenderer.cpp SWRenderer.cpp

View File

@ -0,0 +1,131 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Software/SWGfx.h"
#include "Common/GL/GLContext.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWTexture.h"
#include "VideoCommon/AbstractPipeline.h"
#include "VideoCommon/AbstractShader.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/Present.h"
namespace SW
{
SWGfx::SWGfx(std::unique_ptr<SWOGLWindow> window) : m_window(std::move(window))
{
}
bool SWGfx::IsHeadless() const
{
return m_window->IsHeadless();
}
bool SWGfx::SupportsUtilityDrawing() const
{
return false;
}
std::unique_ptr<AbstractTexture> SWGfx::CreateTexture(const TextureConfig& config,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<SWTexture>(config);
}
std::unique_ptr<AbstractStagingTexture> SWGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return std::make_unique<SWStagingTexture>(type, config);
}
std::unique_ptr<AbstractFramebuffer> SWGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return SWFramebuffer::Create(static_cast<SWTexture*>(color_attachment),
static_cast<SWTexture*>(depth_attachment));
}
void SWGfx::BindBackbuffer(const ClearColor& clear_color)
{
// Look for framebuffer resizes
if (!g_presenter->SurfaceResizedTestAndClear())
return;
GLContext* context = m_window->GetContext();
context->Update();
g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight());
}
class SWShader final : public AbstractShader
{
public:
explicit SWShader(ShaderStage stage) : AbstractShader(stage) {}
~SWShader() = default;
BinaryData GetBinary() const override { return {}; }
};
std::unique_ptr<AbstractShader>
SWGfx::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<SWShader>(stage);
}
std::unique_ptr<AbstractShader>
SWGfx::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<SWShader>(stage);
}
class SWPipeline final : public AbstractPipeline
{
public:
SWPipeline() = default;
~SWPipeline() override = default;
};
std::unique_ptr<AbstractPipeline> SWGfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return std::make_unique<SWPipeline>();
}
// Called on the GPU thread
void SWGfx::ShowImage(const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc)
{
if (!IsHeadless())
m_window->ShowImage(source_texture, source_rc);
}
void SWGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
bool alphaEnable, bool zEnable, u32 color, u32 z)
{
EfbCopy::ClearEfb();
}
std::unique_ptr<NativeVertexFormat>
SWGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<NativeVertexFormat>(vtx_decl);
}
void SWGfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
// BPFunctions calls SetScissorRect with the "best" scissor rect whenever the viewport or scissor
// changes. However, the software renderer is actually able to use multiple scissor rects (which
// is necessary in a few renderering edge cases, such as with Major Minor's Majestic March).
// Thus, we use this as a signal to update the list of scissor rects, but ignore the parameter.
Rasterizer::ScissorChanged();
}
} // namespace SW

View File

@ -0,0 +1,56 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "VideoCommon/AbstractGfx.h"
class SWOGLWindow;
namespace SW
{
class SWGfx final : public AbstractGfx
{
public:
SWGfx(std::unique_ptr<SWOGLWindow> window);
bool IsHeadless() const override;
virtual bool SupportsUtilityDrawing() const override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
void BindBackbuffer(const ClearColor& clear_color = {}) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length,
std::string_view name) override;
std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data = nullptr,
size_t cache_data_length = 0) override;
void ShowImage(const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc) override;
void ScaleTexture(AbstractFramebuffer* dst_framebuffer, const MathUtil::Rectangle<int>& dst_rect,
const AbstractTexture* src_texture,
const MathUtil::Rectangle<int>& src_rect) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z) override;
private:
std::unique_ptr<SWOGLWindow> m_window;
};
} // namespace SW

View File

@ -6,118 +6,18 @@
#include <string> #include <string>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLContext.h" #include "Common/MsgHandler.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/System.h" #include "Core/System.h"
#include "VideoBackends/Software/EfbCopy.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWBoundingBox.h"
#include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWTexture.h"
#include "VideoCommon/AbstractPipeline.h"
#include "VideoCommon/AbstractShader.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelEngine.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
namespace SW namespace SW
{ {
SWRenderer::SWRenderer(std::unique_ptr<SWOGLWindow> window)
: ::Renderer(static_cast<int>(std::max(window->GetContext()->GetBackBufferWidth(), 1u)),
static_cast<int>(std::max(window->GetContext()->GetBackBufferHeight(), 1u)), 1.0f,
AbstractTextureFormat::RGBA8),
m_window(std::move(window))
{
}
bool SWRenderer::IsHeadless() const
{
return m_window->IsHeadless();
}
std::unique_ptr<AbstractTexture> SWRenderer::CreateTexture(const TextureConfig& config,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<SWTexture>(config);
}
std::unique_ptr<AbstractStagingTexture>
SWRenderer::CreateStagingTexture(StagingTextureType type, const TextureConfig& config)
{
return std::make_unique<SWStagingTexture>(type, config);
}
std::unique_ptr<AbstractFramebuffer>
SWRenderer::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
{
return SWFramebuffer::Create(static_cast<SWTexture*>(color_attachment),
static_cast<SWTexture*>(depth_attachment));
}
void SWRenderer::BindBackbuffer(const ClearColor& clear_color)
{
// Look for framebuffer resizes
if (!m_surface_resized.TestAndClear())
return;
GLContext* context = m_window->GetContext();
context->Update();
m_backbuffer_width = context->GetBackBufferWidth();
m_backbuffer_height = context->GetBackBufferHeight();
}
class SWShader final : public AbstractShader
{
public:
explicit SWShader(ShaderStage stage) : AbstractShader(stage) {}
~SWShader() = default;
BinaryData GetBinary() const override { return {}; }
};
std::unique_ptr<AbstractShader>
SWRenderer::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<SWShader>(stage);
}
std::unique_ptr<AbstractShader>
SWRenderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return std::make_unique<SWShader>(stage);
}
class SWPipeline final : public AbstractPipeline
{
public:
SWPipeline() = default;
~SWPipeline() override = default;
};
std::unique_ptr<AbstractPipeline> SWRenderer::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return std::make_unique<SWPipeline>();
}
// Called on the GPU thread
void SWRenderer::RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc)
{
if (!IsHeadless())
m_window->ShowImage(source_texture, source_rc);
}
u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
{ {
u32 value = 0; u32 value = 0;
@ -166,29 +66,4 @@ u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
return value; return value;
} }
std::unique_ptr<BoundingBox> SWRenderer::CreateBoundingBox() const
{
return std::make_unique<SWBoundingBox>();
}
void SWRenderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z)
{
EfbCopy::ClearEfb();
}
std::unique_ptr<NativeVertexFormat>
SWRenderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<NativeVertexFormat>(vtx_decl);
}
void SWRenderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
// BPFunctions calls SetScissorRect with the "best" scissor rect whenever the viewport or scissor
// changes. However, the software renderer is actually able to use multiple scissor rects (which
// is necessary in a few renderering edge cases, such as with Major Minor's Majestic March).
// Thus, we use this as a signal to update the list of scissor rects, but ignore the parameter.
Rasterizer::ScissorChanged();
}
} // namespace SW } // namespace SW

View File

@ -10,60 +10,14 @@
#include "VideoCommon/RenderBase.h" #include "VideoCommon/RenderBase.h"
class BoundingBox;
class SWOGLWindow;
namespace SW namespace SW
{ {
class SWRenderer final : public Renderer class SWRenderer final : public Renderer
{ {
public: public:
SWRenderer(std::unique_ptr<SWOGLWindow> window);
bool IsHeadless() const override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
void BindBackbuffer(const ClearColor& clear_color = {}) override;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
std::string_view name) override;
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length,
std::string_view name) override;
std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data = nullptr,
size_t cache_data_length = 0) override;
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {} void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
void RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc) override;
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z) override;
void ReinterpretPixelData(EFBReinterpretType convtype) override {} void ReinterpretPixelData(EFBReinterpretType convtype) override {}
void ScaleTexture(AbstractFramebuffer* dst_framebuffer, const MathUtil::Rectangle<int>& dst_rect,
const AbstractTexture* src_texture,
const MathUtil::Rectangle<int>& src_rect) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
protected:
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private:
std::unique_ptr<SWOGLWindow> m_window;
}; };
} // namespace SW } // namespace SW

View File

@ -8,7 +8,7 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "VideoBackends/Software/CopyRegion.h" #include "VideoBackends/Software/CopyRegion.h"
#include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWGfx.h"
namespace SW namespace SW
{ {
@ -48,10 +48,10 @@ void CopyTextureData(const TextureConfig& src_config, const u8* src_ptr, u32 src
} }
} // namespace } // namespace
void SWRenderer::ScaleTexture(AbstractFramebuffer* dst_framebuffer, void SWGfx::ScaleTexture(AbstractFramebuffer* dst_framebuffer,
const MathUtil::Rectangle<int>& dst_rect, const MathUtil::Rectangle<int>& dst_rect,
const AbstractTexture* src_texture, const AbstractTexture* src_texture,
const MathUtil::Rectangle<int>& src_rect) const MathUtil::Rectangle<int>& src_rect)
{ {
const SWTexture* software_source_texture = static_cast<const SWTexture*>(src_texture); const SWTexture* software_source_texture = static_cast<const SWTexture*>(src_texture);
SWTexture* software_dest_texture = static_cast<SWTexture*>(dst_framebuffer->GetColorAttachment()); SWTexture* software_dest_texture = static_cast<SWTexture*>(dst_framebuffer->GetColorAttachment());

View File

@ -18,6 +18,7 @@
#include "VideoBackends/Software/Tev.h" #include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TransformUnit.h" #include "VideoBackends/Software/TransformUnit.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/CPMemory.h" #include "VideoCommon/CPMemory.h"
#include "VideoCommon/DataReader.h" #include "VideoCommon/DataReader.h"
#include "VideoCommon/IndexGenerator.h" #include "VideoCommon/IndexGenerator.h"
@ -62,8 +63,8 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_
} }
// Flush bounding box here because software overrides the base function // Flush bounding box here because software overrides the base function
if (g_renderer->IsBBoxEnabled()) if (g_bounding_box->IsEnabled())
g_renderer->BBoxFlush(); g_bounding_box->Flush();
m_setup_unit.Init(primitive_type); m_setup_unit.Init(primitive_type);
Rasterizer::SetTevKonstColors(); Rasterizer::SetTevKonstColors();

View File

@ -16,6 +16,8 @@
#include "VideoBackends/Software/Clipper.h" #include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/Rasterizer.h"
#include "VideoBackends/Software/SWBoundingBox.h"
#include "VideoBackends/Software/SWGfx.h"
#include "VideoBackends/Software/SWOGLWindow.h" #include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWRenderer.h"
#include "VideoBackends/Software/SWTexture.h" #include "VideoBackends/Software/SWTexture.h"
@ -23,6 +25,7 @@
#include "VideoBackends/Software/TextureCache.h" #include "VideoBackends/Software/TextureCache.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -96,8 +99,6 @@ void VideoSoftware::InitBackendInfo()
bool VideoSoftware::Initialize(const WindowSystemInfo& wsi) bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
{ {
InitializeShared();
std::unique_ptr<SWOGLWindow> window = SWOGLWindow::Create(wsi); std::unique_ptr<SWOGLWindow> window = SWOGLWindow::Create(wsi);
if (!window) if (!window)
return false; return false;
@ -105,40 +106,14 @@ bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
Clipper::Init(); Clipper::Init();
Rasterizer::Init(); Rasterizer::Init();
g_renderer = std::make_unique<SWRenderer>(std::move(window)); return InitializeShared(std::make_unique<SWGfx>(std::move(window)),
g_vertex_manager = std::make_unique<SWVertexLoader>(); std::make_unique<SWVertexLoader>(), std::make_unique<PerfQuery>(),
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>(); std::make_unique<SWBoundingBox>(), std::make_unique<SWRenderer>(),
g_framebuffer_manager = std::make_unique<FramebufferManager>(); std::make_unique<TextureCache>());
g_perf_query = std::make_unique<PerfQuery>();
g_texture_cache = std::make_unique<TextureCache>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
PanicAlertFmt("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache();
return true;
} }
void VideoSoftware::Shutdown() void VideoSoftware::Shutdown()
{ {
if (g_shader_cache)
g_shader_cache->Shutdown();
if (g_renderer)
g_renderer->Shutdown();
g_texture_cache.reset();
g_perf_query.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
g_vertex_manager.reset();
g_renderer.reset();
ShutdownShared(); ShutdownShared();
} }
} // namespace SW } // namespace SW

View File

@ -19,7 +19,7 @@ protected:
TextureEncoder::Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, TextureEncoder::Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride,
src_rect, scale_by_half, y_scale, gamma); src_rect, scale_by_half, y_scale, gamma);
} }
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, void CopyEFBToCacheEntry(RcTcacheEntry& entry, bool is_depth_copy,
const MathUtil::Rectangle<int>& src_rect, bool scale_by_half, const MathUtil::Rectangle<int>& src_rect, bool scale_by_half,
bool linear_filter, EFBCopyFormat dst_format, bool is_intensity, bool linear_filter, EFBCopyFormat dst_format, bool is_intensity,
float gamma, bool clamp_top, bool clamp_bottom, float gamma, bool clamp_top, bool clamp_bottom,

View File

@ -17,8 +17,8 @@ add_library(videovulkan
VKPerfQuery.h VKPerfQuery.h
VKPipeline.cpp VKPipeline.cpp
VKPipeline.h VKPipeline.h
VKRenderer.cpp VKGfx.cpp
VKRenderer.h VKGfx.h
VKShader.cpp VKShader.cpp
VKShader.h VKShader.h
VKStreamBuffer.cpp VKStreamBuffer.cpp

View File

@ -7,8 +7,8 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VKPipeline.h" #include "VideoBackends/Vulkan/VKPipeline.h"
#include "VideoBackends/Vulkan/VKRenderer.h"
#include "VideoBackends/Vulkan/VKShader.h" #include "VideoBackends/Vulkan/VKShader.h"
#include "VideoBackends/Vulkan/VKTexture.h" #include "VideoBackends/Vulkan/VKTexture.h"
#include "VideoBackends/Vulkan/VKVertexFormat.h" #include "VideoBackends/Vulkan/VKVertexFormat.h"

View File

@ -9,7 +9,6 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Vulkan/Constants.h" #include "VideoBackends/Vulkan/Constants.h"
#include "VideoCommon/RenderBase.h"
namespace Vulkan namespace Vulkan
{ {

View File

@ -11,7 +11,7 @@
#include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h" #include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h" #include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
namespace Vulkan namespace Vulkan
@ -65,7 +65,7 @@ std::vector<BBoxType> VKBoundingBox::Read(u32 index, u32 length)
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
// Wait until these commands complete. // Wait until these commands complete.
Renderer::GetInstance()->ExecuteCommandBuffer(false, true); VKGfx::GetInstance()->ExecuteCommandBuffer(false, true);
// Cache is now valid. // Cache is now valid.
m_readback_buffer->InvalidateCPUCache(); m_readback_buffer->InvalidateCPUCache();

View File

@ -8,6 +8,7 @@
#include <string> #include <string>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/VulkanLoader.h" #include "VideoBackends/Vulkan/VulkanLoader.h"
#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BoundingBox.h"

View File

@ -1,7 +1,7 @@
// Copyright 2016 Dolphin Emulator Project // Copyright 2016 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Vulkan/VKRenderer.h" #include "VideoBackends/Vulkan/VKGfx.h"
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
@ -15,152 +15,98 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Core/Core.h"
#include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKBoundingBox.h"
#include "VideoBackends/Vulkan/VKPerfQuery.h"
#include "VideoBackends/Vulkan/VKPipeline.h" #include "VideoBackends/Vulkan/VKPipeline.h"
#include "VideoBackends/Vulkan/VKShader.h" #include "VideoBackends/Vulkan/VKShader.h"
#include "VideoBackends/Vulkan/VKStreamBuffer.h"
#include "VideoBackends/Vulkan/VKSwapChain.h" #include "VideoBackends/Vulkan/VKSwapChain.h"
#include "VideoBackends/Vulkan/VKTexture.h" #include "VideoBackends/Vulkan/VKTexture.h"
#include "VideoBackends/Vulkan/VKVertexFormat.h" #include "VideoBackends/Vulkan/VKVertexFormat.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderState.h" #include "VideoCommon/RenderState.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace Vulkan namespace Vulkan
{ {
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale) VKGfx::VKGfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? static_cast<int>(swap_chain->GetWidth()) : 1, : m_swap_chain(std::move(swap_chain)), m_backbuffer_scale(backbuffer_scale)
swap_chain ? static_cast<int>(swap_chain->GetHeight()) : 0, backbuffer_scale,
swap_chain ? swap_chain->GetTextureFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
{ {
UpdateActiveConfig(); UpdateActiveConfig();
for (SamplerState& m_sampler_state : m_sampler_states) for (SamplerState& sampler_state : m_sampler_states)
m_sampler_state = RenderState::GetPointSamplerState(); sampler_state = RenderState::GetPointSamplerState();
}
Renderer::~Renderer() = default;
bool Renderer::IsHeadless() const
{
return m_swap_chain == nullptr;
}
bool Renderer::Initialize()
{
if (!::Renderer::Initialize())
return false;
// Various initialization routines will have executed commands on the command buffer. // Various initialization routines will have executed commands on the command buffer.
// Execute what we have done before beginning the first frame. // Execute what we have done before beginning the first frame.
ExecuteCommandBuffer(true, false); ExecuteCommandBuffer(true, false);
return true;
} }
void Renderer::Shutdown() VKGfx::~VKGfx() = default;
bool VKGfx::IsHeadless() const
{ {
::Renderer::Shutdown(); return m_swap_chain == nullptr;
m_swap_chain.reset();
} }
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> VKGfx::CreateTexture(const TextureConfig& config,
std::string_view name) std::string_view name)
{ {
return VKTexture::Create(config, name); return VKTexture::Create(config, name);
} }
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type, std::unique_ptr<AbstractStagingTexture> VKGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config) const TextureConfig& config)
{ {
return VKStagingTexture::Create(type, config); return VKStagingTexture::Create(type, config);
} }
std::unique_ptr<AbstractShader> std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name) VKGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{ {
return VKShader::CreateFromSource(stage, source, name); return VKShader::CreateFromSource(stage, source, name);
} }
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage, std::unique_ptr<AbstractShader> VKGfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
const void* data, size_t length, size_t length, std::string_view name)
std::string_view name)
{ {
return VKShader::CreateFromBinary(stage, data, length, name); return VKShader::CreateFromBinary(stage, data, length, name);
} }
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) VKGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
return std::make_unique<VertexFormat>(vtx_decl); return std::make_unique<VertexFormat>(vtx_decl);
} }
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config, std::unique_ptr<AbstractPipeline> VKGfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data, const void* cache_data,
size_t cache_data_length) size_t cache_data_length)
{ {
return VKPipeline::Create(config); return VKPipeline::Create(config);
} }
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment, std::unique_ptr<AbstractFramebuffer> VKGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment) AbstractTexture* depth_attachment)
{ {
return VKFramebuffer::Create(static_cast<VKTexture*>(color_attachment), return VKFramebuffer::Create(static_cast<VKTexture*>(color_attachment),
static_cast<VKTexture*>(depth_attachment)); static_cast<VKTexture*>(depth_attachment));
} }
void Renderer::SetPipeline(const AbstractPipeline* pipeline) void VKGfx::SetPipeline(const AbstractPipeline* pipeline)
{ {
StateTracker::GetInstance()->SetPipeline(static_cast<const VKPipeline*>(pipeline)); StateTracker::GetInstance()->SetPipeline(static_cast<const VKPipeline*>(pipeline));
} }
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const void VKGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable,
bool alpha_enable, bool z_enable, u32 color, u32 z)
{ {
return std::make_unique<VKBoundingBox>();
}
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable,
bool z_enable, u32 color, u32 z)
{
g_framebuffer_manager->FlushEFBPokes();
g_framebuffer_manager->FlagPeekCacheAsOutOfDate();
// Native -> EFB coordinates
MathUtil::Rectangle<int> target_rc = Renderer::ConvertEFBRectangle(rc);
// Size we pass this size to vkBeginRenderPass, it has to be clamped to the framebuffer
// dimensions. The other backends just silently ignore this case.
target_rc.ClampUL(0, 0, m_target_width, m_target_height);
VkRect2D target_vk_rc = { VkRect2D target_vk_rc = {
{target_rc.left, target_rc.top}, {target_rc.left, target_rc.top},
{static_cast<uint32_t>(target_rc.GetWidth()), static_cast<uint32_t>(target_rc.GetHeight())}}; {static_cast<uint32_t>(target_rc.GetWidth()), static_cast<uint32_t>(target_rc.GetHeight())}};
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF. This hopefully allows us to use the fast path in most cases.
if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 ||
bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 ||
bpmem.zcontrol.pixel_format == PixelFormat::Z24)
{
// Force alpha writes, and clear the alpha channel. This is different from the other backends,
// where the existing values of the alpha channel are preserved.
alpha_enable = true;
color &= 0x00FFFFFF;
}
// Convert RGBA8 -> floating-point values. // Convert RGBA8 -> floating-point values.
VkClearValue clear_color_value = {}; VkClearValue clear_color_value = {};
VkClearValue clear_depth_value = {}; VkClearValue clear_depth_value = {};
@ -244,20 +190,20 @@ void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable
if (!color_enable && !alpha_enable && !z_enable) if (!color_enable && !alpha_enable && !z_enable)
return; return;
g_framebuffer_manager->ClearEFB(rc, color_enable, alpha_enable, z_enable, color, z); AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z);
} }
void Renderer::Flush() void VKGfx::Flush()
{ {
ExecuteCommandBuffer(true, false); ExecuteCommandBuffer(true, false);
} }
void Renderer::WaitForGPUIdle() void VKGfx::WaitForGPUIdle()
{ {
ExecuteCommandBuffer(false, true); ExecuteCommandBuffer(false, true);
} }
void Renderer::BindBackbuffer(const ClearColor& clear_color) void VKGfx::BindBackbuffer(const ClearColor& clear_color)
{ {
StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->EndRenderPass();
@ -334,7 +280,7 @@ void Renderer::BindBackbuffer(const ClearColor& clear_color)
ClearColor{{0.0f, 0.0f, 0.0f, 1.0f}}); ClearColor{{0.0f, 0.0f, 0.0f, 1.0f}});
} }
void Renderer::PresentBackbuffer() void VKGfx::PresentBackbuffer()
{ {
// End drawing to backbuffer // End drawing to backbuffer
StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->EndRenderPass();
@ -355,7 +301,7 @@ void Renderer::PresentBackbuffer()
StateTracker::GetInstance()->InvalidateCachedState(); StateTracker::GetInstance()->InvalidateCachedState();
} }
void Renderer::SetFullscreen(bool enable_fullscreen) void VKGfx::SetFullscreen(bool enable_fullscreen)
{ {
if (!m_swap_chain->IsFullscreenSupported()) if (!m_swap_chain->IsFullscreenSupported())
return; return;
@ -363,12 +309,12 @@ void Renderer::SetFullscreen(bool enable_fullscreen)
m_swap_chain->SetNextFullscreenState(enable_fullscreen); m_swap_chain->SetNextFullscreenState(enable_fullscreen);
} }
bool Renderer::IsFullscreen() const bool VKGfx::IsFullscreen() const
{ {
return m_swap_chain && m_swap_chain->GetCurrentFullscreenState(); return m_swap_chain && m_swap_chain->GetCurrentFullscreenState();
} }
void Renderer::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion) void VKGfx::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion)
{ {
StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->EndRenderPass();
@ -377,9 +323,9 @@ void Renderer::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_comple
StateTracker::GetInstance()->InvalidateCachedState(); StateTracker::GetInstance()->InvalidateCachedState();
} }
void Renderer::CheckForSurfaceChange() void VKGfx::CheckForSurfaceChange()
{ {
if (!m_surface_changed.TestAndClear() || !m_swap_chain) if (!g_presenter->SurfaceChangedTestAndClear() || !m_swap_chain)
return; return;
// Submit the current draws up until rendering the XFB. // Submit the current draws up until rendering the XFB.
@ -389,17 +335,16 @@ void Renderer::CheckForSurfaceChange()
g_command_buffer_mgr->CheckLastPresentFail(); g_command_buffer_mgr->CheckLastPresentFail();
// Recreate the surface. If this fails we're in trouble. // Recreate the surface. If this fails we're in trouble.
if (!m_swap_chain->RecreateSurface(m_new_surface_handle)) if (!m_swap_chain->RecreateSurface(g_presenter->GetNewSurfaceHandle()))
PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue."); PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue.");
m_new_surface_handle = nullptr;
// Handle case where the dimensions are now different. // Handle case where the dimensions are now different.
OnSwapChainResized(); OnSwapChainResized();
} }
void Renderer::CheckForSurfaceResize() void VKGfx::CheckForSurfaceResize()
{ {
if (!m_surface_resized.TestAndClear()) if (!g_presenter->SurfaceResizedTestAndClear())
return; return;
// If we don't have a surface, how can we resize the swap chain? // If we don't have a surface, how can we resize the swap chain?
@ -421,8 +366,10 @@ void Renderer::CheckForSurfaceResize()
OnSwapChainResized(); OnSwapChainResized();
} }
void Renderer::OnConfigChanged(u32 bits) void VKGfx::OnConfigChanged(u32 bits)
{ {
AbstractGfx::OnConfigChanged(bits);
if (bits & CONFIG_CHANGE_BIT_HOST_CONFIG) if (bits & CONFIG_CHANGE_BIT_HOST_CONFIG)
g_object_cache->ReloadPipelineCache(); g_object_cache->ReloadPipelineCache();
@ -448,13 +395,12 @@ void Renderer::OnConfigChanged(u32 bits)
} }
} }
void Renderer::OnSwapChainResized() void VKGfx::OnSwapChainResized()
{ {
m_backbuffer_width = m_swap_chain->GetWidth(); g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
m_backbuffer_height = m_swap_chain->GetHeight();
} }
void Renderer::BindFramebuffer(VKFramebuffer* fb) void VKGfx::BindFramebuffer(VKFramebuffer* fb)
{ {
StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->EndRenderPass();
@ -475,7 +421,7 @@ void Renderer::BindFramebuffer(VKFramebuffer* fb)
m_current_framebuffer = fb; m_current_framebuffer = fb;
} }
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) void VKGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{ {
if (m_current_framebuffer == framebuffer) if (m_current_framebuffer == framebuffer)
return; return;
@ -484,7 +430,7 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
BindFramebuffer(vkfb); BindFramebuffer(vkfb);
} }
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) void VKGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{ {
if (m_current_framebuffer == framebuffer) if (m_current_framebuffer == framebuffer)
return; return;
@ -497,8 +443,8 @@ void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
StateTracker::GetInstance()->BeginDiscardRenderPass(); StateTracker::GetInstance()->BeginDiscardRenderPass();
} }
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, void VKGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
const ClearColor& color_value, float depth_value) float depth_value)
{ {
VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer); VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb); BindFramebuffer(vkfb);
@ -521,7 +467,7 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
num_clear_values); num_clear_values);
} }
void Renderer::SetTexture(u32 index, const AbstractTexture* texture) void VKGfx::SetTexture(u32 index, const AbstractTexture* texture)
{ {
// Texture should always be in SHADER_READ_ONLY layout prior to use. // Texture should always be in SHADER_READ_ONLY layout prior to use.
// This is so we don't need to transition during render passes. // This is so we don't need to transition during render passes.
@ -532,7 +478,7 @@ void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
{ {
if (StateTracker::GetInstance()->InRenderPass()) if (StateTracker::GetInstance()->InRenderPass())
{ {
WARN_LOG_FMT(VIDEO, "Transitioning image in render pass in Renderer::SetTexture()"); WARN_LOG_FMT(VIDEO, "Transitioning image in render pass in VKGfx::SetTexture()");
StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->EndRenderPass();
} }
@ -548,7 +494,7 @@ void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
} }
} }
void Renderer::SetSamplerState(u32 index, const SamplerState& state) void VKGfx::SetSamplerState(u32 index, const SamplerState& state)
{ {
// Skip lookup if the state hasn't changed. // Skip lookup if the state hasn't changed.
if (m_sampler_states[index] == state) if (m_sampler_states[index] == state)
@ -566,7 +512,7 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
m_sampler_states[index] = state; m_sampler_states[index] = state;
} }
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) void VKGfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{ {
VKTexture* vk_texture = static_cast<VKTexture*>(texture); VKTexture* vk_texture = static_cast<VKTexture*>(texture);
if (vk_texture) if (vk_texture)
@ -584,12 +530,12 @@ void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool
} }
} }
void Renderer::UnbindTexture(const AbstractTexture* texture) void VKGfx::UnbindTexture(const AbstractTexture* texture)
{ {
StateTracker::GetInstance()->UnbindTexture(static_cast<const VKTexture*>(texture)->GetView()); StateTracker::GetInstance()->UnbindTexture(static_cast<const VKTexture*>(texture)->GetView());
} }
void Renderer::ResetSamplerStates() void VKGfx::ResetSamplerStates()
{ {
// Invalidate all sampler states, next draw will re-initialize them. // Invalidate all sampler states, next draw will re-initialize them.
for (u32 i = 0; i < m_sampler_states.size(); i++) for (u32 i = 0; i < m_sampler_states.size(); i++)
@ -602,7 +548,7 @@ void Renderer::ResetSamplerStates()
g_object_cache->ClearSamplerCache(); g_object_cache->ClearSamplerCache();
} }
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) void VKGfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{ {
VkRect2D scissor = {{rc.left, rc.top}, VkRect2D scissor = {{rc.left, rc.top},
{static_cast<u32>(rc.GetWidth()), static_cast<u32>(rc.GetHeight())}}; {static_cast<u32>(rc.GetWidth()), static_cast<u32>(rc.GetHeight())}};
@ -622,14 +568,14 @@ void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
StateTracker::GetInstance()->SetScissor(scissor); StateTracker::GetInstance()->SetScissor(scissor);
} }
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth, void VKGfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) float far_depth)
{ {
VkViewport viewport = {x, y, width, height, near_depth, far_depth}; VkViewport viewport = {x, y, width, height, near_depth, far_depth};
StateTracker::GetInstance()->SetViewport(viewport); StateTracker::GetInstance()->SetViewport(viewport);
} }
void Renderer::Draw(u32 base_vertex, u32 num_vertices) void VKGfx::Draw(u32 base_vertex, u32 num_vertices)
{ {
if (!StateTracker::GetInstance()->Bind()) if (!StateTracker::GetInstance()->Bind())
return; return;
@ -637,7 +583,7 @@ void Renderer::Draw(u32 base_vertex, u32 num_vertices)
vkCmdDraw(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_vertices, 1, base_vertex, 0); vkCmdDraw(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_vertices, 1, base_vertex, 0);
} }
void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) void VKGfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{ {
if (!StateTracker::GetInstance()->Bind()) if (!StateTracker::GetInstance()->Bind())
return; return;
@ -646,12 +592,19 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
base_vertex, 0); base_vertex, 0);
} }
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y, void VKGfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{ {
StateTracker::GetInstance()->SetComputeShader(static_cast<const VKShader*>(shader)); StateTracker::GetInstance()->SetComputeShader(static_cast<const VKShader*>(shader));
if (StateTracker::GetInstance()->BindCompute()) if (StateTracker::GetInstance()->BindCompute())
vkCmdDispatch(g_command_buffer_mgr->GetCurrentCommandBuffer(), groups_x, groups_y, groups_z); vkCmdDispatch(g_command_buffer_mgr->GetCurrentCommandBuffer(), groups_x, groups_y, groups_z);
} }
SurfaceInfo VKGfx::GetSurfaceInfo() const
{
return {m_swap_chain ? m_swap_chain->GetWidth() : 1u,
m_swap_chain ? m_swap_chain->GetHeight() : 0u, m_backbuffer_scale,
m_swap_chain ? m_swap_chain->GetTextureFormat() : AbstractTextureFormat::Undefined};
}
} // namespace Vulkan } // namespace Vulkan

View File

@ -4,16 +4,12 @@
#pragma once #pragma once
#include <array> #include <array>
#include <cstddef>
#include <memory> #include <memory>
#include <string_view> #include <string_view>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/Vulkan/Constants.h" #include "VideoBackends/Vulkan/Constants.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/AbstractGfx.h"
class BoundingBox;
struct XFBSourceBase;
namespace Vulkan namespace Vulkan
{ {
@ -23,19 +19,16 @@ class VKFramebuffer;
class VKPipeline; class VKPipeline;
class VKTexture; class VKTexture;
class Renderer : public ::Renderer class VKGfx final : public ::AbstractGfx
{ {
public: public:
Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale); VKGfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~Renderer() override; ~VKGfx() override;
static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); } static VKGfx* GetInstance() { return static_cast<VKGfx*>(g_gfx.get()); }
bool IsHeadless() const override; bool IsHeadless() const override;
bool Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override; std::string_view name) override;
std::unique_ptr<AbstractStagingTexture> std::unique_ptr<AbstractStagingTexture>
@ -60,7 +53,7 @@ public:
void WaitForGPUIdle() override; void WaitForGPUIdle() override;
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable, void ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable, bool alpha_enable,
bool z_enable, u32 color, u32 z) override; bool z_enable, u32 color, u32 z) override;
void SetPipeline(const AbstractPipeline* pipeline) override; void SetPipeline(const AbstractPipeline* pipeline) override;
@ -84,13 +77,12 @@ public:
void SetFullscreen(bool enable_fullscreen) override; void SetFullscreen(bool enable_fullscreen) override;
bool IsFullscreen() const override; bool IsFullscreen() const override;
virtual SurfaceInfo GetSurfaceInfo() const override;
// Completes the current render pass, executes the command buffer, and restores state ready for // Completes the current render pass, executes the command buffer, and restores state ready for
// next render. Use when you want to kick the current buffer to make room for new data. // next render. Use when you want to kick the current buffer to make room for new data.
void ExecuteCommandBuffer(bool execute_off_thread, bool wait_for_completion = false); void ExecuteCommandBuffer(bool execute_off_thread, bool wait_for_completion = false);
protected:
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private: private:
void CheckForSurfaceChange(); void CheckForSurfaceChange();
void CheckForSurfaceResize(); void CheckForSurfaceResize();
@ -101,6 +93,7 @@ private:
void BindFramebuffer(VKFramebuffer* fb); void BindFramebuffer(VKFramebuffer* fb);
std::unique_ptr<SwapChain> m_swap_chain; std::unique_ptr<SwapChain> m_swap_chain;
float m_backbuffer_scale;
// Keep a copy of sampler states to avoid cache lookups every draw // Keep a copy of sampler states to avoid cache lookups every draw
std::array<SamplerState, NUM_PIXEL_SHADER_SAMPLERS> m_sampler_states = {}; std::array<SamplerState, NUM_PIXEL_SHADER_SAMPLERS> m_sampler_states = {};

View File

@ -12,8 +12,9 @@
#include "VideoBackends/Vulkan/Constants.h" #include "VideoBackends/Vulkan/Constants.h"
#include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKBoundingBox.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VKPerfQuery.h" #include "VideoBackends/Vulkan/VKPerfQuery.h"
#include "VideoBackends/Vulkan/VKRenderer.h"
#include "VideoBackends/Vulkan/VKSwapChain.h" #include "VideoBackends/Vulkan/VKSwapChain.h"
#include "VideoBackends/Vulkan/VKVertexManager.h" #include "VideoBackends/Vulkan/VKVertexManager.h"
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
@ -193,8 +194,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
g_Config.backend_info.bSupportsExclusiveFullscreen = g_Config.backend_info.bSupportsExclusiveFullscreen =
enable_surface && g_vulkan_context->SupportsExclusiveFullscreen(wsi, surface); enable_surface && g_vulkan_context->SupportsExclusiveFullscreen(wsi, surface);
// With the backend information populated, we can now initialize videocommon. UpdateActiveConfig();
InitializeShared();
// Create command buffers. We do this separately because the other classes depend on it. // Create command buffers. We do this separately because the other classes depend on it.
g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading); g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
@ -234,25 +234,13 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
return false; return false;
} }
// Create main wrapper instances. auto gfx = std::make_unique<VKGfx>(std::move(swap_chain), wsi.render_surface_scale);
g_renderer = std::make_unique<Renderer>(std::move(swap_chain), wsi.render_surface_scale); auto vertex_manager = std::make_unique<VertexManager>();
g_vertex_manager = std::make_unique<VertexManager>(); auto perf_query = std::make_unique<PerfQuery>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>(); auto bounding_box = std::make_unique<VKBoundingBox>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_perf_query = std::make_unique<PerfQuery>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() || return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query),
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() || std::move(bounding_box));
!g_texture_cache->Initialize() || !PerfQuery::GetInstance()->Initialize())
{
PanicAlertFmt("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache();
return true;
} }
void VideoBackend::Shutdown() void VideoBackend::Shutdown()
@ -260,26 +248,15 @@ void VideoBackend::Shutdown()
if (g_vulkan_context) if (g_vulkan_context)
vkDeviceWaitIdle(g_vulkan_context->GetDevice()); vkDeviceWaitIdle(g_vulkan_context->GetDevice());
if (g_shader_cache)
g_shader_cache->Shutdown();
if (g_object_cache) if (g_object_cache)
g_object_cache->Shutdown(); g_object_cache->Shutdown();
if (g_renderer) ShutdownShared();
g_renderer->Shutdown();
g_perf_query.reset();
g_texture_cache.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
g_vertex_manager.reset();
g_renderer.reset();
g_object_cache.reset(); g_object_cache.reset();
StateTracker::DestroyInstance(); StateTracker::DestroyInstance();
g_command_buffer_mgr.reset(); g_command_buffer_mgr.reset();
g_vulkan_context.reset(); g_vulkan_context.reset();
ShutdownShared();
UnloadVulkanLibrary(); UnloadVulkanLibrary();
} }

View File

@ -13,8 +13,9 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h" #include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
namespace Vulkan namespace Vulkan
@ -218,8 +219,8 @@ void PerfQuery::ReadbackQueries(u32 query_count)
// NOTE: Reported pixel metrics should be referenced to native resolution // NOTE: Reported pixel metrics should be referenced to native resolution
const u64 native_res_result = static_cast<u64>(m_query_result_buffer[i]) * EFB_WIDTH / const u64 native_res_result = static_cast<u64>(m_query_result_buffer[i]) * EFB_WIDTH /
g_renderer->GetTargetWidth() * EFB_HEIGHT / g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight(); g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result), m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed); std::memory_order_relaxed);
} }
@ -234,7 +235,7 @@ void PerfQuery::PartialFlush(bool blocking)
if (blocking || m_query_buffer[m_query_readback_pos].fence_counter == if (blocking || m_query_buffer[m_query_readback_pos].fence_counter ==
g_command_buffer_mgr->GetCurrentFenceCounter()) g_command_buffer_mgr->GetCurrentFenceCounter())
{ {
Renderer::GetInstance()->ExecuteCommandBuffer(true, blocking); VKGfx::GetInstance()->ExecuteCommandBuffer(true, blocking);
} }
ReadbackQueries(); ReadbackQueries();

View File

@ -20,7 +20,7 @@ public:
static PerfQuery* GetInstance() { return static_cast<PerfQuery*>(g_perf_query.get()); } static PerfQuery* GetInstance() { return static_cast<PerfQuery*>(g_perf_query.get()); }
bool Initialize(); bool Initialize() override;
void EnableQuery(PerfQueryGroup group) override; void EnableQuery(PerfQueryGroup group) override;
void DisableQuery(PerfQueryGroup group) override; void DisableQuery(PerfQueryGroup group) override;

View File

@ -15,7 +15,7 @@
#include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/VKTexture.h" #include "VideoBackends/Vulkan/VKTexture.h"
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#if defined(VK_USE_PLATFORM_XLIB_KHR) #if defined(VK_USE_PLATFORM_XLIB_KHR)
#include <X11/Xlib.h> #include <X11/Xlib.h>
@ -265,8 +265,8 @@ bool SwapChain::CreateSwapChain()
VkExtent2D size = surface_capabilities.currentExtent; VkExtent2D size = surface_capabilities.currentExtent;
if (size.width == UINT32_MAX) if (size.width == UINT32_MAX)
{ {
size.width = std::max(g_renderer->GetBackbufferWidth(), 1); size.width = std::max(g_presenter->GetBackbufferWidth(), 1);
size.height = std::max(g_renderer->GetBackbufferHeight(), 1); size.height = std::max(g_presenter->GetBackbufferHeight(), 1);
} }
size.width = std::clamp(size.width, surface_capabilities.minImageExtent.width, size.width = std::clamp(size.width, surface_capabilities.minImageExtent.width,
surface_capabilities.maxImageExtent.width); surface_capabilities.maxImageExtent.width);

View File

@ -17,7 +17,7 @@
#include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h" #include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h" #include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VKStreamBuffer.h" #include "VideoBackends/Vulkan/VKStreamBuffer.h"
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
@ -367,7 +367,7 @@ void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8*
// Execute the command buffer first. // Execute the command buffer first.
WARN_LOG_FMT(VIDEO, WARN_LOG_FMT(VIDEO,
"Executing command list while waiting for space in texture upload buffer"); "Executing command list while waiting for space in texture upload buffer");
Renderer::GetInstance()->ExecuteCommandBuffer(false); VKGfx::GetInstance()->ExecuteCommandBuffer(false);
// Try allocating again. This may cause a fence wait. // Try allocating again. This may cause a fence wait.
if (!stream_buffer->ReserveMemory(upload_size, upload_alignment)) if (!stream_buffer->ReserveMemory(upload_size, upload_alignment))
@ -967,7 +967,7 @@ void VKStagingTexture::Flush()
if (g_command_buffer_mgr->GetCurrentFenceCounter() == m_flush_fence_counter) if (g_command_buffer_mgr->GetCurrentFenceCounter() == m_flush_fence_counter)
{ {
// Execute the command buffer and wait for it to finish. // Execute the command buffer and wait for it to finish.
Renderer::GetInstance()->ExecuteCommandBuffer(false, true); VKGfx::GetInstance()->ExecuteCommandBuffer(false, true);
} }
else else
{ {

View File

@ -14,7 +14,7 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h" #include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VKStreamBuffer.h" #include "VideoBackends/Vulkan/VKStreamBuffer.h"
#include "VideoBackends/Vulkan/VKVertexFormat.h" #include "VideoBackends/Vulkan/VKVertexFormat.h"
#include "VideoBackends/Vulkan/VulkanContext.h" #include "VideoBackends/Vulkan/VulkanContext.h"
@ -152,7 +152,7 @@ void VertexManager::ResetBuffer(u32 vertex_stride)
{ {
// Flush any pending commands first, so that we can wait on the fences // Flush any pending commands first, so that we can wait on the fences
WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in vertex/index buffer"); WARN_LOG_FMT(VIDEO, "Executing command list while waiting for space in vertex/index buffer");
Renderer::GetInstance()->ExecuteCommandBuffer(false); VKGfx::GetInstance()->ExecuteCommandBuffer(false);
// Attempt to allocate again, this may cause a fence wait // Attempt to allocate again, this may cause a fence wait
if (!has_vbuffer_allocation) if (!has_vbuffer_allocation)
@ -266,7 +266,7 @@ bool VertexManager::ReserveConstantStorage()
// The only places that call constant updates are safe to have state restored. // The only places that call constant updates are safe to have state restored.
WARN_LOG_FMT(VIDEO, "Executing command buffer while waiting for space in uniform buffer"); WARN_LOG_FMT(VIDEO, "Executing command buffer while waiting for space in uniform buffer");
Renderer::GetInstance()->ExecuteCommandBuffer(false); VKGfx::GetInstance()->ExecuteCommandBuffer(false);
// Since we are on a new command buffer, all constants have been invalidated, and we need // Since we are on a new command buffer, all constants have been invalidated, and we need
// to reupload them. We may as well do this now, since we're issuing a draw anyway. // to reupload them. We may as well do this now, since we're issuing a draw anyway.
@ -337,7 +337,7 @@ void VertexManager::UploadUtilityUniforms(const void* data, u32 data_size)
g_vulkan_context->GetUniformBufferAlignment())) g_vulkan_context->GetUniformBufferAlignment()))
{ {
WARN_LOG_FMT(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer"); WARN_LOG_FMT(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer");
Renderer::GetInstance()->ExecuteCommandBuffer(false); VKGfx::GetInstance()->ExecuteCommandBuffer(false);
} }
StateTracker::GetInstance()->SetUtilityUniformBuffer( StateTracker::GetInstance()->SetUtilityUniformBuffer(
@ -358,7 +358,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
{ {
// Try submitting cmdbuffer. // Try submitting cmdbuffer.
WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer"); WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer");
Renderer::GetInstance()->ExecuteCommandBuffer(false, false); VKGfx::GetInstance()->ExecuteCommandBuffer(false, false);
if (!m_texel_stream_buffer->ReserveMemory(data_size, elem_size)) if (!m_texel_stream_buffer->ReserveMemory(data_size, elem_size))
{ {
PanicAlertFmt("Failed to allocate {} bytes from texel buffer", data_size); PanicAlertFmt("Failed to allocate {} bytes from texel buffer", data_size);
@ -388,7 +388,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
{ {
// Try submitting cmdbuffer. // Try submitting cmdbuffer.
WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer"); WARN_LOG_FMT(VIDEO, "Submitting command buffer while waiting for space in texel buffer");
Renderer::GetInstance()->ExecuteCommandBuffer(false, false); VKGfx::GetInstance()->ExecuteCommandBuffer(false, false);
if (!m_texel_stream_buffer->ReserveMemory(reserve_size, elem_size)) if (!m_texel_stream_buffer->ReserveMemory(reserve_size, elem_size))
{ {
PanicAlertFmt("Failed to allocate {} bytes from texel buffer", reserve_size); PanicAlertFmt("Failed to allocate {} bytes from texel buffer", reserve_size);

View File

@ -0,0 +1,180 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/AbstractGfx.h"
#include "Common/Assert.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/ShaderCache.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoConfig.h"
std::unique_ptr<AbstractGfx> g_gfx;
AbstractGfx::AbstractGfx()
{
ConfigChangedEvent::Register([this](u32 bits) { OnConfigChanged(bits); }, "AbstractGfx");
}
bool AbstractGfx::IsHeadless() const
{
return true;
}
void AbstractGfx::BeginUtilityDrawing()
{
g_vertex_manager->Flush();
}
void AbstractGfx::EndUtilityDrawing()
{
// Reset framebuffer/scissor/viewport. Pipeline will be reset at next draw.
g_framebuffer_manager->BindEFBFramebuffer();
BPFunctions::SetScissorAndViewport();
}
void AbstractGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
m_current_framebuffer = framebuffer;
}
void AbstractGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
m_current_framebuffer = framebuffer;
}
void AbstractGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
m_current_framebuffer = framebuffer;
}
void AbstractGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
bool alphaEnable, bool zEnable, u32 color, u32 z)
{
// This is a generic fallback for any ClearRegion operations that backends don't support.
// It simply draws a Quad.
BeginUtilityDrawing();
// Set up uniforms.
struct Uniforms
{
float clear_color[4];
float clear_depth;
float padding1, padding2, padding3;
};
static_assert(std::is_standard_layout<Uniforms>::value);
Uniforms uniforms = {{static_cast<float>((color >> 16) & 0xFF) / 255.0f,
static_cast<float>((color >> 8) & 0xFF) / 255.0f,
static_cast<float>((color >> 0) & 0xFF) / 255.0f,
static_cast<float>((color >> 24) & 0xFF) / 255.0f},
static_cast<float>(z & 0xFFFFFF) / 16777216.0f};
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
uniforms.clear_depth = 1.0f - uniforms.clear_depth;
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
g_gfx->SetPipeline(g_framebuffer_manager->GetClearPipeline(colorEnable, alphaEnable, zEnable));
g_gfx->SetViewportAndScissor(target_rc);
g_gfx->Draw(0, 3);
EndUtilityDrawing();
}
void AbstractGfx::SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth,
float max_depth)
{
SetViewport(static_cast<float>(rect.left), static_cast<float>(rect.top),
static_cast<float>(rect.GetWidth()), static_cast<float>(rect.GetHeight()), min_depth,
max_depth);
SetScissorRect(rect);
}
void AbstractGfx::ScaleTexture(AbstractFramebuffer* dst_framebuffer,
const MathUtil::Rectangle<int>& dst_rect,
const AbstractTexture* src_texture,
const MathUtil::Rectangle<int>& src_rect)
{
ASSERT(dst_framebuffer->GetColorFormat() == AbstractTextureFormat::RGBA8);
BeginUtilityDrawing();
// The shader needs to know the source rectangle.
const auto converted_src_rect =
ConvertFramebufferRectangle(src_rect, src_texture->GetWidth(), src_texture->GetHeight());
const float rcp_src_width = 1.0f / src_texture->GetWidth();
const float rcp_src_height = 1.0f / src_texture->GetHeight();
const std::array<float, 4> uniforms = {{converted_src_rect.left * rcp_src_width,
converted_src_rect.top * rcp_src_height,
converted_src_rect.GetWidth() * rcp_src_width,
converted_src_rect.GetHeight() * rcp_src_height}};
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
// Discard if we're overwriting the whole thing.
if (static_cast<u32>(dst_rect.GetWidth()) == dst_framebuffer->GetWidth() &&
static_cast<u32>(dst_rect.GetHeight()) == dst_framebuffer->GetHeight())
{
SetAndDiscardFramebuffer(dst_framebuffer);
}
else
{
SetFramebuffer(dst_framebuffer);
}
SetViewportAndScissor(ConvertFramebufferRectangle(dst_rect, dst_framebuffer));
SetPipeline(dst_framebuffer->GetLayers() > 1 ? g_shader_cache->GetRGBA8StereoCopyPipeline() :
g_shader_cache->GetRGBA8CopyPipeline());
SetTexture(0, src_texture);
SetSamplerState(0, RenderState::GetLinearSamplerState());
Draw(0, 3);
EndUtilityDrawing();
if (dst_framebuffer->GetColorAttachment())
dst_framebuffer->GetColorAttachment()->FinishedRendering();
}
MathUtil::Rectangle<int>
AbstractGfx::ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
const AbstractFramebuffer* framebuffer) const
{
return ConvertFramebufferRectangle(rect, framebuffer->GetWidth(), framebuffer->GetHeight());
}
MathUtil::Rectangle<int>
AbstractGfx::ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect, u32 fb_width,
u32 fb_height) const
{
MathUtil::Rectangle<int> ret = rect;
if (g_ActiveConfig.backend_info.bUsesLowerLeftOrigin)
{
ret.top = fb_height - rect.bottom;
ret.bottom = fb_height - rect.top;
}
return ret;
}
std::unique_ptr<VideoCommon::AsyncShaderCompiler> AbstractGfx::CreateAsyncShaderCompiler()
{
return std::make_unique<VideoCommon::AsyncShaderCompiler>();
}
void AbstractGfx::OnConfigChanged(u32 changed_bits)
{
// If there's any shader changes, wait for the GPU to finish before destroying anything.
if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES))
{
WaitForGPUIdle();
SetPipeline(nullptr);
}
}
bool AbstractGfx::UseGeometryShaderForUI() const
{
// OpenGL doesn't render to a 2-layer backbuffer like D3D/Vulkan for quad-buffered stereo,
// instead drawing twice and the eye selected by glDrawBuffer() (see Presenter::RenderXFBToScreen)
return g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer &&
g_ActiveConfig.backend_info.api_type != APIType::OpenGL;
}

View File

@ -0,0 +1,171 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "Common/MathUtil.h"
#include "VideoCommon/RenderState.h"
#include <array>
#include <memory>
class AbstractFramebuffer;
class AbstractPipeline;
class AbstractShader;
class AbstractTexture;
class AbstractStagingTexture;
class NativeVertexFormat;
struct ComputePipelineConfig;
struct AbstractPipelineConfig;
struct PortableVertexDeclaration;
struct TextureConfig;
enum class AbstractTextureFormat : u32;
enum class ShaderStage;
enum class StagingTextureType;
struct SurfaceInfo
{
u32 width = 0;
u32 height = 0;
float scale = 0.0f;
AbstractTextureFormat format = {};
};
namespace VideoCommon
{
class AsyncShaderCompiler;
}
using ClearColor = std::array<float, 4>;
// AbstractGfx is the root of Dolphin's Graphics API abstraction layer.
//
// Abstract knows nothing about the internals of the GameCube/Wii, that is all handled elsewhere in
// VideoCommon.
class AbstractGfx
{
public:
AbstractGfx();
virtual ~AbstractGfx() = default;
virtual bool IsHeadless() const = 0;
// Does the backend support drawing a UI or doing post-processing
virtual bool SupportsUtilityDrawing() const { return true; }
virtual void SetPipeline(const AbstractPipeline* pipeline) {}
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
virtual void SetTexture(u32 index, const AbstractTexture* texture) {}
virtual void SetSamplerState(u32 index, const SamplerState& state) {}
virtual void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) {}
virtual void UnbindTexture(const AbstractTexture* texture) {}
virtual void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
}
virtual void SetFullscreen(bool enable_fullscreen) {}
virtual bool IsFullscreen() const { return false; }
virtual void BeginUtilityDrawing();
virtual void EndUtilityDrawing();
virtual std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name = "") = 0;
virtual std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
virtual std::unique_ptr<AbstractFramebuffer>
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0;
// Framebuffer operations.
virtual void SetFramebuffer(AbstractFramebuffer* framebuffer);
virtual void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer);
virtual void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value = {}, float depth_value = 0.0f);
virtual void ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
bool alphaEnable, bool zEnable, u32 color, u32 z);
// Drawing with currently-bound pipeline state.
virtual void Draw(u32 base_vertex, u32 num_vertices) {}
virtual void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) {}
// Dispatching compute shaders with currently-bound state.
virtual void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
}
// Binds the backbuffer for rendering. The buffer will be cleared immediately after binding.
// This is where any window size changes are detected, therefore m_backbuffer_width and/or
// m_backbuffer_height may change after this function returns.
virtual void BindBackbuffer(const ClearColor& clear_color = {}) {}
// Presents the backbuffer to the window system, or "swaps buffers".
virtual void PresentBackbuffer() {}
// Shader modules/objects.
virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
std::string_view source,
std::string_view name = "") = 0;
virtual std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length,
std::string_view name = "") = 0;
virtual std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0;
virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data = nullptr,
size_t cache_data_length = 0) = 0;
AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }
// Sets viewport and scissor to the specified rectangle. rect is assumed to be in framebuffer
// coordinates, i.e. lower-left origin in OpenGL.
void SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth = 0.0f,
float max_depth = 1.0f);
// Scales a GPU texture using a copy shader.
virtual void ScaleTexture(AbstractFramebuffer* dst_framebuffer,
const MathUtil::Rectangle<int>& dst_rect,
const AbstractTexture* src_texture,
const MathUtil::Rectangle<int>& src_rect);
// Converts an upper-left to lower-left if required by the backend, optionally
// clamping to the framebuffer size.
MathUtil::Rectangle<int> ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
u32 fb_width, u32 fb_height) const;
MathUtil::Rectangle<int>
ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
const AbstractFramebuffer* framebuffer) const;
virtual void Flush() {}
virtual void WaitForGPUIdle() {}
// For opengl's glDrawBuffer
virtual void SelectLeftBuffer() {}
virtual void SelectRightBuffer() {}
virtual void SelectMainBuffer() {}
// A simple presentation fallback, only used by video software
virtual void ShowImage(const AbstractTexture* source_texture,
const MathUtil::Rectangle<int>& source_rc)
{
}
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
// Called when the configuration changes, and backend structures need to be updated.
virtual void OnConfigChanged(u32 changed_bits);
// Returns true if a layer-expanding geometry shader should be used when rendering the user
// interface and final XFB.
bool UseGeometryShaderForUI() const;
// Returns info about the main surface (aka backbuffer)
virtual SurfaceInfo GetSurfaceInfo() const { return {}; }
protected:
AbstractFramebuffer* m_current_framebuffer = nullptr;
const AbstractPipeline* m_current_pipeline = nullptr;
};
extern std::unique_ptr<AbstractGfx> g_gfx;

View File

@ -8,8 +8,8 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/Image.h" #include "Common/Image.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractStagingTexture.h" #include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/RenderBase.h"
AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c) AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c)
{ {
@ -36,7 +36,7 @@ bool AbstractTexture::Save(const std::string& filename, unsigned int level)
TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1, TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1,
AbstractTextureFormat::RGBA8, 0); AbstractTextureFormat::RGBA8, 0);
auto readback_texture = auto readback_texture =
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config); g_gfx->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
if (!readback_texture) if (!readback_texture)
return false; return false;

View File

@ -6,12 +6,16 @@
#include <mutex> #include <mutex>
#include "Core/System.h" #include "Core/System.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h" #include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoEvents.h"
#include "VideoCommon/VideoState.h" #include "VideoCommon/VideoState.h"
AsyncRequests AsyncRequests::s_singleton; AsyncRequests AsyncRequests::s_singleton;
@ -152,12 +156,12 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e)
break; break;
case Event::SWAP_EVENT: case Event::SWAP_EVENT:
g_renderer->Swap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride,
e.swap_event.fbHeight, e.time); e.swap_event.fbHeight, e.time);
break; break;
case Event::BBOX_READ: case Event::BBOX_READ:
*e.bbox.data = g_renderer->BBoxRead(e.bbox.index); *e.bbox.data = g_bounding_box->Get(e.bbox.index);
break; break;
case Event::FIFO_RESET: case Event::FIFO_RESET:

View File

@ -12,11 +12,13 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoCommon/AbstractFramebuffer.h" #include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/BPMemory.h" #include "VideoCommon/BPMemory.h"
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/RenderBase.h"
#include "VideoCommon/RenderState.h" #include "VideoCommon/RenderState.h"
#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h" #include "VideoCommon/XFMemory.h"
@ -157,11 +159,11 @@ ScissorResult::ScissorResult(const BPMemory& bpmemory, std::pair<float, float> v
for (const auto& x_range : x_ranges) for (const auto& x_range : x_ranges)
{ {
DEBUG_ASSERT(x_range.start < x_range.end); DEBUG_ASSERT(x_range.start < x_range.end);
DEBUG_ASSERT(x_range.end <= EFB_WIDTH); DEBUG_ASSERT(static_cast<u32>(x_range.end) <= EFB_WIDTH);
for (const auto& y_range : y_ranges) for (const auto& y_range : y_ranges)
{ {
DEBUG_ASSERT(y_range.start < y_range.end); DEBUG_ASSERT(y_range.start < y_range.end);
DEBUG_ASSERT(y_range.end <= EFB_HEIGHT); DEBUG_ASSERT(static_cast<u32>(y_range.end) <= EFB_HEIGHT);
m_result.emplace_back(x_range, y_range); m_result.emplace_back(x_range, y_range);
} }
} }
@ -197,10 +199,9 @@ void SetScissorAndViewport()
{ {
auto native_rc = ComputeScissorRects().Best(); auto native_rc = ComputeScissorRects().Best();
auto target_rc = g_renderer->ConvertEFBRectangle(native_rc.rect); auto target_rc = g_framebuffer_manager->ConvertEFBRectangle(native_rc.rect);
auto converted_rc = auto converted_rc = g_gfx->ConvertFramebufferRectangle(target_rc, g_gfx->GetCurrentFramebuffer());
g_renderer->ConvertFramebufferRectangle(target_rc, g_renderer->GetCurrentFramebuffer()); g_gfx->SetScissorRect(converted_rc);
g_renderer->SetScissorRect(converted_rc);
float raw_x = (xfmem.viewport.xOrig - native_rc.x_off) - xfmem.viewport.wd; float raw_x = (xfmem.viewport.xOrig - native_rc.x_off) - xfmem.viewport.wd;
float raw_y = (xfmem.viewport.yOrig - native_rc.y_off) + xfmem.viewport.ht; float raw_y = (xfmem.viewport.yOrig - native_rc.y_off) + xfmem.viewport.ht;
@ -216,10 +217,10 @@ void SetScissorAndViewport()
raw_height = std::round(raw_height); raw_height = std::round(raw_height);
} }
float x = g_renderer->EFBToScaledXf(raw_x); float x = g_framebuffer_manager->EFBToScaledXf(raw_x);
float y = g_renderer->EFBToScaledYf(raw_y); float y = g_framebuffer_manager->EFBToScaledYf(raw_y);
float width = g_renderer->EFBToScaledXf(raw_width); float width = g_framebuffer_manager->EFBToScaledXf(raw_width);
float height = g_renderer->EFBToScaledYf(raw_height); float height = g_framebuffer_manager->EFBToScaledYf(raw_height);
float min_depth = (xfmem.viewport.farZ - xfmem.viewport.zRange) / 16777216.0f; float min_depth = (xfmem.viewport.farZ - xfmem.viewport.zRange) / 16777216.0f;
float max_depth = xfmem.viewport.farZ / 16777216.0f; float max_depth = xfmem.viewport.farZ / 16777216.0f;
if (width < 0.f) if (width < 0.f)
@ -246,7 +247,7 @@ void SetScissorAndViewport()
max_depth = std::clamp(max_depth, 0.0f, GX_MAX_DEPTH); max_depth = std::clamp(max_depth, 0.0f, GX_MAX_DEPTH);
} }
if (g_renderer->UseVertexDepthRange()) if (VertexShaderManager::UseVertexDepthRange())
{ {
// We need to ensure depth values are clamped the maximum value supported by the console GPU. // We need to ensure depth values are clamped the maximum value supported by the console GPU.
// Taking into account whether the depth range is inverted or not. // Taking into account whether the depth range is inverted or not.
@ -280,9 +281,9 @@ void SetScissorAndViewport()
// Lower-left flip. // Lower-left flip.
if (g_ActiveConfig.backend_info.bUsesLowerLeftOrigin) if (g_ActiveConfig.backend_info.bUsesLowerLeftOrigin)
y = static_cast<float>(g_renderer->GetCurrentFramebuffer()->GetHeight()) - y - height; y = static_cast<float>(g_gfx->GetCurrentFramebuffer()->GetHeight()) - y - height;
g_renderer->SetViewport(x, y, width, height, near_depth, far_depth); g_gfx->SetViewport(x, y, width, height, near_depth, far_depth);
} }
void SetDepthMode() void SetDepthMode()
@ -342,7 +343,7 @@ void ClearScreen(const MathUtil::Rectangle<int>& rc)
color = RGBA8ToRGB565ToRGBA8(color); color = RGBA8ToRGB565ToRGBA8(color);
z = Z24ToZ16ToZ24(z); z = Z24ToZ16ToZ24(z);
} }
g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); g_framebuffer_manager->ClearEFB(rc, colorEnable, alphaEnable, zEnable, color, z);
} }
} }
@ -364,9 +365,9 @@ void OnPixelFormatChange()
if (!g_ActiveConfig.bEFBEmulateFormatChanges) if (!g_ActiveConfig.bEFBEmulateFormatChanges)
return; return;
const auto old_format = g_renderer->GetPrevPixelFormat(); const auto old_format = g_framebuffer_manager->GetPrevPixelFormat();
const auto new_format = bpmem.zcontrol.pixel_format; const auto new_format = bpmem.zcontrol.pixel_format;
g_renderer->StorePixelFormat(new_format); g_framebuffer_manager->StorePixelFormat(new_format);
DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", new_format, bpmem.zcontrol.zformat); DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", new_format, bpmem.zcontrol.zformat);

View File

@ -33,7 +33,7 @@
#include "VideoCommon/PerfQueryBase.h" #include "VideoCommon/PerfQueryBase.h"
#include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h" #include "VideoCommon/Present.h"
#include "VideoCommon/Statistics.h" #include "VideoCommon/Statistics.h"
#include "VideoCommon/TMEM.h" #include "VideoCommon/TMEM.h"
#include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureCacheBase.h"
@ -42,6 +42,7 @@
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#include "VideoCommon/VideoEvents.h"
using namespace BPFunctions; using namespace BPFunctions;
@ -185,6 +186,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
{ {
INCSTAT(g_stats.this_frame.num_draw_done); INCSTAT(g_stats.this_frame.num_draw_done);
g_texture_cache->FlushEFBCopies(); g_texture_cache->FlushEFBCopies();
g_texture_cache->FlushStaleBinds();
g_framebuffer_manager->InvalidatePeekCache(false); g_framebuffer_manager->InvalidatePeekCache(false);
g_framebuffer_manager->RefreshPeekCache(); g_framebuffer_manager->RefreshPeekCache();
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -203,6 +205,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
{ {
INCSTAT(g_stats.this_frame.num_token); INCSTAT(g_stats.this_frame.num_token);
g_texture_cache->FlushEFBCopies(); g_texture_cache->FlushEFBCopies();
g_texture_cache->FlushStaleBinds();
g_framebuffer_manager->InvalidatePeekCache(false); g_framebuffer_manager->InvalidatePeekCache(false);
g_framebuffer_manager->RefreshPeekCache(); g_framebuffer_manager->RefreshPeekCache();
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -218,6 +221,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
{ {
INCSTAT(g_stats.this_frame.num_token_int); INCSTAT(g_stats.this_frame.num_token_int);
g_texture_cache->FlushEFBCopies(); g_texture_cache->FlushEFBCopies();
g_texture_cache->FlushStaleBinds();
g_framebuffer_manager->InvalidatePeekCache(false); g_framebuffer_manager->InvalidatePeekCache(false);
g_framebuffer_manager->RefreshPeekCache(); g_framebuffer_manager->RefreshPeekCache();
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
@ -282,7 +286,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
if (PE_copy.copy_to_xfb == 1) if (PE_copy.copy_to_xfb == 1)
{ {
// Make sure we disable Bounding box to match the side effects of the non-failure path // Make sure we disable Bounding box to match the side effects of the non-failure path
g_renderer->BBoxDisable(pixel_shader_manager); g_bounding_box->Disable(pixel_shader_manager);
} }
return; return;
@ -313,7 +317,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
// We should be able to get away with deactivating the current bbox tracking // We should be able to get away with deactivating the current bbox tracking
// here. Not sure if there's a better spot to put this. // here. Not sure if there's a better spot to put this.
// the number of lines copied is determined by the y scale * source efb height // the number of lines copied is determined by the y scale * source efb height
g_renderer->BBoxDisable(pixel_shader_manager); g_bounding_box->Disable(pixel_shader_manager);
float yScale; float yScale;
if (PE_copy.scale_invert) if (PE_copy.scale_invert)
@ -337,14 +341,26 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top,
bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients()); bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients());
// This stays in to signal end of a "frame" // This is as closest as we have to an "end of the frame"
g_renderer->RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]); // It works 99% of the time.
// But sometimes games want to render an XFB larger than the EFB's 640x528 pixel resolution
// (especially when using the 3xMSAA mode, which cuts EFB resolution to 640x264). So they
// render multiple sub-frames and arrange the XFB copies in next to each-other in main memory
// so they form a single completed XFB.
// See https://dolphin-emu.org/blog/2017/11/19/hybridxfb/ for examples and more detail.
AfterFrameEvent::Trigger();
// Note: Theoretically, in the future we could track the VI configuration and try to detect
// when an XFB is the last XFB copy of a frame. Not only would we get a clean "end of
// the frame", but we would also be able to use ImmediateXFB even for these games.
// Might also clean up some issues with games doing XFB copies they don't intend to
// display.
if (g_ActiveConfig.bImmediateXFB) if (g_ActiveConfig.bImmediateXFB)
{ {
// below div two to convert from bytes to pixels - it expects width, not stride // below div two to convert from bytes to pixels - it expects width, not stride
g_renderer->Swap(destAddr, destStride / 2, destStride, height, u64 ticks = Core::System::GetInstance().GetCoreTiming().GetTicks();
Core::System::GetInstance().GetCoreTiming().GetTicks()); g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height, ticks);
} }
else else
{ {
@ -481,10 +497,10 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
case BPMEM_CLEARBBOX2: case BPMEM_CLEARBBOX2:
{ {
const u8 offset = bp.address & 2; const u8 offset = bp.address & 2;
g_renderer->BBoxEnable(pixel_shader_manager); g_bounding_box->Enable(pixel_shader_manager);
g_renderer->BBoxWrite(offset, bp.newvalue & 0x3ff); g_bounding_box->Set(offset, bp.newvalue & 0x3ff);
g_renderer->BBoxWrite(offset + 1, bp.newvalue >> 10); g_bounding_box->Set(offset + 1, bp.newvalue >> 10);
} }
return; return;
case BPMEM_TEXINVALIDATE: case BPMEM_TEXINVALIDATE:

Some files were not shown because too many files have changed in this diff Show More