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 "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h"
#include "jni/AndroidCommon/AndroidCommon.h"
@ -456,8 +456,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
if (s_surf == nullptr)
__android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
if (g_renderer)
g_renderer->ChangeSurface(s_surf);
if (g_presenter)
g_presenter->ChangeSurface(s_surf);
}
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);
if (g_renderer)
g_renderer->ChangeSurface(nullptr);
if (g_presenter)
g_presenter->ChangeSurface(nullptr);
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*,
jclass)
{
return g_renderer->CalculateDrawAspectRatio();
return g_presenter->CalculateDrawAspectRatio();
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv*, jclass)

View File

@ -62,6 +62,7 @@ add_library(common
GekkoDisassembler.h
Hash.cpp
Hash.h
HookableEvent.h
HttpRequest.cpp
HttpRequest.h
Image.cpp
@ -115,6 +116,7 @@ add_library(common
SocketContext.cpp
SocketContext.h
SPSCQueue.h
StringLiteral.h
StringUtil.cpp
StringUtil.h
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/Fifo.h"
#include "VideoCommon/FrameDumper.h"
#include "VideoCommon/HiresTextures.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PerformanceMetrics.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoEvents.h"
#ifdef ANDROID
#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 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()
{
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(); }};
// 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)
Config::SetBaseOrCurrent(Config::MAIN_DSP_THREAD, cpu_info.num_cores > 4);
else
@ -731,13 +737,13 @@ static std::string GenerateScreenshotName()
void SaveScreenShot()
{
Core::RunAsCPUThread([] { g_renderer->SaveScreenshot(GenerateScreenshotName()); });
Core::RunAsCPUThread([] { g_frame_dumper->SaveScreenshot(GenerateScreenshotName()); });
}
void SaveScreenShot(std::string_view 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/System.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoEvents.h"
#include "VideoCommon/XFMemory.h"
#include "VideoCommon/XFStructs.h"
class FifoRecorder::FifoRecordAnalyzer : public OpcodeDecoder::Callback
@ -249,6 +254,42 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
m_RequestedRecordingEnd = false;
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()
@ -391,11 +432,14 @@ void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd)
m_SkipFutureData = true;
// Signal video backend that it should not call this function when the next frame ends
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,
const u32* xfRegs, u32 xfRegsSize, const u8* texMem)
const u32* xfRegs, u32 xfRegsSize, const u8* texMem_ptr)
{
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);
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);

View File

@ -9,6 +9,7 @@
#include <vector>
#include "Common/Assert.h"
#include "Common/HookableEvent.h"
#include "Core/FifoPlayer/FifoDataFile.h"
class FifoRecorder
@ -50,6 +51,8 @@ public:
private:
class FifoRecordAnalyzer;
void RecordInitialVideoMemory();
// Accessed from both GUI and video threads
std::recursive_mutex m_mutex;
@ -72,4 +75,6 @@ private:
std::vector<u8> m_FifoData;
std::vector<u8> m_Ram;
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/System.h"
#include "VideoCommon/FrameDump.h"
#include "VideoCommon/FrameDumpFFMpeg.h"
#include "VideoCommon/OnScreenDisplay.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;
// 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.
// 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\GLX11Window.h" />
<ClInclude Include="Common\Hash.h" />
<ClInclude Include="Common\HookableEvent.h" />
<ClInclude Include="Common\HRWrap.h" />
<ClInclude Include="Common\HttpRequest.h" />
<ClInclude Include="Common\Image.h" />
@ -145,6 +146,7 @@
<ClInclude Include="Common\SFMLHelper.h" />
<ClInclude Include="Common\SocketContext.h" />
<ClInclude Include="Common\SPSCQueue.h" />
<ClInclude Include="Common\StringLiteral.h" />
<ClInclude Include="Common\StringUtil.h" />
<ClInclude Include="Common\Swap.h" />
<ClInclude Include="Common\SymbolDB.h" />
@ -534,7 +536,7 @@
<ClInclude Include="VideoBackends\D3D\D3DBase.h" />
<ClInclude Include="VideoBackends\D3D\D3DBoundingBox.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\D3DSwapChain.h" />
<ClInclude Include="VideoBackends\D3D\D3DVertexManager.h" />
@ -545,7 +547,7 @@
<ClInclude Include="VideoBackends\D3D12\Common.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12BoundingBox.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\D3D12SwapChain.h" />
<ClInclude Include="VideoBackends\D3D12\D3D12VertexManager.h" />
@ -561,7 +563,7 @@
<ClInclude Include="VideoBackends\D3DCommon\Shader.h" />
<ClInclude Include="VideoBackends\D3DCommon\SwapChain.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\NullVertexManager.h" />
<ClInclude Include="VideoBackends\Null\PerfQuery.h" />
@ -569,9 +571,10 @@
<ClInclude Include="VideoBackends\Null\VideoBackend.h" />
<ClInclude Include="VideoBackends\OGL\GPUTimer.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\OGLPipeline.h" />
<ClInclude Include="VideoBackends\OGL\OGLRender.h" />
<ClInclude Include="VideoBackends\OGL\OGLShader.h" />
<ClInclude Include="VideoBackends\OGL\OGLStreamBuffer.h" />
<ClInclude Include="VideoBackends\OGL\OGLTexture.h" />
@ -587,6 +590,7 @@
<ClInclude Include="VideoBackends\Software\Rasterizer.h" />
<ClInclude Include="VideoBackends\Software\SetupUnit.h" />
<ClInclude Include="VideoBackends\Software\SWBoundingBox.h" />
<ClInclude Include="VideoBackends\Software\SWGfx.h" />
<ClInclude Include="VideoBackends\Software\SWOGLWindow.h" />
<ClInclude Include="VideoBackends\Software\SWRenderer.h" />
<ClInclude Include="VideoBackends\Software\SWTexture.h" />
@ -608,7 +612,7 @@
<ClInclude Include="VideoBackends\Vulkan\VKBoundingBox.h" />
<ClInclude Include="VideoBackends\Vulkan\VKPerfQuery.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\VKStreamBuffer.h" />
<ClInclude Include="VideoBackends\Vulkan\VKSwapChain.h" />
@ -618,6 +622,7 @@
<ClInclude Include="VideoBackends\Vulkan\VulkanContext.h" />
<ClInclude Include="VideoBackends\Vulkan\VulkanLoader.h" />
<ClInclude Include="VideoCommon\AbstractFramebuffer.h" />
<ClInclude Include="VideoCommon\AbstractGfx.h" />
<ClInclude Include="VideoCommon\AbstractPipeline.h" />
<ClInclude Include="VideoCommon\AbstractShader.h" />
<ClInclude Include="VideoCommon\AbstractStagingTexture.h" />
@ -638,7 +643,8 @@
<ClInclude Include="VideoCommon\Fifo.h" />
<ClInclude Include="VideoCommon\FramebufferManager.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\GeometryShaderGen.h" />
<ClInclude Include="VideoCommon\GeometryShaderManager.h" />
@ -668,6 +674,8 @@
<ClInclude Include="VideoCommon\NetPlayChatUI.h" />
<ClInclude Include="VideoCommon\NetPlayGolfUI.h" />
<ClInclude Include="VideoCommon\OnScreenDisplay.h" />
<ClInclude Include="VideoCommon\OnScreenUI.h" />
<ClInclude Include="VideoCommon\OnScreenUIKeyMap.h" />
<ClInclude Include="VideoCommon\OpcodeDecoding.h" />
<ClInclude Include="VideoCommon\PerfQueryBase.h" />
<ClInclude Include="VideoCommon\PerformanceMetrics.h" />
@ -676,6 +684,7 @@
<ClInclude Include="VideoCommon\PixelShaderGen.h" />
<ClInclude Include="VideoCommon\PixelShaderManager.h" />
<ClInclude Include="VideoCommon\PostProcessing.h" />
<ClInclude Include="VideoCommon\Present.h" />
<ClInclude Include="VideoCommon\RenderBase.h" />
<ClInclude Include="VideoCommon\RenderState.h" />
<ClInclude Include="VideoCommon\ShaderCache.h" />
@ -707,7 +716,9 @@
<ClInclude Include="VideoCommon\VideoBackendBase.h" />
<ClInclude Include="VideoCommon\VideoCommon.h" />
<ClInclude Include="VideoCommon\VideoConfig.h" />
<ClInclude Include="VideoCommon\VideoEvents.h" />
<ClInclude Include="VideoCommon\VideoState.h" />
<ClInclude Include="VideoCommon\Widescreen.h" />
<ClInclude Include="VideoCommon\XFMemory.h" />
<ClInclude Include="VideoCommon\XFStructs.h" />
</ItemGroup>
@ -1142,7 +1153,7 @@
<ClCompile Include="VideoBackends\D3D\D3DMain.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DNativeVertexFormat.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\D3DSwapChain.cpp" />
<ClCompile Include="VideoBackends\D3D\D3DVertexManager.cpp" />
@ -1151,7 +1162,7 @@
<ClCompile Include="VideoBackends\D3D\DXTexture.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12BoundingBox.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\D3D12SwapChain.cpp" />
<ClCompile Include="VideoBackends\D3D12\D3D12VertexManager.cpp" />
@ -1167,15 +1178,16 @@
<ClCompile Include="VideoBackends\D3DCommon\Shader.cpp" />
<ClCompile Include="VideoBackends\D3DCommon\SwapChain.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\NullVertexManager.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\OGLNativeVertexFormat.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLPerfQuery.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLPipeline.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLRender.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLShader.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLStreamBuffer.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLTexture.cpp" />
@ -1189,6 +1201,7 @@
<ClCompile Include="VideoBackends\Software\SetupUnit.cpp" />
<ClCompile Include="VideoBackends\Software\SWmain.cpp" />
<ClCompile Include="VideoBackends\Software\SWBoundingBox.cpp" />
<ClCompile Include="VideoBackends\Software\SWGfx.cpp" />
<ClCompile Include="VideoBackends\Software\SWOGLWindow.cpp" />
<ClCompile Include="VideoBackends\Software\SWRenderer.cpp" />
<ClCompile Include="VideoBackends\Software\SWTexture.cpp" />
@ -1206,7 +1219,7 @@
<ClCompile Include="VideoBackends\Vulkan\VKMain.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKPerfQuery.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\VKStreamBuffer.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VKSwapChain.cpp" />
@ -1216,6 +1229,7 @@
<ClCompile Include="VideoBackends\Vulkan\VulkanContext.cpp" />
<ClCompile Include="VideoBackends\Vulkan\VulkanLoader.cpp" />
<ClCompile Include="VideoCommon\AbstractFramebuffer.cpp" />
<ClCompile Include="VideoCommon\AbstractGfx.cpp" />
<ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" />
<ClCompile Include="VideoCommon\AbstractTexture.cpp" />
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
@ -1231,7 +1245,8 @@
<ClCompile Include="VideoCommon\Fifo.cpp" />
<ClCompile Include="VideoCommon\FramebufferManager.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\GeometryShaderGen.cpp" />
<ClCompile Include="VideoCommon\GeometryShaderManager.cpp" />
@ -1254,6 +1269,7 @@
<ClCompile Include="VideoCommon\NetPlayChatUI.cpp" />
<ClCompile Include="VideoCommon\NetPlayGolfUI.cpp" />
<ClCompile Include="VideoCommon\OnScreenDisplay.cpp" />
<ClCompile Include="VideoCommon\OnScreenUI.cpp" />
<ClCompile Include="VideoCommon\OpcodeDecoding.cpp" />
<ClCompile Include="VideoCommon\PerfQueryBase.cpp" />
<ClCompile Include="VideoCommon\PerformanceMetrics.cpp" />
@ -1262,6 +1278,7 @@
<ClCompile Include="VideoCommon\PixelShaderGen.cpp" />
<ClCompile Include="VideoCommon\PixelShaderManager.cpp" />
<ClCompile Include="VideoCommon\PostProcessing.cpp" />
<ClCompile Include="VideoCommon\Present.cpp" />
<ClCompile Include="VideoCommon\RenderBase.cpp" />
<ClCompile Include="VideoCommon\RenderState.cpp" />
<ClCompile Include="VideoCommon\ShaderCache.cpp" />
@ -1291,6 +1308,7 @@
<ClCompile Include="VideoCommon\VideoBackendBase.cpp" />
<ClCompile Include="VideoCommon\VideoConfig.cpp" />
<ClCompile Include="VideoCommon\VideoState.cpp" />
<ClCompile Include="VideoCommon\Widescreen.cpp" />
<ClCompile Include="VideoCommon\XFMemory.cpp" />
<ClCompile Include="VideoCommon\XFStructs.cpp" />
</ItemGroup>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,8 +19,6 @@
#include <QTimer>
#include <QWindow>
#include <imgui.h>
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/State.h"
@ -32,7 +30,8 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/OnScreenUI.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h"
#ifdef _WIN32
@ -62,7 +61,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
if (state == Core::State::Running)
SetImGuiKeyMap();
SetPresenterKeyMap();
});
// 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)
{
PassEventToImGui(event);
PassEventToPresenter(event);
switch (event->type())
{
@ -470,7 +469,7 @@ bool RenderWidget::event(QEvent* event)
return QWidget::event(event);
}
void RenderWidget::PassEventToImGui(const QEvent* event)
void RenderWidget::PassEventToPresenter(const QEvent* event)
{
if (!Core::IsRunningAndStarted())
return;
@ -487,38 +486,40 @@ void RenderWidget::PassEventToImGui(const QEvent* event)
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
const bool is_down = event->type() == QEvent::KeyPress;
const u32 key = static_cast<u32>(key_event->key() & 0x1FF);
auto lock = g_renderer->GetImGuiLock();
if (key < std::size(ImGui::GetIO().KeysDown))
ImGui::GetIO().KeysDown[key] = is_down;
const char* chars = nullptr;
if (is_down)
{
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;
case QEvent::MouseMove:
{
auto lock = g_renderer->GetImGuiLock();
// 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
// native coordinates, as the UI (and game) is rendered at native resolution.
const float scale = devicePixelRatio();
ImGui::GetIO().MousePos.x = static_cast<const QMouseEvent*>(event)->pos().x() * scale;
ImGui::GetIO().MousePos.y = static_cast<const QMouseEvent*>(event)->pos().y() * scale;
float x = static_cast<const QMouseEvent*>(event)->pos().x() * scale;
float y = static_cast<const QMouseEvent*>(event)->pos().y() * scale;
g_presenter->SetMousePos(x, y);
}
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
{
auto lock = g_renderer->GetImGuiLock();
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++)
ImGui::GetIO().MouseDown[i] = (button_mask & (1u << i)) != 0;
g_presenter->SetMousePress(button_mask);
}
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{{
{ImGuiKey_Tab, Qt::Key_Tab},
{ImGuiKey_LeftArrow, Qt::Key_Left},
{ImGuiKey_RightArrow, Qt::Key_Right},
{ImGuiKey_UpArrow, Qt::Key_Up},
{ImGuiKey_DownArrow, Qt::Key_Down},
{ImGuiKey_PageUp, Qt::Key_PageUp},
{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();
static constexpr DolphinKeyMap key_map = {
Qt::Key_Tab, Qt::Key_Left, Qt::Key_Right, Qt::Key_Up, Qt::Key_Down,
Qt::Key_PageUp, Qt::Key_PageDown, Qt::Key_Home, Qt::Key_End, Qt::Key_Insert,
Qt::Key_Delete, Qt::Key_Backspace, Qt::Key_Space, Qt::Key_Return, Qt::Key_Escape,
Qt::Key_Enter, // Keypad enter
Qt::Key_A, Qt::Key_C, Qt::Key_V, Qt::Key_X, Qt::Key_Y,
Qt::Key_Z,
};
if (!ImGui::GetCurrentContext())
return;
for (auto [imgui_key, qt_key] : key_map)
ImGui::GetIO().KeyMap[imgui_key] = (qt_key & 0x1FF);
g_presenter->SetKeyMap(key_map);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// Copyright 2010 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/D3D/D3DRender.h"
#include "VideoBackends/D3D/D3DGfx.h"
#include <algorithm>
#include <array>
@ -30,48 +30,46 @@
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace DX11
{
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0,
backbuffer_scale,
swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
Gfx::Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: m_backbuffer_scale(backbuffer_scale), 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;
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
std::string_view name)
std::unique_ptr<AbstractTexture> Gfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return DXTexture::Create(config, name);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return DXStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment));
}
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);
if (!bytecode)
@ -80,21 +78,20 @@ Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std
return DXShader::CreateFromBytecode(stage, std::move(*bytecode), name);
}
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length,
std::string_view name)
std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length, std::string_view name)
{
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name);
}
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
std::unique_ptr<AbstractPipeline> Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
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);
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
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);
}
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
void Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
// TODO: Move to stateman
const CD3D11_VIEWPORT vp(x, y, width, height, near_depth, far_depth);
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::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::context->DrawIndexed(num_indices, base_index, base_vertex);
}
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
D3D::stateman->SyncComputeBindings();
D3D::context->Dispatch(groups_x, groups_y, groups_z);
}
void Renderer::BindBackbuffer(const ClearColor& clear_color)
void Gfx::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSwapChainChanges();
SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
}
void Renderer::PresentBackbuffer()
void Gfx::PresentBackbuffer()
{
m_swap_chain->Present();
}
void Renderer::OnConfigChanged(u32 bits)
void Gfx::OnConfigChanged(u32 bits)
{
AbstractGfx::OnConfigChanged(bits);
// Quad-buffer changes require swap chain recreation.
if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain)
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 =
m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange();
g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
if (!surface_changed && !surface_resized)
return;
if (surface_changed)
{
m_swap_chain->ChangeSurface(m_new_surface_handle);
m_new_surface_handle = nullptr;
m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
}
else
{
m_swap_chain->ResizeSwapChain();
}
m_backbuffer_width = m_swap_chain->GetWidth();
m_backbuffer_height = m_swap_chain->GetHeight();
g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
}
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
@ -219,13 +216,13 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
m_current_framebuffer = fb;
}
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
SetFramebuffer(framebuffer);
}
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
float depth_value)
{
SetFramebuffer(framebuffer);
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() :
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));
}
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);
}
void Renderer::UnbindTexture(const AbstractTexture* texture)
void Gfx::UnbindTexture(const AbstractTexture* texture)
{
if (D3D::stateman->UnsetTexture(static_cast<const DXTexture*>(texture)->GetD3DSRV()) != 0)
D3D::stateman->ApplyTextures();
}
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const
{
return std::make_unique<D3DBoundingBox>();
}
void Renderer::Flush()
void Gfx::Flush()
{
D3D::context->Flush();
}
void Renderer::WaitForGPUIdle()
void Gfx::WaitForGPUIdle()
{
// There is no glFinish() equivalent in D3D.
D3D::context->Flush();
}
void Renderer::SetFullscreen(bool enable_fullscreen)
void Gfx::SetFullscreen(bool enable_fullscreen)
{
if (m_swap_chain)
m_swap_chain->SetFullscreen(enable_fullscreen);
}
bool Renderer::IsFullscreen() const
bool Gfx::IsFullscreen() const
{
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DRender.h"
#include "VideoBackends/D3D/D3DGfx.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DVertexManager.h"
#include "VideoBackends/D3D/DXShader.h"
@ -32,7 +32,7 @@ DXPipeline::~DXPipeline() = default;
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);
ID3D11DepthStencilState* depth_state = state_cache.Get(config.depth_state);
ID3D11BlendState* blend_state = state_cache.Get(config.blending_state);

View File

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

View File

@ -6,7 +6,7 @@
#include "Common/Assert.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D12/D3D12Renderer.h"
#include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/DX12Context.h"
namespace DX12
@ -22,7 +22,7 @@ bool D3D12BoundingBox::Initialize()
if (!CreateBuffers())
return false;
Renderer::GetInstance()->SetPixelShaderUAV(m_gpu_descriptor.cpu_handle);
Gfx::GetInstance()->SetPixelShaderUAV(m_gpu_descriptor.cpu_handle);
return true;
}
@ -35,7 +35,7 @@ std::vector<BBoxType> D3D12BoundingBox::Read(u32 index, u32 length)
0, BUFFER_SIZE);
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(),
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
Renderer::GetInstance()->ExecuteCommandList(true);
Gfx::GetInstance()->ExecuteCommandList(true);
// Read back to cached values.
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)))
{
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)))
{
PanicAlertFmt("Failed to allocate bbox stream buffer space");

View File

@ -1,7 +1,7 @@
// Copyright 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/D3D12/D3D12Renderer.h"
#include "VideoBackends/D3D12/D3D12Gfx.h"
#include "Common/Logging/Log.h"
@ -15,6 +15,7 @@
#include "VideoBackends/D3D12/DX12Texture.h"
#include "VideoBackends/D3D12/DX12VertexFormat.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h"
namespace DX12
@ -27,11 +28,8 @@ static bool UsesDynamicVertexLoader(const AbstractPipeline* pipeline)
(g_ActiveConfig.UseVSForLinePointExpand() && usage != AbstractPipelineUsage::Utility);
}
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0,
backbuffer_scale,
swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
Gfx::Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: m_backbuffer_scale(backbuffer_scale), m_swap_chain(std::move(swap_chain))
{
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;
}
bool Renderer::Initialize()
{
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)
std::unique_ptr<AbstractTexture> Gfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return DXTexture::Create(config, name);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
std::unique_ptr<AbstractStagingTexture> Gfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return DXStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer> Gfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return DXFramebuffer::Create(static_cast<DXTexture*>(color_attachment),
static_cast<DXTexture*>(depth_attachment));
}
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);
}
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length,
std::string_view name)
std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length, std::string_view name)
{
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length), name);
}
std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<DXVertexFormat>(vtx_decl);
}
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
std::unique_ptr<AbstractPipeline> Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return DXPipeline::Create(config, cache_data, cache_data_length);
}
std::unique_ptr<BoundingBox> Renderer::CreateBoundingBox() const
{
return std::make_unique<D3D12BoundingBox>();
}
void Renderer::Flush()
void Gfx::Flush()
{
ExecuteCommandList(false);
}
void Renderer::WaitForGPUIdle()
void Gfx::WaitForGPUIdle()
{
ExecuteCommandList(true);
}
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable,
bool z_enable, u32 color, u32 z)
void Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable,
bool alpha_enable, bool z_enable, u32 color, u32 z)
{
// 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)
{
MathUtil::Rectangle<int> native_rc = ConvertEFBRectangle(rc);
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};
const D3D12_RECT d3d_clear_rc{target_rc.left, target_rc.top, target_rc.right, target_rc.bottom};
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.
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);
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())
{
@ -225,7 +200,7 @@ void Renderer::BindFramebuffer(DXFramebuffer* fb)
m_dirty_bits &= ~DirtyState_Framebuffer;
}
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
@ -234,7 +209,7 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
m_dirty_bits |= DirtyState_Framebuffer;
}
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
void Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
SetFramebuffer(framebuffer);
@ -253,8 +228,8 @@ void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
}
}
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
void Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
float depth_value)
{
DXFramebuffer* dxfb = static_cast<DXFramebuffer*>(framebuffer);
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 &&
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;
}
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
void Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{
const DXTexture* dxtex = static_cast<const DXTexture*>(texture);
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;
}
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
void Gfx::SetSamplerState(u32 index, const SamplerState& state)
{
if (m_state.samplers.states[index] == state)
return;
@ -309,7 +284,7 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
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);
if (m_state.compute_image_texture == dxtex)
@ -322,7 +297,7 @@ void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool
m_dirty_bits |= DirtyState_ComputeImageTexture;
}
void Renderer::UnbindTexture(const AbstractTexture* texture)
void Gfx::UnbindTexture(const AbstractTexture* texture)
{
const auto srv_shadow_descriptor =
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,
float far_depth)
void Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
if (m_state.viewport.TopLeftX == x && m_state.viewport.TopLeftY == y &&
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;
}
void Renderer::Draw(u32 base_vertex, u32 num_vertices)
void Gfx::Draw(u32 base_vertex, u32 num_vertices)
{
if (!ApplyState())
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);
}
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())
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);
}
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
SetRootSignatures();
SetDescriptorHeaps();
@ -411,17 +386,17 @@ void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize
m_dirty_bits |= DirtyState_Pipeline;
}
void Renderer::BindBackbuffer(const ClearColor& clear_color)
void Gfx::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSwapChainChanges();
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 =
m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange();
g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
if (!surface_changed && !surface_resized)
return;
@ -429,19 +404,17 @@ void Renderer::CheckForSwapChainChanges()
WaitForGPUIdle();
if (surface_changed)
{
m_swap_chain->ChangeSurface(m_new_surface_handle);
m_new_surface_handle = nullptr;
m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
}
else
{
m_swap_chain->ResizeSwapChain();
}
m_backbuffer_width = m_swap_chain->GetWidth();
m_backbuffer_height = m_swap_chain->GetHeight();
g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
}
void Renderer::PresentBackbuffer()
void Gfx::PresentBackbuffer()
{
m_current_framebuffer = nullptr;
@ -451,9 +424,16 @@ void Renderer::PresentBackbuffer()
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.
if (m_swap_chain && bits & CONFIG_CHANGE_BIT_STEREO_MODE)
@ -475,14 +455,14 @@ void Renderer::OnConfigChanged(u32 bits)
g_dx_context->RecreateGXRootSignature();
}
void Renderer::ExecuteCommandList(bool wait_for_completion)
void Gfx::ExecuteCommandList(bool wait_for_completion)
{
PerfQuery::GetInstance()->ResolveQueries();
g_dx_context->ExecuteCommandList(wait_for_completion);
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)
return;
@ -491,7 +471,7 @@ void Renderer::SetConstantBuffer(u32 index, D3D12_GPU_VIRTUAL_ADDRESS address)
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)
return;
@ -500,7 +480,7 @@ void Renderer::SetTextureDescriptor(u32 index, D3D12_CPU_DESCRIPTOR_HANDLE handl
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)
return;
@ -509,8 +489,8 @@ void Renderer::SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
m_dirty_bits |= DirtyState_PS_UAV;
}
void Renderer::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESCRIPTOR_HANDLE srv,
u32 stride, u32 size)
void Gfx::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESCRIPTOR_HANDLE srv,
u32 stride, u32 size)
{
if (m_state.vertex_buffer.BufferLocation != address ||
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 &&
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;
}
bool Renderer::ApplyState()
bool Gfx::ApplyState()
{
if (!m_current_framebuffer || !m_current_pipeline)
return false;
@ -637,7 +617,7 @@ bool Renderer::ApplyState()
return true;
}
void Renderer::SetRootSignatures()
void Gfx::SetRootSignatures()
{
const u32 dirty_bits = m_dirty_bits;
if (dirty_bits & DirtyState_RootSignature)
@ -650,7 +630,7 @@ void Renderer::SetRootSignatures()
m_dirty_bits &= ~(DirtyState_RootSignature | DirtyState_ComputeRootSignature);
}
void Renderer::SetDescriptorHeaps()
void Gfx::SetDescriptorHeaps()
{
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.
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};
DescriptorHandle dst_base_handle;
@ -700,7 +680,7 @@ bool Renderer::UpdateSRVDescriptorTable()
return true;
}
bool Renderer::UpdateSamplerDescriptorTable()
bool Gfx::UpdateSamplerDescriptorTable()
{
if (!g_dx_context->GetSamplerAllocator()->GetGroupHandle(m_state.samplers,
&m_state.sampler_descriptor_base))
@ -713,7 +693,7 @@ bool Renderer::UpdateSamplerDescriptorTable()
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.
if (!g_ActiveConfig.bBBoxEnable)
@ -730,7 +710,7 @@ bool Renderer::UpdateUAVDescriptorTable()
return true;
}
bool Renderer::UpdateVSSRVDescriptorTable()
bool Gfx::UpdateVSSRVDescriptorTable()
{
if (!UsesDynamicVertexLoader(m_current_pipeline))
{
@ -748,7 +728,7 @@ bool Renderer::UpdateVSSRVDescriptorTable()
return true;
}
bool Renderer::UpdateComputeUAVDescriptorTable()
bool Gfx::UpdateComputeUAVDescriptorTable()
{
DescriptorHandle handle;
if (!g_dx_context->GetDescriptorAllocator()->Allocate(1, &handle))

View File

@ -6,9 +6,7 @@
#include <d3d12.h>
#include "VideoBackends/D3D12/DescriptorAllocator.h"
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
#include "VideoCommon/RenderBase.h"
class BoundingBox;
#include "VideoCommon/AbstractGfx.h"
namespace DX12
{
@ -18,19 +16,16 @@ class DXShader;
class DXPipeline;
class SwapChain;
class Renderer final : public ::Renderer
class Gfx final : public ::AbstractGfx
{
public:
Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~Renderer() override;
Gfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~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 Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override;
std::unique_ptr<AbstractStagingTexture>
@ -52,7 +47,7 @@ public:
void Flush() 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;
void SetPipeline(const AbstractPipeline* pipeline) override;
@ -74,6 +69,8 @@ public:
void BindBackbuffer(const ClearColor& clear_color = {}) override;
void PresentBackbuffer() override;
SurfaceInfo GetSurfaceInfo() const override;
// 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.
void ExecuteCommandList(bool wait_for_completion);
@ -98,8 +95,6 @@ public:
protected:
void OnConfigChanged(u32 bits) override;
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private:
static const u32 MAX_TEXTURES = 8;
static const u32 NUM_CONSTANT_BUFFERS = 3;
@ -152,6 +147,8 @@ private:
bool UpdateComputeUAVDescriptorTable();
bool UpdateSamplerDescriptorTable();
float m_backbuffer_scale;
// Owned objects
std::unique_ptr<SwapChain> m_swap_chain;

View File

@ -9,8 +9,9 @@
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/D3D12Renderer.h"
#include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/DX12Context.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h"
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
// 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.
Renderer::GetInstance()->ApplyState();
Gfx::GetInstance()->ApplyState();
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
const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH /
g_renderer->GetTargetWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight();
g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
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).
if (resolve && m_unresolved_queries > 0)
Renderer::GetInstance()->ExecuteCommandList(false);
Gfx::GetInstance()->ExecuteCommandList(false);
ReadbackQueries(blocking);
}

View File

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

View File

@ -10,7 +10,7 @@
#include "Core/System.h"
#include "VideoBackends/D3D12/D3D12Renderer.h"
#include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/D3D12StreamBuffer.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
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
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_index_streamed, static_cast<int>(index_data_size));
Renderer::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(),
m_vertex_srv.cpu_handle, vertex_stride,
m_vertex_stream_buffer.GetSize());
Renderer::GetInstance()->SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(),
m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);
Gfx::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(),
m_vertex_srv.cpu_handle, vertex_stride,
m_vertex_stream_buffer.GetSize());
Gfx::GetInstance()->SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(),
m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);
}
void VertexManager::UploadUniforms()
@ -151,7 +151,7 @@ void VertexManager::UpdateVertexShaderConstants()
if (!vertex_shader_manager.dirty || !ReserveConstantStorage())
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,
sizeof(VertexShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(VertexShaderConstants));
@ -167,7 +167,7 @@ void VertexManager::UpdateGeometryShaderConstants()
if (!geometry_shader_manager.dirty || !ReserveConstantStorage())
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,
sizeof(GeometryShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(GeometryShaderConstants));
@ -183,7 +183,7 @@ void VertexManager::UpdatePixelShaderConstants()
if (!pixel_shader_manager.dirty || !ReserveConstantStorage())
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,
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.
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
// 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
Renderer::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer() +
pixel_constants_offset);
Renderer::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer() +
vertex_constants_offset);
Renderer::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer() +
geometry_constants_offset);
Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer() +
pixel_constants_offset);
Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer() +
vertex_constants_offset);
Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer() +
geometry_constants_offset);
auto& system = Core::System::GetInstance();
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))
{
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());
Renderer::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer());
Renderer::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer());
Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer());
Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer());
Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), data, data_size);
m_uniform_stream_buffer.CommitMemory(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.
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))
{
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;
m_texel_stream_buffer.CommitMemory(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;
}
@ -323,7 +323,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
{
// Try submitting cmdbuffer.
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))
{
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);
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, palette_byte_offset + palette_size);
Renderer::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(0, m_texel_buffer_views[format].cpu_handle);
Gfx::GetInstance()->SetTextureDescriptor(1, m_texel_buffer_views[palette_format].cpu_handle);
return true;
}

View File

@ -8,7 +8,7 @@
#include "Common/StringUtil.h"
#include "VideoBackends/D3D12/Common.h"
#include "VideoBackends/D3D12/D3D12Renderer.h"
#include "VideoBackends/D3D12/D3D12Gfx.h"
#include "VideoBackends/D3D12/D3D12StreamBuffer.h"
#include "VideoBackends/D3D12/DX12Context.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,
"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(
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
// command list with the copy has been submitted, we only need to wait for the fence.
if (m_completed_fence == g_dx_context->GetCurrentFenceValue())
Renderer::GetInstance()->ExecuteCommandList(true);
Gfx::GetInstance()->ExecuteCommandList(true);
else
g_dx_context->WaitForFence(m_completed_fence);
}

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// Copyright 2022 Dolphin Emulator Project
// 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/MTLObjectCache.h"
@ -13,36 +13,31 @@
#include "VideoBackends/Metal/MTLVertexManager.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h"
Metal::Renderer::Renderer(MRCOwned<CAMetalLayer*> layer, int width, int height, float layer_scale)
: ::Renderer(width, height, layer_scale, Util::ToAbstract([layer pixelFormat])),
m_layer(std::move(layer))
#include <fstream>
Metal::Gfx::Gfx(MRCOwned<CAMetalLayer*> layer) : m_layer(std::move(layer))
{
UpdateActiveConfig();
[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;
}
bool Metal::Renderer::Initialize()
{
if (!::Renderer::Initialize())
return false;
SetupSurface();
g_state_tracker->FlushEncoders();
return true;
}
// MARK: Texture Creation
std::unique_ptr<AbstractTexture> Metal::Renderer::CreateTexture(const TextureConfig& config,
std::string_view name)
std::unique_ptr<AbstractTexture> Metal::Gfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
@autoreleasepool
{
@ -77,7 +72,7 @@ std::unique_ptr<AbstractTexture> Metal::Renderer::CreateTexture(const TextureCon
}
std::unique_ptr<AbstractStagingTexture>
Metal::Renderer::CreateStagingTexture(StagingTextureType type, const TextureConfig& config)
Metal::Gfx::CreateStagingTexture(StagingTextureType type, const TextureConfig& config)
{
@autoreleasepool
{
@ -98,8 +93,7 @@ Metal::Renderer::CreateStagingTexture(StagingTextureType type, const TextureConf
}
std::unique_ptr<AbstractFramebuffer>
Metal::Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
{
AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment;
return std::make_unique<Framebuffer>(
@ -110,9 +104,9 @@ Metal::Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
// MARK: Pipeline Creation
std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromSource(ShaderStage stage,
std::string_view source,
std::string_view name)
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromSource(ShaderStage stage,
std::string_view source,
std::string_view name)
{
std::optional<std::string> msl = Util::TranslateShaderToMSL(stage, source);
if (!msl.has_value())
@ -124,10 +118,9 @@ std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromSource(ShaderSt
return CreateShaderFromMSL(stage, std::move(*msl), source, name);
}
std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromBinary(ShaderStage stage,
const void* data,
size_t length,
std::string_view name)
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length,
std::string_view 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
std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromMSL(ShaderStage stage,
std::string msl,
std::string_view glsl,
std::string_view name)
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromMSL(ShaderStage stage, std::string msl,
std::string_view glsl,
std::string_view name)
{
@autoreleasepool
{
@ -243,7 +235,7 @@ std::unique_ptr<AbstractShader> Metal::Renderer::CreateShaderFromMSL(ShaderStage
}
std::unique_ptr<NativeVertexFormat>
Metal::Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
Metal::Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
@autoreleasepool
{
@ -251,14 +243,14 @@ Metal::Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_d
}
}
std::unique_ptr<AbstractPipeline>
Metal::Renderer::CreatePipeline(const AbstractPipelineConfig& config, const void* cache_data,
size_t cache_data_length)
std::unique_ptr<AbstractPipeline> Metal::Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return g_object_cache->CreatePipeline(config);
}
void Metal::Renderer::Flush()
void Metal::Gfx::Flush()
{
@autoreleasepool
{
@ -266,7 +258,7 @@ void Metal::Renderer::Flush()
}
}
void Metal::Renderer::WaitForGPUIdle()
void Metal::Gfx::WaitForGPUIdle()
{
@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)
[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,
bool alpha_enable, bool z_enable, u32 color, u32 z)
void Metal::Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable,
bool alpha_enable, bool z_enable, u32 color, u32 z)
{
MathUtil::Rectangle<int> target_rc = Renderer::ConvertEFBRectangle(rc);
target_rc.ClampUL(0, 0, m_target_width, m_target_height);
u32 framebuffer_width = m_current_framebuffer->GetWidth();
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
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
// 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_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);
}
void Metal::Renderer::SetPipeline(const AbstractPipeline* pipeline)
void Metal::Gfx::SetPipeline(const AbstractPipeline* 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.
if (AbstractTexture* color = framebuffer->GetColorAttachment())
@ -355,7 +348,7 @@ void Metal::Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
g_state_tracker->SetCurrentFramebuffer(static_cast<Framebuffer*>(framebuffer));
}
void Metal::Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
void Metal::Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
@autoreleasepool
{
@ -364,8 +357,8 @@ void Metal::Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
}
}
void Metal::Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
void Metal::Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
@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);
}
void Metal::Renderer::SetTexture(u32 index, const AbstractTexture* texture)
void Metal::Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{
g_state_tracker->SetTexture(
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);
}
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));
}
void Metal::Renderer::UnbindTexture(const AbstractTexture* texture)
void Metal::Gfx::UnbindTexture(const AbstractTexture* texture)
{
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,
float far_depth)
void Metal::Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float 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
{
@ -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
{
@ -424,9 +417,9 @@ void Metal::Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vert
}
}
void Metal::Renderer::DispatchComputeShader(const AbstractShader* shader, //
u32 groupsize_x, u32 groupsize_y, u32 groupsize_z,
u32 groups_x, u32 groups_y, u32 groups_z)
void Metal::Gfx::DispatchComputeShader(const AbstractShader* shader, //
u32 groupsize_x, u32 groupsize_y, u32 groupsize_z,
u32 groups_x, u32 groups_y, u32 groups_z)
{
@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
{
@ -448,7 +441,7 @@ void Metal::Renderer::BindBackbuffer(const ClearColor& clear_color)
}
}
void Metal::Renderer::PresentBackbuffer()
void Metal::Gfx::PresentBackbuffer()
{
@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>();
}
void Metal::Renderer::CheckForSurfaceChange()
{
if (!m_surface_changed.TestAndClear())
if (!g_presenter->SurfaceChangedTestAndClear())
return;
m_layer = MRCRetain(static_cast<CAMetalLayer*>(m_new_surface_handle));
m_new_surface_handle = nullptr;
m_layer = MRCRetain(static_cast<CAMetalLayer*>(g_presenter->GetNewSurfaceHandle()));
SetupSurface();
}
void Metal::Renderer::CheckForSurfaceResize()
void Metal::Gfx::CheckForSurfaceResize()
{
if (!m_surface_resized.TestAndClear())
if (!g_presenter->SurfaceResizedTestAndClear())
return;
SetupSurface();
}
void Metal::Renderer::SetupSurface()
void Metal::Gfx::SetupSurface()
{
CGSize size = [m_layer bounds].size;
// TODO: Update m_backbuffer_scale (need to make doing that not break everything)
const float backbuffer_scale = [m_layer contentsScale];
size.width *= backbuffer_scale;
size.height *= backbuffer_scale;
[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,
auto info = GetSurfaceInfo();
[m_layer setDrawableSize:{static_cast<double>(info.width), static_cast<double>(info.height)}];
TextureConfig cfg(info.width, info.height, 1, 1, 1, info.format,
AbstractTextureFlag_RenderTarget);
m_bb_texture = std::make_unique<Texture>(nullptr, cfg);
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/MsgHandler.h"
#include "VideoBackends/Metal/MTLBoundingBox.h"
#include "VideoBackends/Metal/MTLGfx.h"
#include "VideoBackends/Metal/MTLObjectCache.h"
#include "VideoBackends/Metal/MTLPerfQuery.h"
#include "VideoBackends/Metal/MTLRenderer.h"
#include "VideoBackends/Metal/MTLStateTracker.h"
#include "VideoBackends/Metal/MTLUtil.h"
#include "VideoBackends/Metal/MTLVertexManager.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.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]);
Util::PopulateBackendInfoFeatures(&g_Config, adapter);
// With the backend information populated, we can now initialize videocommon.
InitializeShared();
UpdateActiveConfig();
MRCOwned<CAMetalLayer*> layer = MRCRetain(static_cast<CAMetalLayer*>(wsi.render_surface));
[layer setDevice:adapter];
if (Util::ToAbstract([layer pixelFormat]) == AbstractTextureFormat::Undefined)
[layer setPixelFormat:MTLPixelFormatBGRA8Unorm];
CGSize size = [layer bounds].size;
float scale = [layer contentsScale];
if (!layer) // headless
scale = 1.0;
ObjectCache::Initialize(std::move(adapter));
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() ||
!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;
return InitializeShared(
std::make_unique<Metal::Gfx>(std::move(layer)), std::make_unique<Metal::VertexManager>(),
std::make_unique<Metal::PerfQuery>(), std::make_unique<Metal::BoundingBox>());
}
}
void Metal::VideoBackend::Shutdown()
{
g_shader_cache->Shutdown();
g_renderer->Shutdown();
ShutdownShared();
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();
ObjectCache::Shutdown();
ShutdownShared();
}
void Metal::VideoBackend::InitBackendInfo()

View File

@ -8,6 +8,7 @@
#include "VideoBackends/Metal/MRCHelpers.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/RenderState.h"
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)
{
u64 native_res_result = data[i] * (EFB_WIDTH * EFB_HEIGHT) /
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight());
u64 native_res_result =
data[i] * (EFB_WIDTH * EFB_HEIGHT) /
(g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
native_res_result /= g_ActiveConfig.iMultisamples;

View File

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

View File

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

View File

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

View File

@ -11,12 +11,14 @@
#include "Common/Common.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/PerfQuery.h"
#include "VideoBackends/Null/TextureCache.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
@ -69,39 +71,13 @@ void VideoBackend::InitBackendInfo()
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
InitializeShared();
g_renderer = std::make_unique<Renderer>();
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;
return InitializeShared(std::make_unique<NullGfx>(), std::make_unique<VertexManager>(),
std::make_unique<PerfQuery>(), std::make_unique<NullBoundingBox>(),
std::make_unique<NullRenderer>(), std::make_unique<TextureCache>());
}
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();
}

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
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/RenderBase.h"
class BoundingBox;
namespace Null
{
class Renderer final : public ::Renderer
class NullGfx final : public AbstractGfx
{
public:
Renderer();
~Renderer() override;
NullGfx();
~NullGfx() override;
bool IsHeadless() const override;
virtual bool SupportsUtilityDrawing() const override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override;
@ -34,18 +34,18 @@ public:
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data = nullptr,
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; }
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 {}
protected:
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
};
} // 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,
bool linear_filter, EFBCopyFormat dst_format, bool is_intensity,
float gamma, bool clamp_top, bool clamp_bottom,

View File

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

View File

@ -3,7 +3,7 @@
#include "VideoBackends/OGL/OGLBoundingBox.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoCommon/DriverDetails.h"
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.
// Using glGetBufferSubData instead does not seem to exhibit this slowdown.
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
// 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
#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/GLUtil.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/Logging/LogManager.h"
#include "Common/MathUtil.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.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/FramebufferManager.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#include <cstdio>
#include <string>
#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);
}
static void InitDriverInfo()
void InitDriverInfo()
{
const std::string_view svendor(g_ogl_config.gl_vendor);
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);
}
// Init functions
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())
bool PopulateConfig(GLContext* m_main_gl_context)
{
// 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 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_version = (const char*)glGetString(GL_VERSION);
InitDriverInfo();
if (!m_main_gl_context->IsGLES())
{
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?");
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.
@ -693,29 +555,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
}
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;
glGetIntegerv(GL_SAMPLES, &samples);
if (samples > 1)
@ -732,11 +571,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
}
if (!bSuccess)
{
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return;
}
return false;
g_Config.VerifyValidity();
UpdateActiveConfig();
@ -771,565 +606,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ",
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;
}
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

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
#pragma once
#include <array>
#include <string>
#include <string_view>
#include "VideoCommon/AbstractGfx.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoCommon/RenderBase.h"
class BoundingBox;
class GLContext;
namespace OGL
{
class OGLFramebuffer;
class OGLPipeline;
class OGLTexture;
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;
};
extern VideoConfig g_ogl_config;
class Renderer : public ::Renderer
class OGLGfx final : public AbstractGfx
{
public:
Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale);
~Renderer() override;
static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); }
OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale);
~OGLGfx();
bool IsHeadless() const override;
bool Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override;
std::unique_ptr<AbstractStagingTexture>
@ -116,6 +42,8 @@ public:
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
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 SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
@ -135,35 +63,32 @@ public:
void Flush() 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 ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
bool zEnable, u32 color, u32 z) override;
virtual void SelectLeftBuffer() override;
virtual void SelectRightBuffer() override;
virtual void SelectMainBuffer() override;
std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;
// Only call methods from this on the GPU thread.
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.
void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; }
// The shared framebuffer exists for copying textures when extensions are not available. It is
// slower, but the only way to do these things otherwise.
GLuint GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
GLuint GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
u32 GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
u32 GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
void BindSharedReadFramebuffer();
void BindSharedDrawFramebuffer();
// Restores FBO binding after it's been changed.
void RestoreFramebufferBinding();
protected:
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
SurfaceInfo GetSurfaceInfo() const override;
private:
void CheckForSurfaceChange();
@ -180,7 +105,14 @@ private:
RasterizationState m_current_rasterization_state;
DepthState m_current_depth_state;
BlendingState m_current_blend_state;
GLuint m_shared_read_framebuffer = 0;
GLuint m_shared_draw_framebuffer = 0;
u32 m_shared_read_framebuffer = 0;
u32 m_shared_draw_framebuffer = 0;
float m_backbuffer_scale;
};
inline OGLGfx* GetOGLGfx()
{
return static_cast<OGLGfx*>(g_gfx.get());
}
} // namespace OGL

View File

@ -46,8 +46,10 @@ Make AA apply instantly during gameplay if possible
#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/OGLRender.h"
#include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h"
@ -115,6 +117,8 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsTextureQueryLevels = false;
g_Config.backend_info.bSupportsSettingObjectNames = false;
g_Config.backend_info.bUsesExplictQuadBuffering = true;
g_Config.backend_info.Adapters.clear();
// 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())
return false;
InitializeShared();
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context), wsi.render_surface_scale);
auto gfx = std::make_unique<OGLGfx>(std::move(main_gl_context), wsi.render_surface_scale);
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>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
PanicAlertFmtT("Failed to initialize renderer classes");
Shutdown();
return false;
}
auto vertex_manager = std::make_unique<VertexManager>();
auto perf_query = GetPerfQuery(gfx->IsGLES());
auto bounding_box = std::make_unique<OGLBoundingBox>();
g_shader_cache->InitializeShaderCache();
return true;
return InitializeShared(std::move(gfx), std::move(vertex_manager), std::move(perf_query),
std::move(bounding_box));
}
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();
ProgramShaderCache::Shutdown();
g_sampler_cache.reset();
}
} // namespace OGL

View File

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

View File

@ -8,15 +8,15 @@
#include "Common/CommonTypes.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/VideoConfig.h"
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"))
return std::make_unique<PerfQueryGLESNV>();
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
// hardware behavior when drawing triangles.
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
if (g_ActiveConfig.iMultisamples > 1)
@ -264,8 +264,9 @@ void PerfQueryGLESNV::FlushOne()
// NOTE: Reported pixel metrics should be referenced to native resolution
// TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles.
const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT /
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight());
const u64 native_res_result =
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),
std::memory_order_relaxed);

View File

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

View File

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

View File

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

View File

@ -7,6 +7,8 @@
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/VideoConfig.h"
@ -160,7 +162,7 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config, std::string_view name)
OGLTexture::~OGLTexture()
{
Renderer::GetInstance()->UnbindTexture(this);
GetOGLGfx()->UnbindTexture(this);
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,
u32 dst_level)
{
Renderer::GetInstance()->BindSharedReadFramebuffer();
GetOGLGfx()->BindSharedReadFramebuffer();
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
src_layer);
Renderer::GetInstance()->BindSharedDrawFramebuffer();
GetOGLGfx()->BindSharedDrawFramebuffer();
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
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
// restore, as the framebuffer and scissor test are the only things we changed.
glEnable(GL_SCISSOR_TEST);
Renderer::GetInstance()->RestoreFramebufferBinding();
GetOGLGfx()->RestoreFramebufferBinding();
}
void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
@ -391,7 +393,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
else
{
// Mutate the shared framebuffer.
Renderer::GetInstance()->BindSharedReadFramebuffer();
GetOGLGfx()->BindSharedReadFramebuffer();
if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
{
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(),
GetGLFormatForTextureFormat(src->GetFormat()),
GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset));
Renderer::GetInstance()->RestoreFramebufferBinding();
GetOGLGfx()->RestoreFramebufferBinding();
}
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);
Renderer::GetInstance()->RestoreFramebufferBinding();
GetOGLGfx()->RestoreFramebufferBinding();
return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
depth_format, width, height, layers, samples, fbo);

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,8 @@ add_library(videosoftware
SWmain.cpp
SWBoundingBox.cpp
SWBoundingBox.h
SWGfx.cpp
SWGfx.h
SWOGLWindow.cpp
SWOGLWindow.h
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 "Common/CommonTypes.h"
#include "Common/GL/GLContext.h"
#include "Common/MsgHandler.h"
#include "Core/HW/Memmap.h"
#include "Core/System.h"
#include "VideoBackends/Software/EfbCopy.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/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
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 value = 0;
@ -166,29 +66,4 @@ u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
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

View File

@ -10,60 +10,14 @@
#include "VideoCommon/RenderBase.h"
class BoundingBox;
class SWOGLWindow;
namespace SW
{
class SWRenderer final : public Renderer
{
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;
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 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

View File

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

View File

@ -18,6 +18,7 @@
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TransformUnit.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/DataReader.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
if (g_renderer->IsBBoxEnabled())
g_renderer->BBoxFlush();
if (g_bounding_box->IsEnabled())
g_bounding_box->Flush();
m_setup_unit.Init(primitive_type);
Rasterizer::SetTevKonstColors();

View File

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

View File

@ -19,7 +19,7 @@ protected:
TextureEncoder::Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride,
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,
bool linear_filter, EFBCopyFormat dst_format, bool is_intensity,
float gamma, bool clamp_top, bool clamp_bottom,

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
#include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
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);
// Wait until these commands complete.
Renderer::GetInstance()->ExecuteCommandBuffer(false, true);
VKGfx::GetInstance()->ExecuteCommandBuffer(false, true);
// Cache is now valid.
m_readback_buffer->InvalidateCPUCache();

View File

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

View File

@ -1,7 +1,7 @@
// Copyright 2016 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Vulkan/VKRenderer.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include <algorithm>
#include <cstddef>
@ -15,152 +15,98 @@
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Core/Core.h"
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKBoundingBox.h"
#include "VideoBackends/Vulkan/VKPerfQuery.h"
#include "VideoBackends/Vulkan/VKPipeline.h"
#include "VideoBackends/Vulkan/VKShader.h"
#include "VideoBackends/Vulkan/VKStreamBuffer.h"
#include "VideoBackends/Vulkan/VKSwapChain.h"
#include "VideoBackends/Vulkan/VKTexture.h"
#include "VideoBackends/Vulkan/VKVertexFormat.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
namespace Vulkan
{
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: ::Renderer(swap_chain ? static_cast<int>(swap_chain->GetWidth()) : 1,
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))
VKGfx::VKGfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale)
: m_swap_chain(std::move(swap_chain)), m_backbuffer_scale(backbuffer_scale)
{
UpdateActiveConfig();
for (SamplerState& m_sampler_state : m_sampler_states)
m_sampler_state = RenderState::GetPointSamplerState();
}
Renderer::~Renderer() = default;
bool Renderer::IsHeadless() const
{
return m_swap_chain == nullptr;
}
bool Renderer::Initialize()
{
if (!::Renderer::Initialize())
return false;
for (SamplerState& sampler_state : m_sampler_states)
sampler_state = RenderState::GetPointSamplerState();
// Various initialization routines will have executed commands on the command buffer.
// Execute what we have done before beginning the first frame.
ExecuteCommandBuffer(true, false);
return true;
}
void Renderer::Shutdown()
VKGfx::~VKGfx() = default;
bool VKGfx::IsHeadless() const
{
::Renderer::Shutdown();
m_swap_chain.reset();
return m_swap_chain == nullptr;
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
std::string_view name)
std::unique_ptr<AbstractTexture> VKGfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return VKTexture::Create(config, name);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
std::unique_ptr<AbstractStagingTexture> VKGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return VKStagingTexture::Create(type, config);
}
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);
}
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length,
std::string_view name)
std::unique_ptr<AbstractShader> VKGfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length, std::string_view name)
{
return VKShader::CreateFromBinary(stage, data, length, name);
}
std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
VKGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<VertexFormat>(vtx_decl);
}
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
std::unique_ptr<AbstractPipeline> VKGfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return VKPipeline::Create(config);
}
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
std::unique_ptr<AbstractFramebuffer> VKGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return VKFramebuffer::Create(static_cast<VKTexture*>(color_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));
}
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 = {
{target_rc.left, target_rc.top},
{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.
VkClearValue clear_color_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)
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);
}
void Renderer::WaitForGPUIdle()
void VKGfx::WaitForGPUIdle()
{
ExecuteCommandBuffer(false, true);
}
void Renderer::BindBackbuffer(const ClearColor& clear_color)
void VKGfx::BindBackbuffer(const ClearColor& clear_color)
{
StateTracker::GetInstance()->EndRenderPass();
@ -334,7 +280,7 @@ void Renderer::BindBackbuffer(const ClearColor& clear_color)
ClearColor{{0.0f, 0.0f, 0.0f, 1.0f}});
}
void Renderer::PresentBackbuffer()
void VKGfx::PresentBackbuffer()
{
// End drawing to backbuffer
StateTracker::GetInstance()->EndRenderPass();
@ -355,7 +301,7 @@ void Renderer::PresentBackbuffer()
StateTracker::GetInstance()->InvalidateCachedState();
}
void Renderer::SetFullscreen(bool enable_fullscreen)
void VKGfx::SetFullscreen(bool enable_fullscreen)
{
if (!m_swap_chain->IsFullscreenSupported())
return;
@ -363,12 +309,12 @@ void Renderer::SetFullscreen(bool enable_fullscreen)
m_swap_chain->SetNextFullscreenState(enable_fullscreen);
}
bool Renderer::IsFullscreen() const
bool VKGfx::IsFullscreen() const
{
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();
@ -377,9 +323,9 @@ void Renderer::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_comple
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;
// Submit the current draws up until rendering the XFB.
@ -389,17 +335,16 @@ void Renderer::CheckForSurfaceChange()
g_command_buffer_mgr->CheckLastPresentFail();
// 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.");
m_new_surface_handle = nullptr;
// Handle case where the dimensions are now different.
OnSwapChainResized();
}
void Renderer::CheckForSurfaceResize()
void VKGfx::CheckForSurfaceResize()
{
if (!m_surface_resized.TestAndClear())
if (!g_presenter->SurfaceResizedTestAndClear())
return;
// If we don't have a surface, how can we resize the swap chain?
@ -421,8 +366,10 @@ void Renderer::CheckForSurfaceResize()
OnSwapChainResized();
}
void Renderer::OnConfigChanged(u32 bits)
void VKGfx::OnConfigChanged(u32 bits)
{
AbstractGfx::OnConfigChanged(bits);
if (bits & CONFIG_CHANGE_BIT_HOST_CONFIG)
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();
m_backbuffer_height = m_swap_chain->GetHeight();
g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
}
void Renderer::BindFramebuffer(VKFramebuffer* fb)
void VKGfx::BindFramebuffer(VKFramebuffer* fb)
{
StateTracker::GetInstance()->EndRenderPass();
@ -475,7 +421,7 @@ void Renderer::BindFramebuffer(VKFramebuffer* fb)
m_current_framebuffer = fb;
}
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
void VKGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
@ -484,7 +430,7 @@ void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
BindFramebuffer(vkfb);
}
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
void VKGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
@ -497,8 +443,8 @@ void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
StateTracker::GetInstance()->BeginDiscardRenderPass();
}
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
void VKGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
float depth_value)
{
VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer);
BindFramebuffer(vkfb);
@ -521,7 +467,7 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
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.
// 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())
{
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();
}
@ -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.
if (m_sampler_states[index] == state)
@ -566,7 +512,7 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& 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);
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());
}
void Renderer::ResetSamplerStates()
void VKGfx::ResetSamplerStates()
{
// Invalidate all sampler states, next draw will re-initialize them.
for (u32 i = 0; i < m_sampler_states.size(); i++)
@ -602,7 +548,7 @@ void Renderer::ResetSamplerStates()
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},
{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);
}
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
void VKGfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
VkViewport viewport = {x, y, width, height, near_depth, far_depth};
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())
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);
}
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())
return;
@ -646,12 +592,19 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
base_vertex, 0);
}
void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
void VKGfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
StateTracker::GetInstance()->SetComputeShader(static_cast<const VKShader*>(shader));
if (StateTracker::GetInstance()->BindCompute())
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

View File

@ -4,16 +4,12 @@
#pragma once
#include <array>
#include <cstddef>
#include <memory>
#include <string_view>
#include "Common/CommonTypes.h"
#include "VideoBackends/Vulkan/Constants.h"
#include "VideoCommon/RenderBase.h"
class BoundingBox;
struct XFBSourceBase;
#include "VideoCommon/AbstractGfx.h"
namespace Vulkan
{
@ -23,19 +19,16 @@ class VKFramebuffer;
class VKPipeline;
class VKTexture;
class Renderer : public ::Renderer
class VKGfx final : public ::AbstractGfx
{
public:
Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~Renderer() override;
VKGfx(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale);
~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 Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override;
std::unique_ptr<AbstractStagingTexture>
@ -60,7 +53,7 @@ public:
void WaitForGPUIdle() 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;
void SetPipeline(const AbstractPipeline* pipeline) override;
@ -84,13 +77,12 @@ public:
void SetFullscreen(bool enable_fullscreen) override;
bool IsFullscreen() const override;
virtual SurfaceInfo GetSurfaceInfo() const override;
// 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.
void ExecuteCommandBuffer(bool execute_off_thread, bool wait_for_completion = false);
protected:
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
private:
void CheckForSurfaceChange();
void CheckForSurfaceResize();
@ -101,6 +93,7 @@ private:
void BindFramebuffer(VKFramebuffer* fb);
std::unique_ptr<SwapChain> m_swap_chain;
float m_backbuffer_scale;
// Keep a copy of sampler states to avoid cache lookups every draw
std::array<SamplerState, NUM_PIXEL_SHADER_SAMPLERS> m_sampler_states = {};

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@
#include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VKStreamBuffer.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.
WARN_LOG_FMT(VIDEO,
"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.
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)
{
// Execute the command buffer and wait for it to finish.
Renderer::GetInstance()->ExecuteCommandBuffer(false, true);
VKGfx::GetInstance()->ExecuteCommandBuffer(false, true);
}
else
{

View File

@ -14,7 +14,7 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKRenderer.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VKStreamBuffer.h"
#include "VideoBackends/Vulkan/VKVertexFormat.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
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
if (!has_vbuffer_allocation)
@ -266,7 +266,7 @@ bool VertexManager::ReserveConstantStorage()
// 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");
Renderer::GetInstance()->ExecuteCommandBuffer(false);
VKGfx::GetInstance()->ExecuteCommandBuffer(false);
// 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.
@ -337,7 +337,7 @@ void VertexManager::UploadUtilityUniforms(const void* data, u32 data_size)
g_vulkan_context->GetUniformBufferAlignment()))
{
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(
@ -358,7 +358,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
{
// Try submitting cmdbuffer.
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))
{
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.
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))
{
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/Image.h"
#include "Common/MsgHandler.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/RenderBase.h"
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,
AbstractTextureFormat::RGBA8, 0);
auto readback_texture =
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
g_gfx->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
if (!readback_texture)
return false;

View File

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

View File

@ -12,11 +12,13 @@
#include "Common/Logging/Log.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.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)
{
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)
{
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);
}
}
@ -197,10 +199,9 @@ void SetScissorAndViewport()
{
auto native_rc = ComputeScissorRects().Best();
auto target_rc = g_renderer->ConvertEFBRectangle(native_rc.rect);
auto converted_rc =
g_renderer->ConvertFramebufferRectangle(target_rc, g_renderer->GetCurrentFramebuffer());
g_renderer->SetScissorRect(converted_rc);
auto target_rc = g_framebuffer_manager->ConvertEFBRectangle(native_rc.rect);
auto converted_rc = g_gfx->ConvertFramebufferRectangle(target_rc, g_gfx->GetCurrentFramebuffer());
g_gfx->SetScissorRect(converted_rc);
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;
@ -216,10 +217,10 @@ void SetScissorAndViewport()
raw_height = std::round(raw_height);
}
float x = g_renderer->EFBToScaledXf(raw_x);
float y = g_renderer->EFBToScaledYf(raw_y);
float width = g_renderer->EFBToScaledXf(raw_width);
float height = g_renderer->EFBToScaledYf(raw_height);
float x = g_framebuffer_manager->EFBToScaledXf(raw_x);
float y = g_framebuffer_manager->EFBToScaledYf(raw_y);
float width = g_framebuffer_manager->EFBToScaledXf(raw_width);
float height = g_framebuffer_manager->EFBToScaledYf(raw_height);
float min_depth = (xfmem.viewport.farZ - xfmem.viewport.zRange) / 16777216.0f;
float max_depth = xfmem.viewport.farZ / 16777216.0f;
if (width < 0.f)
@ -246,7 +247,7 @@ void SetScissorAndViewport()
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.
// Taking into account whether the depth range is inverted or not.
@ -280,9 +281,9 @@ void SetScissorAndViewport()
// Lower-left flip.
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()
@ -342,7 +343,7 @@ void ClearScreen(const MathUtil::Rectangle<int>& rc)
color = RGBA8ToRGB565ToRGBA8(color);
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)
return;
const auto old_format = g_renderer->GetPrevPixelFormat();
const auto old_format = g_framebuffer_manager->GetPrevPixelFormat();
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);

View File

@ -33,7 +33,7 @@
#include "VideoCommon/PerfQueryBase.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/TMEM.h"
#include "VideoCommon/TextureCacheBase.h"
@ -42,6 +42,7 @@
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/VideoEvents.h"
using namespace BPFunctions;
@ -185,6 +186,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
{
INCSTAT(g_stats.this_frame.num_draw_done);
g_texture_cache->FlushEFBCopies();
g_texture_cache->FlushStaleBinds();
g_framebuffer_manager->InvalidatePeekCache(false);
g_framebuffer_manager->RefreshPeekCache();
auto& system = Core::System::GetInstance();
@ -203,6 +205,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
{
INCSTAT(g_stats.this_frame.num_token);
g_texture_cache->FlushEFBCopies();
g_texture_cache->FlushStaleBinds();
g_framebuffer_manager->InvalidatePeekCache(false);
g_framebuffer_manager->RefreshPeekCache();
auto& system = Core::System::GetInstance();
@ -218,6 +221,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
{
INCSTAT(g_stats.this_frame.num_token_int);
g_texture_cache->FlushEFBCopies();
g_texture_cache->FlushStaleBinds();
g_framebuffer_manager->InvalidatePeekCache(false);
g_framebuffer_manager->RefreshPeekCache();
auto& system = Core::System::GetInstance();
@ -282,7 +286,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
if (PE_copy.copy_to_xfb == 1)
{
// 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;
@ -313,7 +317,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
// 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.
// 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;
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,
bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients());
// This stays in to signal end of a "frame"
g_renderer->RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]);
// This is as closest as we have to an "end of the frame"
// 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)
{
// below div two to convert from bytes to pixels - it expects width, not stride
g_renderer->Swap(destAddr, destStride / 2, destStride, height,
Core::System::GetInstance().GetCoreTiming().GetTicks());
u64 ticks = Core::System::GetInstance().GetCoreTiming().GetTicks();
g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height, ticks);
}
else
{
@ -481,10 +497,10 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
case BPMEM_CLEARBBOX2:
{
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_renderer->BBoxWrite(offset + 1, bp.newvalue >> 10);
g_bounding_box->Set(offset, bp.newvalue & 0x3ff);
g_bounding_box->Set(offset + 1, bp.newvalue >> 10);
}
return;
case BPMEM_TEXINVALIDATE:

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