Merge pull request #11522 from phire/KillRendererWithFire
Kill Renderer (with phire)
This commit is contained in:
commit
ccf92a3e56
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
#include "InputCommon/GCAdapter.h"
|
||||
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
|
||||
static std::unique_ptr<Platform> s_platform;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
|
||||
#include "VideoCommon/NetPlayChatUI.h"
|
||||
#include "VideoCommon/NetPlayGolfUI.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
|
||||
#include "VideoCommon/NetPlayChatUI.h"
|
||||
#include "VideoCommon/NetPlayGolfUI.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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))
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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])};
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "VideoBackends/Metal/MRCHelpers.h"
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
struct AbstractPipelineConfig;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
namespace OGL
|
||||
{
|
||||
std::unique_ptr<PerfQueryBase> GetPerfQuery();
|
||||
std::unique_ptr<PerfQueryBase> GetPerfQuery(bool is_gles);
|
||||
|
||||
class PerfQuery : public PerfQueryBase
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "VideoBackends/OGL/OGLRender.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
|
|
@ -14,6 +14,8 @@ add_library(videosoftware
|
|||
SWmain.cpp
|
||||
SWBoundingBox.cpp
|
||||
SWBoundingBox.h
|
||||
SWGfx.cpp
|
||||
SWGfx.h
|
||||
SWOGLWindow.cpp
|
||||
SWOGLWindow.h
|
||||
SWRenderer.cpp
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Vulkan/StagingBuffer.h"
|
||||
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
||||
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
|
|
|
@ -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
|
|
@ -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 = {};
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue