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