Generic hw renderer

This commit is contained in:
Stenzek 2023-08-02 21:40:49 +10:00
parent 7d7a06b9f7
commit 2834635f59
22 changed files with 378 additions and 302 deletions

View File

@ -85,7 +85,6 @@
<ClCompile Include="gpu\vulkan_gpu_device.cpp" />
<ClCompile Include="gpu_backend.cpp" />
<ClCompile Include="gpu_commands.cpp" />
<ClCompile Include="gpu_hw_d3d11.cpp" />
<ClCompile Include="gpu_hw_d3d12.cpp" />
<ClCompile Include="gpu_hw_shadergen.cpp" />
<ClCompile Include="gpu_hw_vulkan.cpp">
@ -211,7 +210,6 @@
<ClInclude Include="gpu\vulkan\util.h" />
<ClInclude Include="gpu\vulkan_gpu_device.h" />
<ClInclude Include="gpu_backend.h" />
<ClInclude Include="gpu_hw_d3d11.h" />
<ClInclude Include="gpu_hw_d3d12.h" />
<ClInclude Include="gpu_hw_shadergen.h" />
<ClInclude Include="gpu_hw_vulkan.h">

View File

@ -23,7 +23,6 @@
<ClCompile Include="gpu_commands.cpp" />
<ClCompile Include="gpu_sw.cpp" />
<ClCompile Include="gpu_hw_shadergen.cpp" />
<ClCompile Include="gpu_hw_d3d11.cpp" />
<ClCompile Include="bios.cpp" />
<ClCompile Include="cpu_code_cache.cpp" />
<ClCompile Include="cpu_recompiler_register_cache.cpp" />
@ -204,7 +203,6 @@
<ClInclude Include="settings.h" />
<ClInclude Include="gpu_sw.h" />
<ClInclude Include="gpu_hw_shadergen.h" />
<ClInclude Include="gpu_hw_d3d11.h" />
<ClInclude Include="bios.h" />
<ClInclude Include="cpu_recompiler_types.h" />
<ClInclude Include="cpu_code_cache.h" />

View File

@ -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();

View File

@ -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

View File

@ -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<IDXGIFactory5> 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<IDXGIFactory5> 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<GPUFramebuffer> D3D11Device::CreateFramebuffer(GPUTexture* rt, u
if (rt)
{
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
rtv_desc.Format = static_cast<D3D11Texture*>(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<D3D11Texture*>(rt)->GetD3DRTV();
}
else
{
if (rt->GetLayers() > 1)
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
rtv_desc.Format = static_cast<D3D11Texture*>(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<D3D11Texture*>(rt)->GetD3DTexture(), &rtv_desc,
rtv.GetAddressOf())))
{
Log_ErrorPrintf("CreateRenderTargetView() failed: %08X", hr);
return {};
if (FAILED(hr = m_device->CreateRenderTargetView(static_cast<D3D11Texture*>(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<D3D11Texture*>(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<D3D11Texture*>(ds)->GetD3DDSV();
}
else
{
if (ds->GetLayers() > 1)
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
dsv_desc.Format = static_cast<D3D11Texture*>(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<D3D11Texture*>(ds)->GetD3DTexture(), &dsv_desc,
dsv.GetAddressOf())))
{
Log_ErrorPrintf("CreateDepthStencilView() failed: %08X", hr);
return {};
if (FAILED(hr = m_device->CreateDepthStencilView(static_cast<D3D11Texture*>(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<DXGI_FORMAT, static_cast<u32>(Format::MaxCount)> dxgi_formats = {{
DXGI_FORMAT_R16_UINT,
}};
CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(m_buffer.GetD3DBuffer(), dxgi_formats[static_cast<u32>(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<GPUTextureBuffer> D3D11Device::CreateTextureBuffer(GPUTextureBuffer::Format format,
u32 size_in_elements)
{
std::unique_ptr<D3D11TextureBuffer> tb = std::make_unique<D3D11TextureBuffer>(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<D3D11TextureBuffer*>(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
#endif

View File

@ -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<ID3D11ShaderResourceView> 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<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
std::unique_ptr<GPUTextureBuffer> 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);

View File

@ -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<u32, static_cast<u32>(Format::MaxCount)> element_size = {{
sizeof(u16),
}};
return element_size[static_cast<u32>(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<GPUSampler> GPUDevice::CreateSampler(const GPUSampler::Config& c
return {};
}
std::unique_ptr<GPUTextureBuffer> GPUDevice::CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements)
{
// TODO: REMOVE ME
UnreachableCode();
return {};
}
std::unique_ptr<GPUFramebuffer> GPUDevice::CreateFramebuffer(GPUTexture* rt, u32 rt_layer, u32 rt_level, GPUTexture* ds,
u32 ds_layer, u32 ds_level)
{

View File

@ -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<std::string> 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<s32>(m_window_info.surface_width); }
ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(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<GPUSampler> CreateSampler(const GPUSampler::Config& config);
virtual std::unique_ptr<GPUTextureBuffer> 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<GPUShader> CreateShader(GPUShaderStage stage, const std::string_view& source);
virtual std::unique_ptr<GPUPipeline> 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;

View File

@ -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<u32> bounds = GetVRAMTransferBounds(x, y, width, height);
DebugAssert((x + width) <= VRAM_WIDTH && (y + height) <= VRAM_HEIGHT);
IncludeVRAMDirtyRectangle(Common::Rectangle<u32>::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<u32> 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> GPU::CreateHardwareD3D11Renderer()
{
if (!Host::AcquireHostDisplay(RenderAPI::D3D11))
{
Log_ErrorPrintf("Host render API is incompatible");
return nullptr;
}
std::unique_ptr<GPU_HW> gpu(std::make_unique<GPU_HW>());
if (!gpu->Initialize())
return nullptr;
return gpu;
}

View File

@ -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<GPUFramebuffer> m_vram_readback_framebuffer;
std::unique_ptr<GPUFramebuffer> m_display_framebuffer;
std::unique_ptr<GPUTextureBuffer> m_vram_upload_buffer;
HeapArray<u16, VRAM_WIDTH * VRAM_HEIGHT> m_vram_shadow;
std::unique_ptr<GPU_SW_Backend> m_sw_renderer;

View File

@ -1,134 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// 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<u32> 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<u32> 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> GPU::CreateHardwareD3D11Renderer()
{
if (!Host::AcquireHostDisplay(RenderAPI::D3D11))
{
Log_ErrorPrintf("Host render API is incompatible");
return nullptr;
}
std::unique_ptr<GPU_HW_D3D11> gpu(std::make_unique<GPU_HW_D3D11>());
if (!gpu->Initialize())
return nullptr;
return gpu;
}

View File

@ -1,32 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// 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<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
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<ID3D11ShaderResourceView> m_texture_stream_buffer_srv_r16ui;
};

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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))

View File

@ -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;

View File

@ -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();
}

View File

@ -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);