diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index cf038dc1a..2e1e912d8 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -85,7 +85,6 @@
-
@@ -211,7 +210,6 @@
-
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 8122d5e0c..46355f68d 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -23,7 +23,6 @@
-
@@ -204,7 +203,6 @@
-
diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp
index b42d49a10..7c8dd47e3 100644
--- a/src/core/gpu.cpp
+++ b/src/core/gpu.cpp
@@ -78,12 +78,6 @@ void GPU::UpdateSettings()
g_host_display->SetGPUTimingEnabled(g_settings.display_show_gpu);
}
-bool GPU::IsHardwareRenderer()
-{
- const GPURenderer renderer = GetRendererType();
- return (renderer != GPURenderer::Software);
-}
-
void GPU::CPUClockChanged()
{
UpdateCRTCConfig();
diff --git a/src/core/gpu.h b/src/core/gpu.h
index 5fb66e060..a8edc18c1 100644
--- a/src/core/gpu.h
+++ b/src/core/gpu.h
@@ -80,8 +80,8 @@ public:
GPU();
virtual ~GPU();
- virtual GPURenderer GetRendererType() const = 0;
virtual const Threading::Thread* GetSWThread() const = 0;
+ virtual bool IsHardwareRenderer() const = 0;
virtual bool Initialize();
virtual void Reset(bool clear_vram);
@@ -93,7 +93,6 @@ public:
// Render statistics debug window.
void DrawDebugStateWindow();
- bool IsHardwareRenderer();
void CPUClockChanged();
// MMIO access
diff --git a/src/core/gpu/d3d11_device.cpp b/src/core/gpu/d3d11_device.cpp
index 3270acbda..dde18fb8b 100644
--- a/src/core/gpu/d3d11_device.cpp
+++ b/src/core/gpu/d3d11_device.cpp
@@ -6,8 +6,8 @@
#include "../settings.h"
#include "../shader_cache_version.h"
-#include "common/assert.h"
#include "common/align.h"
+#include "common/assert.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
@@ -451,17 +451,7 @@ bool D3D11Device::CreateDevice(const WindowInfo& wi, bool vsync)
}
}
- m_allow_tearing_supported = false;
- ComPtr dxgi_factory5;
- hr = m_dxgi_factory.As(&dxgi_factory5);
- if (SUCCEEDED(hr))
- {
- BOOL allow_tearing_supported = false;
- hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
- sizeof(allow_tearing_supported));
- if (SUCCEEDED(hr))
- m_allow_tearing_supported = (allow_tearing_supported == TRUE);
- }
+ SetFeatures();
m_window_info = wi;
m_vsync_enabled = vsync;
@@ -486,6 +476,43 @@ bool D3D11Device::SetupDevice()
return true;
}
+void D3D11Device::SetFeatures()
+{
+ const D3D_FEATURE_LEVEL feature_level = m_device->GetFeatureLevel();
+
+ m_max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ m_max_multisamples = 1;
+ for (u32 multisamples = 2; multisamples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; multisamples++)
+ {
+ UINT num_quality_levels;
+ if (SUCCEEDED(
+ m_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, multisamples, &num_quality_levels)) &&
+ num_quality_levels > 0)
+ {
+ m_max_multisamples = multisamples;
+ }
+ }
+
+ m_features.dual_source_blend = true;
+ m_features.per_sample_shading = (feature_level >= D3D_FEATURE_LEVEL_10_1);
+ m_features.mipmapped_render_targets = true;
+ m_features.noperspective_interpolation = true;
+ m_features.supports_texture_buffers = true;
+ m_features.texture_buffers_emulated_with_ssbo = false;
+
+ m_allow_tearing_supported = false;
+ ComPtr dxgi_factory5;
+ HRESULT hr = m_dxgi_factory.As(&dxgi_factory5);
+ if (SUCCEEDED(hr))
+ {
+ BOOL allow_tearing_supported = false;
+ hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
+ sizeof(allow_tearing_supported));
+ if (SUCCEEDED(hr))
+ m_allow_tearing_supported = (allow_tearing_supported == TRUE);
+ }
+}
+
bool D3D11Device::MakeCurrent()
{
return true;
@@ -1049,85 +1076,99 @@ std::unique_ptr D3D11Device::CreateFramebuffer(GPUTexture* rt, u
if (rt)
{
- D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
- rtv_desc.Format = static_cast(rt)->GetDXGIFormat();
- if (rt->IsMultisampled())
+ if (rt_layer == 0 && rt_level == 0)
{
- Assert(rt_level == 0);
- if (rt->GetLayers() > 1)
- {
- rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
- rtv_desc.Texture2DMSArray.ArraySize = rt->GetLayers();
- rtv_desc.Texture2DMSArray.FirstArraySlice = rt_layer;
- }
- else
- {
- rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
- }
+ rtv = static_cast(rt)->GetD3DRTV();
}
else
{
- if (rt->GetLayers() > 1)
+ D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
+ rtv_desc.Format = static_cast(rt)->GetDXGIFormat();
+ if (rt->IsMultisampled())
{
- rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
- rtv_desc.Texture2DArray.ArraySize = rt->GetLayers();
- rtv_desc.Texture2DArray.FirstArraySlice = rt_layer;
- rtv_desc.Texture2DArray.MipSlice = rt_level;
+ Assert(rt_level == 0);
+ if (rt->GetLayers() > 1)
+ {
+ rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
+ rtv_desc.Texture2DMSArray.ArraySize = rt->GetLayers();
+ rtv_desc.Texture2DMSArray.FirstArraySlice = rt_layer;
+ }
+ else
+ {
+ rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
+ }
}
else
{
- rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
- rtv_desc.Texture2D.MipSlice = rt_level;
+ if (rt->GetLayers() > 1)
+ {
+ rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtv_desc.Texture2DArray.ArraySize = rt->GetLayers();
+ rtv_desc.Texture2DArray.FirstArraySlice = rt_layer;
+ rtv_desc.Texture2DArray.MipSlice = rt_level;
+ }
+ else
+ {
+ rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ rtv_desc.Texture2D.MipSlice = rt_level;
+ }
}
- }
- if (FAILED(hr = m_device->CreateRenderTargetView(static_cast(rt)->GetD3DTexture(), &rtv_desc,
- rtv.GetAddressOf())))
- {
- Log_ErrorPrintf("CreateRenderTargetView() failed: %08X", hr);
- return {};
+ if (FAILED(hr = m_device->CreateRenderTargetView(static_cast(rt)->GetD3DTexture(), &rtv_desc,
+ rtv.GetAddressOf())))
+ {
+ Log_ErrorPrintf("CreateRenderTargetView() failed: %08X", hr);
+ return {};
+ }
}
}
if (ds)
{
- D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
- dsv_desc.Format = static_cast(ds)->GetDXGIFormat();
- if (ds->IsMultisampled())
+ if (ds_layer == 0 && ds_level == 0)
{
- Assert(rt_level == 0);
- if (ds->GetLayers() > 1)
- {
- dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
- dsv_desc.Texture2DMSArray.ArraySize = ds->GetLayers();
- dsv_desc.Texture2DMSArray.FirstArraySlice = rt_layer;
- }
- else
- {
- dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
- }
+ dsv = static_cast(ds)->GetD3DDSV();
}
else
{
- if (ds->GetLayers() > 1)
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
+ dsv_desc.Format = static_cast(ds)->GetDXGIFormat();
+ if (ds->IsMultisampled())
{
- dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
- dsv_desc.Texture2DArray.ArraySize = ds->GetLayers();
- dsv_desc.Texture2DArray.FirstArraySlice = rt_layer;
- dsv_desc.Texture2DArray.MipSlice = rt_level;
+ Assert(rt_level == 0);
+ if (ds->GetLayers() > 1)
+ {
+ dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
+ dsv_desc.Texture2DMSArray.ArraySize = ds->GetLayers();
+ dsv_desc.Texture2DMSArray.FirstArraySlice = rt_layer;
+ }
+ else
+ {
+ dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
+ }
}
else
{
- dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
- dsv_desc.Texture2D.MipSlice = rt_level;
+ if (ds->GetLayers() > 1)
+ {
+ dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
+ dsv_desc.Texture2DArray.ArraySize = ds->GetLayers();
+ dsv_desc.Texture2DArray.FirstArraySlice = rt_layer;
+ dsv_desc.Texture2DArray.MipSlice = rt_level;
+ }
+ else
+ {
+ dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+ dsv_desc.Texture2D.MipSlice = rt_level;
+ }
}
- }
- if (FAILED(hr = m_device->CreateDepthStencilView(static_cast(ds)->GetD3DTexture(), &dsv_desc,
- dsv.GetAddressOf())))
- {
- Log_ErrorPrintf("CreateDepthStencilView() failed: %08X", hr);
- return {};
+ if (FAILED(hr = m_device->CreateDepthStencilView(static_cast(ds)->GetD3DTexture(), &dsv_desc,
+ dsv.GetAddressOf())))
+ {
+ Log_ErrorPrintf("CreateDepthStencilView() failed: %08X", hr);
+ return {};
+ }
}
}
@@ -1911,6 +1952,56 @@ void D3D11Texture::Destroy()
ClearBaseProperties();
}
+D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
+{
+}
+
+D3D11TextureBuffer::~D3D11TextureBuffer() = default;
+
+bool D3D11TextureBuffer::CreateBuffer(ID3D11Device* device)
+{
+ if (!m_buffer.Create(device, D3D11_BIND_SHADER_RESOURCE, GetSizeInBytes()))
+ return false;
+
+ static constexpr std::array(Format::MaxCount)> dxgi_formats = {{
+ DXGI_FORMAT_R16_UINT,
+ }};
+
+ CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(m_buffer.GetD3DBuffer(), dxgi_formats[static_cast(m_format)], 0,
+ m_size_in_elements);
+ const HRESULT hr = device->CreateShaderResourceView(m_buffer.GetD3DBuffer(), &srv_desc, m_srv.GetAddressOf());
+ if (FAILED(hr))
+ {
+ Log_ErrorPrintf("CreateShaderResourceView() failed: %08X", hr);
+ return false;
+ }
+
+ return true;
+}
+
+void* D3D11TextureBuffer::Map(u32 required_elements)
+{
+ const u32 esize = GetElementSize(m_format);
+ const auto res = m_buffer.Map(D3D11Device::GetD3DContext(), esize, esize * required_elements);
+ m_current_position = res.index_aligned;
+ return res.pointer;
+}
+
+void D3D11TextureBuffer::Unmap(u32 used_elements)
+{
+ m_buffer.Unmap(D3D11Device::GetD3DContext(), used_elements * GetElementSize(m_format));
+}
+
+std::unique_ptr D3D11Device::CreateTextureBuffer(GPUTextureBuffer::Format format,
+ u32 size_in_elements)
+{
+ std::unique_ptr tb = std::make_unique(format, size_in_elements);
+ if (!tb->CreateBuffer(m_device.Get()))
+ tb.reset();
+
+ return tb;
+}
+
void D3D11Device::PushDebugGroup(const char* fmt, ...)
{
if (!m_annotation)
@@ -2054,6 +2145,12 @@ void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* s
m_context->PSSetSamplers(0, 1, S->GetSamplerStateArray());
}
+void D3D11Device::SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer)
+{
+ D3D11TextureBuffer* B = static_cast(buffer);
+ m_context->PSSetShaderResources(0, 1, B->GetSRVArray());
+}
+
void D3D11Device::UnbindTexture(D3D11Texture* tex)
{
// TODO
@@ -2316,4 +2413,4 @@ bool D3D11Device::RenderScreenshot(u32 width, u32 height, const Common::Rectangl
return true;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/core/gpu/d3d11_device.h b/src/core/gpu/d3d11_device.h
index 278f868f3..f5f331c79 100644
--- a/src/core/gpu/d3d11_device.h
+++ b/src/core/gpu/d3d11_device.h
@@ -229,6 +229,27 @@ private:
bool m_dynamic = false;
};
+class D3D11TextureBuffer final : public GPUTextureBuffer
+{
+public:
+ D3D11TextureBuffer(Format format, u32 size_in_elements);
+ ~D3D11TextureBuffer() override;
+
+ ALWAYS_INLINE ID3D11Buffer* GetBuffer() const { return m_buffer.GetD3DBuffer(); }
+ ALWAYS_INLINE ID3D11ShaderResourceView* GetSRV() const { return m_srv.Get(); }
+ ALWAYS_INLINE ID3D11ShaderResourceView* const* GetSRVArray() const { return m_srv.GetAddressOf(); }
+
+ bool CreateBuffer(ID3D11Device* device);
+
+ // Inherited via GPUTextureBuffer
+ virtual void* Map(u32 required_elements) override;
+ virtual void Unmap(u32 used_elements) override;
+
+private:
+ D3D11StreamBuffer m_buffer;
+ Microsoft::WRL::ComPtr m_srv;
+};
+
class D3D11Device final : public GPUDevice
{
public:
@@ -270,6 +291,7 @@ public:
const void* data = nullptr, u32 data_stride = 0,
bool dynamic = false) override;
std::unique_ptr CreateSampler(const GPUSampler::Config& config) override;
+ std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 out_data_stride) override;
@@ -303,6 +325,7 @@ public:
void SetFramebuffer(GPUFramebuffer* fb) override;
void SetPipeline(GPUPipeline* pipeline) override;
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
+ void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
void SetViewport(s32 x, s32 y, s32 width, s32 height) override;
void SetScissor(s32 x, s32 y, s32 width, s32 height) override;
void Draw(u32 vertex_count, u32 base_vertex) override;
@@ -338,6 +361,8 @@ private:
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
+ void SetFeatures();
+
void PreDrawCheck();
bool CheckStagingBufferSize(u32 width, u32 height, DXGI_FORMAT format);
diff --git a/src/core/gpu/gpu_device.cpp b/src/core/gpu/gpu_device.cpp
index 49325aa7a..5349a2338 100644
--- a/src/core/gpu/gpu_device.cpp
+++ b/src/core/gpu/gpu_device.cpp
@@ -138,6 +138,21 @@ GPUPipeline::BlendState GPUPipeline::BlendState::GetAlphaBlendingState()
return ret;
}
+GPUTextureBuffer::GPUTextureBuffer(Format format, u32 size) : m_format(format), m_size_in_elements(size)
+{
+}
+
+GPUTextureBuffer::~GPUTextureBuffer() = default;
+
+u32 GPUTextureBuffer::GetElementSize(Format format)
+{
+ static constexpr std::array(Format::MaxCount)> element_size = {{
+ sizeof(u16),
+ }};
+
+ return element_size[static_cast(format)];
+}
+
GPUDevice::~GPUDevice()
{
// TODO: move to Destroy() method
@@ -426,6 +441,12 @@ void GPUDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sam
UnreachableCode();
}
+void GPUDevice::SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer)
+{
+ // TODO: REMOVE ME
+ UnreachableCode();
+}
+
void GPUDevice::SetViewport(s32 x, s32 y, s32 width, s32 height)
{
// TODO: REMOVE ME
@@ -528,6 +549,13 @@ std::unique_ptr GPUDevice::CreateSampler(const GPUSampler::Config& c
return {};
}
+std::unique_ptr GPUDevice::CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements)
+{
+ // TODO: REMOVE ME
+ UnreachableCode();
+ return {};
+}
+
std::unique_ptr GPUDevice::CreateFramebuffer(GPUTexture* rt, u32 rt_layer, u32 rt_level, GPUTexture* ds,
u32 ds_layer, u32 ds_level)
{
diff --git a/src/core/gpu/gpu_device.h b/src/core/gpu/gpu_device.h
index cd6c4a301..9bd2fde5d 100644
--- a/src/core/gpu/gpu_device.h
+++ b/src/core/gpu/gpu_device.h
@@ -340,12 +340,51 @@ public:
virtual void SetDebugName(const std::string_view& name) = 0;
};
+class GPUTextureBuffer
+{
+public:
+ enum class Format
+ {
+ R16UI,
+
+ MaxCount
+ };
+
+ GPUTextureBuffer(Format format, u32 size_in_elements);
+ virtual ~GPUTextureBuffer();
+
+ static u32 GetElementSize(Format format);
+
+ ALWAYS_INLINE Format GetFormat() const { return m_format; }
+ ALWAYS_INLINE u32 GetSizeInElements() const { return m_size_in_elements; }
+ ALWAYS_INLINE u32 GetSizeInBytes() const { return m_size_in_elements * GetElementSize(m_format); }
+ ALWAYS_INLINE u32 GetCurrentPosition() const { return m_current_position; }
+
+ virtual void* Map(u32 required_elements) = 0;
+ virtual void Unmap(u32 used_elements) = 0;
+
+protected:
+ Format m_format;
+ u32 m_size_in_elements;
+ u32 m_current_position;
+};
+
class GPUDevice
{
public:
// TODO: drop virtuals
using DrawIndex = u16;
+ struct Features
+ {
+ bool dual_source_blend : 1;
+ bool per_sample_shading : 1;
+ bool mipmapped_render_targets : 1;
+ bool noperspective_interpolation : 1;
+ bool supports_texture_buffers : 1;
+ bool texture_buffers_emulated_with_ssbo : 1;
+ };
+
struct AdapterAndModeList
{
std::vector adapter_names;
@@ -363,6 +402,10 @@ public:
/// Converts a fullscreen mode to a string.
static std::string GetFullscreenModeString(u32 width, u32 height, float refresh_rate);
+ ALWAYS_INLINE const Features& GetFeatures() const { return m_features; }
+ ALWAYS_INLINE u32 GetMaxTextureSize() const { return m_max_texture_size; }
+ ALWAYS_INLINE u32 GetMaxMultisamples() const { return m_max_multisamples; }
+
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; }
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast(m_window_info.surface_width); }
ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast(m_window_info.surface_height); }
@@ -419,6 +462,7 @@ public:
const void* data = nullptr, u32 data_stride = 0,
bool dynamic = false) = 0;
virtual std::unique_ptr CreateSampler(const GPUSampler::Config& config);
+ virtual std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements);
virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 out_data_stride) = 0;
@@ -437,7 +481,7 @@ public:
u32 ds_layer = 0, u32 ds_level = 0);
/// Shader abstraction.
- // TODO: entry point?
+ // TODO: entry point? source format?
std::unique_ptr CreateShader(GPUShaderStage stage, const std::string_view& source);
virtual std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config);
@@ -465,6 +509,7 @@ public:
virtual void SetFramebuffer(GPUFramebuffer* fb);
virtual void SetPipeline(GPUPipeline* pipeline);
virtual void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler);
+ virtual void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer);
virtual void SetViewport(s32 x, s32 y, s32 width, s32 height);
virtual void SetScissor(s32 x, s32 y, s32 width, s32 height);
void SetViewportAndScissor(s32 x, s32 y, s32 width, s32 height);
@@ -567,6 +612,10 @@ protected:
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture);
+ Features m_features = {};
+ u32 m_max_texture_size = 0;
+ u32 m_max_multisamples = 0;
+
WindowInfo m_window_info;
GPUShaderCache m_shader_cache;
diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp
index 919e43f58..594f9595b 100644
--- a/src/core/gpu_hw.cpp
+++ b/src/core/gpu_hw.cpp
@@ -67,11 +67,23 @@ const Threading::Thread* GPU_HW::GetSWThread() const
return m_sw_renderer ? m_sw_renderer->GetThread() : nullptr;
}
+bool GPU_HW::IsHardwareRenderer() const
+{
+ return true;
+}
+
bool GPU_HW::Initialize()
{
if (!GPU::Initialize())
return false;
+ const GPUDevice::Features features = g_host_display->GetFeatures();
+ m_max_resolution_scale = g_host_display->GetMaxTextureSize() / VRAM_WIDTH;
+ m_supports_dual_source_blend = features.dual_source_blend;
+ m_supports_per_sample_shading = features.per_sample_shading;
+ m_supports_adaptive_downsampling = features.mipmapped_render_targets;
+ m_supports_disable_color_perspective = features.noperspective_interpolation;
+
m_resolution_scale = CalculateResolutionScale();
m_multisamples = std::min(g_settings.gpu_multisamples, m_max_multisamples);
m_render_api = g_host_display->GetRenderAPI();
@@ -124,12 +136,13 @@ bool GPU_HW::Initialize()
return false;
}
- if (!CreateFramebuffer())
+ if (!CreateBuffers())
{
Log_ErrorPrintf("Failed to create framebuffer");
return false;
}
+ RestoreGraphicsAPIState();
return true;
}
@@ -224,7 +237,7 @@ void GPU_HW::UpdateSettings()
RestoreGraphicsAPIState();
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
g_host_display->ClearDisplayTexture();
- CreateFramebuffer();
+ CreateBuffers();
}
if (shaders_changed)
@@ -243,6 +256,7 @@ void GPU_HW::UpdateSettings()
}
}
+// TODO: Merge into UpdateSettings()
void GPU_HW::UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed)
{
const u32 resolution_scale = CalculateResolutionScale();
@@ -402,9 +416,9 @@ void GPU_HW::PrintSettingsToLog()
Log_InfoPrintf("Using software renderer for readbacks: %s", m_sw_renderer ? "YES" : "NO");
}
-bool GPU_HW::CreateFramebuffer()
+bool GPU_HW::CreateBuffers()
{
- DestroyFramebuffer();
+ DestroyBuffers();
// scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
@@ -444,6 +458,13 @@ bool GPU_HW::CreateFramebuffer()
GL_OBJECT_NAME(m_vram_readback_framebuffer, "VRAM Readback Framebuffer");
GL_OBJECT_NAME(m_display_framebuffer, "Display Framebuffer");
+ // TODO: check caps
+ if (!(m_vram_upload_buffer = g_host_display->CreateTextureBuffer(GPUTextureBuffer::Format::R16UI,
+ VRAM_UPDATE_TEXTURE_BUFFER_SIZE / sizeof(u16))))
+ {
+ return false;
+ }
+
Log_InfoPrintf("Created HW framebuffer of %ux%u", texture_width, texture_height);
#if 0
@@ -503,8 +524,9 @@ void GPU_HW::ClearFramebuffer()
m_last_depth_z = 1.0f;
}
-void GPU_HW::DestroyFramebuffer()
+void GPU_HW::DestroyBuffers()
{
+ m_vram_upload_buffer.reset();
m_display_framebuffer.reset();
m_vram_readback_framebuffer.reset();
m_vram_update_depth_framebuffer.reset();
@@ -2080,6 +2102,11 @@ void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask)
{
+ if (IsUsingSoftwareRendererForReadbacks())
+ UpdateSoftwareRendererVRAM(x, y, width, height, data, set_mask, check_mask);
+
+ const Common::Rectangle bounds = GetVRAMTransferBounds(x, y, width, height);
+
DebugAssert((x + width) <= VRAM_WIDTH && (y + height) <= VRAM_HEIGHT);
IncludeVRAMDirtyRectangle(Common::Rectangle::FromExtents(x, y, width, height));
@@ -2088,6 +2115,34 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
// set new vertex counter since we want this to take into consideration previous masked pixels
m_current_depth++;
}
+ else
+ {
+ const TextureReplacementTexture* rtex = g_texture_replacements.GetVRAMWriteReplacement(width, height, data);
+ if (rtex && BlitVRAMReplacementTexture(rtex, x * m_resolution_scale, y * m_resolution_scale,
+ width * m_resolution_scale, height * m_resolution_scale))
+ {
+ return;
+ }
+ }
+
+ const u32 num_pixels = width * height;
+ void* map = m_vram_upload_buffer->Map(num_pixels);
+ const u32 map_index = m_vram_upload_buffer->GetCurrentPosition();
+ std::memcpy(map, data, num_pixels * sizeof(u16));
+ m_vram_upload_buffer->Unmap(num_pixels);
+
+ const VRAMWriteUBOData uniforms = GetVRAMWriteUBOData(x, y, width, height, map_index, set_mask, check_mask);
+
+ // the viewport should already be set to the full vram, so just adjust the scissor
+ const Common::Rectangle scaled_bounds = bounds * m_resolution_scale;
+ g_host_display->SetScissor(scaled_bounds.left, scaled_bounds.top, scaled_bounds.GetWidth(),
+ scaled_bounds.GetHeight());
+ g_host_display->SetPipeline(m_vram_write_pipelines[BoolToUInt8(check_mask && !m_pgxp_depth_buffer)].get());
+ g_host_display->PushUniformBuffer(&uniforms, sizeof(uniforms));
+ g_host_display->SetTextureBuffer(0, m_vram_upload_buffer.get());
+ g_host_display->Draw(3, 0);
+
+ RestoreGraphicsAPIState();
}
void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height)
@@ -2585,3 +2640,18 @@ void GPU_HW::ShaderCompileProgressTracker::Increment()
m_last_update_time = tv;
}
}
+
+std::unique_ptr GPU::CreateHardwareD3D11Renderer()
+{
+ if (!Host::AcquireHostDisplay(RenderAPI::D3D11))
+ {
+ Log_ErrorPrintf("Host render API is incompatible");
+ return nullptr;
+ }
+
+ std::unique_ptr gpu(std::make_unique());
+ if (!gpu->Initialize())
+ return nullptr;
+
+ return gpu;
+}
diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h
index 29eb329a9..6ba69d478 100644
--- a/src/core/gpu_hw.h
+++ b/src/core/gpu_hw.h
@@ -42,6 +42,7 @@ public:
~GPU_HW() override;
const Threading::Thread* GetSWThread() const override;
+ bool IsHardwareRenderer() const override;
bool Initialize() override;
void Reset(bool clear_vram) override;
@@ -209,9 +210,9 @@ protected:
void UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed);
- bool CreateFramebuffer();
+ bool CreateBuffers();
void ClearFramebuffer();
- void DestroyFramebuffer();
+ void DestroyBuffers();
bool CompilePipelines();
void DestroyPipelines();
@@ -390,6 +391,8 @@ protected:
std::unique_ptr m_vram_readback_framebuffer;
std::unique_ptr m_display_framebuffer;
+ std::unique_ptr m_vram_upload_buffer;
+
HeapArray m_vram_shadow;
std::unique_ptr m_sw_renderer;
diff --git a/src/core/gpu_hw_d3d11.cpp b/src/core/gpu_hw_d3d11.cpp
deleted file mode 100644
index 2d88bfcf9..000000000
--- a/src/core/gpu_hw_d3d11.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin
-// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
-
-#include "gpu_hw_d3d11.h"
-#include "common/assert.h"
-#include "common/log.h"
-
-Log_SetChannel(GPU_HW_D3D11);
-
-GPU_HW_D3D11::GPU_HW_D3D11() = default;
-
-GPU_HW_D3D11::~GPU_HW_D3D11() = default;
-
-GPURenderer GPU_HW_D3D11::GetRendererType() const
-{
- return GPURenderer::HardwareD3D11;
-}
-
-bool GPU_HW_D3D11::Initialize()
-{
- SetCapabilities();
-
- if (!GPU_HW::Initialize())
- return false;
-
- if (!CreateTextureBuffer())
- {
- Log_ErrorPrintf("Failed to create texture buffer");
- return false;
- }
-
- RestoreGraphicsAPIState();
- return true;
-}
-
-void GPU_HW_D3D11::SetCapabilities()
-{
- const u32 max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
- const u32 max_texture_scale = max_texture_size / VRAM_WIDTH;
-
- ID3D11Device* device = D3D11Device::GetD3DDevice();
-
- m_max_resolution_scale = max_texture_scale;
- m_supports_dual_source_blend = true;
- m_supports_per_sample_shading = (device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_1);
- m_supports_adaptive_downsampling = true;
- m_supports_disable_color_perspective = true;
-
- m_max_multisamples = 1;
- for (u32 multisamples = 2; multisamples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; multisamples++)
- {
- UINT num_quality_levels;
- if (SUCCEEDED(
- device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, multisamples, &num_quality_levels)) &&
- num_quality_levels > 0)
- {
- m_max_multisamples = multisamples;
- }
- }
-}
-
-bool GPU_HW_D3D11::CreateTextureBuffer()
-{
- ID3D11Device* device = D3D11Device::GetD3DDevice();
-
- if (!m_texture_stream_buffer.Create(device, D3D11_BIND_SHADER_RESOURCE, VRAM_UPDATE_TEXTURE_BUFFER_SIZE))
- return false;
-
- const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_BUFFER, DXGI_FORMAT_R16_UINT, 0,
- VRAM_UPDATE_TEXTURE_BUFFER_SIZE / sizeof(u16));
- const HRESULT hr = device->CreateShaderResourceView(m_texture_stream_buffer.GetD3DBuffer(), &srv_desc,
- m_texture_stream_buffer_srv_r16ui.ReleaseAndGetAddressOf());
- if (FAILED(hr))
- {
- Log_ErrorPrintf("Creation of texture buffer SRV failed: 0x%08X", hr);
- return false;
- }
-
- return true;
-}
-
-void GPU_HW_D3D11::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask)
-{
- if (IsUsingSoftwareRendererForReadbacks())
- UpdateSoftwareRendererVRAM(x, y, width, height, data, set_mask, check_mask);
-
- const Common::Rectangle bounds = GetVRAMTransferBounds(x, y, width, height);
- GPU_HW::UpdateVRAM(bounds.left, bounds.top, bounds.GetWidth(), bounds.GetHeight(), data, set_mask, check_mask);
-
- if (!check_mask)
- {
- const TextureReplacementTexture* rtex = g_texture_replacements.GetVRAMWriteReplacement(width, height, data);
- if (rtex && BlitVRAMReplacementTexture(rtex, x * m_resolution_scale, y * m_resolution_scale,
- width * m_resolution_scale, height * m_resolution_scale))
- {
- return;
- }
- }
-
- const u32 num_pixels = width * height;
- const auto map_result =
- m_texture_stream_buffer.Map(D3D11Device::GetD3DContext(), sizeof(u16), num_pixels * sizeof(u16));
- std::memcpy(map_result.pointer, data, num_pixels * sizeof(u16));
- m_texture_stream_buffer.Unmap(D3D11Device::GetD3DContext(), num_pixels * sizeof(u16));
-
- const VRAMWriteUBOData uniforms =
- GetVRAMWriteUBOData(x, y, width, height, map_result.index_aligned, set_mask, check_mask);
-
- // the viewport should already be set to the full vram, so just adjust the scissor
- const Common::Rectangle scaled_bounds = bounds * m_resolution_scale;
- g_host_display->SetScissor(scaled_bounds.left, scaled_bounds.top, scaled_bounds.GetWidth(),
- scaled_bounds.GetHeight());
- g_host_display->SetPipeline(m_vram_write_pipelines[BoolToUInt8(check_mask && !m_pgxp_depth_buffer)].get());
- g_host_display->PushUniformBuffer(&uniforms, sizeof(uniforms));
- D3D11Device::GetD3DContext()->PSSetShaderResources(0, 1, m_texture_stream_buffer_srv_r16ui.GetAddressOf());
- g_host_display->Draw(3, 0);
-
- RestoreGraphicsAPIState();
-}
-
-std::unique_ptr GPU::CreateHardwareD3D11Renderer()
-{
- if (!Host::AcquireHostDisplay(RenderAPI::D3D11))
- {
- Log_ErrorPrintf("Host render API is incompatible");
- return nullptr;
- }
-
- std::unique_ptr gpu(std::make_unique());
- if (!gpu->Initialize())
- return nullptr;
-
- return gpu;
-}
diff --git a/src/core/gpu_hw_d3d11.h b/src/core/gpu_hw_d3d11.h
deleted file mode 100644
index 8b7a5ec60..000000000
--- a/src/core/gpu_hw_d3d11.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin
-// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
-
-#pragma once
-#include "gpu/d3d11_device.h"
-#include "gpu_hw.h"
-
-class GPU_HW_D3D11 final : public GPU_HW
-{
-public:
- template
- using ComPtr = Microsoft::WRL::ComPtr;
-
- GPU_HW_D3D11();
- ~GPU_HW_D3D11() override;
-
- GPURenderer GetRendererType() const override;
-
- bool Initialize() override;
-
-protected:
- void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask) override;
-
-private:
- void SetCapabilities();
-
- bool CreateTextureBuffer();
-
- D3D11StreamBuffer m_texture_stream_buffer;
-
- ComPtr m_texture_stream_buffer_srv_r16ui;
-};
diff --git a/src/core/gpu_hw_d3d12.cpp b/src/core/gpu_hw_d3d12.cpp
index c55773321..430473830 100644
--- a/src/core/gpu_hw_d3d12.cpp
+++ b/src/core/gpu_hw_d3d12.cpp
@@ -25,11 +25,6 @@ GPU_HW_D3D12::~GPU_HW_D3D12()
DestroyResources();
}
-GPURenderer GPU_HW_D3D12::GetRendererType() const
-{
- return GPURenderer::HardwareD3D12;
-}
-
bool GPU_HW_D3D12::Initialize()
{
SetCapabilities();
@@ -67,7 +62,7 @@ bool GPU_HW_D3D12::Initialize()
return false;
}
- if (!CreateFramebuffer())
+ if (!CreateBuffers())
{
Log_ErrorPrintf("Failed to create framebuffer");
return false;
@@ -133,7 +128,7 @@ void GPU_HW_D3D12::UpdateSettings()
g_d3d12_context->ExecuteCommandList(true);
if (framebuffer_changed)
- CreateFramebuffer();
+ CreateBuffers();
if (shaders_changed)
{
@@ -239,7 +234,7 @@ void GPU_HW_D3D12::DestroyResources()
if (g_d3d12_context)
g_d3d12_context->ExecuteCommandList(true);
- DestroyFramebuffer();
+ DestroyBuffers();
DestroyPipelines();
g_d3d12_context->GetSamplerHeapManager().Free(&m_point_sampler);
@@ -297,9 +292,9 @@ bool GPU_HW_D3D12::CreateSamplers()
return true;
}
-bool GPU_HW_D3D12::CreateFramebuffer()
+bool GPU_HW_D3D12::CreateBuffers()
{
- DestroyFramebuffer();
+ DestroyBuffers();
// scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
@@ -349,7 +344,7 @@ void GPU_HW_D3D12::ClearFramebuffer()
SetFullVRAMDirtyRectangle();
}
-void GPU_HW_D3D12::DestroyFramebuffer()
+void GPU_HW_D3D12::DestroyBuffers()
{
m_vram_read_texture.Destroy(false);
m_vram_depth_texture.Destroy(false);
diff --git a/src/core/gpu_hw_d3d12.h b/src/core/gpu_hw_d3d12.h
index d8bf6e093..2a2d77f24 100644
--- a/src/core/gpu_hw_d3d12.h
+++ b/src/core/gpu_hw_d3d12.h
@@ -21,8 +21,6 @@ public:
GPU_HW_D3D12();
~GPU_HW_D3D12() override;
- GPURenderer GetRendererType() const override;
-
bool Initialize() override;
void Reset(bool clear_vram) override;
@@ -49,9 +47,9 @@ private:
bool CreateRootSignatures();
bool CreateSamplers();
- bool CreateFramebuffer();
+ bool CreateBuffers();
void ClearFramebuffer();
- void DestroyFramebuffer();
+ void DestroyBuffers();
bool CreateVertexBuffer();
bool CreateUniformBuffer();
diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp
index 66b3ec8ac..f14c3fd32 100644
--- a/src/core/gpu_hw_opengl.cpp
+++ b/src/core/gpu_hw_opengl.cpp
@@ -35,11 +35,6 @@ GPU_HW_OpenGL::~GPU_HW_OpenGL()
glUseProgram(0);
}
-GPURenderer GPU_HW_OpenGL::GetRendererType() const
-{
- return GPURenderer::HardwareOpenGL;
-}
-
bool GPU_HW_OpenGL::Initialize()
{
SetCapabilities();
@@ -47,7 +42,7 @@ bool GPU_HW_OpenGL::Initialize()
if (!GPU_HW::Initialize())
return false;
- if (!CreateFramebuffer())
+ if (!CreateBuffers())
{
Log_ErrorPrintf("Failed to create framebuffer");
return false;
@@ -181,7 +176,7 @@ void GPU_HW_OpenGL::UpdateSettings()
RestoreGraphicsAPIState();
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
g_host_display->ClearDisplayTexture();
- CreateFramebuffer();
+ CreateBuffers();
}
if (shaders_changed)
CompilePrograms();
@@ -316,7 +311,7 @@ void GPU_HW_OpenGL::SetCapabilities()
m_supports_disable_color_perspective = (g_host_display->GetRenderAPI() == RenderAPI::OpenGL);
}
-bool GPU_HW_OpenGL::CreateFramebuffer()
+bool GPU_HW_OpenGL::CreateBuffers()
{
// scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
diff --git a/src/core/gpu_hw_opengl.h b/src/core/gpu_hw_opengl.h
index 28cf26483..7f6e0a3d7 100644
--- a/src/core/gpu_hw_opengl.h
+++ b/src/core/gpu_hw_opengl.h
@@ -19,8 +19,6 @@ public:
GPU_HW_OpenGL();
~GPU_HW_OpenGL() override;
- GPURenderer GetRendererType() const override;
-
bool Initialize() override;
void Reset(bool clear_vram) override;
@@ -49,7 +47,7 @@ private:
ALWAYS_INLINE bool IsGLES() const { return (m_render_api == RenderAPI::OpenGLES); }
void SetCapabilities();
- bool CreateFramebuffer();
+ bool CreateBuffers();
void ClearFramebuffer();
bool CreateVertexBuffer();
diff --git a/src/core/gpu_hw_vulkan.cpp b/src/core/gpu_hw_vulkan.cpp
index b5f0672f8..146472e9c 100644
--- a/src/core/gpu_hw_vulkan.cpp
+++ b/src/core/gpu_hw_vulkan.cpp
@@ -24,11 +24,6 @@ GPU_HW_Vulkan::~GPU_HW_Vulkan()
DestroyResources();
}
-GPURenderer GPU_HW_Vulkan::GetRendererType() const
-{
- return GPURenderer::HardwareVulkan;
-}
-
bool GPU_HW_Vulkan::Initialize()
{
SetCapabilities();
@@ -66,7 +61,7 @@ bool GPU_HW_Vulkan::Initialize()
return false;
}
- if (!CreateFramebuffer())
+ if (!CreateBuffers())
{
Log_ErrorPrintf("Failed to create framebuffer");
return false;
@@ -128,7 +123,7 @@ void GPU_HW_Vulkan::UpdateSettings()
g_vulkan_context->ExecuteCommandBuffer(true);
if (framebuffer_changed)
- CreateFramebuffer();
+ CreateBuffers();
if (shaders_changed)
{
@@ -261,7 +256,7 @@ void GPU_HW_Vulkan::DestroyResources()
if (g_vulkan_context)
g_vulkan_context->ExecuteCommandBuffer(true);
- DestroyFramebuffer();
+ DestroyBuffers();
DestroyPipelines();
Vulkan::Util::SafeDestroyPipelineLayout(m_downsample_pipeline_layout);
@@ -454,9 +449,9 @@ bool GPU_HW_Vulkan::CreateSamplers()
return true;
}
-bool GPU_HW_Vulkan::CreateFramebuffer()
+bool GPU_HW_Vulkan::CreateBuffers()
{
- DestroyFramebuffer();
+ DestroyBuffers();
// scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
@@ -722,7 +717,7 @@ void GPU_HW_Vulkan::ClearFramebuffer()
SetFullVRAMDirtyRectangle();
}
-void GPU_HW_Vulkan::DestroyFramebuffer()
+void GPU_HW_Vulkan::DestroyBuffers()
{
Vulkan::Util::SafeFreeGlobalDescriptorSet(m_downsample_composite_descriptor_set);
diff --git a/src/core/gpu_hw_vulkan.h b/src/core/gpu_hw_vulkan.h
index f1ef84682..a6c6aaabf 100644
--- a/src/core/gpu_hw_vulkan.h
+++ b/src/core/gpu_hw_vulkan.h
@@ -17,8 +17,6 @@ public:
GPU_HW_Vulkan();
~GPU_HW_Vulkan() override;
- GPURenderer GetRendererType() const override;
-
bool Initialize() override;
void Reset(bool clear_vram) override;
@@ -51,9 +49,9 @@ private:
bool CreatePipelineLayouts();
bool CreateSamplers();
- bool CreateFramebuffer();
+ bool CreateBuffers();
void ClearFramebuffer();
- void DestroyFramebuffer();
+ void DestroyBuffers();
bool CreateVertexBuffer();
bool CreateUniformBuffer();
diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp
index 9caecbdf6..7def67447 100644
--- a/src/core/gpu_sw.cpp
+++ b/src/core/gpu_sw.cpp
@@ -42,16 +42,16 @@ GPU_SW::~GPU_SW()
g_host_display->ClearDisplayTexture();
}
-GPURenderer GPU_SW::GetRendererType() const
-{
- return GPURenderer::Software;
-}
-
const Threading::Thread* GPU_SW::GetSWThread() const
{
return m_backend.GetThread();
}
+bool GPU_SW::IsHardwareRenderer() const
+{
+ return false;
+}
+
bool GPU_SW::Initialize()
{
if (!GPU::Initialize() || !m_backend.Initialize(false))
diff --git a/src/core/gpu_sw.h b/src/core/gpu_sw.h
index b85462f58..6207ab642 100644
--- a/src/core/gpu_sw.h
+++ b/src/core/gpu_sw.h
@@ -24,8 +24,8 @@ public:
ALWAYS_INLINE const GPU_SW_Backend& GetBackend() const { return m_backend; }
- GPURenderer GetRendererType() const override;
const Threading::Thread* GetSWThread() const override;
+ bool IsHardwareRenderer() const override;
bool Initialize() override;
bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override;
diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp
index f02892fef..213aed329 100644
--- a/src/duckstation-qt/qthost.cpp
+++ b/src/duckstation-qt/qthost.cpp
@@ -1634,7 +1634,8 @@ void EmuThread::updatePerformanceCounters()
if (g_gpu)
{
- renderer = g_gpu->GetRendererType();
+ // TODO: Fix renderer type
+ renderer = g_gpu->IsHardwareRenderer() ? GPURenderer::HardwareD3D11 : GPURenderer::Software;
std::tie(render_width, render_height) = g_gpu->GetEffectiveDisplayResolution();
}
diff --git a/src/frontend-common/imgui_overlays.cpp b/src/frontend-common/imgui_overlays.cpp
index 253feaf2f..a74a056e8 100644
--- a/src/frontend-common/imgui_overlays.cpp
+++ b/src/frontend-common/imgui_overlays.cpp
@@ -407,9 +407,10 @@ void ImGuiManager::DrawPerformanceOverlay()
void ImGuiManager::DrawEnhancementsOverlay()
{
+ // TODO: Fix device type name
LargeString text;
text.AppendFmtString("{} {}", Settings::GetConsoleRegionName(System::GetRegion()),
- Settings::GetRendererName(g_gpu->GetRendererType()));
+ g_gpu->IsHardwareRenderer() ? "HW" : "SW");
if (g_settings.rewind_enable)
text.AppendFormattedString(" RW=%g/%u", g_settings.rewind_save_frequency, g_settings.rewind_save_slots);