diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 998b30cd0..43cd717bf 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -15,6 +15,8 @@ add_library(common fifo_queue.h file_system.cpp file_system.h + gpu_texture.cpp + gpu_texture.h image.cpp image.h hash_combine.h diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 0fdb9eb11..50773b429 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -46,6 +46,7 @@ true + @@ -142,6 +143,7 @@ true + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 14449df6a..30df8cc14 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -129,6 +129,7 @@ + @@ -233,6 +234,7 @@ + diff --git a/src/common/d3d11/texture.cpp b/src/common/d3d11/texture.cpp index ab4af3dca..f68347958 100644 --- a/src/common/d3d11/texture.cpp +++ b/src/common/d3d11/texture.cpp @@ -1,38 +1,63 @@ #include "texture.h" #include "../log.h" +#include Log_SetChannel(D3D11); -namespace D3D11 { +static constexpr std::array(GPUTexture::Format::Count)> s_dxgi_mapping = { + {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_D16_UNORM}}; -Texture::Texture() : m_width(0), m_height(0), m_samples(0) {} +D3D11::Texture::Texture() = default; -Texture::Texture(ComPtr texture, ComPtr srv, - ComPtr rtv) +D3D11::Texture::Texture(ComPtr texture, ComPtr srv, + ComPtr rtv) : m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv(std::move(rtv)) { const D3D11_TEXTURE2D_DESC desc = GetDesc(); m_width = static_cast(desc.Width); m_height = static_cast(desc.Height); - m_layers = static_cast(desc.ArraySize); + m_layers = static_cast(desc.ArraySize); m_levels = static_cast(desc.MipLevels); m_samples = static_cast(desc.SampleDesc.Count); + m_format = LookupBaseFormat(desc.Format); + m_dynamic = (desc.Usage == D3D11_USAGE_DYNAMIC); } -Texture::~Texture() +D3D11::Texture::~Texture() { Destroy(); } -D3D11_TEXTURE2D_DESC Texture::GetDesc() const +DXGI_FORMAT D3D11::Texture::GetDXGIFormat(Format format) +{ + return s_dxgi_mapping[static_cast(format)]; +} + +GPUTexture::Format D3D11::Texture::LookupBaseFormat(DXGI_FORMAT dformat) +{ + for (u32 i = 0; i < static_cast(s_dxgi_mapping.size()); i++) + { + if (s_dxgi_mapping[i] == dformat) + return static_cast(i); + } + return GPUTexture::Format::Unknown; +} + +D3D11_TEXTURE2D_DESC D3D11::Texture::GetDesc() const { D3D11_TEXTURE2D_DESC desc; m_texture->GetDesc(&desc); return desc; } -bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, - DXGI_FORMAT format, u32 bind_flags, const void* initial_data /* = nullptr */, - u32 initial_data_stride /* = 0 */, bool dynamic /* = false */) +bool D3D11::Texture::IsValid() const +{ + return static_cast(m_texture); +} + +bool D3D11::Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, + Format format, u32 bind_flags, const void* initial_data /* = nullptr */, + u32 initial_data_stride /* = 0 */, bool dynamic /* = false */) { if (width > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION || height > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION || layers > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION || (layers > 1 && samples > 1)) @@ -42,7 +67,7 @@ bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u3 return false; } - CD3D11_TEXTURE2D_DESC desc(format, width, height, layers, levels, bind_flags, + CD3D11_TEXTURE2D_DESC desc(GetDXGIFormat(format), width, height, layers, levels, bind_flags, dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0, samples, 0, 0); @@ -96,13 +121,15 @@ bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u3 m_rtv = std::move(rtv); m_width = static_cast(width); m_height = static_cast(height); - m_layers = static_cast(layers); + m_layers = static_cast(layers); m_levels = static_cast(levels); m_samples = static_cast(samples); + m_format = format; + m_dynamic = dynamic; return true; } -bool Texture::Adopt(ID3D11Device* device, ComPtr texture) +bool D3D11::Texture::Adopt(ID3D11Device* device, ComPtr texture) { D3D11_TEXTURE2D_DESC desc; texture->GetDesc(&desc); @@ -140,22 +167,18 @@ bool Texture::Adopt(ID3D11Device* device, ComPtr texture) m_rtv = std::move(rtv); m_width = static_cast(desc.Width); m_height = static_cast(desc.Height); - m_layers = static_cast(desc.ArraySize); + m_layers = static_cast(desc.ArraySize); m_levels = static_cast(desc.MipLevels); m_samples = static_cast(desc.SampleDesc.Count); + m_dynamic = (desc.Usage == D3D11_USAGE_DYNAMIC); return true; } -void Texture::Destroy() +void D3D11::Texture::Destroy() { m_rtv.Reset(); m_srv.Reset(); m_texture.Reset(); - m_width = 0; - m_height = 0; - m_layers = 0; - m_levels = 0; - m_samples = 0; + m_dynamic = false; + ClearBaseProperties(); } - -} // namespace D3D11 diff --git a/src/common/d3d11/texture.h b/src/common/d3d11/texture.h index 402fee2de..8c5d602f7 100644 --- a/src/common/d3d11/texture.h +++ b/src/common/d3d11/texture.h @@ -1,11 +1,12 @@ #pragma once -#include "../types.h" +#include "../gpu_texture.h" #include "../windows_headers.h" #include #include namespace D3D11 { -class Texture + +class Texture final : public GPUTexture { public: template @@ -15,27 +16,27 @@ public: Texture(ComPtr texture, ComPtr srv, ComPtr rtv); ~Texture(); + static DXGI_FORMAT GetDXGIFormat(Format format); + static Format LookupBaseFormat(DXGI_FORMAT dformat); + ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } ALWAYS_INLINE ID3D11RenderTargetView* GetD3DRTV() const { return m_rtv.Get(); } ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); } ALWAYS_INLINE ID3D11RenderTargetView* const* GetD3DRTVArray() const { return m_rtv.GetAddressOf(); } - - ALWAYS_INLINE u16 GetWidth() const { return m_width; } - ALWAYS_INLINE u16 GetHeight() const { return m_height; } - ALWAYS_INLINE u16 GetLayers() const { return m_layers; } - ALWAYS_INLINE u8 GetLevels() const { return m_levels; } - ALWAYS_INLINE u8 GetSamples() const { return m_samples; } - ALWAYS_INLINE bool IsMultisampled() const { return m_samples > 1; } - ALWAYS_INLINE DXGI_FORMAT GetFormat() const { return GetDesc().Format; } - D3D11_TEXTURE2D_DESC GetDesc() const; + ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return GetDXGIFormat(m_format); } + ALWAYS_INLINE bool IsDynamic() const { return m_dynamic; } ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); } ALWAYS_INLINE operator ID3D11ShaderResourceView*() const { return m_srv.Get(); } ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); } ALWAYS_INLINE operator bool() const { return static_cast(m_texture); } - bool Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, DXGI_FORMAT format, + D3D11_TEXTURE2D_DESC GetDesc() const; + + bool IsValid() const override; + + bool Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Format format, u32 bind_flags, const void* initial_data = nullptr, u32 initial_data_stride = 0, bool dynamic = false); bool Adopt(ID3D11Device* device, ComPtr texture); @@ -45,10 +46,7 @@ private: ComPtr m_texture; ComPtr m_srv; ComPtr m_rtv; - u16 m_width; - u16 m_height; - u16 m_layers; - u8 m_levels; - u8 m_samples; + bool m_dynamic = false; }; + } // namespace D3D11 \ No newline at end of file diff --git a/src/common/d3d12/texture.cpp b/src/common/d3d12/texture.cpp index 4ceab3644..a9b7bb4a4 100644 --- a/src/common/d3d12/texture.cpp +++ b/src/common/d3d12/texture.cpp @@ -8,79 +8,111 @@ #include "util.h" Log_SetChannel(D3D12); -namespace D3D12 { +static constexpr std::array(GPUTexture::Format::Count)> s_dxgi_mapping = { + {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_D16_UNORM}}; -Texture::Texture() = default; +D3D12::Texture::Texture() = default; -Texture::Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state) : m_resource(std::move(resource)) +D3D12::Texture::Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state) : m_resource(std::move(resource)) { const D3D12_RESOURCE_DESC desc = GetDesc(); - m_width = static_cast(desc.Width); - m_height = desc.Height; - m_samples = desc.SampleDesc.Count; - m_format = desc.Format; + m_width = static_cast(desc.Width); + m_height = static_cast(desc.Height); + m_layers = static_cast(desc.DepthOrArraySize); + m_levels = static_cast(desc.MipLevels); + m_samples = static_cast(desc.SampleDesc.Count); + m_format = LookupBaseFormat(desc.Format); } -Texture::Texture(Texture&& texture) +D3D12::Texture::Texture(Texture&& texture) : m_resource(std::move(texture.m_resource)), m_srv_descriptor(texture.m_srv_descriptor), - m_rtv_or_dsv_descriptor(texture.m_rtv_or_dsv_descriptor), m_width(texture.m_width), m_height(texture.m_height), - m_samples(texture.m_samples), m_format(texture.m_format), m_state(texture.m_state), - m_is_depth_view(texture.m_is_depth_view) + m_rtv_or_dsv_descriptor(texture.m_rtv_or_dsv_descriptor), m_is_depth_view(texture.m_is_depth_view) { + m_width = texture.m_width; + m_height = texture.m_height; + m_layers = texture.m_layers; + m_levels = texture.m_levels; + m_samples = texture.m_samples; texture.m_srv_descriptor = {}; texture.m_rtv_or_dsv_descriptor = {}; - texture.m_width = 0; - texture.m_height = 0; - texture.m_samples = 0; - texture.m_format = DXGI_FORMAT_UNKNOWN; texture.m_state = D3D12_RESOURCE_STATE_COMMON; texture.m_is_depth_view = false; + texture.ClearBaseProperties(); } -Texture::~Texture() +DXGI_FORMAT D3D12::Texture::GetDXGIFormat(Format format) +{ + return s_dxgi_mapping[static_cast(format)]; +} + +GPUTexture::Format D3D12::Texture::LookupBaseFormat(DXGI_FORMAT dformat) +{ + for (u32 i = 0; i < static_cast(s_dxgi_mapping.size()); i++) + { + if (s_dxgi_mapping[i] == dformat) + return static_cast(i); + } + return GPUTexture::Format::Unknown; +} + +D3D12::Texture::~Texture() { Destroy(); } -Texture& Texture::operator=(Texture&& texture) +D3D12::Texture& D3D12::Texture::operator=(Texture&& texture) { Destroy(); + + m_width = texture.m_width; + m_height = texture.m_height; + m_layers = texture.m_layers; + m_levels = texture.m_levels; + m_samples = texture.m_samples; + m_resource = std::move(texture.m_resource); m_srv_descriptor = texture.m_srv_descriptor; m_rtv_or_dsv_descriptor = texture.m_rtv_or_dsv_descriptor; - m_width = texture.m_width; - m_height = texture.m_height; - m_samples = texture.m_samples; - m_format = texture.m_format; m_state = texture.m_state; m_is_depth_view = texture.m_is_depth_view; + + texture.ClearBaseProperties(); texture.m_srv_descriptor = {}; texture.m_rtv_or_dsv_descriptor = {}; - texture.m_width = 0; - texture.m_height = 0; - texture.m_samples = 0; - texture.m_format = DXGI_FORMAT_UNKNOWN; texture.m_state = D3D12_RESOURCE_STATE_COMMON; texture.m_is_depth_view = false; return *this; } -D3D12_RESOURCE_DESC Texture::GetDesc() const +D3D12_RESOURCE_DESC D3D12::Texture::GetDesc() const { return m_resource->GetDesc(); } -bool Texture::Create(u32 width, u32 height, u32 samples, DXGI_FORMAT format, DXGI_FORMAT srv_format, - DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags) +bool D3D12::Texture::IsValid() const +{ + return static_cast(m_resource); +} + +bool D3D12::Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, DXGI_FORMAT format, + DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, + D3D12_RESOURCE_FLAGS flags) { constexpr D3D12_HEAP_PROPERTIES heap_properties = {D3D12_HEAP_TYPE_DEFAULT}; + if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES) + { + Log_ErrorPrintf("Invalid dimensions: %ux%ux%u %u %u", width, height, layers, levels, samples); + return false; + } + D3D12_RESOURCE_DESC desc = {}; desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; desc.Width = width; - desc.Height = height; - desc.DepthOrArraySize = 1; - desc.MipLevels = 1; + desc.Height = static_cast(height); + desc.DepthOrArraySize = static_cast(layers); + desc.MipLevels = static_cast(levels); desc.Format = format; desc.SampleDesc.Count = samples; desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; @@ -147,17 +179,19 @@ bool Texture::Create(u32 width, u32 height, u32 samples, DXGI_FORMAT format, DXG m_resource = std::move(resource); m_srv_descriptor = std::move(srv_descriptor); m_rtv_or_dsv_descriptor = std::move(rtv_descriptor); - m_width = width; - m_height = height; - m_samples = samples; - m_format = format; + m_width = static_cast(width); + m_height = static_cast(height); + m_layers = static_cast(layers); + m_levels = static_cast(levels); + m_samples = static_cast(samples); + m_format = LookupBaseFormat(format); m_state = state; m_is_depth_view = is_depth_view; return true; } -bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, - DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state) +bool D3D12::Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, + DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state) { const D3D12_RESOURCE_DESC desc(texture->GetDesc()); @@ -168,6 +202,8 @@ bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI return false; } + m_is_depth_view = false; + if (rtv_format != DXGI_FORMAT_UNKNOWN) { Assert(dsv_format == DXGI_FORMAT_UNKNOWN); @@ -184,20 +220,24 @@ bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); return false; } + + m_is_depth_view = true; } m_resource = std::move(texture); m_srv_descriptor = std::move(srv_descriptor); m_rtv_or_dsv_descriptor = std::move(rtv_descriptor); - m_width = static_cast(desc.Width); - m_height = desc.Height; - m_samples = desc.SampleDesc.Count; - m_format = desc.Format; + m_width = static_cast(desc.Width); + m_height = static_cast(desc.Height); + m_layers = static_cast(desc.DepthOrArraySize); + m_levels = static_cast(desc.MipLevels); + m_samples = static_cast(desc.SampleDesc.Count); + m_format = LookupBaseFormat(desc.Format); m_state = state; return true; } -void Texture::Destroy(bool defer /* = true */) +void D3D12::Texture::Destroy(bool defer /* = true */) { if (defer) { @@ -220,14 +260,11 @@ void Texture::Destroy(bool defer /* = true */) m_resource.Reset(); } - m_width = 0; - m_height = 0; - m_samples = 0; - m_format = DXGI_FORMAT_UNKNOWN; + ClearBaseProperties(); m_is_depth_view = false; } -void Texture::TransitionToState(D3D12_RESOURCE_STATES state) const +void D3D12::Texture::TransitionToState(D3D12_RESOURCE_STATES state) const { if (m_state == state) return; @@ -236,9 +273,9 @@ void Texture::TransitionToState(D3D12_RESOURCE_STATES state) const m_state = state; } -bool Texture::BeginStreamUpdate(u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch) +bool D3D12::Texture::BeginStreamUpdate(u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch) { - const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + const u32 copy_pitch = Common::AlignUpPow2(width * GetPixelSize(), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 upload_size = copy_pitch * height; if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) @@ -258,9 +295,9 @@ bool Texture::BeginStreamUpdate(u32 x, u32 y, u32 width, u32 height, void** out_ return true; } -void Texture::EndStreamUpdate(u32 x, u32 y, u32 width, u32 height) +void D3D12::Texture::EndStreamUpdate(u32 x, u32 y, u32 width, u32 height) { - const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + const u32 copy_pitch = Common::AlignUpPow2(width * GetPixelSize(), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 upload_size = copy_pitch * height; StreamBuffer& sb = g_d3d12_context->GetTextureStreamBuffer(); @@ -270,7 +307,8 @@ void Texture::EndStreamUpdate(u32 x, u32 y, u32 width, u32 height) CopyFromBuffer(x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset); } -void Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset) +void D3D12::Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, + u32 buffer_offset) { D3D12_TEXTURE_COPY_LOCATION src; src.pResource = buffer; @@ -281,7 +319,7 @@ void Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3 src.PlacedFootprint.Footprint.Height = height; src.PlacedFootprint.Footprint.Depth = 1; src.PlacedFootprint.Footprint.RowPitch = pitch; - src.PlacedFootprint.Footprint.Format = m_format; + src.PlacedFootprint.Footprint.Format = GetDXGIFormat(); D3D12_TEXTURE_COPY_LOCATION dst; dst.pResource = m_resource.Get(); @@ -295,15 +333,15 @@ void Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3 TransitionToState(old_state); } -bool Texture::LoadData(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) +bool D3D12::Texture::LoadData(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) { - const u32 texel_size = GetTexelSize(m_format); + const u32 texel_size = GetPixelSize(); const u32 upload_pitch = Common::AlignUpPow2(width * texel_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 upload_size = upload_pitch * height; if (upload_size >= g_d3d12_context->GetTextureStreamBuffer().GetSize()) { StagingTexture st; - if (!st.Create(width, height, m_format, true) || !st.WritePixels(0, 0, width, height, data, pitch)) + if (!st.Create(width, height, GetDXGIFormat(), true) || !st.WritePixels(0, 0, width, height, data, pitch)) return false; D3D12_RESOURCE_STATES old_state = m_state; @@ -324,7 +362,7 @@ bool Texture::LoadData(u32 x, u32 y, u32 width, u32 height, const void* data, u3 return true; } -void Texture::CopyToUploadBuffer(const void* src_data, u32 src_pitch, u32 height, void* dst_data, u32 dst_pitch) +void D3D12::Texture::CopyToUploadBuffer(const void* src_data, u32 src_pitch, u32 height, void* dst_data, u32 dst_pitch) { const u8* src_ptr = static_cast(src_data); u8* dst_ptr = static_cast(dst_data); @@ -344,7 +382,8 @@ void Texture::CopyToUploadBuffer(const void* src_data, u32 src_pitch, u32 height } } -bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, DescriptorHandle* dh) +bool D3D12::Texture::CreateSRVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, + DescriptorHandle* dh) { if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) { @@ -362,7 +401,8 @@ bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, return true; } -bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, DescriptorHandle* dh) +bool D3D12::Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, + DescriptorHandle* dh) { if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh)) { @@ -377,7 +417,8 @@ bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, return true; } -bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, DescriptorHandle* dh) +bool D3D12::Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, + DescriptorHandle* dh) { if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh)) { @@ -391,5 +432,3 @@ bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle); return true; } - -} // namespace D3D12 \ No newline at end of file diff --git a/src/common/d3d12/texture.h b/src/common/d3d12/texture.h index 50b60aa18..ec47f15b1 100644 --- a/src/common/d3d12/texture.h +++ b/src/common/d3d12/texture.h @@ -1,5 +1,5 @@ #pragma once -#include "../types.h" +#include "../gpu_texture.h" #include "../windows_headers.h" #include "descriptor_heap_manager.h" #include @@ -9,7 +9,7 @@ namespace D3D12 { class StreamBuffer; -class Texture final +class Texture final : public GPUTexture { public: template @@ -21,21 +21,21 @@ public: Texture(const Texture&) = delete; ~Texture(); + static DXGI_FORMAT GetDXGIFormat(Format format); + static Format LookupBaseFormat(DXGI_FORMAT dformat); + ALWAYS_INLINE ID3D12Resource* GetResource() const { return m_resource.Get(); } ALWAYS_INLINE const DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; } ALWAYS_INLINE const DescriptorHandle& GetRTVOrDSVDescriptor() const { return m_rtv_or_dsv_descriptor; } ALWAYS_INLINE D3D12_RESOURCE_STATES GetState() const { return m_state; } - - ALWAYS_INLINE u32 GetWidth() const { return m_width; } - ALWAYS_INLINE u32 GetHeight() const { return m_height; } - ALWAYS_INLINE u32 GetSamples() const { return m_samples; } - ALWAYS_INLINE DXGI_FORMAT GetFormat() const { return m_format; } - ALWAYS_INLINE bool IsMultisampled() const { return m_samples > 1; } + ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return GetDXGIFormat(m_format); } ALWAYS_INLINE operator ID3D12Resource*() const { return m_resource.Get(); } ALWAYS_INLINE operator bool() const { return static_cast(m_resource); } - bool Create(u32 width, u32 height, u32 samples, DXGI_FORMAT format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, + bool IsValid() const override; + + bool Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, DXGI_FORMAT format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags); bool Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state); @@ -68,10 +68,6 @@ private: ComPtr m_resource; DescriptorHandle m_srv_descriptor = {}; DescriptorHandle m_rtv_or_dsv_descriptor = {}; - u32 m_width = 0; - u32 m_height = 0; - u32 m_samples = 0; - DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN; mutable D3D12_RESOURCE_STATES m_state = D3D12_RESOURCE_STATE_COMMON; diff --git a/src/common/gl/texture.cpp b/src/common/gl/texture.cpp index 2d821e66a..9a0034073 100644 --- a/src/common/gl/texture.cpp +++ b/src/common/gl/texture.cpp @@ -1,51 +1,78 @@ #include "texture.h" #include "../assert.h" #include "../log.h" +#include #include +#include Log_SetChannel(GL); -namespace GL { - -static constexpr u32 MAX_DIMENSIONS = std::numeric_limits::max(); -static constexpr u8 MAX_LEVELS = std::numeric_limits::max(); -static constexpr u8 MAX_SAMPLES = std::numeric_limits::max(); - -Texture::Texture() = default; - -Texture::Texture(Texture&& moved) - : m_id(moved.m_id), m_width(moved.m_width), m_height(moved.m_height), m_samples(moved.m_samples), - m_fbo_id(moved.m_fbo_id) +const std::tuple& GL::Texture::GetPixelFormatMapping(GPUTexture::Format format) { - moved.m_id = 0; - moved.m_width = 0; - moved.m_height = 0; - moved.m_samples = 0; - moved.m_fbo_id = 0; + static constexpr std::array, static_cast(GPUTexture::Format::Count)> mapping = + {{ + {}, // Unknown + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8 + {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 + {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 + {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // RGBA5551 + {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8 + {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_SHORT}, // D16 + }}; + + static constexpr std::array, static_cast(GPUTexture::Format::Count)> + mapping_gles2 = {{ + {}, // Unknown + {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8 + {}, // BGRA8 + {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 + {}, // RGBA5551 + {}, // R8 + {}, // D16 + }}; + + if (!GLAD_GL_ES_VERSION_2_0 || GLAD_GL_ES_VERSION_3_0) + return mapping[static_cast(format)]; + else + return mapping_gles2[static_cast(format)]; } -Texture::~Texture() +GL::Texture::Texture() = default; + +GL::Texture::Texture(Texture&& moved) : m_id(moved.m_id), m_fbo_id(moved.m_fbo_id) +{ + m_width = moved.m_width; + m_height = moved.m_height; + m_levels = moved.m_levels; + m_layers = moved.m_layers; + m_samples = moved.m_samples; + m_format = moved.m_format; + moved.m_id = 0; + moved.m_fbo_id = 0; + moved.ClearBaseProperties(); +} + +GL::Texture::~Texture() { Destroy(); } -bool Texture::UseTextureStorage(bool multisampled) +bool GL::Texture::UseTextureStorage(bool multisampled) { return GLAD_GL_ARB_texture_storage || (multisampled ? GLAD_GL_ES_VERSION_3_1 : GLAD_GL_ES_VERSION_3_0); } -bool Texture::UseTextureStorage() const +bool GL::Texture::UseTextureStorage() const { return UseTextureStorage(IsMultisampled()); } -bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GLenum internal_format, GLenum format, - GLenum type, const void* data /* = nullptr */, bool linear_filter /* = false */, - bool wrap /* = false */) +bool GL::Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Format format, + const void* data /* = nullptr */, u32 data_pitch /* = 0 */, bool linear /* = true */, + bool wrap /* = true */) { glGetError(); - if (width > MAX_DIMENSIONS || height > MAX_DIMENSIONS || layers > MAX_DIMENSIONS || levels > MAX_DIMENSIONS || - samples > MAX_SAMPLES) + if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES) { Log_ErrorPrintf("Invalid dimensions: %ux%ux%u %u %u", width, height, layers, levels, samples); return false; @@ -65,6 +92,7 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, const GLenum target = ((samples > 1) ? ((layers > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : ((layers > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D)); + const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(format); GLuint id; glGenTextures(1, &id); @@ -76,16 +104,16 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, if (UseTextureStorage(true)) { if (layers > 1) - glTexStorage3DMultisample(target, samples, internal_format, width, height, layers, GL_FALSE); + glTexStorage3DMultisample(target, samples, gl_internal_format, width, height, layers, GL_FALSE); else - glTexStorage2DMultisample(target, samples, internal_format, width, height, GL_FALSE); + glTexStorage2DMultisample(target, samples, gl_internal_format, width, height, GL_FALSE); } else { if (layers > 1) - glTexImage3DMultisample(target, samples, internal_format, width, height, layers, GL_FALSE); + glTexImage3DMultisample(target, samples, gl_internal_format, width, height, layers, GL_FALSE); else - glTexImage2DMultisample(target, samples, internal_format, width, height, GL_FALSE); + glTexImage2DMultisample(target, samples, gl_internal_format, width, height, GL_FALSE); } } else @@ -93,17 +121,17 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, if (UseTextureStorage(false)) { if (layers > 1) - glTexStorage3D(target, levels, internal_format, width, height, layers); + glTexStorage3D(target, levels, gl_internal_format, width, height, layers); else - glTexStorage2D(target, levels, internal_format, width, height); + glTexStorage2D(target, levels, gl_internal_format, width, height); if (data) { // TODO: Fix data for mipmaps here. if (layers > 1) - glTexSubImage3D(target, 0, 0, 0, 0, width, height, layers, format, type, data); + glTexSubImage3D(target, 0, 0, 0, 0, width, height, layers, gl_format, gl_type, data); else - glTexSubImage2D(target, 0, 0, 0, width, height, format, type, data); + glTexSubImage2D(target, 0, 0, 0, width, height, gl_format, gl_type, data); } } else @@ -112,17 +140,17 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, { // TODO: Fix data pointer here. if (layers > 1) - glTexImage3D(target, i, internal_format, width, height, layers, 0, format, type, data); + glTexImage3D(target, i, gl_internal_format, width, height, layers, 0, gl_format, gl_type, data); else - glTexImage2D(target, i, internal_format, width, height, 0, format, type, data); + glTexImage2D(target, i, gl_internal_format, width, height, 0, gl_format, gl_type, data); } glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels); } - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); @@ -148,16 +176,16 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, m_id = id; m_width = static_cast(width); m_height = static_cast(height); - m_layers = static_cast(layers); + m_layers = static_cast(layers); m_levels = static_cast(levels); m_samples = static_cast(samples); + m_format = format; return true; } -void Texture::Replace(u32 width, u32 height, GLenum internal_format, GLenum format, GLenum type, const void* data) +void GL::Texture::Replace(u32 width, u32 height, GLenum internal_format, GLenum format, GLenum type, const void* data) { - Assert(IsValid() && width < MAX_DIMENSIONS && height < MAX_DIMENSIONS && m_layers == 1 && m_samples == 1 && - m_levels == 1); + Assert(IsValid() && width < MAX_WIDTH && height < MAX_HEIGHT && m_layers == 1 && m_samples == 1 && m_levels == 1); const bool size_changed = (width != m_width || height != m_height); @@ -186,7 +214,7 @@ void Texture::Replace(u32 width, u32 height, GLenum internal_format, GLenum form } } -void Texture::ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, const void* data) +void GL::Texture::ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, const void* data) { Assert(IsValid() && !IsMultisampled()); @@ -197,8 +225,8 @@ void Texture::ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, con glTexSubImage2D(target, level, 0, 0, m_width, m_height, format, type, data); } -void Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type, - const void* data) +void GL::Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type, + const void* data) { Assert(IsValid() && !IsMultisampled()); @@ -209,7 +237,7 @@ void Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 glTexSubImage2D(target, level, x, y, width, height, format, type, data); } -void Texture::SetLinearFilter(bool enabled) const +void GL::Texture::SetLinearFilter(bool enabled) const { Assert(!IsMultisampled()); @@ -220,7 +248,17 @@ void Texture::SetLinearFilter(bool enabled) const glTexParameteri(target, GL_TEXTURE_MAG_FILTER, enabled ? GL_LINEAR : GL_NEAREST); } -bool Texture::CreateFramebuffer() +void GL::Texture::SetWrap(bool enabled) const +{ + const GLenum target = GetGLTarget(); + glTexParameteri(target, GL_TEXTURE_WRAP_S, enabled ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, enabled ? GL_REPEAT : GL_CLAMP_TO_EDGE); + + if (m_layers > 1) + glTexParameteri(target, GL_TEXTURE_WRAP_R, enabled ? GL_REPEAT : GL_CLAMP_TO_EDGE); +} + +bool GL::Texture::CreateFramebuffer() { if (!IsValid()) return false; @@ -244,7 +282,7 @@ bool Texture::CreateFramebuffer() return true; } -void Texture::Destroy() +void GL::Texture::Destroy() { if (m_fbo_id != 0) { @@ -257,54 +295,46 @@ void Texture::Destroy() m_id = 0; } - m_width = 0; - m_height = 0; - m_layers = 0; - m_levels = 0; - m_samples = 0; + ClearBaseProperties(); } -void Texture::Bind() const +void GL::Texture::Bind() const { glBindTexture(GetGLTarget(), m_id); } -void Texture::BindFramebuffer(GLenum target /*= GL_DRAW_FRAMEBUFFER*/) const +void GL::Texture::BindFramebuffer(GLenum target /*= GL_DRAW_FRAMEBUFFER*/) const { DebugAssert(m_fbo_id != 0); glBindFramebuffer(target, m_fbo_id); } -void Texture::Unbind() const +void GL::Texture::Unbind() const { glBindTexture(GetGLTarget(), 0); } -Texture& Texture::operator=(Texture&& moved) +GL::Texture& GL::Texture::operator=(Texture&& moved) { Destroy(); m_id = moved.m_id; + m_fbo_id = moved.m_fbo_id; m_width = moved.m_width; m_height = moved.m_height; m_layers = moved.m_layers; m_levels = moved.m_levels; m_samples = moved.m_samples; - m_fbo_id = moved.m_fbo_id; moved.m_id = 0; - moved.m_width = 0; - moved.m_height = 0; - moved.m_layers = 0; - moved.m_levels = 0; - moved.m_samples = 0; moved.m_fbo_id = 0; + moved.ClearBaseProperties(); return *this; } -void Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, - GLsizei bufSize, void* pixels) +void GL::Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + GLsizei bufSize, void* pixels) { if (GLAD_GL_VERSION_4_5 || GLAD_GL_ARB_get_texture_sub_image) { @@ -341,5 +371,3 @@ void Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLi glBindFramebuffer(target, old_read_fbo); glDeleteFramebuffers(1, &temp_fbo); } - -} // namespace GL diff --git a/src/common/gl/texture.h b/src/common/gl/texture.h index f5fc25b06..2979ec2a3 100644 --- a/src/common/gl/texture.h +++ b/src/common/gl/texture.h @@ -1,9 +1,11 @@ #pragma once -#include "../types.h" +#include "../gpu_texture.h" #include "loader.h" +#include namespace GL { -class Texture + +class Texture final : public GPUTexture { public: Texture(); @@ -11,29 +13,25 @@ public: ~Texture(); static bool UseTextureStorage(bool multisampled); + static const std::tuple& GetPixelFormatMapping(Format format); + + ALWAYS_INLINE GLuint GetGLId() const { return m_id; } + bool IsValid() const override { return m_id != 0; } + + bool Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Format format, const void* data = nullptr, + u32 data_pitch = 0, bool linear = true, bool wrap = true); + void Destroy(); - bool Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GLenum internal_format, GLenum format, - GLenum type, const void* data = nullptr, bool linear_filter = false, bool wrap = false); void Replace(u32 width, u32 height, GLenum internal_format, GLenum format, GLenum type, const void* data); void ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, const void* data); void ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type, const void* data); bool CreateFramebuffer(); - void Destroy(); - bool UseTextureStorage() const; - void SetLinearFilter(bool enabled) const; - ALWAYS_INLINE bool IsValid() const { return m_id != 0; } - ALWAYS_INLINE bool IsTextureArray() const { return m_layers > 1; } - ALWAYS_INLINE bool IsMultisampled() const { return m_samples > 1; } - ALWAYS_INLINE GLuint GetGLId() const { return m_id; } - ALWAYS_INLINE u16 GetWidth() const { return m_width; } - ALWAYS_INLINE u16 GetHeight() const { return m_height; } - ALWAYS_INLINE u16 GetLayers() const { return m_layers; } - ALWAYS_INLINE u8 GetLevels() const { return m_levels; } - ALWAYS_INLINE u8 GetSamples() const { return m_samples; } + void SetLinearFilter(bool enabled) const; + void SetWrap(bool enabled) const; ALWAYS_INLINE GLuint GetGLFramebufferID() const { return m_fbo_id; } ALWAYS_INLINE GLenum GetGLTarget() const @@ -56,12 +54,6 @@ public: private: GLuint m_id = 0; - u16 m_width = 0; - u16 m_height = 0; - u16 m_layers = 0; - u8 m_levels = 0; - u8 m_samples = 0; - GLuint m_fbo_id = 0; }; diff --git a/src/common/gpu_texture.cpp b/src/common/gpu_texture.cpp new file mode 100644 index 000000000..5eb4a3688 --- /dev/null +++ b/src/common/gpu_texture.cpp @@ -0,0 +1,145 @@ +#include "gpu_texture.h" +#include "log.h" +#include "string_util.h" +Log_SetChannel(GPUTexture); + +GPUTexture::GPUTexture() = default; + +GPUTexture::GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, GPUTexture::Format format) + : m_width(width), m_height(height), m_layers(layers), m_levels(levels), m_samples(samples), m_format(format) +{ +} + +GPUTexture::~GPUTexture() = default; + +void GPUTexture::ClearBaseProperties() +{ + m_width = 0; + m_height = 0; + m_layers = 0; + m_levels = 0; + m_samples = 0; + m_format = GPUTexture::Format::Unknown; +} + +u32 GPUTexture::GPUTexture::GetPixelSize(GPUTexture::Format format) +{ + switch (format) + { + case Format::RGBA8: + case Format::BGRA8: + return 4; + + case Format::RGBA5551: + case Format::RGB565: + case Format::D16: + return 2; + + case Format::R8: + return 1; + + default: + return 0; + } +} + +bool GPUTexture::IsDepthFormat(Format format) +{ + return (format == Format::D16); +} + +bool GPUTexture::ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector& texture_data, + u32& texture_data_stride, GPUTexture::Format format) +{ + switch (format) + { + case GPUTexture::Format::BGRA8: + { + for (u32 y = 0; y < height; y++) + { + u32* pixels = reinterpret_cast(reinterpret_cast(texture_data.data()) + (y * texture_data_stride)); + for (u32 x = 0; x < width; x++) + pixels[x] = (pixels[x] & 0xFF00FF00) | ((pixels[x] & 0xFF) << 16) | ((pixels[x] >> 16) & 0xFF); + } + + return true; + } + + case GPUTexture::Format::RGBA8: + return true; + + case GPUTexture::Format::RGB565: + { + std::vector temp(width * height); + + for (u32 y = 0; y < height; y++) + { + const u8* pixels_in = reinterpret_cast(texture_data.data()) + (y * texture_data_stride); + u32* pixels_out = &temp[y * width]; + + for (u32 x = 0; x < width; x++) + { + // RGB565 -> RGBA8 + u16 pixel_in; + std::memcpy(&pixel_in, pixels_in, sizeof(u16)); + pixels_in += sizeof(u16); + const u8 r5 = Truncate8(pixel_in >> 11); + const u8 g6 = Truncate8((pixel_in >> 5) & 0x3F); + const u8 b5 = Truncate8(pixel_in & 0x1F); + *(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 2) | (g6 & 3)) << 8) | + (ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (0xFF000000u); + } + } + + texture_data = std::move(temp); + texture_data_stride = sizeof(u32) * width; + return true; + } + + case GPUTexture::Format::RGBA5551: + { + std::vector temp(width * height); + + for (u32 y = 0; y < height; y++) + { + const u8* pixels_in = reinterpret_cast(texture_data.data()) + (y * texture_data_stride); + u32* pixels_out = &temp[y * width]; + + for (u32 x = 0; x < width; x++) + { + // RGBA5551 -> RGBA8 + u16 pixel_in; + std::memcpy(&pixel_in, pixels_in, sizeof(u16)); + pixels_in += sizeof(u16); + const u8 a1 = Truncate8(pixel_in >> 15); + const u8 r5 = Truncate8((pixel_in >> 10) & 0x1F); + const u8 g6 = Truncate8((pixel_in >> 5) & 0x1F); + const u8 b5 = Truncate8(pixel_in & 0x1F); + *(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 3) | (g6 & 7)) << 8) | + (ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (a1 ? 0xFF000000u : 0u); + } + } + + texture_data = std::move(temp); + texture_data_stride = sizeof(u32) * width; + return true; + } + + default: + Log_ErrorPrintf("Unknown pixel format %u", static_cast(format)); + return false; + } +} + +void GPUTexture::FlipTextureDataRGBA8(u32 width, u32 height, std::vector& texture_data, u32 texture_data_stride) +{ + std::vector temp(width); + for (u32 flip_row = 0; flip_row < (height / 2); flip_row++) + { + u32* top_ptr = &texture_data[flip_row * width]; + u32* bottom_ptr = &texture_data[((height - 1) - flip_row) * width]; + std::memcpy(temp.data(), top_ptr, texture_data_stride); + std::memcpy(top_ptr, bottom_ptr, texture_data_stride); + std::memcpy(bottom_ptr, temp.data(), texture_data_stride); + } +} \ No newline at end of file diff --git a/src/common/gpu_texture.h b/src/common/gpu_texture.h new file mode 100644 index 000000000..3ae3a6dcd --- /dev/null +++ b/src/common/gpu_texture.h @@ -0,0 +1,68 @@ +#pragma once +#include "types.h" +#include +#include + +class GPUTexture +{ +public: + enum : u32 + { + MAX_WIDTH = 65535, + MAX_HEIGHT = 65535, + MAX_LAYERS = 255, + MAX_LEVELS = 255, + MAX_SAMPLES = 255, + }; + + enum class Format : u8 + { + Unknown, + RGBA8, + BGRA8, + RGB565, + RGBA5551, + R8, + D16, + Count + }; + +public: + virtual ~GPUTexture(); + + ALWAYS_INLINE u32 GetWidth() const { return m_width; } + ALWAYS_INLINE u32 GetHeight() const { return m_height; } + ALWAYS_INLINE u32 GetLayers() const { return m_layers; } + ALWAYS_INLINE u32 GetLevels() const { return m_levels; } + ALWAYS_INLINE u32 GetSamples() const { return m_samples; } + ALWAYS_INLINE GPUTexture::Format GetFormat() const { return m_format; } + + ALWAYS_INLINE bool IsTextureArray() const { return m_layers > 1; } + ALWAYS_INLINE bool IsMultisampled() const { return m_samples > 1; } + + ALWAYS_INLINE u32 GetPixelSize() const { return GetPixelSize(m_format); } + ALWAYS_INLINE u32 GetMipWidth(u32 level) const { return std::max(m_width >> level, 1u); } + ALWAYS_INLINE u32 GetMipHeight(u32 level) const { return std::max(m_height >> level, 1u); } + + virtual bool IsValid() const = 0; + + static u32 GetPixelSize(GPUTexture::Format format); + static bool IsDepthFormat(GPUTexture::Format format); + + static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector& texture_data, u32& texture_data_stride, + GPUTexture::Format format); + static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector& texture_data, u32 texture_data_stride); + +protected: + GPUTexture(); + GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Format format); + + void ClearBaseProperties(); + + u16 m_width = 0; + u16 m_height = 0; + u8 m_layers = 0; + u8 m_levels = 0; + u8 m_samples = 0; + Format m_format = Format::Unknown; +}; diff --git a/src/common/vulkan/texture.cpp b/src/common/vulkan/texture.cpp index f3db36ae7..2419380f0 100644 --- a/src/common/vulkan/texture.cpp +++ b/src/common/vulkan/texture.cpp @@ -8,22 +8,26 @@ #include Log_SetChannel(Texture); +static constexpr std::array(GPUTexture::Format::Count)> s_vk_mapping = { + {VK_FORMAT_UNDEFINED, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16, + VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_R8_UNORM, VK_FORMAT_D16_UNORM}}; + static constexpr VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; Vulkan::Texture::Texture() = default; Vulkan::Texture::Texture(Texture&& move) - : m_width(move.m_width), m_height(move.m_height), m_levels(move.m_levels), m_layers(move.m_layers), - m_format(move.m_format), m_samples(move.m_samples), m_view_type(move.m_view_type), m_layout(move.m_layout), - m_image(move.m_image), m_allocation(move.m_allocation), m_view(move.m_view) + : m_view_type(move.m_view_type), m_layout(move.m_layout), m_image(move.m_image), m_allocation(move.m_allocation), + m_view(move.m_view) { - move.m_width = 0; - move.m_height = 0; - move.m_levels = 0; - move.m_layers = 0; - move.m_format = VK_FORMAT_UNDEFINED; - move.m_samples = VK_SAMPLE_COUNT_1_BIT; + m_width = move.m_width; + m_height = move.m_height; + m_layers = move.m_layers; + m_levels = move.m_levels; + m_samples = move.m_samples; + + move.ClearBaseProperties(); move.m_view_type = VK_IMAGE_VIEW_TYPE_2D; move.m_layout = VK_IMAGE_LAYOUT_UNDEFINED; move.m_image = VK_NULL_HANDLE; @@ -37,6 +41,26 @@ Vulkan::Texture::~Texture() Destroy(true); } +VkFormat Vulkan::Texture::GetVkFormat(Format format) +{ + return s_vk_mapping[static_cast(format)]; +} + +GPUTexture::Format Vulkan::Texture::LookupBaseFormat(VkFormat vformat) +{ + for (u32 i = 0; i < static_cast(s_vk_mapping.size()); i++) + { + if (s_vk_mapping[i] == vformat) + return static_cast(i); + } + return GPUTexture::Format::Unknown; +} + +bool Vulkan::Texture::IsValid() const +{ + return (m_image != VK_NULL_HANDLE); +} + Vulkan::Texture& Vulkan::Texture::operator=(Texture&& move) { if (IsValid()) @@ -129,12 +153,12 @@ bool Vulkan::Texture::Create(u32 width, u32 height, u32 levels, u32 layers, VkFo if (IsValid()) Destroy(true); - m_width = width; - m_height = height; - m_levels = levels; - m_layers = layers; - m_format = format; - m_samples = samples; + m_width = static_cast(width); + m_height = static_cast(height); + m_levels = static_cast(levels); + m_layers = static_cast(layers); + m_samples = static_cast(samples); + m_format = LookupBaseFormat(format); m_view_type = view_type; m_image = image; m_allocation = allocation; @@ -171,12 +195,12 @@ bool Vulkan::Texture::Adopt(VkImage existing_image, VkImageViewType view_type, u if (IsValid()) Destroy(true); - m_width = width; - m_height = height; - m_levels = levels; - m_layers = layers; - m_format = format; - m_samples = samples; + m_width = static_cast(width); + m_height = static_cast(height); + m_levels = static_cast(levels); + m_layers = static_cast(layers); + m_format = LookupBaseFormat(format); + m_samples = static_cast(samples); m_view_type = view_type; m_image = existing_image; m_view = view; @@ -206,11 +230,7 @@ void Vulkan::Texture::Destroy(bool defer /* = true */) m_allocation = VK_NULL_HANDLE; } - m_width = 0; - m_height = 0; - m_levels = 0; - m_layers = 0; - m_format = VK_FORMAT_UNDEFINED; + ClearBaseProperties(); m_samples = VK_SAMPLE_COUNT_1_BIT; m_view_type = VK_IMAGE_VIEW_TYPE_2D; m_layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -252,8 +272,7 @@ void Vulkan::Texture::TransitionSubresourcesToLayout(VkCommandBuffer command_buf VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex m_image, // VkImage image - {static_cast(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : - VK_IMAGE_ASPECT_COLOR_BIT), + {static_cast(IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), start_level, num_levels, start_layer, num_layers} // VkImageSubresourceRange subresourceRange }; @@ -392,13 +411,12 @@ void Vulkan::Texture::UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 la u32 Vulkan::Texture::CalcUpdatePitch(u32 width) const { - return Common::AlignUp(width * Vulkan::Util::GetTexelSize(m_format), - g_vulkan_context->GetBufferCopyRowPitchAlignment()); + return Common::AlignUp(width * GetPixelSize(), g_vulkan_context->GetBufferCopyRowPitchAlignment()); } u32 Vulkan::Texture::CalcUpdateRowLength(u32 pitch) const { - return pitch / Vulkan::Util::GetTexelSize(m_format); + return pitch / GetPixelSize(); } bool Vulkan::Texture::BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) diff --git a/src/common/vulkan/texture.h b/src/common/vulkan/texture.h index 5f72bd30a..8aea75e77 100644 --- a/src/common/vulkan/texture.h +++ b/src/common/vulkan/texture.h @@ -1,11 +1,12 @@ #pragma once -#include "../types.h" +#include "../gpu_texture.h" #include "loader.h" #include #include namespace Vulkan { -class Texture + +class Texture final : public GPUTexture { public: Texture(); @@ -16,7 +17,10 @@ public: Texture& operator=(Texture&& move); Texture& operator=(const Texture&) = delete; - ALWAYS_INLINE bool IsValid() const { return (m_image != VK_NULL_HANDLE); } + static VkFormat GetVkFormat(Format format); + static Format LookupBaseFormat(VkFormat vformat); + + bool IsValid() const override; /// An image is considered owned/managed if we control the memory. ALWAYS_INLINE bool IsOwned() const { return (m_allocation != VK_NULL_HANDLE); } @@ -25,10 +29,9 @@ public: ALWAYS_INLINE u32 GetHeight() const { return m_height; } ALWAYS_INLINE u32 GetLevels() const { return m_levels; } ALWAYS_INLINE u32 GetLayers() const { return m_layers; } - ALWAYS_INLINE u32 GetMipWidth(u32 level) const { return std::max(m_width >> level, 1u); } - ALWAYS_INLINE u32 GetMipHeight(u32 level) const { return std::max(m_height >> level, 1u); } - ALWAYS_INLINE VkFormat GetFormat() const { return m_format; } - ALWAYS_INLINE VkSampleCountFlagBits GetSamples() const { return m_samples; } + + ALWAYS_INLINE VkFormat GetVkFormat() const { return GetVkFormat(m_format); } + ALWAYS_INLINE VkSampleCountFlagBits GetVkSamples() const { return static_cast(m_samples); } ALWAYS_INLINE VkImageLayout GetLayout() const { return m_layout; } ALWAYS_INLINE VkImageViewType GetViewType() const { return m_view_type; } ALWAYS_INLINE VkImage GetImage() const { return m_image; } @@ -65,12 +68,6 @@ public: bool Update(u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer, const void* data, u32 data_pitch); private: - u32 m_width = 0; - u32 m_height = 0; - u32 m_levels = 0; - u32 m_layers = 0; - VkFormat m_format = VK_FORMAT_UNDEFINED; - VkSampleCountFlagBits m_samples = VK_SAMPLE_COUNT_1_BIT; VkImageViewType m_view_type = VK_IMAGE_VIEW_TYPE_2D; VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED; diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 7c68d9ac1..84bd33271 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -163,7 +163,7 @@ void GPU::SoftReset() UpdateGPUIdle(); } -bool GPU::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) +bool GPU::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) { if (sw.IsReading()) { diff --git a/src/core/gpu.h b/src/core/gpu.h index 69906598a..40b0ef460 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -15,7 +15,7 @@ class StateWrapper; class HostDisplay; -class HostDisplayTexture; +class GPUTexture; class TimingEvent; class Timers; @@ -83,7 +83,7 @@ public: virtual bool Initialize(); virtual void Reset(bool clear_vram); - virtual bool DoState(StateWrapper& sw, HostDisplayTexture** save_to_texture, bool update_display); + virtual bool DoState(StateWrapper& sw, GPUTexture** save_to_texture, bool update_display); // Graphics API state reset/restore - call when drawing the UI etc. virtual void ResetGraphicsAPIState(); diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 41b4d9833..1e2c34ae4 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -123,7 +123,7 @@ void GPU_HW::Reset(bool clear_vram) SetFullVRAMDirtyRectangle(); } -bool GPU_HW::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) +bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) { if (!GPU::DoState(sw, host_texture, update_display)) return false; diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 45d211557..8deebce53 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -37,7 +37,7 @@ public: virtual bool Initialize() override; virtual void Reset(bool clear_vram) override; - virtual bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; + virtual bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override; void UpdateResolutionScale() override final; std::tuple GetEffectiveDisplayResolution(bool scaled = true) override final; diff --git a/src/core/gpu_hw_d3d11.cpp b/src/core/gpu_hw_d3d11.cpp index 9007794e0..b6794b7b0 100644 --- a/src/core/gpu_hw_d3d11.cpp +++ b/src/core/gpu_hw_d3d11.cpp @@ -99,13 +99,13 @@ void GPU_HW_D3D11::Reset(bool clear_vram) ClearFramebuffer(); } -bool GPU_HW_D3D11::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) +bool GPU_HW_D3D11::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) { if (host_texture) { ComPtr resource; - HostDisplayTexture* tex = *host_texture; + D3D11::Texture* tex = static_cast(*host_texture); if (sw.IsReading()) { if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || @@ -114,8 +114,7 @@ bool GPU_HW_D3D11::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, return false; } - static_cast(tex->GetHandle())->GetResource(resource.GetAddressOf()); - m_context->CopySubresourceRegion(m_vram_texture.GetD3DTexture(), 0, 0, 0, 0, resource.Get(), 0, nullptr); + m_context->CopySubresourceRegion(m_vram_texture.GetD3DTexture(), 0, 0, 0, 0, tex->GetD3DTexture(), 0, nullptr); } else { @@ -124,17 +123,17 @@ bool GPU_HW_D3D11::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, { delete tex; - tex = g_host_display - ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, - m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) - .release(); + tex = static_cast(g_host_display + ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, + 1, m_vram_texture.GetSamples(), GPUTexture::Format::RGBA8, + nullptr, 0, false) + .release()); *host_texture = tex; if (!tex) return false; } - static_cast(tex->GetHandle())->GetResource(resource.GetAddressOf()); - m_context->CopySubresourceRegion(resource.Get(), 0, 0, 0, 0, m_vram_texture.GetD3DTexture(), 0, nullptr); + m_context->CopySubresourceRegion(tex->GetD3DTexture(), 0, 0, 0, 0, m_vram_texture.GetD3DTexture(), 0, nullptr); } } @@ -254,9 +253,9 @@ bool GPU_HW_D3D11::CreateFramebuffer() // scale vram size to internal resolution const u32 texture_width = VRAM_WIDTH * m_resolution_scale; const u32 texture_height = VRAM_HEIGHT * m_resolution_scale; - const u16 samples = static_cast(m_multisamples); - const DXGI_FORMAT texture_format = DXGI_FORMAT_R8G8B8A8_UNORM; - const DXGI_FORMAT depth_format = DXGI_FORMAT_D16_UNORM; + const u8 samples = static_cast(m_multisamples); + const GPUTexture::Format texture_format = GPUTexture::Format::RGBA8; + const GPUTexture::Format depth_format = GPUTexture::Format::D16; if (!m_vram_texture.Create(m_device.Get(), texture_width, texture_height, 1, 1, samples, texture_format, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) || @@ -275,8 +274,9 @@ bool GPU_HW_D3D11::CreateFramebuffer() return false; } - const CD3D11_DEPTH_STENCIL_VIEW_DESC depth_view_desc( - samples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D, depth_format); + const CD3D11_DEPTH_STENCIL_VIEW_DESC depth_view_desc(samples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : + D3D11_DSV_DIMENSION_TEXTURE2D, + D3D11::Texture::GetDXGIFormat(depth_format)); HRESULT hr = m_device->CreateDepthStencilView(m_vram_depth_texture, &depth_view_desc, m_vram_depth_view.GetAddressOf()); if (FAILED(hr)) @@ -289,7 +289,7 @@ bool GPU_HW_D3D11::CreateFramebuffer() if (!m_downsample_texture.Create(m_device.Get(), texture_width, texture_height, 1, static_cast(levels), 1, texture_format, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) || !m_downsample_weight_texture.Create(m_device.Get(), texture_width >> (levels - 1), - texture_height >> (levels - 1), 1, 1, 1, DXGI_FORMAT_R8_UNORM, + texture_height >> (levels - 1), 1, 1, 1, GPUTexture::Format::R8, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) { return false; @@ -299,9 +299,9 @@ bool GPU_HW_D3D11::CreateFramebuffer() for (u32 i = 0; i < levels; i++) { const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(m_downsample_texture, D3D11_SRV_DIMENSION_TEXTURE2D, - texture_format, i, 1); - const CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(m_downsample_texture, D3D11_RTV_DIMENSION_TEXTURE2D, texture_format, - i, 1); + m_downsample_texture.GetDXGIFormat(), i, 1); + const CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(m_downsample_texture, D3D11_RTV_DIMENSION_TEXTURE2D, + m_downsample_texture.GetDXGIFormat(), i, 1); hr = m_device->CreateShaderResourceView(m_downsample_texture, &srv_desc, m_downsample_mip_views[i].first.GetAddressOf()); @@ -749,7 +749,7 @@ bool GPU_HW_D3D11::BlitVRAMReplacementTexture(const TextureReplacementTexture* t m_vram_replacement_texture.GetHeight() < tex->GetHeight()) { if (!m_vram_replacement_texture.Create(m_device.Get(), tex->GetWidth(), tex->GetHeight(), 1, 1, 1, - DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_BIND_SHADER_RESOURCE, tex->GetPixels(), + GPUTexture::Format::RGBA8, D3D11_BIND_SHADER_RESOURCE, tex->GetPixels(), tex->GetPitch(), true)) { return false; @@ -841,15 +841,12 @@ void GPU_HW_D3D11::UpdateDisplay() if (IsUsingMultisampling()) { UpdateVRAMReadTexture(); - g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, - m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, - m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); + g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, 0, m_vram_read_texture.GetWidth(), + m_vram_read_texture.GetHeight()); } else { - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight()); + g_host_display->SetDisplayTexture(&m_vram_texture, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); } g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, @@ -889,8 +886,7 @@ void GPU_HW_D3D11::UpdateDisplay() } else { - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y, + g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y, scaled_display_width, scaled_display_height); } } @@ -916,15 +912,9 @@ void GPU_HW_D3D11::UpdateDisplay() DrawUtilityShader(display_pixel_shader, uniforms, sizeof(uniforms)); if (IsUsingDownsampling()) - { DownsampleFramebuffer(m_display_texture, 0, 0, scaled_display_width, scaled_display_height); - } else - { - g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, - m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0, - scaled_display_width, scaled_display_height); - } + g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height); RestoreGraphicsAPIState(); } @@ -954,9 +944,9 @@ void GPU_HW_D3D11::ReadVRAM(u32 x, u32 y, u32 width, u32 height) DrawUtilityShader(m_vram_read_pixel_shader.Get(), uniforms, sizeof(uniforms)); // Stage the readback and copy it into our shadow buffer. - g_host_display->DownloadTexture( - &m_vram_encoding_texture, HostDisplayPixelFormat::RGBA8, 0, 0, encoded_width, encoded_height, - reinterpret_cast(&m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left]), VRAM_WIDTH * sizeof(u16)); + g_host_display->DownloadTexture(&m_vram_encoding_texture, 0, 0, encoded_width, encoded_height, + reinterpret_cast(&m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left]), + VRAM_WIDTH * sizeof(u16)); RestoreGraphicsAPIState(); } @@ -1080,7 +1070,7 @@ void GPU_HW_D3D11::UpdateVRAMReadTexture() if (m_vram_texture.IsMultisampled()) { m_context->ResolveSubresource(m_vram_read_texture.GetD3DTexture(), 0, m_vram_texture.GetD3DTexture(), 0, - m_vram_texture.GetFormat()); + m_vram_texture.GetDXGIFormat()); } else { @@ -1191,8 +1181,7 @@ void GPU_HW_D3D11::DownsampleFramebufferAdaptive(D3D11::Texture& source, u32 lef RestoreGraphicsAPIState(); - g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), - m_display_texture.GetHeight(), left, top, width, height); + g_host_display->SetDisplayTexture(&m_display_texture, left, top, width, height); } void GPU_HW_D3D11::DownsampleFramebufferBoxFilter(D3D11::Texture& source, u32 left, u32 top, u32 width, u32 height) @@ -1215,9 +1204,7 @@ void GPU_HW_D3D11::DownsampleFramebufferBoxFilter(D3D11::Texture& source, u32 le RestoreGraphicsAPIState(); - g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, - m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top, - ds_width, ds_height); + g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height); } std::unique_ptr GPU::CreateHardwareD3D11Renderer() diff --git a/src/core/gpu_hw_d3d11.h b/src/core/gpu_hw_d3d11.h index 78eec6316..0a427c474 100644 --- a/src/core/gpu_hw_d3d11.h +++ b/src/core/gpu_hw_d3d11.h @@ -23,7 +23,7 @@ public: bool Initialize() override; void Reset(bool clear_vram) override; - bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; + bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override; void ResetGraphicsAPIState() override; void RestoreGraphicsAPIState() override; diff --git a/src/core/gpu_hw_d3d12.cpp b/src/core/gpu_hw_d3d12.cpp index 296b92f7e..277e380b0 100644 --- a/src/core/gpu_hw_d3d12.cpp +++ b/src/core/gpu_hw_d3d12.cpp @@ -319,16 +319,16 @@ bool GPU_HW_D3D12::CreateFramebuffer() const DXGI_FORMAT texture_format = DXGI_FORMAT_R8G8B8A8_UNORM; const DXGI_FORMAT depth_format = DXGI_FORMAT_D16_UNORM; - if (!m_vram_texture.Create(texture_width, texture_height, m_multisamples, texture_format, texture_format, + if (!m_vram_texture.Create(texture_width, texture_height, 1, 1, m_multisamples, texture_format, texture_format, texture_format, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) || !m_vram_depth_texture.Create( - texture_width, texture_height, m_multisamples, depth_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + texture_width, texture_height, 1, 1, m_multisamples, depth_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, depth_format, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) || - !m_vram_read_texture.Create(texture_width, texture_height, 1, texture_format, texture_format, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE) || - !m_display_texture.Create(texture_width, texture_height, 1, texture_format, texture_format, texture_format, + !m_vram_read_texture.Create(texture_width, texture_height, 1, 1, 1, texture_format, texture_format, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE) || + !m_display_texture.Create(texture_width, texture_height, 1, 1, 1, texture_format, texture_format, texture_format, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) || - !m_vram_readback_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, texture_format, texture_format, texture_format, + !m_vram_readback_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, texture_format, texture_format, texture_format, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) || !m_vram_readback_staging_texture.Create(VRAM_WIDTH / 2, VRAM_HEIGHT, texture_format, false)) { @@ -476,8 +476,8 @@ bool GPU_HW_D3D12::CompilePipelines() const bool textured = (static_cast(texture_mode) != GPUTextureMode::Disabled); gpbuilder.SetRootSignature(m_batch_root_signature.Get()); - gpbuilder.SetRenderTarget(0, m_vram_texture.GetFormat()); - gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetFormat()); + gpbuilder.SetRenderTarget(0, m_vram_texture.GetDXGIFormat()); + gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetDXGIFormat()); gpbuilder.AddVertexAttribute("ATTR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(BatchVertex, x)); gpbuilder.AddVertexAttribute("ATTR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(BatchVertex, color)); @@ -547,16 +547,16 @@ bool GPU_HW_D3D12::CompilePipelines() // common state gpbuilder.SetRootSignature(m_single_sampler_root_signature.Get()); - gpbuilder.SetRenderTarget(0, m_vram_texture.GetFormat()); - gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetFormat()); + gpbuilder.SetRenderTarget(0, m_vram_texture.GetDXGIFormat()); + gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetDXGIFormat()); gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE); gpbuilder.SetNoCullRasterizationState(); gpbuilder.SetNoDepthTestState(); gpbuilder.SetNoBlendingState(); gpbuilder.SetVertexShader(fullscreen_quad_vertex_shader.Get()); gpbuilder.SetMultisamples(m_multisamples); - gpbuilder.SetRenderTarget(0, m_vram_texture.GetFormat()); - gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetFormat()); + gpbuilder.SetRenderTarget(0, m_vram_texture.GetDXGIFormat()); + gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetDXGIFormat()); // VRAM fill for (u8 wrapped = 0; wrapped < 2; wrapped++) @@ -663,7 +663,7 @@ bool GPU_HW_D3D12::CompilePipelines() gpbuilder.SetNoCullRasterizationState(); gpbuilder.SetNoDepthTestState(); gpbuilder.SetNoBlendingState(); - gpbuilder.SetRenderTarget(0, m_vram_readback_texture.GetFormat()); + gpbuilder.SetRenderTarget(0, m_vram_readback_texture.GetDXGIFormat()); gpbuilder.ClearDepthStencilFormat(); m_vram_readback_pipeline = gpbuilder.Create(g_d3d12_context->GetDevice(), shader_cache, false); @@ -685,7 +685,7 @@ bool GPU_HW_D3D12::CompilePipelines() gpbuilder.SetNoCullRasterizationState(); gpbuilder.SetNoDepthTestState(); gpbuilder.SetNoBlendingState(); - gpbuilder.SetRenderTarget(0, m_display_texture.GetFormat()); + gpbuilder.SetRenderTarget(0, m_display_texture.GetDXGIFormat()); for (u8 depth_24 = 0; depth_24 < 2; depth_24++) { @@ -775,7 +775,7 @@ bool GPU_HW_D3D12::BlitVRAMReplacementTexture(const TextureReplacementTexture* t if (m_vram_write_replacement_texture.GetWidth() < tex->GetWidth() || m_vram_write_replacement_texture.GetHeight() < tex->GetHeight()) { - if (!m_vram_write_replacement_texture.Create(tex->GetWidth(), tex->GetHeight(), 1, DXGI_FORMAT_R8G8B8A8_UNORM, + if (!m_vram_write_replacement_texture.Create(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE)) { @@ -867,16 +867,13 @@ void GPU_HW_D3D12::UpdateDisplay() if (IsUsingMultisampling()) { UpdateVRAMReadTexture(); - g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, - m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, - m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); + g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, 0, m_vram_read_texture.GetWidth(), + m_vram_read_texture.GetHeight()); } else { m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight()); + g_host_display->SetDisplayTexture(&m_vram_texture, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); } g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, static_cast(VRAM_WIDTH) / static_cast(VRAM_HEIGHT)); @@ -908,8 +905,7 @@ void GPU_HW_D3D12::UpdateDisplay() (scaled_vram_offset_y + scaled_display_height) <= m_vram_texture.GetHeight()) { m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y, + g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y, scaled_display_width, scaled_display_height); } else @@ -936,9 +932,7 @@ void GPU_HW_D3D12::UpdateDisplay() m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); - g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), - m_display_texture.GetHeight(), 0, 0, scaled_display_width, - scaled_display_height); + g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height); RestoreGraphicsAPIState(); } @@ -1150,7 +1144,7 @@ void GPU_HW_D3D12::UpdateVRAMReadTexture() { m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RESOLVE_SOURCE); m_vram_read_texture.TransitionToState(D3D12_RESOURCE_STATE_RESOLVE_DEST); - cmdlist->ResolveSubresource(m_vram_read_texture, 0, m_vram_texture, 0, m_vram_texture.GetFormat()); + cmdlist->ResolveSubresource(m_vram_read_texture, 0, m_vram_texture, 0, m_vram_texture.GetDXGIFormat()); } else { diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 0f2a6f5c3..2de16eae9 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -108,11 +108,11 @@ void GPU_HW_OpenGL::Reset(bool clear_vram) ClearFramebuffer(); } -bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) +bool GPU_HW_OpenGL::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) { if (host_texture) { - HostDisplayTexture* tex = *host_texture; + GPUTexture* tex = *host_texture; if (sw.IsReading()) { if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || @@ -121,9 +121,9 @@ bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, return false; } - CopyFramebufferForState( - m_vram_texture.GetGLTarget(), static_cast(reinterpret_cast(tex->GetHandle())), 0, 0, 0, - m_vram_texture.GetGLId(), m_vram_fbo_id, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); + CopyFramebufferForState(m_vram_texture.GetGLTarget(), static_cast(tex)->GetGLId(), 0, 0, 0, + m_vram_texture.GetGLId(), m_vram_fbo_id, 0, 0, m_vram_texture.GetWidth(), + m_vram_texture.GetHeight()); } else { @@ -134,7 +134,7 @@ bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, tex = g_host_display ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, - m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) + m_vram_texture.GetSamples(), GPUTexture::Format::RGBA8, nullptr, 0, false) .release(); *host_texture = tex; if (!tex) @@ -142,8 +142,8 @@ bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, } CopyFramebufferForState(m_vram_texture.GetGLTarget(), m_vram_texture.GetGLId(), m_vram_fbo_id, 0, 0, - static_cast(reinterpret_cast(tex->GetHandle())), 0, 0, 0, - m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); + static_cast(tex)->GetGLId(), 0, 0, 0, m_vram_texture.GetWidth(), + m_vram_texture.GetHeight()); } } @@ -285,17 +285,11 @@ void GPU_HW_OpenGL::UnmapBatchVertexPointer(u32 used_vertices) DebugAssert(m_batch_start_vertex_ptr); m_vertex_stream_buffer->Unmap(used_vertices * sizeof(BatchVertex)); - m_vertex_stream_buffer->Bind(); m_batch_start_vertex_ptr = nullptr; m_batch_end_vertex_ptr = nullptr; m_batch_current_vertex_ptr = nullptr; } -std::tuple GPU_HW_OpenGL::ConvertToFramebufferCoordinates(s32 x, s32 y) -{ - return std::make_tuple(x, static_cast(static_cast(VRAM_HEIGHT) - y)); -} - void GPU_HW_OpenGL::SetCapabilities() { GLint max_texture_size = VRAM_WIDTH; @@ -396,18 +390,18 @@ bool GPU_HW_OpenGL::CreateFramebuffer() const u32 texture_height = VRAM_HEIGHT * m_resolution_scale; const u32 multisamples = m_multisamples; - if (!m_vram_texture.Create(texture_width, texture_height, 1, 1, multisamples, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, - nullptr, false, true) || - !m_vram_depth_texture.Create(texture_width, texture_height, 1, 1, multisamples, GL_DEPTH_COMPONENT16, - GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr, false) || - !m_vram_read_texture.Create(texture_width, texture_height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, - false, true) || + if (!m_vram_texture.Create(texture_width, texture_height, 1, 1, multisamples, GPUTexture::Format::RGBA8, nullptr, 0, + true, true) || + !m_vram_depth_texture.Create(texture_width, texture_height, 1, 1, multisamples, GPUTexture::Format::D16, nullptr, + 0, false, true) || + !m_vram_read_texture.Create(texture_width, texture_height, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0, false, + true) || !m_vram_read_texture.CreateFramebuffer() || - !m_vram_encoding_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, - false) || + !m_vram_encoding_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0, false, + true) || !m_vram_encoding_texture.CreateFramebuffer() || !m_display_texture.Create(GPU_MAX_DISPLAY_WIDTH * m_resolution_scale, GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, - 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) || + 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0, true, true) || !m_display_texture.CreateFramebuffer()) { return false; @@ -425,7 +419,7 @@ bool GPU_HW_OpenGL::CreateFramebuffer() if (m_downsample_mode == GPUDownsampleMode::Box) { - if (!m_downsample_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE) || + if (!m_downsample_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, GPUTexture::Format::RGBA8) || !m_downsample_texture.CreateFramebuffer()) { return false; @@ -778,8 +772,8 @@ bool GPU_HW_OpenGL::BlitVRAMReplacementTexture(const TextureReplacementTexture* { if (!m_vram_write_replacement_texture.IsValid()) { - if (!m_vram_write_replacement_texture.Create(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GL_RGBA8, GL_RGBA, - GL_UNSIGNED_BYTE, tex->GetPixels(), true) || + if (!m_vram_write_replacement_texture.Create(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, + GPUTexture::Format::RGBA8) || !m_vram_write_replacement_texture.CreateFramebuffer()) { m_vram_write_replacement_texture.Destroy(); @@ -795,7 +789,6 @@ bool GPU_HW_OpenGL::BlitVRAMReplacementTexture(const TextureReplacementTexture* glDisable(GL_SCISSOR_TEST); m_vram_write_replacement_texture.BindFramebuffer(GL_READ_FRAMEBUFFER); - dst_y = m_vram_texture.GetHeight() - dst_y - height; glBlitFramebuffer(0, tex->GetHeight(), tex->GetWidth(), 0, dst_x, dst_y, dst_x + width, dst_y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); @@ -826,7 +819,7 @@ void GPU_HW_OpenGL::SetScissorFromDrawingArea() const int width = right - left; const int height = bottom - top; const int x = left; - const int y = m_vram_texture.GetHeight() - bottom; + const int y = top; Log_DebugPrintf("SetScissor: (%d-%d, %d-%d)", x, x + width, y, y + height); glScissor(x, y, width, height); @@ -867,16 +860,13 @@ void GPU_HW_OpenGL::UpdateDisplay() { UpdateVRAMReadTexture(); - g_host_display->SetDisplayTexture( - &m_vram_read_texture, HostDisplayPixelFormat::RGBA8, m_vram_read_texture.GetWidth(), - static_cast(m_vram_read_texture.GetHeight()), 0, m_vram_read_texture.GetHeight(), - m_vram_read_texture.GetWidth(), -static_cast(m_vram_read_texture.GetHeight())); + g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, m_vram_read_texture.GetHeight(), + m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); } else { - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - static_cast(m_vram_texture.GetHeight()), 0, m_vram_texture.GetHeight(), - m_vram_texture.GetWidth(), -static_cast(m_vram_texture.GetHeight())); + g_host_display->SetDisplayTexture(&m_vram_texture, 0, m_vram_texture.GetHeight(), m_vram_texture.GetWidth(), + m_vram_texture.GetHeight()); } g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, static_cast(VRAM_WIDTH) / static_cast(VRAM_HEIGHT)); @@ -914,10 +904,8 @@ void GPU_HW_OpenGL::UpdateDisplay() } else { - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), scaled_vram_offset_x, - m_vram_texture.GetHeight() - scaled_vram_offset_y, scaled_display_width, - -static_cast(scaled_display_height)); + g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y, + scaled_display_width, scaled_display_height); } } else @@ -936,14 +924,11 @@ void GPU_HW_OpenGL::UpdateDisplay() glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast(attachments.size()), attachments.data()); } - const u8 height_div2 = BoolToUInt8(interlaced == GPU_HW::InterlacedRenderMode::SeparateFields); const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0; - const u32 scaled_flipped_vram_offset_y = m_vram_texture.GetHeight() - scaled_vram_offset_y - - reinterpret_field_offset - (scaled_display_height >> height_div2); const u32 reinterpret_start_x = m_crtc_state.regs.X * resolution_scale; const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * resolution_scale; - const u32 uniforms[4] = {reinterpret_start_x, scaled_flipped_vram_offset_y, reinterpret_crop_left, - reinterpret_field_offset}; + const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset, + reinterpret_crop_left, reinterpret_field_offset}; UploadUniformBuffer(uniforms, sizeof(uniforms)); m_batch_ubo_dirty = true; @@ -960,10 +945,7 @@ void GPU_HW_OpenGL::UpdateDisplay() } else { - g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, - m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, - scaled_display_height, scaled_display_width, - -static_cast(scaled_display_height)); + g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height); } // restore state @@ -993,8 +975,7 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height) const u32 encoded_height = copy_rect.GetHeight(); // Encode the 24-bit texture as 16-bit. - const u32 uniforms[4] = {copy_rect.left, VRAM_HEIGHT - copy_rect.top - copy_rect.GetHeight(), copy_rect.GetWidth(), - copy_rect.GetHeight()}; + const u32 uniforms[4] = {copy_rect.left, copy_rect.top, copy_rect.GetWidth(), copy_rect.GetHeight()}; m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.Bind(); m_vram_read_program.Bind(); @@ -1024,9 +1005,8 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) GPU_HW::FillVRAM(x, y, width, height, color); const Common::Rectangle bounds(GetVRAMTransferBounds(x, y, width, height)); - glScissor(bounds.left * m_resolution_scale, - m_vram_texture.GetHeight() - (bounds.top * m_resolution_scale) - (height * m_resolution_scale), - width * m_resolution_scale, height * m_resolution_scale); + glScissor(bounds.left * m_resolution_scale, bounds.top * m_resolution_scale, width * m_resolution_scale, + height * m_resolution_scale); // fast path when not using interlaced rendering const bool wrapped = IsVRAMFillOversized(x, y, width, height); @@ -1096,9 +1076,7 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* // the viewport should already be set to the full vram, so just adjust the scissor const Common::Rectangle scaled_bounds = bounds * m_resolution_scale; - glScissor(scaled_bounds.left, m_vram_texture.GetHeight() - scaled_bounds.top - scaled_bounds.GetHeight(), - scaled_bounds.GetWidth(), scaled_bounds.GetHeight()); - + glScissor(scaled_bounds.left, scaled_bounds.top, scaled_bounds.GetWidth(), scaled_bounds.GetHeight()); glBindVertexArray(m_attributeless_vao_id); glDrawArrays(GL_TRIANGLES, 0, 3); @@ -1120,9 +1098,8 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* const auto map_result = m_texture_stream_buffer->Map(sizeof(u32), num_pixels * sizeof(u32)); - // reverse copy the rows so it matches opengl's lower-left origin const u32 source_stride = width * sizeof(u16); - const u8* source_ptr = static_cast(data) + (source_stride * (height - 1)); + const u8* source_ptr = static_cast(data); const u16 mask_or = set_mask ? 0x8000 : 0x0000; u32* dest_ptr = static_cast(map_result.pointer); for (u32 row = 0; row < height; row++) @@ -1137,7 +1114,7 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* *(dest_ptr++) = VRAMRGBA5551ToRGBA8888(src_col | mask_or); } - source_ptr -= source_stride; + source_ptr += source_stride; } m_texture_stream_buffer->Unmap(num_pixels * sizeof(u32)); @@ -1149,11 +1126,8 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* else m_vram_texture.Bind(); - // lower-left origin flip happens here - const u32 flipped_y = VRAM_HEIGHT - y - height; - // update texture data - glTexSubImage2D(m_vram_texture.GetGLTarget(), 0, x, flipped_y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, + glTexSubImage2D(m_vram_texture.GetGLTarget(), 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast(static_cast(map_result.buffer_offset))); m_texture_stream_buffer->Unbind(); @@ -1164,11 +1138,10 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* const u32 scaled_height = height * m_resolution_scale; const u32 scaled_x = x * m_resolution_scale; const u32 scaled_y = y * m_resolution_scale; - const u32 scaled_flipped_y = m_vram_texture.GetHeight() - scaled_y - scaled_height; glDisable(GL_SCISSOR_TEST); m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER); - glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y, - scaled_x + scaled_width, scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(x, y, x + width, y + height, scaled_x, scaled_y, scaled_x + scaled_width, + scaled_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glEnable(GL_SCISSOR_TEST); } } @@ -1189,9 +1162,7 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid UpdateVRAMReadTexture(); IncludeVRAMDirtyRectangle(dst_bounds); - VRAMCopyUBOData uniforms = GetVRAMCopyUBOData(src_x, src_y, dst_x, dst_y, width, height); - uniforms.u_src_y = m_vram_texture.GetHeight() - uniforms.u_src_y - uniforms.u_height; - uniforms.u_dst_y = m_vram_texture.GetHeight() - uniforms.u_dst_y - uniforms.u_height; + const VRAMCopyUBOData uniforms = GetVRAMCopyUBOData(src_x, src_y, dst_x, dst_y, width, height); UploadUniformBuffer(&uniforms, sizeof(uniforms)); glDisable(GL_SCISSOR_TEST); @@ -1199,9 +1170,8 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid SetDepthFunc((m_GPUSTAT.check_mask_before_draw && !m_pgxp_depth_buffer) ? GL_GEQUAL : GL_ALWAYS); const Common::Rectangle dst_bounds_scaled(dst_bounds * m_resolution_scale); - glViewport(dst_bounds_scaled.left, - m_vram_texture.GetHeight() - dst_bounds_scaled.top - dst_bounds_scaled.GetHeight(), - dst_bounds_scaled.GetWidth(), dst_bounds_scaled.GetHeight()); + glViewport(dst_bounds_scaled.left, dst_bounds_scaled.top, dst_bounds_scaled.GetWidth(), + dst_bounds_scaled.GetHeight()); m_vram_read_texture.Bind(); m_vram_copy_program.Bind(); glBindVertexArray(m_attributeless_vao_id); @@ -1224,10 +1194,6 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid width *= m_resolution_scale; height *= m_resolution_scale; - // lower-left origin flip - src_y = m_vram_texture.GetHeight() - src_y - height; - dst_y = m_vram_texture.GetHeight() - dst_y - height; - if (GLAD_GL_VERSION_4_3) { glCopyImageSubData(m_vram_texture.GetGLId(), m_vram_texture.GetGLTarget(), 0, src_x, src_y, 0, @@ -1266,7 +1232,7 @@ void GPU_HW_OpenGL::UpdateVRAMReadTexture() const u32 width = scaled_rect.GetWidth(); const u32 height = scaled_rect.GetHeight(); const u32 x = scaled_rect.left; - const u32 y = m_vram_texture.GetHeight() - scaled_rect.top - height; + const u32 y = scaled_rect.top; const bool multisampled = m_vram_texture.IsMultisampled(); if (!multisampled && GLAD_GL_VERSION_4_3) @@ -1344,7 +1310,7 @@ void GPU_HW_OpenGL::DownsampleFramebufferBoxFilter(GL::Texture& source, u32 left glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glViewport(ds_left, m_downsample_texture.GetHeight() - ds_top - ds_height, ds_width, ds_height); + glViewport(ds_left, ds_top, ds_width, ds_height); glBindVertexArray(m_attributeless_vao_id); source.Bind(); m_downsample_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); @@ -1353,9 +1319,7 @@ void GPU_HW_OpenGL::DownsampleFramebufferBoxFilter(GL::Texture& source, u32 left RestoreGraphicsAPIState(); - g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, - m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, - m_downsample_texture.GetHeight() - ds_top, ds_width, -static_cast(ds_height)); + g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height); } std::unique_ptr GPU::CreateHardwareOpenGLRenderer() diff --git a/src/core/gpu_hw_opengl.h b/src/core/gpu_hw_opengl.h index e50829370..8bb33aeda 100644 --- a/src/core/gpu_hw_opengl.h +++ b/src/core/gpu_hw_opengl.h @@ -20,7 +20,7 @@ public: bool Initialize() override; void Reset(bool clear_vram) override; - bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; + bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override; void ResetGraphicsAPIState() override; void RestoreGraphicsAPIState() override; @@ -55,8 +55,6 @@ private: ALWAYS_INLINE bool IsGLES() const { return (m_render_api == RenderAPI::OpenGLES); } - std::tuple ConvertToFramebufferCoordinates(s32 x, s32 y); - void SetCapabilities(); bool CreateFramebuffer(); void ClearFramebuffer(); diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index 7f5ad4ce9..8ced70087 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -25,25 +25,6 @@ void GPU_HW_ShaderGen::WriteCommonFunctions(std::stringstream& ss) ss << "CONSTANT uint MULTISAMPLES = " << m_multisamples << "u;\n"; ss << "CONSTANT bool PER_SAMPLE_SHADING = " << (m_per_sample_shading ? "true" : "false") << ";\n"; ss << R"( - -float fixYCoord(float y) -{ -#if API_OPENGL || API_OPENGL_ES - return 1.0 - RCP_VRAM_SIZE.y - y; -#else - return y; -#endif -} - -uint fixYCoord(uint y) -{ -#if API_OPENGL || API_OPENGL_ES - return VRAM_SIZE.y - y - 1u; -#else - return y; -#endif -} - uint RGBA8ToRGBA5551(float4 v) { uint r = uint(roundEven(v.r * 31.0)); @@ -85,23 +66,6 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured) WriteCommonFunctions(ss); WriteBatchUniformBuffer(ss); - ss << R"( - -// OpenGL seems to be off by one pixel in the Y direction due to lower-left origin, but only on -// Intel and NVIDIA drivers. AMD is fine. V3D requires coordinates to be slightly offset even further. -#if API_OPENGL || API_OPENGL_ES - #ifdef DRIVER_V3D - CONSTANT float POS_EPSILON = 0.0001; - #else - #ifdef DRIVER_POWERVR - CONSTANT float POS_EPSILON = 0.001; - #else - CONSTANT float POS_EPSILON = 0.00001; - #endif - #endif -#endif -)"; - if (textured) { if (m_uv_limits) @@ -145,14 +109,12 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured) #endif #if API_OPENGL || API_OPENGL_ES - pos_y += POS_EPSILON; - // 0..1 to -1..1 depth range. pos_z = (pos_z * 2.0) - 1.0; #endif // NDC space Y flip in Vulkan. -#if API_VULKAN +#if API_OPENGL || API_OPENGL_ES || API_VULKAN pos_y = -pos_y; #endif @@ -767,7 +729,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) #endif // fixup coords - uint2 vicoord = uint2(texpage.x + index_coord.x * RESOLUTION_SCALE, fixYCoord(texpage.y + index_coord.y * RESOLUTION_SCALE)); + uint2 vicoord = texpage.xy + (index_coord * uint2(RESOLUTION_SCALE, RESOLUTION_SCALE)); // load colour/palette float4 texel = SAMPLE_TEXTURE(samp0, float2(vicoord) * RCP_VRAM_SIZE); @@ -783,12 +745,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) #endif // sample palette - uint2 palette_icoord = uint2(texpage.z + (palette_index * RESOLUTION_SCALE), fixYCoord(texpage.w)); + uint2 palette_icoord = uint2(texpage.z + (palette_index * RESOLUTION_SCALE), texpage.w); return SAMPLE_TEXTURE(samp0, float2(palette_icoord) * RCP_VRAM_SIZE); #else // Direct texturing. Render-to-texture effects. Use upscaled coordinates. uint2 icoord = ApplyUpscaledTextureWindow(FloatToIntegerCoords(coords)); - uint2 direct_icoord = uint2(texpage.x + icoord.x, fixYCoord(texpage.y + icoord.y)); + uint2 direct_icoord = texpage.xy + icoord; return SAMPLE_TEXTURE(samp0, float2(direct_icoord) * RCP_VRAM_SIZE); #endif } @@ -831,7 +793,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) float oalpha; #if INTERLACING - if ((fixYCoord(uint(v_pos.y)) & 1u) == u_interlaced_displayed_field) + if ((uint(v_pos.y) & 1u) == u_interlaced_displayed_field) discard; #endif @@ -1097,7 +1059,7 @@ float3 SampleVRAM24Smoothed(uint2 icoords) uint2 icoords = uint2(v_pos.xy) + uint2(u_crop_left, 0u); #if INTERLACED - if ((fixYCoord(icoords.y) & 1u) != u_field_offset) + if ((icoords.y & 1u) != u_field_offset) discard; #if !INTERLEAVED @@ -1167,13 +1129,6 @@ uint SampleVRAM(uint2 coords) ss << R"( { uint2 sample_coords = uint2(uint(v_pos.x) * 2u, uint(v_pos.y)); - - #if API_OPENGL || API_OPENGL_ES - // Lower-left origin flip for OpenGL. - // We want to write the image out upside-down so we can read it top-to-bottom. - sample_coords.y = u_size.y - sample_coords.y - 1u; - #endif - sample_coords += u_base_coords; // We're encoding as 32-bit, so the output width is halved and we pack two 16-bit pixels in one 32-bit pixel. @@ -1222,7 +1177,7 @@ std::string GPU_HW_ShaderGen::GenerateVRAMWriteFragmentShader(bool use_ssbo) DeclareFragmentEntryPoint(ss, 0, 1, {}, true, 1, true); ss << R"( { - uint2 coords = uint2(uint(v_pos.x) / RESOLUTION_SCALE, fixYCoord(uint(v_pos.y)) / RESOLUTION_SCALE); + uint2 coords = uint2(v_pos.xy) / uint2(RESOLUTION_SCALE, RESOLUTION_SCALE); // make sure it's not oversized and out of range if ((coords.x < u_base_coords.x && coords.x >= u_end_coords.x) || @@ -1320,7 +1275,7 @@ std::string GPU_HW_ShaderGen::GenerateVRAMFillFragmentShader(bool wrapped, bool ss << R"( { #if INTERLACED || WRAPPED - uint2 dst_coords = uint2(uint(v_pos.x), fixYCoord(uint(v_pos.y))); + uint2 dst_coords = uint2(v_pos.xy); #endif #if INTERLACED diff --git a/src/core/gpu_hw_vulkan.cpp b/src/core/gpu_hw_vulkan.cpp index 6d8baf8e7..02bdaaa3e 100644 --- a/src/core/gpu_hw_vulkan.cpp +++ b/src/core/gpu_hw_vulkan.cpp @@ -102,7 +102,7 @@ void GPU_HW_Vulkan::Reset(bool clear_vram) ClearFramebuffer(); } -bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) +bool GPU_HW_Vulkan::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) { if (host_texture) { @@ -119,7 +119,7 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, if (sw.IsReading()) { - Vulkan::Texture* tex = static_cast((*host_texture)->GetHandle()); + Vulkan::Texture* tex = static_cast(*host_texture); if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || tex->GetSamples() != m_vram_texture.GetSamples()) { @@ -137,22 +137,22 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, } else { - HostDisplayTexture* htex = *host_texture; - if (!htex || htex->GetWidth() != m_vram_texture.GetWidth() || htex->GetHeight() != m_vram_texture.GetHeight() || - htex->GetSamples() != static_cast(m_vram_texture.GetSamples())) + Vulkan::Texture* tex = static_cast(*host_texture); + if (!tex || tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || + tex->GetSamples() != static_cast(m_vram_texture.GetSamples())) { - delete htex; + delete tex; - htex = g_host_display - ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, - m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) - .release(); - *host_texture = htex; - if (!htex) + tex = static_cast(g_host_display + ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, + 1, m_vram_texture.GetSamples(), GPUTexture::Format::RGBA8, + nullptr, 0, false) + .release()); + *host_texture = tex; + if (!tex) return false; } - Vulkan::Texture* tex = static_cast(htex->GetHandle()); if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || tex->GetSamples() != m_vram_texture.GetSamples()) { @@ -612,13 +612,13 @@ bool GPU_HW_Vulkan::CreateFramebuffer() m_vram_update_depth_render_pass = g_vulkan_context->GetRenderPass(VK_FORMAT_UNDEFINED, depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE); m_display_load_render_pass = g_vulkan_context->GetRenderPass( - m_display_texture.GetFormat(), VK_FORMAT_UNDEFINED, m_display_texture.GetSamples(), VK_ATTACHMENT_LOAD_OP_LOAD); + m_display_texture.GetVkFormat(), VK_FORMAT_UNDEFINED, m_display_texture.GetVkSamples(), VK_ATTACHMENT_LOAD_OP_LOAD); m_display_discard_render_pass = - g_vulkan_context->GetRenderPass(m_display_texture.GetFormat(), VK_FORMAT_UNDEFINED, m_display_texture.GetSamples(), - VK_ATTACHMENT_LOAD_OP_DONT_CARE); + g_vulkan_context->GetRenderPass(m_display_texture.GetVkFormat(), VK_FORMAT_UNDEFINED, + m_display_texture.GetVkSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); m_vram_readback_render_pass = - g_vulkan_context->GetRenderPass(m_vram_readback_texture.GetFormat(), VK_FORMAT_UNDEFINED, - m_vram_readback_texture.GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); + g_vulkan_context->GetRenderPass(m_vram_readback_texture.GetVkFormat(), VK_FORMAT_UNDEFINED, + m_vram_readback_texture.GetVkSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); if (m_vram_render_pass == VK_NULL_HANDLE || m_vram_update_depth_render_pass == VK_NULL_HANDLE || m_display_load_render_pass == VK_NULL_HANDLE || m_vram_readback_render_pass == VK_NULL_HANDLE) @@ -704,10 +704,11 @@ bool GPU_HW_Vulkan::CreateFramebuffer() m_downsample_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_downsample_render_pass = g_vulkan_context->GetRenderPass(m_downsample_texture.GetFormat(), VK_FORMAT_UNDEFINED, + m_downsample_render_pass = g_vulkan_context->GetRenderPass(m_downsample_texture.GetVkFormat(), VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR); - m_downsample_weight_render_pass = g_vulkan_context->GetRenderPass( - m_downsample_weight_texture.GetFormat(), VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR); + m_downsample_weight_render_pass = + g_vulkan_context->GetRenderPass(m_downsample_weight_texture.GetVkFormat(), VK_FORMAT_UNDEFINED, + VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR); if (m_downsample_render_pass == VK_NULL_HANDLE || m_downsample_weight_render_pass == VK_NULL_HANDLE) return false; @@ -725,7 +726,7 @@ bool GPU_HW_Vulkan::CreateFramebuffer() 0, m_downsample_texture.GetImage(), VK_IMAGE_VIEW_TYPE_2D, - m_downsample_texture.GetFormat(), + m_downsample_texture.GetVkFormat(), {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, {VK_IMAGE_ASPECT_COLOR_BIT, i, 1u, 0u, 1u}}; @@ -776,7 +777,7 @@ bool GPU_HW_Vulkan::CreateFramebuffer() return false; } - m_downsample_render_pass = g_vulkan_context->GetRenderPass(m_downsample_texture.GetFormat(), VK_FORMAT_UNDEFINED, + m_downsample_render_pass = g_vulkan_context->GetRenderPass(m_downsample_texture.GetVkFormat(), VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR); m_downsample_mip_views.resize(1); @@ -1433,15 +1434,12 @@ void GPU_HW_Vulkan::UpdateDisplay() UpdateVRAMReadTexture(); } - g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, - m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, - m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); + g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, 0, m_vram_read_texture.GetWidth(), + m_vram_read_texture.GetHeight()); } else { - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight()); + g_host_display->SetDisplayTexture(&m_vram_texture, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); } g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, static_cast(VRAM_WIDTH) / static_cast(VRAM_HEIGHT)); @@ -1479,8 +1477,7 @@ void GPU_HW_Vulkan::UpdateDisplay() } else { - g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), - m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y, + g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y, scaled_display_width, scaled_display_height); } } @@ -1526,9 +1523,7 @@ void GPU_HW_Vulkan::UpdateDisplay() } else { - g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, - m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0, - scaled_display_width, scaled_display_height); + g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height); RestoreGraphicsAPIState(); } } @@ -1577,8 +1572,8 @@ void GPU_HW_Vulkan::ReadVRAM(u32 x, u32 y, u32 width, u32 height) m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // Stage the readback and copy it into our shadow buffer (will execute command buffer and stall). - g_host_display->DownloadTexture(&m_vram_readback_texture, HostDisplayPixelFormat::RGBA8, 0, 0, encoded_width, - encoded_height, &m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left], + g_host_display->DownloadTexture(&m_vram_readback_texture, 0, 0, encoded_width, encoded_height, + &m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left], VRAM_WIDTH * sizeof(u16)); } @@ -1890,9 +1885,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferBoxFilter(Vulkan::Texture& source, u32 RestoreGraphicsAPIState(); - g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, - m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top, - ds_width, ds_height); + g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height); } void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 left, u32 top, u32 width, u32 height) @@ -1989,8 +1982,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l } RestoreGraphicsAPIState(); - g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), - m_display_texture.GetHeight(), left, top, width, height); + g_host_display->SetDisplayTexture(&m_display_texture, left, top, width, height); } std::unique_ptr GPU::CreateHardwareVulkanRenderer() diff --git a/src/core/gpu_hw_vulkan.h b/src/core/gpu_hw_vulkan.h index 2d291d9c8..95fe3fad5 100644 --- a/src/core/gpu_hw_vulkan.h +++ b/src/core/gpu_hw_vulkan.h @@ -18,7 +18,7 @@ public: bool Initialize() override; void Reset(bool clear_vram) override; - bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; + bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override; void ResetGraphicsAPIState() override; void RestoreGraphicsAPIState() override; diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp index f4c23057e..edf6c69c3 100644 --- a/src/core/gpu_sw.cpp +++ b/src/core/gpu_sw.cpp @@ -59,22 +59,22 @@ bool GPU_SW::Initialize() if (!GPU::Initialize() || !m_backend.Initialize(false)) return false; - static constexpr auto formats_for_16bit = make_array(HostDisplayPixelFormat::RGB565, HostDisplayPixelFormat::RGBA5551, - HostDisplayPixelFormat::RGBA8, HostDisplayPixelFormat::BGRA8); + static constexpr auto formats_for_16bit = make_array(GPUTexture::Format::RGB565, GPUTexture::Format::RGBA5551, + GPUTexture::Format::RGBA8, GPUTexture::Format::BGRA8); static constexpr auto formats_for_24bit = - make_array(HostDisplayPixelFormat::RGBA8, HostDisplayPixelFormat::BGRA8, HostDisplayPixelFormat::RGB565, - HostDisplayPixelFormat::RGBA5551); - for (const HostDisplayPixelFormat format : formats_for_16bit) + make_array(GPUTexture::Format::RGBA8, GPUTexture::Format::BGRA8, GPUTexture::Format::RGB565, + GPUTexture::Format::RGBA5551); + for (const GPUTexture::Format format : formats_for_16bit) { - if (g_host_display->SupportsDisplayPixelFormat(format)) + if (g_host_display->SupportsTextureFormat(format)) { m_16bit_display_format = format; break; } } - for (const HostDisplayPixelFormat format : formats_for_24bit) + for (const GPUTexture::Format format : formats_for_24bit) { - if (g_host_display->SupportsDisplayPixelFormat(format)) + if (g_host_display->SupportsTextureFormat(format)) { m_24bit_display_format = format; break; @@ -84,7 +84,7 @@ bool GPU_SW::Initialize() return true; } -bool GPU_SW::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) +bool GPU_SW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) { // ignore the host texture for software mode, since we want to save vram here return GPU::DoState(sw, nullptr, update_display); @@ -103,7 +103,7 @@ void GPU_SW::UpdateSettings() m_backend.UpdateSettings(); } -HostDisplayTexture* GPU_SW::GetDisplayTexture(u32 width, u32 height, HostDisplayPixelFormat format) +GPUTexture* GPU_SW::GetDisplayTexture(u32 width, u32 height, GPUTexture::Format format) { if (!m_display_texture || m_display_texture->GetWidth() != width || m_display_texture->GetHeight() != height || m_display_texture->GetFormat() != format) @@ -118,32 +118,32 @@ HostDisplayTexture* GPU_SW::GetDisplayTexture(u32 width, u32 height, HostDisplay return m_display_texture.get(); } -template +template static void CopyOutRow16(const u16* src_ptr, out_type* dst_ptr, u32 width); -template +template static out_type VRAM16ToOutput(u16 value); template<> -ALWAYS_INLINE u16 VRAM16ToOutput(u16 value) +ALWAYS_INLINE u16 VRAM16ToOutput(u16 value) { return (value & 0x3E0) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 10); } template<> -ALWAYS_INLINE u16 VRAM16ToOutput(u16 value) +ALWAYS_INLINE u16 VRAM16ToOutput(u16 value) { return ((value & 0x3E0) << 1) | ((value & 0x20) << 1) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 11); } template<> -ALWAYS_INLINE u32 VRAM16ToOutput(u16 value) +ALWAYS_INLINE u32 VRAM16ToOutput(u16 value) { return VRAMRGBA5551ToRGBA8888(value); } template<> -ALWAYS_INLINE u32 VRAM16ToOutput(u16 value) +ALWAYS_INLINE u32 VRAM16ToOutput(u16 value) { const u32 value32 = ZeroExtend32(value); const u32 r = VRAMConvert5To8(value32 & 31u); @@ -153,7 +153,7 @@ ALWAYS_INLINE u32 VRAM16ToOutput(u16 value) } template<> -ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u16* dst_ptr, u32 width) +ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u16* dst_ptr, u32 width) { u32 col = 0; @@ -188,11 +188,11 @@ ALWAYS_INLINE void CopyOutRow16(const u16 #endif for (; col < width; col++) - *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); + *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); } template<> -ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u16* dst_ptr, u32 width) +ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u16* dst_ptr, u32 width) { u32 col = 0; @@ -229,39 +229,39 @@ ALWAYS_INLINE void CopyOutRow16(const u16* #endif for (; col < width; col++) - *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); + *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); } template<> -ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u32* dst_ptr, u32 width) +ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u32* dst_ptr, u32 width) { for (u32 col = 0; col < width; col++) - *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); + *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); } template<> -ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u32* dst_ptr, u32 width) +ALWAYS_INLINE void CopyOutRow16(const u16* src_ptr, u32* dst_ptr, u32 width) { for (u32 col = 0; col < width; col++) - *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); + *(dst_ptr++) = VRAM16ToOutput(*(src_ptr++)); } -template +template void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved) { u8* dst_ptr; u32 dst_stride; using OutputPixelType = std::conditional_t< - display_format == HostDisplayPixelFormat::RGBA8 || display_format == HostDisplayPixelFormat::BGRA8, u32, u16>; + display_format == GPUTexture::Format::RGBA8 || display_format == GPUTexture::Format::BGRA8, u32, u16>; - HostDisplayTexture* texture = GetDisplayTexture(width, height, display_format); + GPUTexture* texture = GetDisplayTexture(width, height, display_format); if (!texture) return; if (!interlaced) { - if (!texture->BeginUpdate(width, height, reinterpret_cast(&dst_ptr), &dst_stride)) + if (!g_host_display->BeginTextureUpdate(texture, width, height, reinterpret_cast(&dst_ptr), &dst_stride)) return; } else @@ -309,36 +309,36 @@ void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field } if (!interlaced) - texture->EndUpdate(0, 0, width, height); + g_host_display->EndTextureUpdate(texture, 0, 0, width, height); else - texture->Update(0, 0, width, height, m_display_texture_buffer.data(), output_stride); + g_host_display->UpdateTexture(texture, 0, 0, width, height, m_display_texture_buffer.data(), output_stride); - g_host_display->SetDisplayTexture(texture->GetHandle(), display_format, width, height, 0, 0, width, height); + g_host_display->SetDisplayTexture(texture, 0, 0, width, height); } -void GPU_SW::CopyOut15Bit(HostDisplayPixelFormat display_format, u32 src_x, u32 src_y, u32 width, u32 height, u32 field, +void GPU_SW::CopyOut15Bit(GPUTexture::Format display_format, u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved) { switch (display_format) { - case HostDisplayPixelFormat::RGBA5551: - CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); + case GPUTexture::Format::RGBA5551: + CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); break; - case HostDisplayPixelFormat::RGB565: - CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); + case GPUTexture::Format::RGB565: + CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); break; - case HostDisplayPixelFormat::RGBA8: - CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); + case GPUTexture::Format::RGBA8: + CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); break; - case HostDisplayPixelFormat::BGRA8: - CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); + case GPUTexture::Format::BGRA8: + CopyOut15Bit(src_x, src_y, width, height, field, interlaced, interleaved); break; default: break; } } -template +template void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced, bool interleaved) { @@ -346,15 +346,15 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh u32 dst_stride; using OutputPixelType = std::conditional_t< - display_format == HostDisplayPixelFormat::RGBA8 || display_format == HostDisplayPixelFormat::BGRA8, u32, u16>; + display_format == GPUTexture::Format::RGBA8 || display_format == GPUTexture::Format::BGRA8, u32, u16>; - HostDisplayTexture* texture = GetDisplayTexture(width, height, display_format); + GPUTexture* texture = GetDisplayTexture(width, height, display_format); if (!texture) return; if (!interlaced) { - if (!texture->BeginUpdate(width, height, reinterpret_cast(&dst_ptr), &dst_stride)) + if (!g_host_display->BeginTextureUpdate(texture, width, height, reinterpret_cast(&dst_ptr), &dst_stride)) return; } else @@ -375,7 +375,7 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh const u32 src_stride = (VRAM_WIDTH << interleaved_shift) * sizeof(u16); for (u32 row = 0; row < rows; row++) { - if constexpr (display_format == HostDisplayPixelFormat::RGBA8) + if constexpr (display_format == GPUTexture::Format::RGBA8) { const u8* src_row_ptr = src_ptr; u8* dst_row_ptr = reinterpret_cast(dst_ptr); @@ -387,7 +387,7 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh *(dst_row_ptr++) = 0xFF; } } - else if constexpr (display_format == HostDisplayPixelFormat::BGRA8) + else if constexpr (display_format == GPUTexture::Format::BGRA8) { const u8* src_row_ptr = src_ptr; u8* dst_row_ptr = reinterpret_cast(dst_ptr); @@ -400,7 +400,7 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh src_row_ptr += 3; } } - else if constexpr (display_format == HostDisplayPixelFormat::RGB565) + else if constexpr (display_format == GPUTexture::Format::RGB565) { const u8* src_row_ptr = src_ptr; u16* dst_row_ptr = reinterpret_cast(dst_ptr); @@ -411,7 +411,7 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh src_row_ptr += 3; } } - else if constexpr (display_format == HostDisplayPixelFormat::RGBA5551) + else if constexpr (display_format == GPUTexture::Format::RGBA5551) { const u8* src_row_ptr = src_ptr; u16* dst_row_ptr = reinterpret_cast(dst_ptr); @@ -442,19 +442,19 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh const u8 shift = static_cast(col & 1u) * 8; const u32 rgb = (((ZeroExtend32(s1) << 16) | ZeroExtend32(s0)) >> shift); - if constexpr (display_format == HostDisplayPixelFormat::RGBA8) + if constexpr (display_format == GPUTexture::Format::RGBA8) { *(dst_row_ptr++) = rgb | 0xFF000000u; } - else if constexpr (display_format == HostDisplayPixelFormat::BGRA8) + else if constexpr (display_format == GPUTexture::Format::BGRA8) { *(dst_row_ptr++) = (rgb & 0x00FF00) | ((rgb & 0xFF) << 16) | ((rgb >> 16) & 0xFF) | 0xFF000000u; } - else if constexpr (display_format == HostDisplayPixelFormat::RGB565) + else if constexpr (display_format == GPUTexture::Format::RGB565) { *(dst_row_ptr++) = ((rgb >> 3) & 0x1F) | (((rgb >> 10) << 5) & 0x7E0) | (((rgb >> 19) << 11) & 0x3E0000); } - else if constexpr (display_format == HostDisplayPixelFormat::RGBA5551) + else if constexpr (display_format == GPUTexture::Format::RGBA5551) { *(dst_row_ptr++) = ((rgb >> 3) & 0x1F) | (((rgb >> 11) << 5) & 0x3E0) | (((rgb >> 19) << 10) & 0x1F0000); } @@ -466,30 +466,30 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh } if (!interlaced) - texture->EndUpdate(0, 0, width, height); + g_host_display->EndTextureUpdate(texture, 0, 0, width, height); else - texture->Update(0, 0, width, height, m_display_texture_buffer.data(), output_stride); + g_host_display->UpdateTexture(texture, 0, 0, width, height, m_display_texture_buffer.data(), output_stride); - g_host_display->SetDisplayTexture(texture->GetHandle(), display_format, width, height, 0, 0, width, height); + g_host_display->SetDisplayTexture(texture, 0, 0, width, height); } -void GPU_SW::CopyOut24Bit(HostDisplayPixelFormat display_format, u32 src_x, u32 src_y, u32 skip_x, u32 width, +void GPU_SW::CopyOut24Bit(GPUTexture::Format display_format, u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced, bool interleaved) { switch (display_format) { - case HostDisplayPixelFormat::RGBA5551: - CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, + case GPUTexture::Format::RGBA5551: + CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); break; - case HostDisplayPixelFormat::RGB565: - CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); + case GPUTexture::Format::RGB565: + CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); break; - case HostDisplayPixelFormat::RGBA8: - CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); + case GPUTexture::Format::RGBA8: + CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); break; - case HostDisplayPixelFormat::BGRA8: - CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); + case GPUTexture::Format::BGRA8: + CopyOut24Bit(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); break; default: break; diff --git a/src/core/gpu_sw.h b/src/core/gpu_sw.h index c33d1d8d2..0186f3f6d 100644 --- a/src/core/gpu_sw.h +++ b/src/core/gpu_sw.h @@ -12,7 +12,7 @@ namespace Threading class Thread; } -class HostDisplayTexture; +class GPUTexture; class GPU_SW final : public GPU { @@ -26,7 +26,7 @@ public: const Threading::Thread* GetSWThread() const override; bool Initialize() override; - bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; + bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override; void Reset(bool clear_vram) override; void UpdateSettings() override; @@ -36,15 +36,15 @@ protected: void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask) override; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; - template + template void CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved); - void CopyOut15Bit(HostDisplayPixelFormat display_format, u32 src_x, u32 src_y, u32 width, u32 height, u32 field, + void CopyOut15Bit(GPUTexture::Format display_format, u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved); - template + template void CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced, bool interleaved); - void CopyOut24Bit(HostDisplayPixelFormat display_format, u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, + void CopyOut24Bit(GPUTexture::Format display_format, u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced, bool interleaved); void ClearDisplay() override; @@ -55,12 +55,12 @@ protected: void FillBackendCommandParameters(GPUBackendCommand* cmd) const; void FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) const; - HostDisplayTexture* GetDisplayTexture(u32 width, u32 height, HostDisplayPixelFormat format); + GPUTexture* GetDisplayTexture(u32 width, u32 height, GPUTexture::Format format); HeapArray m_display_texture_buffer; - HostDisplayPixelFormat m_16bit_display_format = HostDisplayPixelFormat::RGB565; - HostDisplayPixelFormat m_24bit_display_format = HostDisplayPixelFormat::RGBA8; - std::unique_ptr m_display_texture; + GPUTexture::Format m_16bit_display_format = GPUTexture::Format::RGB565; + GPUTexture::Format m_24bit_display_format = GPUTexture::Format::RGBA8; + std::unique_ptr m_display_texture; GPU_SW_Backend m_backend; }; diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index 49bceda35..0dca4aded 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -18,27 +18,6 @@ Log_SetChannel(HostDisplay); std::unique_ptr g_host_display; -HostDisplayTexture::~HostDisplayTexture() = default; - -bool HostDisplayTexture::BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) /* = 0*/ -{ - return false; -} - -void HostDisplayTexture::EndUpdate(u32 x, u32 y, u32 width, u32 height) /* = 0*/ {} - -bool HostDisplayTexture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) -{ - void* map_ptr; - u32 map_pitch; - if (!BeginUpdate(width, height, &map_ptr, &map_pitch)) - return false; - - StringUtil::StrideMemCpy(map_ptr, map_pitch, data, pitch, std::min(pitch, map_pitch), height); - EndUpdate(x, y, width, height); - return true; -} - HostDisplay::~HostDisplay() = default; RenderAPI HostDisplay::GetPreferredAPI() @@ -50,6 +29,18 @@ RenderAPI HostDisplay::GetPreferredAPI() #endif } +bool HostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) +{ + void* map_ptr; + u32 map_pitch; + if (!BeginTextureUpdate(texture, width, height, &map_ptr, &map_pitch)) + return false; + + StringUtil::StrideMemCpy(map_ptr, map_pitch, data, pitch, std::min(pitch, map_pitch), height); + EndTextureUpdate(texture, x, y, width, height); + return true; +} + bool HostDisplay::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate) { if (!mode.empty()) @@ -126,23 +117,6 @@ bool HostDisplay::ShouldSkipDisplayingFrame() return false; } -u32 HostDisplay::GetDisplayPixelFormatSize(HostDisplayPixelFormat format) -{ - switch (format) - { - case HostDisplayPixelFormat::RGBA8: - case HostDisplayPixelFormat::BGRA8: - return 4; - - case HostDisplayPixelFormat::RGBA5551: - case HostDisplayPixelFormat::RGB565: - return 2; - - default: - return 0; - } -} - bool HostDisplay::GetHostRefreshRate(float* refresh_rate) { if (m_window_info.surface_refresh_rate > 0.0f) @@ -164,7 +138,7 @@ float HostDisplay::GetAndResetAccumulatedGPUTime() return 0.0f; } -void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, float scale /*= 1.0f*/) +void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, float scale /*= 1.0f*/) { m_cursor_texture = std::move(texture); m_cursor_texture_scale = scale; @@ -172,8 +146,8 @@ void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/) { - std::unique_ptr tex = - CreateTexture(width, height, 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixels, stride, false); + std::unique_ptr tex = + CreateTexture(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, pixels, stride, false); if (!tex) return false; @@ -198,8 +172,8 @@ bool HostDisplay::SetSoftwareCursor(const char* path, float scale /*= 1.0f*/) return false; } - std::unique_ptr tex = - CreateTexture(static_cast(width), static_cast(height), 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixel_data, + std::unique_ptr tex = + CreateTexture(static_cast(width), static_cast(height), 1, 1, 1, GPUTexture::Format::RGBA8, pixel_data, sizeof(u32) * static_cast(width), false); stbi_image_free(pixel_data); if (!tex) @@ -371,106 +345,10 @@ std::tuple HostDisplay::ConvertWindowCoordinatesToDisplayCoordinat return std::make_tuple(display_x, display_y); } -bool HostDisplay::ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector& texture_data, - u32& texture_data_stride, HostDisplayPixelFormat format) -{ - switch (format) - { - case HostDisplayPixelFormat::BGRA8: - { - for (u32 y = 0; y < height; y++) - { - u32* pixels = reinterpret_cast(reinterpret_cast(texture_data.data()) + (y * texture_data_stride)); - for (u32 x = 0; x < width; x++) - pixels[x] = (pixels[x] & 0xFF00FF00) | ((pixels[x] & 0xFF) << 16) | ((pixels[x] >> 16) & 0xFF); - } - - return true; - } - - case HostDisplayPixelFormat::RGBA8: - return true; - - case HostDisplayPixelFormat::RGB565: - { - std::vector temp(width * height); - - for (u32 y = 0; y < height; y++) - { - const u8* pixels_in = reinterpret_cast(texture_data.data()) + (y * texture_data_stride); - u32* pixels_out = &temp[y * width]; - - for (u32 x = 0; x < width; x++) - { - // RGB565 -> RGBA8 - u16 pixel_in; - std::memcpy(&pixel_in, pixels_in, sizeof(u16)); - pixels_in += sizeof(u16); - const u8 r5 = Truncate8(pixel_in >> 11); - const u8 g6 = Truncate8((pixel_in >> 5) & 0x3F); - const u8 b5 = Truncate8(pixel_in & 0x1F); - *(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 2) | (g6 & 3)) << 8) | - (ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (0xFF000000u); - } - } - - texture_data = std::move(temp); - texture_data_stride = sizeof(u32) * width; - return true; - } - - case HostDisplayPixelFormat::RGBA5551: - { - std::vector temp(width * height); - - for (u32 y = 0; y < height; y++) - { - const u8* pixels_in = reinterpret_cast(texture_data.data()) + (y * texture_data_stride); - u32* pixels_out = &temp[y * width]; - - for (u32 x = 0; x < width; x++) - { - // RGBA5551 -> RGBA8 - u16 pixel_in; - std::memcpy(&pixel_in, pixels_in, sizeof(u16)); - pixels_in += sizeof(u16); - const u8 a1 = Truncate8(pixel_in >> 15); - const u8 r5 = Truncate8((pixel_in >> 10) & 0x1F); - const u8 g6 = Truncate8((pixel_in >> 5) & 0x1F); - const u8 b5 = Truncate8(pixel_in & 0x1F); - *(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 3) | (g6 & 7)) << 8) | - (ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (a1 ? 0xFF000000u : 0u); - } - } - - texture_data = std::move(temp); - texture_data_stride = sizeof(u32) * width; - return true; - } - - default: - Log_ErrorPrintf("Unknown pixel format %u", static_cast(format)); - return false; - } -} - -void HostDisplay::FlipTextureDataRGBA8(u32 width, u32 height, std::vector& texture_data, u32 texture_data_stride) -{ - std::vector temp(width); - for (u32 flip_row = 0; flip_row < (height / 2); flip_row++) - { - u32* top_ptr = &texture_data[flip_row * width]; - u32* bottom_ptr = &texture_data[((height - 1) - flip_row) * width]; - std::memcpy(temp.data(), top_ptr, texture_data_stride); - std::memcpy(top_ptr, bottom_ptr, texture_data_stride); - std::memcpy(bottom_ptr, temp.data(), texture_data_stride); - } -} - static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string filename, FileSystem::ManagedCFilePtr fp, bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height, std::vector texture_data, u32 texture_data_stride, - HostDisplayPixelFormat texture_format) + GPUTexture::Format texture_format) { const char* extension = std::strrchr(filename.c_str(), '.'); @@ -480,7 +358,7 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil return false; } - if (!HostDisplay::ConvertTextureDataToRGBA8(width, height, texture_data, texture_data_stride, texture_format)) + if (!GPUTexture::ConvertTextureDataToRGBA8(width, height, texture_data, texture_data_stride, texture_format)) return false; if (clear_alpha) @@ -490,7 +368,7 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil } if (flip_y) - HostDisplay::FlipTextureDataRGBA8(width, height, texture_data, texture_data_stride); + GPUTexture::FlipTextureDataRGBA8(width, height, texture_data, texture_data_stride); if (resize_width > 0 && resize_height > 0 && (resize_width != width || resize_height != height)) { @@ -542,14 +420,14 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil return true; } -bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, - HostDisplayPixelFormat format, std::string filename, bool clear_alpha /* = true */, - bool flip_y /* = false */, u32 resize_width /* = 0 */, u32 resize_height /* = 0 */, +bool HostDisplay::WriteTextureToFile(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, std::string filename, + bool clear_alpha /* = true */, bool flip_y /* = false */, + u32 resize_width /* = 0 */, u32 resize_height /* = 0 */, bool compress_on_thread /* = false */) { std::vector texture_data(width * height); - u32 texture_data_stride = Common::AlignUpPow2(GetDisplayPixelFormatSize(format) * width, 4); - if (!DownloadTexture(texture_handle, format, x, y, width, height, texture_data.data(), texture_data_stride)) + u32 texture_data_stride = Common::AlignUpPow2(GPUTexture::GetPixelSize(texture->GetFormat()) * width, 4); + if (!DownloadTexture(texture, x, y, width, height, texture_data.data(), texture_data_stride)) { Log_ErrorPrintf("Texture download failed"); return false; @@ -566,12 +444,12 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u { return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data), texture_data_stride, - format); + texture->GetFormat()); } std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp), clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data), - texture_data_stride, format); + texture_data_stride, texture->GetFormat()); compress_thread.detach(); return true; } @@ -579,7 +457,7 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_resolution /* = true */, bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = false */) { - if (!m_display_texture_handle) + if (!m_display_texture) return false; s32 resize_width = 0; @@ -612,18 +490,19 @@ bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_reso if (flip_y) { read_height = -m_display_texture_view_height; - read_y = (m_display_texture_height - read_height) - (m_display_texture_height - m_display_texture_view_y); + read_y = + (m_display_texture->GetHeight() - read_height) - (m_display_texture->GetHeight() - m_display_texture_view_y); } - return WriteTextureToFile(m_display_texture_handle, m_display_texture_view_x, read_y, m_display_texture_view_width, - read_height, m_display_texture_format, std::move(filename), true, flip_y, - static_cast(resize_width), static_cast(resize_height), compress_on_thread); + return WriteTextureToFile(m_display_texture, m_display_texture_view_x, read_y, m_display_texture_view_width, + read_height, std::move(filename), true, flip_y, static_cast(resize_width), + static_cast(resize_height), compress_on_thread); } bool HostDisplay::WriteDisplayTextureToBuffer(std::vector* buffer, u32 resize_width /* = 0 */, u32 resize_height /* = 0 */, bool clear_alpha /* = true */) { - if (!m_display_texture_handle) + if (!m_display_texture) return false; const bool flip_y = (m_display_texture_view_height < 0); @@ -634,22 +513,25 @@ bool HostDisplay::WriteDisplayTextureToBuffer(std::vector* buffer, u32 resi if (flip_y) { read_height = -m_display_texture_view_height; - read_y = (m_display_texture_height - read_height) - (m_display_texture_height - m_display_texture_view_y); + read_y = + (m_display_texture->GetHeight() - read_height) - (m_display_texture->GetHeight() - m_display_texture_view_y); } u32 width = static_cast(read_width); u32 height = static_cast(read_height); std::vector texture_data(width * height); - u32 texture_data_stride = Common::AlignUpPow2(GetDisplayPixelFormatSize(m_display_texture_format) * width, 4); - if (!DownloadTexture(m_display_texture_handle, m_display_texture_format, read_x, read_y, width, height, - texture_data.data(), texture_data_stride)) + u32 texture_data_stride = Common::AlignUpPow2(m_display_texture->GetPixelSize() * width, 4); + if (!DownloadTexture(m_display_texture, read_x, read_y, width, height, texture_data.data(), texture_data_stride)) { Log_ErrorPrintf("Failed to download texture from GPU."); return false; } - if (!ConvertTextureDataToRGBA8(width, height, texture_data, texture_data_stride, m_display_texture_format)) + if (!GPUTexture::ConvertTextureDataToRGBA8(width, height, texture_data, texture_data_stride, + m_display_texture->GetFormat())) + { return false; + } if (clear_alpha) { @@ -704,7 +586,7 @@ bool HostDisplay::WriteScreenshotToFile(std::string filename, bool compress_on_t std::vector pixels; u32 pixels_stride; - HostDisplayPixelFormat pixels_format; + GPUTexture::Format pixels_format; if (!RenderScreenshot(width, height, &pixels, &pixels_stride, &pixels_format)) { Log_ErrorPrintf("Failed to render %ux%u screenshot", width, height); diff --git a/src/core/host_display.h b/src/core/host_display.h index 38915f7c9..89ada874b 100644 --- a/src/core/host_display.h +++ b/src/core/host_display.h @@ -1,4 +1,5 @@ #pragma once +#include "common/gpu_texture.h" #include "common/rectangle.h" #include "common/window_info.h" #include "types.h" @@ -18,35 +19,6 @@ enum class RenderAPI : u32 OpenGLES }; -enum class HostDisplayPixelFormat : u32 -{ - Unknown, - RGBA8, - BGRA8, - RGB565, - RGBA5551, - Count -}; - -// An abstracted RGBA8 texture. -class HostDisplayTexture -{ -public: - virtual ~HostDisplayTexture(); - - virtual void* GetHandle() const = 0; - virtual u32 GetWidth() const = 0; - virtual u32 GetHeight() const = 0; - virtual u32 GetLayers() const = 0; - virtual u32 GetLevels() const = 0; - virtual u32 GetSamples() const = 0; - virtual HostDisplayPixelFormat GetFormat() const = 0; - - virtual bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch)/* = 0*/; - virtual void EndUpdate(u32 x, u32 y, u32 width, u32 height)/* = 0*/; - virtual bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch); -}; - // Interface to the frontend's renderer. class HostDisplay { @@ -89,7 +61,7 @@ public: m_mouse_position_y = y; } - ALWAYS_INLINE const void* GetDisplayTextureHandle() const { return m_display_texture_handle; } + ALWAYS_INLINE const void* GetDisplayTextureHandle() const { return m_display_texture; } ALWAYS_INLINE s32 GetDisplayTopMargin() const { return m_display_top_margin; } ALWAYS_INLINE s32 GetDisplayWidth() const { return m_display_width; } ALWAYS_INLINE s32 GetDisplayHeight() const { return m_display_height; } @@ -124,18 +96,23 @@ public: virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) = 0; /// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below. - virtual std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, - HostDisplayPixelFormat format, const void* data, - u32 data_stride, bool dynamic = false) = 0; - virtual bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, - u32 width, u32 height, void* out_data, u32 out_data_stride) = 0; + virtual std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, u32 data_stride, + bool dynamic = false) = 0; + virtual bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) = 0; + virtual void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) = 0; + + virtual bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch); + + virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) = 0; /// Returns false if the window was completely occluded. virtual bool Render(bool skip_present) = 0; /// Renders the display with postprocessing to the specified image. virtual bool RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) = 0; + GPUTexture::Format* out_format) = 0; virtual void SetVSync(bool enabled) = 0; @@ -150,9 +127,7 @@ public: void ClearDisplayTexture() { - m_display_texture_handle = nullptr; - m_display_texture_width = 0; - m_display_texture_height = 0; + m_display_texture = nullptr; m_display_texture_view_x = 0; m_display_texture_view_y = 0; m_display_texture_view_width = 0; @@ -160,13 +135,9 @@ public: m_display_changed = true; } - void SetDisplayTexture(void* texture_handle, HostDisplayPixelFormat texture_format, s32 texture_width, - s32 texture_height, s32 view_x, s32 view_y, s32 view_width, s32 view_height) + void SetDisplayTexture(GPUTexture* texture, s32 view_x, s32 view_y, s32 view_width, s32 view_height) { - m_display_texture_handle = texture_handle; - m_display_texture_format = texture_format; - m_display_texture_width = texture_width; - m_display_texture_height = texture_height; + m_display_texture = texture; m_display_texture_view_x = view_x; m_display_texture_view_y = view_y; m_display_texture_view_width = view_width; @@ -196,12 +167,7 @@ public: m_display_changed = true; } - static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format); - static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector& texture_data, u32& texture_data_stride, - HostDisplayPixelFormat format); - static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector& texture_data, u32 texture_data_stride); - - virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0; + virtual bool SupportsTextureFormat(GPUTexture::Format format) const = 0; virtual bool GetHostRefreshRate(float* refresh_rate); @@ -215,7 +181,7 @@ public: void SetDisplayAlignment(Alignment alignment) { m_display_alignment = alignment; } /// Sets the software cursor to the specified texture. Ownership of the texture is transferred. - void SetSoftwareCursor(std::unique_ptr texture, float scale = 1.0f); + void SetSoftwareCursor(std::unique_ptr texture, float scale = 1.0f); /// Sets the software cursor to the specified image. bool SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale = 1.0f); @@ -235,9 +201,8 @@ public: s32 window_height, s32 top_margin) const; /// Helper function to save texture data to a PNG. If flip_y is set, the image will be flipped aka OpenGL. - bool WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, - HostDisplayPixelFormat format, std::string filename, bool clear_alpha = true, - bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0, + bool WriteTextureToFile(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, std::string filename, + bool clear_alpha = true, bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0, bool compress_on_thread = false); /// Helper function to save current display texture to PNG. @@ -253,7 +218,7 @@ public: protected: ALWAYS_INLINE bool HasSoftwareCursor() const { return static_cast(m_cursor_texture); } - ALWAYS_INLINE bool HasDisplayTexture() const { return (m_display_texture_handle != nullptr); } + ALWAYS_INLINE bool HasDisplayTexture() const { return (m_display_texture != nullptr); } bool IsUsingLinearFiltering() const; @@ -280,10 +245,7 @@ protected: float m_display_aspect_ratio = 1.0f; float m_display_frame_interval = 0.0f; - void* m_display_texture_handle = nullptr; - HostDisplayPixelFormat m_display_texture_format = HostDisplayPixelFormat::Count; - s32 m_display_texture_width = 0; - s32 m_display_texture_height = 0; + GPUTexture* m_display_texture = nullptr; s32 m_display_texture_view_x = 0; s32 m_display_texture_view_y = 0; s32 m_display_texture_view_width = 0; @@ -292,7 +254,7 @@ protected: s32 m_display_top_margin = 0; Alignment m_display_alignment = Alignment::Center; - std::unique_ptr m_cursor_texture; + std::unique_ptr m_cursor_texture; float m_cursor_texture_scale = 1.0f; bool m_display_changed = false; @@ -313,10 +275,10 @@ void ReleaseHostDisplay(); /// Returns false if the window was completely occluded. If frame_skip is set, the frame won't be /// displayed, but the GPU command queue will still be flushed. -//bool BeginPresentFrame(bool frame_skip); +// bool BeginPresentFrame(bool frame_skip); /// Presents the frame to the display, and renders OSD elements. -//void EndPresentFrame(); +// void EndPresentFrame(); /// Provided by the host; renders the display. void RenderDisplay(bool skip_present); diff --git a/src/core/system.cpp b/src/core/system.cpp index a9bc21fff..cbd83bbf5 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -72,7 +72,7 @@ SystemBootParameters::~SystemBootParameters() = default; struct MemorySaveState { - std::unique_ptr vram_texture; + std::unique_ptr vram_texture; std::unique_ptr state_stream; }; @@ -97,7 +97,7 @@ static void ClearRunningGame(); static void DestroySystem(); static std::string GetMediaPathFromSaveState(const char* path); static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display); -static bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display, bool is_memory_state); +static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state); static void DoRunFrame(); static bool CreateGPU(GPURenderer renderer); static bool SaveUndoLoadState(); @@ -880,7 +880,8 @@ bool System::UpdateGameSettingsLayer() } } - Host::Internal::SetInputSettingsLayer(input_interface ? input_interface.get() : Host::Internal::GetBaseSettingsLayer()); + Host::Internal::SetInputSettingsLayer(input_interface ? input_interface.get() : + Host::Internal::GetBaseSettingsLayer()); } else { @@ -1549,7 +1550,7 @@ bool System::CreateGPU(GPURenderer renderer) return true; } -bool System::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display, bool is_memory_state) +bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state) { if (!sw.DoMarker("System")) return false; @@ -1917,11 +1918,11 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 * std::vector screenshot_buffer; u32 screenshot_stride; - HostDisplayPixelFormat screenshot_format; + GPUTexture::Format screenshot_format; if (g_host_display->RenderScreenshot(screenshot_width, screenshot_height, &screenshot_buffer, &screenshot_stride, &screenshot_format) && - g_host_display->ConvertTextureDataToRGBA8(screenshot_width, screenshot_height, screenshot_buffer, - screenshot_stride, screenshot_format)) + GPUTexture::ConvertTextureDataToRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride, + screenshot_format)) { if (screenshot_stride != (screenshot_width * sizeof(u32))) { @@ -1932,8 +1933,7 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 * { if (g_host_display->UsesLowerLeftOrigin()) { - g_host_display->FlipTextureDataRGBA8(screenshot_width, screenshot_height, screenshot_buffer, - screenshot_stride); + GPUTexture::FlipTextureDataRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride); } header.offset_to_screenshot = static_cast(state->GetPosition()); @@ -3336,7 +3336,7 @@ bool System::LoadMemoryState(const MemorySaveState& mss) mss.state_stream->SeekAbsolute(0); StateWrapper sw(mss.state_stream.get(), StateWrapper::Mode::Read, SAVE_STATE_VERSION); - HostDisplayTexture* host_texture = mss.vram_texture.get(); + GPUTexture* host_texture = mss.vram_texture.get(); if (!DoState(sw, &host_texture, true, true)) { Host::ReportErrorAsync("Error", "Failed to load memory save state, resetting."); @@ -3354,7 +3354,7 @@ bool System::SaveMemoryState(MemorySaveState* mss) else mss->state_stream->SeekAbsolute(0); - HostDisplayTexture* host_texture = mss->vram_texture.release(); + GPUTexture* host_texture = mss->vram_texture.release(); StateWrapper sw(mss->state_stream.get(), StateWrapper::Mode::Write, SAVE_STATE_VERSION); if (!DoState(sw, &host_texture, false, true)) { diff --git a/src/duckstation-nogui/win32_nogui_platform.cpp b/src/duckstation-nogui/win32_nogui_platform.cpp index 61387e2b5..460d2c5b2 100644 --- a/src/duckstation-nogui/win32_nogui_platform.cpp +++ b/src/duckstation-nogui/win32_nogui_platform.cpp @@ -327,8 +327,8 @@ LRESULT CALLBACK Win32NoGUIPlatform::WndProc(HWND hwnd, UINT msg, WPARAM wParam, { const WCHAR utf16[1] = {static_cast(wParam)}; char utf8[8] = {}; - const int utf8_len = - WideCharToMultiByte(CP_UTF8, 0, utf16, std::size(utf16), utf8, sizeof(utf8) - 1, nullptr, nullptr); + const int utf8_len = WideCharToMultiByte(CP_UTF8, 0, utf16, static_cast(std::size(utf16)), utf8, + static_cast(sizeof(utf8)) - 1, nullptr, nullptr); if (utf8_len > 0) { utf8[utf8_len] = 0; diff --git a/src/duckstation-regtest/regtest_host_display.cpp b/src/duckstation-regtest/regtest_host_display.cpp index 08f48adcb..141d443ad 100644 --- a/src/duckstation-regtest/regtest_host_display.cpp +++ b/src/duckstation-regtest/regtest_host_display.cpp @@ -128,38 +128,38 @@ bool RegTestHostDisplay::SetPostProcessingChain(const std::string_view& config) return false; } -std::unique_ptr RegTestHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, - u32 samples, HostDisplayPixelFormat format, +std::unique_ptr RegTestHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, + u32 samples, GPUTexture::Format format, const void* data, u32 data_stride, bool dynamic /* = false */) { return nullptr; } -void RegTestHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, +void RegTestHostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride) { } -bool RegTestHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, +bool RegTestHostDisplay::DownloadTexture(const void* texture_handle, GPUTexture::Format texture_format, u32 x, u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride) { - const u32 pixel_size = GetDisplayPixelFormatSize(texture_format); + const u32 pixel_size = GPUTexture::GetPixelSize(texture_format); const u32 input_stride = Common::AlignUpPow2(width * pixel_size, 4); const u8* input_start = static_cast(texture_handle) + (x * pixel_size); StringUtil::StrideMemCpy(out_data, out_data_stride, input_start, input_stride, width * pixel_size, height); return true; } -bool RegTestHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const +bool RegTestHostDisplay::SupportsTextureFormat(GPUTexture::Format format) const { - return (format == HostDisplayPixelFormat::RGBA8); + return (format == GPUTexture::Format::RGBA8); } -bool RegTestHostDisplay::BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer, +bool RegTestHostDisplay::BeginSetDisplayPixels(GPUTexture::Format format, u32 width, u32 height, void** out_buffer, u32* out_pitch) { - const u32 pitch = Common::AlignUpPow2(width * GetDisplayPixelFormatSize(format), 4); + const u32 pitch = Common::AlignUpPow2(width * GPUTexture::GetPixelSize(format), 4); const u32 required_size = height * pitch; if (m_frame_buffer.size() != (required_size / 4)) { @@ -191,7 +191,7 @@ void RegTestHostDisplay::DumpFrame(const std::string& filename) } Common::RGBA8Image image(m_display_texture_width, m_display_texture_height, - static_cast(m_display_texture_handle)); + static_cast(m_display_texture)); // set alpha channel on all pixels u32* pixels = image.GetPixels(); @@ -214,7 +214,7 @@ bool RegTestHostDisplay::Render() } bool RegTestHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) + GPUTexture::Format* out_format) { return false; } diff --git a/src/duckstation-regtest/regtest_host_display.h b/src/duckstation-regtest/regtest_host_display.h index 5fccb310b..bf0ed9cfe 100644 --- a/src/duckstation-regtest/regtest_host_display.h +++ b/src/duckstation-regtest/regtest_host_display.h @@ -43,28 +43,28 @@ public: void DestroyImGuiContext() override; bool UpdateImGuiFontTexture() override; - std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, - HostDisplayPixelFormat format, const void* data, u32 data_stride, + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, u32 data_stride, bool dynamic = false) override; - void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, + void UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride) override; - bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, + bool DownloadTexture(const void* texture_handle, GPUTexture::Format texture_format, u32 x, u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride) override; void SetVSync(bool enabled) override; bool Render() override; bool RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) override; + GPUTexture::Format* out_format) override; - bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override; + bool SupportsTextureFormat(GPUTexture::Format format) const override; - bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer, + bool BeginSetDisplayPixels(GPUTexture::Format format, u32 width, u32 height, void** out_buffer, u32* out_pitch) override; void EndSetDisplayPixels() override; private: std::vector m_frame_buffer; - HostDisplayPixelFormat m_frame_buffer_format = HostDisplayPixelFormat::Unknown; + GPUTexture::Format m_frame_buffer_format = GPUTexture::Format::Unknown; u32 m_frame_buffer_pitch = 0; }; diff --git a/src/frontend-common/common_host.cpp b/src/frontend-common/common_host.cpp index 977ccfaf0..e78faa06b 100644 --- a/src/frontend-common/common_host.cpp +++ b/src/frontend-common/common_host.cpp @@ -412,9 +412,9 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBackground)) { - HostDisplayTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png"); + GPUTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png"); if (tex) - ImGui::Image(tex->GetHandle(), ImVec2(logo_width, logo_height)); + ImGui::Image(tex, ImVec2(logo_width, logo_height)); } ImGui::End(); diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp index 69cc41469..6a00108e4 100644 --- a/src/frontend-common/d3d11_host_display.cpp +++ b/src/frontend-common/d3d11_host_display.cpp @@ -21,69 +21,6 @@ Log_SetChannel(D3D11HostDisplay); #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") -class D3D11HostDisplayTexture final : public HostDisplayTexture -{ -public: - D3D11HostDisplayTexture(D3D11::Texture texture, HostDisplayPixelFormat format, bool dynamic) - : m_texture(std::move(texture)), m_format(format), m_dynamic(dynamic) - { - } - ~D3D11HostDisplayTexture() override = default; - - void* GetHandle() const override { return const_cast(&m_texture); } - u32 GetWidth() const override { return m_texture.GetWidth(); } - u32 GetHeight() const override { return m_texture.GetHeight(); } - u32 GetLayers() const override { return 1; } - u32 GetLevels() const override { return m_texture.GetLevels(); } - u32 GetSamples() const override { return m_texture.GetSamples(); } - HostDisplayPixelFormat GetFormat() const override { return m_format; } - - bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override - { - if (!m_dynamic || m_texture.GetWidth() != width || m_texture.GetHeight() != height) - return false; - - D3D11_MAPPED_SUBRESOURCE sr; - HRESULT hr = static_cast(g_host_display->GetRenderContext()) - ->Map(m_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); - if (FAILED(hr)) - { - Log_ErrorPrintf("Map pixels texture failed: %08X", hr); - return false; - } - - *out_buffer = sr.pData; - *out_pitch = sr.RowPitch; - return true; - } - - void EndUpdate(u32 x, u32 y, u32 width, u32 height) - { - static_cast(g_host_display->GetRenderContext())->Unmap(m_texture, 0); - } - - bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override - { - if (m_dynamic) - return HostDisplayTexture::Update(x, y, width, height, data, pitch); - - const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1); - static_cast(g_host_display->GetRenderContext()) - ->UpdateSubresource(m_texture, 0, &dst_box, data, pitch, pitch * height); - return true; - } - - ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.GetD3DTexture(); } - ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_texture.GetD3DSRV(); } - ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_texture.GetD3DSRVArray(); } - ALWAYS_INLINE bool IsDynamic() const { return m_dynamic; } - -private: - D3D11::Texture m_texture; - HostDisplayPixelFormat m_format; - bool m_dynamic; -}; - D3D11HostDisplay::D3D11HostDisplay() = default; D3D11HostDisplay::~D3D11HostDisplay() @@ -120,34 +57,61 @@ bool D3D11HostDisplay::HasRenderSurface() const return static_cast(m_swap_chain); } -static constexpr std::array(HostDisplayPixelFormat::Count)> - s_display_pixel_format_mapping = {{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM}}; - -std::unique_ptr D3D11HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, - u32 samples, HostDisplayPixelFormat format, - const void* data, u32 data_stride, - bool dynamic /* = false */) +std::unique_ptr D3D11HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, + u32 data_stride, bool dynamic /* = false */) { - if (layers != 1) - return {}; - - D3D11::Texture tex; - if (!tex.Create(m_device.Get(), width, height, layers, levels, samples, - s_display_pixel_format_mapping[static_cast(format)], D3D11_BIND_SHADER_RESOURCE, data, - data_stride, dynamic)) + std::unique_ptr tex(std::make_unique()); + if (!tex->Create(m_device.Get(), width, height, layers, levels, samples, format, D3D11_BIND_SHADER_RESOURCE, data, + data_stride, dynamic)) { - return {}; + tex.reset(); } - return std::make_unique(std::move(tex), format, dynamic); + return tex; } -bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, - u32 width, u32 height, void* out_data, u32 out_data_stride) +bool D3D11HostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) { - const D3D11::Texture* tex = static_cast(texture_handle); - if (!CheckStagingBufferSize(width, height, tex->GetFormat())) + D3D11::Texture* tex = static_cast(texture); + if (!tex->IsDynamic() || tex->GetWidth() != width || tex->GetHeight() != height) + return false; + + D3D11_MAPPED_SUBRESOURCE sr; + HRESULT hr = m_context->Map(tex->GetD3DTexture(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); + if (FAILED(hr)) + { + Log_ErrorPrintf("Map pixels texture failed: %08X", hr); + return false; + } + + *out_buffer = sr.pData; + *out_pitch = sr.RowPitch; + return true; +} + +void D3D11HostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) +{ + D3D11::Texture* tex = static_cast(texture); + m_context->Unmap(tex->GetD3DTexture(), 0); +} + +bool D3D11HostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) +{ + D3D11::Texture* tex = static_cast(texture); + if (tex->IsDynamic()) + return HostDisplay::UpdateTexture(texture, x, y, width, height, data, pitch); + + const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1); + m_context->UpdateSubresource(tex->GetD3DTexture(), 0, &dst_box, data, pitch, pitch * height); + return true; +} + +bool D3D11HostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) +{ + const D3D11::Texture* tex = static_cast(texture); + if (!CheckStagingBufferSize(width, height, tex->GetDXGIFormat())) return false; const CD3D11_BOX box(static_cast(x), static_cast(y), 0, static_cast(x + width), @@ -162,7 +126,7 @@ bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPi return false; } - const u32 copy_size = GetDisplayPixelFormatSize(texture_format) * width; + const u32 copy_size = tex->GetPixelSize() * width; StringUtil::StrideMemCpy(out_data, out_data_stride, sr.pData, sr.RowPitch, copy_size, height); m_context->Unmap(m_readback_staging_texture.Get(), 0); return true; @@ -195,9 +159,9 @@ void D3D11HostDisplay::DestroyStagingBuffer() m_readback_staging_texture_format = DXGI_FORMAT_UNKNOWN; } -bool D3D11HostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const +bool D3D11HostDisplay::SupportsTextureFormat(GPUTexture::Format format) const { - const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast(format)]; + const DXGI_FORMAT dfmt = D3D11::Texture::GetDXGIFormat(format); if (dfmt == DXGI_FORMAT_UNKNOWN) return false; @@ -767,13 +731,12 @@ bool D3D11HostDisplay::Render(bool skip_present) } bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) + GPUTexture::Format* out_format) { - static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; - static constexpr HostDisplayPixelFormat hdformat = HostDisplayPixelFormat::RGBA8; + static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; D3D11::Texture render_texture; - if (!render_texture.Create(m_device.Get(), width, height, 1, 1, 1, format, D3D11_BIND_RENDER_TARGET)) + if (!render_texture.Create(m_device.Get(), width, height, 1, 1, 1, hdformat, D3D11_BIND_RENDER_TARGET)) return false; static constexpr std::array clear_color = {}; @@ -786,24 +749,24 @@ bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* if (!m_post_processing_chain.IsEmpty()) { - ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height, m_display_texture_handle, - m_display_texture_width, m_display_texture_height, m_display_texture_view_x, + ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height, + static_cast(m_display_texture), m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, width, height); } else { - RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, - m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(left, top, draw_width, draw_height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); } } m_context->OMSetRenderTargets(0, nullptr, nullptr); - const u32 stride = GetDisplayPixelFormatSize(hdformat) * width; + const u32 stride = GPUTexture::GetPixelSize(hdformat) * width; out_pixels->resize(width * height); - if (!DownloadTexture(&render_texture, hdformat, 0, 0, width, height, out_pixels->data(), stride)) + if (!DownloadTexture(&render_texture, 0, 0, width, height, out_pixels->data(), stride)) return false; *out_stride = stride; @@ -826,36 +789,36 @@ void D3D11HostDisplay::RenderDisplay() if (!m_post_processing_chain.IsEmpty()) { - ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height, m_display_texture_handle, - m_display_texture_width, m_display_texture_height, m_display_texture_view_x, + ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height, + static_cast(m_display_texture), m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, GetWindowWidth(), GetWindowHeight()); return; } - RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height, - m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, - m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(left, top, width, height, static_cast(m_display_texture), m_display_texture_view_x, + m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, + IsUsingLinearFiltering()); } -void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, - s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, +void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, D3D11::Texture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter) { m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0); m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0); - m_context->PSSetShaderResources(0, 1, static_cast(texture_handle)->GetD3DSRVArray()); + m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray()); m_context->PSSetSamplers(0, 1, linear_filter ? m_linear_sampler.GetAddressOf() : m_point_sampler.GetAddressOf()); const bool linear = IsUsingLinearFiltering(); const float position_adjust = linear ? 0.5f : 0.0f; const float size_adjust = linear ? 1.0f : 0.0f; const float uniforms[4] = { - (static_cast(texture_view_x) + position_adjust) / static_cast(texture_width), - (static_cast(texture_view_y) + position_adjust) / static_cast(texture_height), - (static_cast(texture_view_width) - size_adjust) / static_cast(texture_width), - (static_cast(texture_view_height) - size_adjust) / static_cast(texture_height)}; + (static_cast(texture_view_x) + position_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_y) + position_adjust) / static_cast(texture->GetHeight()), + (static_cast(texture_view_width) - size_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_height) - size_adjust) / static_cast(texture->GetHeight())}; const auto map = m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), sizeof(uniforms)); std::memcpy(map.pointer, uniforms, sizeof(uniforms)); m_display_uniform_buffer.Unmap(m_context.Get(), sizeof(uniforms)); @@ -880,13 +843,12 @@ void D3D11HostDisplay::RenderSoftwareCursor() RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get()); } -void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, - HostDisplayTexture* texture_handle) +void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle) { m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0); m_context->PSSetShader(m_display_alpha_pixel_shader.Get(), nullptr, 0); - m_context->PSSetShaderResources(0, 1, static_cast(texture_handle)->GetD3DSRVArray()); + m_context->PSSetShaderResources(0, 1, static_cast(texture_handle)->GetD3DSRVArray()); m_context->PSSetSamplers(0, 1, m_linear_sampler.GetAddressOf()); const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f}; @@ -1052,7 +1014,7 @@ bool D3D11HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 ta { DebugAssert(!m_post_processing_stages.empty()); - const DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; + const GPUTexture::Format format = GPUTexture::Format::RGBA8; const u32 bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; if (m_post_processing_input_texture.GetWidth() != target_width || @@ -1080,29 +1042,26 @@ bool D3D11HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 ta } void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, - s32 final_width, s32 final_height, void* texture_handle, - u32 texture_width, s32 texture_height, s32 texture_view_x, - s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, - u32 target_width, u32 target_height) + s32 final_width, s32 final_height, D3D11::Texture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, + s32 texture_view_height, u32 target_width, u32 target_height) { static constexpr std::array clear_color = {0.0f, 0.0f, 0.0f, 1.0f}; if (!CheckPostProcessingRenderTargets(target_width, target_height)) { - RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height, - texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y, + texture_view_width, texture_view_height, IsUsingLinearFiltering()); return; } // downsample/upsample - use same viewport for remainder m_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), clear_color.data()); m_context->OMSetRenderTargets(1, m_post_processing_input_texture.GetD3DRTVArray(), nullptr); - RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height, - texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y, + texture_view_width, texture_view_height, IsUsingLinearFiltering()); - texture_handle = &m_post_processing_input_texture; - texture_width = m_post_processing_input_texture.GetWidth(); - texture_height = m_post_processing_input_texture.GetHeight(); + texture = &m_post_processing_input_texture; texture_view_x = final_left; texture_view_y = final_top; texture_view_width = final_width; @@ -1125,13 +1084,13 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0); m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0); - m_context->PSSetShaderResources(0, 1, static_cast(texture_handle)->GetD3DSRVArray()); + m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray()); m_context->PSSetSamplers(0, 1, m_point_sampler.GetAddressOf()); const auto map = m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), pps.uniforms_size); m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( - map.pointer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, + map.pointer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f); m_display_uniform_buffer.Unmap(m_context.Get(), pps.uniforms_size); m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray()); @@ -1140,7 +1099,7 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta m_context->Draw(3, 0); if (i != final_stage) - texture_handle = &pps.output_texture; + texture = &pps.output_texture; } ID3D11ShaderResourceView* null_srv = nullptr; diff --git a/src/frontend-common/d3d11_host_display.h b/src/frontend-common/d3d11_host_display.h index c2c51b20c..79a885baf 100644 --- a/src/frontend-common/d3d11_host_display.h +++ b/src/frontend-common/d3d11_host_display.h @@ -47,12 +47,15 @@ public: bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, - HostDisplayPixelFormat format, const void* data, u32 data_stride, - bool dynamic = false) override; - bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, - u32 height, void* out_data, u32 out_data_stride) override; - bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, u32 data_stride, + bool dynamic = false) override; + bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override; + void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override; + bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override; + bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) override; + bool SupportsTextureFormat(GPUTexture::Format format) const override; bool GetHostRefreshRate(float* refresh_rate) override; @@ -63,7 +66,7 @@ public: bool Render(bool skip_present) override; bool RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) override; + GPUTexture::Format* out_format) override; static AdapterAndModeList StaticGetAdapterAndModeList(); @@ -90,10 +93,9 @@ protected: void RenderSoftwareCursor(); void RenderImGui(); - void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, - s32 texture_height, s32 texture_view_x, 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, HostDisplayTexture* texture_handle); + void RenderDisplay(s32 left, s32 top, s32 width, s32 height, D3D11::Texture* texture, s32 texture_view_x, + 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_handle); struct PostProcessingStage { @@ -105,9 +107,8 @@ protected: bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); void ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width, - s32 final_height, void* texture_handle, u32 texture_width, s32 texture_height, - s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, - u32 target_width, u32 target_height); + s32 final_height, D3D11::Texture* texture, s32 texture_view_x, s32 texture_view_y, + s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height); bool CreateTimestampQueries(); void DestroyTimestampQueries(); diff --git a/src/frontend-common/d3d12_host_display.cpp b/src/frontend-common/d3d12_host_display.cpp index bdaffb209..933c84374 100644 --- a/src/frontend-common/d3d12_host_display.cpp +++ b/src/frontend-common/d3d12_host_display.cpp @@ -15,51 +15,6 @@ #include Log_SetChannel(D3D12HostDisplay); -static constexpr std::array(HostDisplayPixelFormat::Count)> - s_display_pixel_format_mapping = {{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM}}; - -class D3D12HostDisplayTexture final : public HostDisplayTexture -{ -public: - D3D12HostDisplayTexture(D3D12::Texture texture) : m_texture(std::move(texture)) {} - ~D3D12HostDisplayTexture() override = default; - - void* GetHandle() const override { return const_cast(&m_texture); } - u32 GetWidth() const override { return m_texture.GetWidth(); } - u32 GetHeight() const override { return m_texture.GetHeight(); } - u32 GetLayers() const override { return 1; } - u32 GetLevels() const override { return 1; } - u32 GetSamples() const override { return m_texture.GetSamples(); } - - HostDisplayPixelFormat GetFormat() const override - { - for (u32 i = 0; i < static_cast(s_display_pixel_format_mapping.size()); i++) - { - if (m_texture.GetFormat() == s_display_pixel_format_mapping[i]) - return static_cast(i); - } - - return HostDisplayPixelFormat::Count; - } - - bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override - { - return m_texture.BeginStreamUpdate(0, 0, width, height, out_buffer, out_pitch); - } - - void EndUpdate(u32 x, u32 y, u32 width, u32 height) override - { - m_texture.EndStreamUpdate(x, y, width, height); - } - - const D3D12::Texture& GetTexture() const { return m_texture; } - D3D12::Texture& GetTexture() { return m_texture; } - -private: - D3D12::Texture m_texture; -}; - D3D12HostDisplay::D3D12HostDisplay() = default; D3D12HostDisplay::~D3D12HostDisplay() @@ -98,47 +53,62 @@ bool D3D12HostDisplay::HasRenderSurface() const return static_cast(m_swap_chain); } -std::unique_ptr D3D12HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, - u32 samples, HostDisplayPixelFormat format, - const void* data, u32 data_stride, - bool dynamic /* = false */) +std::unique_ptr D3D12HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, + u32 data_stride, bool dynamic /* = false */) { - if (layers != 1) + const DXGI_FORMAT dformat = D3D12::Texture::GetDXGIFormat(format); + if (dformat == DXGI_FORMAT_UNKNOWN) return {}; - const DXGI_FORMAT dxgi_format = s_display_pixel_format_mapping[static_cast(format)]; - D3D12::Texture tex; - if (!tex.Create(width, height, samples, dxgi_format, dxgi_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, - D3D12_RESOURCE_FLAG_NONE)) + std::unique_ptr tex(std::make_unique()); + if (!tex->Create(width, height, layers, levels, samples, dformat, dformat, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + D3D12_RESOURCE_FLAG_NONE)) { return {}; } - if (data && !tex.LoadData(0, 0, width, height, data, data_stride)) + if (data && !tex->LoadData(0, 0, width, height, data, data_stride)) return {}; - return std::make_unique(std::move(tex)); + return tex; } -bool D3D12HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, - u32 width, u32 height, void* out_data, u32 out_data_stride) +bool D3D12HostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) { - const D3D12::Texture* texture = static_cast(texture_handle); + return static_cast(texture)->BeginStreamUpdate(0, 0, width, height, out_buffer, out_pitch); +} - if (!m_readback_staging_texture.EnsureSize(width, height, texture->GetFormat(), false)) +void D3D12HostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) +{ + static_cast(texture)->EndStreamUpdate(x, y, width, height); +} + +bool D3D12HostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, + u32 pitch) +{ + return HostDisplay::UpdateTexture(texture, x, y, width, height, data, pitch); +} + +bool D3D12HostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) +{ + const D3D12::Texture* tex = static_cast(texture); + + if (!m_readback_staging_texture.EnsureSize(width, height, tex->GetDXGIFormat(), false)) return false; - const D3D12_RESOURCE_STATES old_state = texture->GetState(); - texture->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE); - m_readback_staging_texture.CopyFromTexture(texture->GetResource(), 0, x, y, 0, 0, width, height); - texture->TransitionToState(old_state); + const D3D12_RESOURCE_STATES old_state = tex->GetState(); + tex->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE); + m_readback_staging_texture.CopyFromTexture(tex->GetResource(), 0, x, y, 0, 0, width, height); + tex->TransitionToState(old_state); return m_readback_staging_texture.ReadPixels(0, 0, width, height, out_data, out_data_stride); } -bool D3D12HostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const +bool D3D12HostDisplay::SupportsTextureFormat(GPUTexture::Format format) const { - const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast(format)]; + const DXGI_FORMAT dfmt = D3D12::Texture::GetDXGIFormat(format); if (dfmt == DXGI_FORMAT_UNKNOWN) return false; @@ -654,13 +624,13 @@ bool D3D12HostDisplay::Render(bool skip_present) } bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) + GPUTexture::Format* out_format) { static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; - static constexpr HostDisplayPixelFormat hdformat = HostDisplayPixelFormat::RGBA8; + static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; D3D12::Texture render_texture; - if (!render_texture.Create(width, height, 1, format, DXGI_FORMAT_UNKNOWN, format, DXGI_FORMAT_UNKNOWN, + if (!render_texture.Create(width, height, 1, 1, 1, format, DXGI_FORMAT_UNKNOWN, format, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) || !m_readback_staging_texture.EnsureSize(width, height, format, false)) { @@ -676,9 +646,9 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* if (HasDisplayTexture()) { const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0); - RenderDisplay(cmdlist, left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, - m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); } cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr); @@ -728,23 +698,22 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist) // return; // } - RenderDisplay(cmdlist, left, top, width, height, m_display_texture_handle, m_display_texture_width, - m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(cmdlist, left, top, width, height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); } void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, - void* texture_handle, u32 texture_width, s32 texture_height, s32 texture_view_x, - s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, - bool linear_filter) + D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y, + s32 texture_view_width, s32 texture_view_height, bool linear_filter) { const float position_adjust = linear_filter ? 0.5f : 0.0f; const float size_adjust = linear_filter ? 1.0f : 0.0f; const float uniforms[4] = { - (static_cast(texture_view_x) + position_adjust) / static_cast(texture_width), - (static_cast(texture_view_y) + position_adjust) / static_cast(texture_height), - (static_cast(texture_view_width) - size_adjust) / static_cast(texture_width), - (static_cast(texture_view_height) - size_adjust) / static_cast(texture_height)}; + (static_cast(texture_view_x) + position_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_y) + position_adjust) / static_cast(texture->GetHeight()), + (static_cast(texture_view_width) - size_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_height) - size_adjust) / static_cast(texture->GetHeight())}; if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)) Panic("Failed to reserve UBO space"); @@ -755,7 +724,7 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 lef cmdlist->SetGraphicsRootSignature(m_display_root_signature.Get()); cmdlist->SetPipelineState(m_display_pipeline.Get()); cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset); - cmdlist->SetGraphicsRootDescriptorTable(1, reinterpret_cast(texture_handle)->GetSRVDescriptor()); + cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor()); cmdlist->SetGraphicsRootDescriptorTable(2, linear_filter ? m_linear_sampler : m_point_sampler); D3D12::SetViewportAndScissor(cmdlist, left, top, width, height); @@ -774,7 +743,7 @@ void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist) } void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, - s32 height, HostDisplayTexture* texture_handle) + s32 height, GPUTexture* texture_handle) { const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f}; if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)) @@ -786,8 +755,7 @@ void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, cmdlist->SetPipelineState(m_display_pipeline.Get()); cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset); - cmdlist->SetGraphicsRootDescriptorTable( - 1, static_cast(texture_handle)->GetTexture().GetRTVOrDSVDescriptor()); + cmdlist->SetGraphicsRootDescriptorTable(1, static_cast(texture_handle)->GetRTVOrDSVDescriptor()); cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler); D3D12::SetViewportAndScissor(cmdlist, left, top, width, height); diff --git a/src/frontend-common/d3d12_host_display.h b/src/frontend-common/d3d12_host_display.h index e4874ee01..833d3d70f 100644 --- a/src/frontend-common/d3d12_host_display.h +++ b/src/frontend-common/d3d12_host_display.h @@ -49,12 +49,15 @@ public: bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, - HostDisplayPixelFormat format, const void* data, u32 data_stride, - bool dynamic = false) override; - bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, - u32 height, void* out_data, u32 out_data_stride) override; - bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, u32 data_stride, + bool dynamic = false) override; + bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override; + void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override; + bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override; + bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) override; + bool SupportsTextureFormat(GPUTexture::Format format) const override; bool GetHostRefreshRate(float* refresh_rate) override; @@ -62,7 +65,7 @@ public: bool Render(bool skip_present) override; bool RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) override; + GPUTexture::Format* out_format) override; bool SetGPUTimingEnabled(bool enabled) override; float GetAndResetAccumulatedGPUTime() override; @@ -93,11 +96,11 @@ protected: void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist); void RenderImGui(ID3D12GraphicsCommandList* cmdlist); - void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, void* texture_handle, - u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, - s32 texture_view_width, s32 texture_view_height, bool linear_filter); + void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, + D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, + s32 texture_view_height, bool linear_filter); void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, - HostDisplayTexture* texture_handle); + GPUTexture* texture_handle); ComPtr m_dxgi_factory; ComPtr m_swap_chain; diff --git a/src/frontend-common/fullscreen_ui.cpp b/src/frontend-common/fullscreen_ui.cpp index 331877ee5..6372e1d6c 100644 --- a/src/frontend-common/fullscreen_ui.cpp +++ b/src/frontend-common/fullscreen_ui.cpp @@ -218,14 +218,14 @@ static std::deque s_async_ops; static bool LoadResources(); static void DestroyResources(); -static std::shared_ptr s_app_icon_texture; -static std::array, static_cast(GameDatabase::CompatibilityRating::Count)> +static std::shared_ptr s_app_icon_texture; +static std::array, static_cast(GameDatabase::CompatibilityRating::Count)> s_game_compatibility_textures; -static std::shared_ptr s_fallback_disc_texture; -static std::shared_ptr s_fallback_exe_texture; -static std::shared_ptr s_fallback_psf_texture; -static std::shared_ptr s_fallback_playlist_texture; -static std::vector> s_cleanup_textures; +static std::shared_ptr s_fallback_disc_texture; +static std::shared_ptr s_fallback_exe_texture; +static std::shared_ptr s_fallback_psf_texture; +static std::shared_ptr s_fallback_playlist_texture; +static std::vector> s_cleanup_textures; ////////////////////////////////////////////////////////////////////////// // Landing @@ -375,7 +375,7 @@ struct SaveStateListEntry std::string title; std::string summary; std::string path; - std::unique_ptr preview_texture; + std::unique_ptr preview_texture; time_t timestamp; s32 slot; bool global; @@ -415,9 +415,9 @@ static void HandleGameListOptions(const GameList::Entry* entry); static void DrawGameListSettingsPage(const ImVec2& heading_size); static void SwitchToGameList(); static void PopulateGameListEntryList(); -static HostDisplayTexture* GetTextureForGameListEntryType(GameList::EntryType type); -static HostDisplayTexture* GetGameListCover(const GameList::Entry* entry); -static HostDisplayTexture* GetCoverForCurrentGame(); +static GPUTexture* GetTextureForGameListEntryType(GameList::EntryType type); +static GPUTexture* GetGameListCover(const GameList::Entry* entry); +static GPUTexture* GetCoverForCurrentGame(); // Lazily populated cover images. static std::unordered_map s_cover_image_map; @@ -717,7 +717,7 @@ void FullscreenUI::Render() if (!s_initialized) return; - for (std::unique_ptr& tex : s_cleanup_textures) + for (std::unique_ptr& tex : s_cleanup_textures) tex.reset(); s_cleanup_textures.clear(); ImGuiFullscreen::UploadAsyncTextures(); @@ -1077,7 +1077,7 @@ void FullscreenUI::DrawLandingWindow() const float image_size = LayoutScale(380.f); ImGui::SetCursorPos(ImVec2((ImGui::GetWindowWidth() * 0.5f) - (image_size * 0.5f), (ImGui::GetWindowHeight() * 0.5f) - (image_size * 0.5f))); - ImGui::Image(s_app_icon_texture->GetHandle(), ImVec2(image_size, image_size)); + ImGui::Image(s_app_icon_texture.get(), ImVec2(image_size, image_size)); } EndFullscreenColumnWindow(); @@ -3885,7 +3885,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type) const ImVec2 image_min(display_size.x - LayoutScale(20.0f + 50.0f) - rp_height, display_size.y - LayoutScale(20.0f + 50.0f) - rp_height); const ImVec2 image_max(image_min.x + LayoutScale(50.0f) + rp_height, image_min.y + LayoutScale(50.0f) + rp_height); - dl->AddImage(GetCoverForCurrentGame()->GetHandle(), image_min, image_max); + dl->AddImage(GetCoverForCurrentGame(), image_min, image_max); } const ImVec2 window_size(LayoutScale(500.0f, LAYOUT_SCREEN_HEIGHT)); @@ -4087,15 +4087,15 @@ void FullscreenUI::PopulateSaveStateScreenshot(SaveStateListEntry* li, const Ext li->preview_texture.reset(); if (ssi && !ssi->screenshot_data.empty()) { - li->preview_texture = g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, - HostDisplayPixelFormat::RGBA8, ssi->screenshot_data.data(), - sizeof(u32) * ssi->screenshot_width, false); + li->preview_texture = + g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, GPUTexture::Format::RGBA8, + ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false); } else { - li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, - HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA, - sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); + li->preview_texture = + g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, GPUTexture::Format::RGBA8, + PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); } if (!li->preview_texture) @@ -4254,8 +4254,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading, bool fullscreen) ImVec2 pos(bb.Min); // use aspect ratio of screenshot to determine height - const HostDisplayTexture* image = - entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get(); + const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get(); const float image_height = max_image_width / (static_cast(image->GetWidth()) / static_cast(image->GetHeight())); const float image_margin = (max_image_height - image_height) / 2.0f; @@ -4289,10 +4288,9 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading, bool fullscreen) ImGui::PopFont(); - ImGui::GetWindowDrawList()->AddImage(static_cast(entry.preview_texture ? - entry.preview_texture->GetHandle() : - GetPlaceholderTexture()->GetHandle()), - image_bb.Min, image_bb.Max); + ImGui::GetWindowDrawList()->AddImage( + static_cast(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()), + image_bb.Min, image_bb.Max); if (pressed) { @@ -4353,18 +4351,16 @@ void FullscreenUI::DrawResumeStateSelector() ImGui::TextWrapped("A resume save state created at %s was found.\n\nDo you want to load this save and continue?", TimeToPrintableString(entry.timestamp).c_str()); - const HostDisplayTexture* image = - entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get(); + const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get(); const float image_height = LayoutScale(250.0f); const float image_width = image_height * (static_cast(image->GetWidth()) / static_cast(image->GetHeight())); const ImVec2 pos(ImGui::GetCursorScreenPos() + ImVec2((ImGui::GetCurrentWindow()->WorkRect.GetWidth() - image_width) * 0.5f, LayoutScale(20.0f))); const ImRect image_bb(pos, pos + ImVec2(image_width, image_height)); - ImGui::GetWindowDrawList()->AddImage(static_cast(entry.preview_texture ? - entry.preview_texture->GetHandle() : - GetPlaceholderTexture()->GetHandle()), - image_bb.Min, image_bb.Max); + ImGui::GetWindowDrawList()->AddImage( + static_cast(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()), + image_bb.Min, image_bb.Max); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + image_height + LayoutScale(40.0f)); @@ -4564,7 +4560,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) if (!visible) continue; - HostDisplayTexture* cover_texture = GetGameListCover(entry); + GPUTexture* cover_texture = GetGameListCover(entry); if (entry->serial.empty()) { @@ -4582,8 +4578,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast(cover_texture->GetWidth()), static_cast(cover_texture->GetHeight())))); - ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), image_rect.Min, image_rect.Max, - ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); + ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f), + ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); const float midpoint = bb.Min.y + g_large_font->FontSize + LayoutScale(4.0f); const float text_start_x = bb.Min.x + image_size.x + LayoutScale(15.0f); @@ -4623,7 +4619,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) if (BeginFullscreenColumnWindow(-530.0f, 0.0f, "game_list_info", UIPrimaryDarkColor)) { - const HostDisplayTexture* cover_texture = + const GPUTexture* cover_texture = selected_entry ? GetGameListCover(selected_entry) : GetTextureForGameListEntryType(GameList::EntryType::Count); if (cover_texture) { @@ -4632,8 +4628,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) static_cast(cover_texture->GetHeight())))); ImGui::SetCursorPos(LayoutScale(ImVec2(90.0f, 50.0f)) + image_rect.Min); - ImGui::Image(selected_entry ? GetGameListCover(selected_entry)->GetHandle() : - GetTextureForGameListEntryType(GameList::EntryType::Count)->GetHandle(), + ImGui::Image(selected_entry ? GetGameListCover(selected_entry) : + GetTextureForGameListEntryType(GameList::EntryType::Count), image_rect.GetSize()); } @@ -4683,7 +4679,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) fmt::format("fullscreenui/{}.png", Settings::GetDiscRegionName(selected_entry->region))); ImGui::TextUnformatted("Region: "); ImGui::SameLine(); - ImGui::Image(GetCachedTextureAsync(flag_texture.c_str())->GetHandle(), LayoutScale(23.0f, 16.0f)); + ImGui::Image(GetCachedTextureAsync(flag_texture.c_str()), LayoutScale(23.0f, 16.0f)); ImGui::SameLine(); ImGui::Text(" (%s)", Settings::GetDiscRegionDisplayName(selected_entry->region)); } @@ -4701,7 +4697,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) ImGui::SameLine(); if (selected_entry->compatibility != GameDatabase::CompatibilityRating::Unknown) { - ImGui::Image(s_game_compatibility_textures[static_cast(selected_entry->compatibility)]->GetHandle(), + ImGui::Image(s_game_compatibility_textures[static_cast(selected_entry->compatibility)].get(), LayoutScale(64.0f, 16.0f)); ImGui::SameLine(); } @@ -4801,13 +4797,13 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size) bb.Min += style.FramePadding; bb.Max -= style.FramePadding; - const HostDisplayTexture* const cover_texture = GetGameListCover(entry); + GPUTexture* const cover_texture = GetGameListCover(entry); const ImRect image_rect( CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast(cover_texture->GetWidth()), static_cast(cover_texture->GetHeight())))); - ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), image_rect.Min, image_rect.Max, - ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); + ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f), + ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max); const std::string_view title( @@ -5111,7 +5107,7 @@ void FullscreenUI::SwitchToGameList() QueueResetFocus(); } -HostDisplayTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry) +GPUTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry) { // lookup and grab cover image auto cover_it = s_cover_image_map.find(entry->path); @@ -5121,11 +5117,11 @@ HostDisplayTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry) cover_it = s_cover_image_map.emplace(entry->path, std::move(cover_path)).first; } - HostDisplayTexture* tex = (!cover_it->second.empty()) ? GetCachedTextureAsync(cover_it->second.c_str()) : nullptr; + GPUTexture* tex = (!cover_it->second.empty()) ? GetCachedTextureAsync(cover_it->second.c_str()) : nullptr; return tex ? tex : GetTextureForGameListEntryType(entry->type); } -HostDisplayTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type) +GPUTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type) { switch (type) { @@ -5144,7 +5140,7 @@ HostDisplayTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::Entry } } -HostDisplayTexture* FullscreenUI::GetCoverForCurrentGame() +GPUTexture* FullscreenUI::GetCoverForCurrentGame() { auto lock = GameList::GetLock(); @@ -5360,11 +5356,11 @@ void FullscreenUI::DrawAchievement(const Achievements::Achievement& cheevo) const std::string& badge_path = Achievements::GetAchievementBadgePath(cheevo); if (!badge_path.empty()) { - HostDisplayTexture* badge = GetCachedTextureAsync(badge_path.c_str()); + GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str()); if (badge) { - ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f), - ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); + ImGui::GetWindowDrawList()->AddImage(badge, bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), + IM_COL32(255, 255, 255, 255)); } } @@ -5463,11 +5459,11 @@ void FullscreenUI::DrawAchievementsWindow() const std::string& icon_path = Achievements::GetGameIcon(); if (!icon_path.empty()) { - HostDisplayTexture* badge = GetCachedTexture(icon_path.c_str()); + GPUTexture* badge = GetCachedTexture(icon_path.c_str()); if (badge) { - ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), icon_min, icon_max, ImVec2(0.0f, 0.0f), - ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); + ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), + IM_COL32(255, 255, 255, 255)); } } @@ -5602,12 +5598,12 @@ void FullscreenUI::DrawPrimedAchievements() if (badge_path.empty()) return true; - HostDisplayTexture* badge = GetCachedTextureAsync(badge_path.c_str()); + GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str()); if (!badge) return true; ImDrawList* dl = ImGui::GetBackgroundDrawList(); - dl->AddImage(badge->GetHandle(), position, position + image_size); + dl->AddImage(badge, position, position + image_size); position.x -= x_advance; return true; }); @@ -5786,11 +5782,11 @@ void FullscreenUI::DrawLeaderboardsWindow() const std::string& icon_path = Achievements::GetGameIcon(); if (!icon_path.empty()) { - HostDisplayTexture* badge = GetCachedTexture(icon_path.c_str()); + GPUTexture* badge = GetCachedTexture(icon_path.c_str()); if (badge) { - ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), icon_min, icon_max, ImVec2(0.0f, 0.0f), - ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); + ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), + IM_COL32(255, 255, 255, 255)); } } diff --git a/src/frontend-common/fullscreen_ui.h b/src/frontend-common/fullscreen_ui.h index 5fe1cbc9e..7926715a7 100644 --- a/src/frontend-common/fullscreen_ui.h +++ b/src/frontend-common/fullscreen_ui.h @@ -4,7 +4,7 @@ #include #include -class HostDisplayTexture; +class GPUTexture; struct Settings; diff --git a/src/frontend-common/imgui_fullscreen.cpp b/src/frontend-common/imgui_fullscreen.cpp index 08933f9b6..5796e4a29 100644 --- a/src/frontend-common/imgui_fullscreen.cpp +++ b/src/frontend-common/imgui_fullscreen.cpp @@ -32,7 +32,7 @@ namespace ImGuiFullscreen { using MessageDialogCallbackVariant = std::variant; static std::optional LoadTextureImage(const char* path); -static std::shared_ptr UploadTexture(const char* path, const Common::RGBA8Image& image); +static std::shared_ptr UploadTexture(const char* path, const Common::RGBA8Image& image); static void TextureLoaderThread(); static void DrawFileSelector(); @@ -78,8 +78,8 @@ static u32 s_menu_button_index = 0; static u32 s_close_button_state = 0; static bool s_focus_reset_queued = false; -static LRUCache> s_texture_cache(128, true); -static std::shared_ptr s_placeholder_texture; +static LRUCache> s_texture_cache(128, true); +static std::shared_ptr s_placeholder_texture; static std::atomic_bool s_texture_load_thread_quit{false}; static std::mutex s_texture_load_mutex; static std::condition_variable s_texture_load_cv; @@ -231,7 +231,7 @@ void ImGuiFullscreen::Shutdown() s_file_selector_items.clear(); } -const std::shared_ptr& ImGuiFullscreen::GetPlaceholderTexture() +const std::shared_ptr& ImGuiFullscreen::GetPlaceholderTexture() { return s_placeholder_texture; } @@ -262,10 +262,10 @@ std::optional ImGuiFullscreen::LoadTextureImage(const char* return image; } -std::shared_ptr ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image) +std::shared_ptr ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image) { - std::unique_ptr texture = - g_host_display->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, HostDisplayPixelFormat::RGBA8, + std::unique_ptr texture = + g_host_display->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); if (!texture) { @@ -274,16 +274,16 @@ std::shared_ptr ImGuiFullscreen::UploadTexture(const char* p } Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight()); - return std::shared_ptr(std::move(texture)); + return std::shared_ptr(std::move(texture)); } -std::shared_ptr ImGuiFullscreen::LoadTexture(const std::string_view& path) +std::shared_ptr ImGuiFullscreen::LoadTexture(const std::string_view& path) { std::string path_str(path); std::optional image(LoadTextureImage(path_str.c_str())); if (image.has_value()) { - std::shared_ptr ret(UploadTexture(path_str.c_str(), image.value())); + std::shared_ptr ret(UploadTexture(path_str.c_str(), image.value())); if (ret) return ret; } @@ -291,21 +291,21 @@ std::shared_ptr ImGuiFullscreen::LoadTexture(const std::stri return s_placeholder_texture; } -HostDisplayTexture* ImGuiFullscreen::GetCachedTexture(const std::string_view& name) +GPUTexture* ImGuiFullscreen::GetCachedTexture(const std::string_view& name) { - std::shared_ptr* tex_ptr = s_texture_cache.Lookup(name); + std::shared_ptr* tex_ptr = s_texture_cache.Lookup(name); if (!tex_ptr) { - std::shared_ptr tex(LoadTexture(name)); + std::shared_ptr tex(LoadTexture(name)); tex_ptr = s_texture_cache.Insert(std::string(name), std::move(tex)); } return tex_ptr->get(); } -HostDisplayTexture* ImGuiFullscreen::GetCachedTextureAsync(const std::string_view& name) +GPUTexture* ImGuiFullscreen::GetCachedTextureAsync(const std::string_view& name) { - std::shared_ptr* tex_ptr = s_texture_cache.Lookup(name); + std::shared_ptr* tex_ptr = s_texture_cache.Lookup(name); if (!tex_ptr) { // insert the placeholder @@ -334,7 +334,7 @@ void ImGuiFullscreen::UploadAsyncTextures() s_texture_upload_queue.pop_front(); lock.unlock(); - std::shared_ptr tex = UploadTexture(it.first.c_str(), it.second); + std::shared_ptr tex = UploadTexture(it.first.c_str(), it.second); if (tex) s_texture_cache.Insert(std::move(it.first), std::move(tex)); @@ -2389,9 +2389,9 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing) const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size); if (!notif.badge_path.empty()) { - HostDisplayTexture* tex = GetCachedTexture(notif.badge_path.c_str()); + GPUTexture* tex = GetCachedTexture(notif.badge_path.c_str()); if (tex) - dl->AddImage(static_cast(tex->GetHandle()), badge_min, badge_max); + dl->AddImage(tex, badge_min, badge_max); } const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding); diff --git a/src/frontend-common/imgui_fullscreen.h b/src/frontend-common/imgui_fullscreen.h index 3bb2bb1b6..3724afaf0 100644 --- a/src/frontend-common/imgui_fullscreen.h +++ b/src/frontend-common/imgui_fullscreen.h @@ -9,7 +9,7 @@ #include #include -class HostDisplayTexture; +class GPUTexture; namespace ImGuiFullscreen { #define HEX_TO_IMVEC4(hex, alpha) \ @@ -121,10 +121,10 @@ bool UpdateLayoutScale(); void Shutdown(); /// Texture cache. -const std::shared_ptr& GetPlaceholderTexture(); -std::shared_ptr LoadTexture(const std::string_view& path); -HostDisplayTexture* GetCachedTexture(const std::string_view& name); -HostDisplayTexture* GetCachedTextureAsync(const std::string_view& name); +const std::shared_ptr& GetPlaceholderTexture(); +std::shared_ptr LoadTexture(const std::string_view& path); +GPUTexture* GetCachedTexture(const std::string_view& name); +GPUTexture* GetCachedTextureAsync(const std::string_view& name); bool InvalidateCachedTexture(const std::string& path); void UploadAsyncTextures(); diff --git a/src/frontend-common/imgui_impl_dx11.cpp b/src/frontend-common/imgui_impl_dx11.cpp index 85cab85c2..3d8b0f7a6 100644 --- a/src/frontend-common/imgui_impl_dx11.cpp +++ b/src/frontend-common/imgui_impl_dx11.cpp @@ -251,7 +251,7 @@ bool ImGui_ImplDX11_CreateFontsTexture() io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); const u32 stride = sizeof(u32) * width; - if (!bd->FontTexture.Create(bd->pd3dDevice, width, height, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_BIND_SHADER_RESOURCE, pixels, stride)) + if (!bd->FontTexture.Create(bd->pd3dDevice, width, height, 1, 1, 1, GPUTexture::Format::RGBA8, D3D11_BIND_SHADER_RESOURCE, pixels, stride)) return false; // Store our identifier diff --git a/src/frontend-common/imgui_impl_dx12.cpp b/src/frontend-common/imgui_impl_dx12.cpp index f88091209..f1e286eec 100644 --- a/src/frontend-common/imgui_impl_dx12.cpp +++ b/src/frontend-common/imgui_impl_dx12.cpp @@ -266,7 +266,7 @@ bool ImGui_ImplDX12_CreateFontsTexture() // Upload texture to graphics system if (bd->FontTexture.GetWidth() != static_cast(width) || bd->FontTexture.GetHeight() != static_cast(height)) { - if (!bd->FontTexture.Create(width, height, 1, DXGI_FORMAT_R8G8B8A8_UNORM, + if (!bd->FontTexture.Create(width, height, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE)) { diff --git a/src/frontend-common/imgui_impl_opengl3.cpp b/src/frontend-common/imgui_impl_opengl3.cpp index 952be29ad..888782a42 100644 --- a/src/frontend-common/imgui_impl_opengl3.cpp +++ b/src/frontend-common/imgui_impl_opengl3.cpp @@ -110,20 +110,20 @@ // OpenGL Data struct ImGui_ImplOpenGL3_Data { - GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) - char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings. + GLuint GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) + char GlslVersionString[32] = {}; // Specified by user or detected based on compile time GL settings. GL::Texture FontTexture; - GLuint ShaderHandle; - GLint AttribLocationTex; // Uniforms location - GLint AttribLocationProjMtx; - GLuint AttribLocationVtxPos; // Vertex attributes location - GLuint AttribLocationVtxUV; - GLuint AttribLocationVtxColor; - unsigned int VboHandle, ElementsHandle, VaoHandle; - GLsizeiptr VertexBufferSize; - GLsizeiptr IndexBufferSize; + GLuint ShaderHandle = 0; + GLint AttribLocationTex = 0; // Uniforms location + GLint AttribLocationProjMtx = 0; + GLuint AttribLocationVtxPos = 0; // Vertex attributes location + GLuint AttribLocationVtxUV = 0; + GLuint AttribLocationVtxColor = 0; + unsigned int VboHandle = 0, ElementsHandle = 0, VaoHandle = 0; + GLsizeiptr VertexBufferSize = 0; + GLsizeiptr IndexBufferSize = 0; - ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); } + ImGui_ImplOpenGL3_Data() = default; }; // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts @@ -316,7 +316,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture() // Upload texture to graphics system // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture.Create(width, height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + bd->FontTexture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, pixels); bd->FontTexture.SetLinearFilter(true); // Store our identifier @@ -326,7 +326,6 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture() void ImGui_ImplOpenGL3_DestroyFontsTexture() { - ImGuiIO& io = ImGui::GetIO(); ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->FontTexture.IsValid()) bd->FontTexture.Destroy(); diff --git a/src/frontend-common/imgui_overlays.cpp b/src/frontend-common/imgui_overlays.cpp index f95dec611..6f3c73ba0 100644 --- a/src/frontend-common/imgui_overlays.cpp +++ b/src/frontend-common/imgui_overlays.cpp @@ -409,7 +409,7 @@ struct ListEntry std::string game_code; std::string title; std::string formatted_timestamp; - std::unique_ptr preview_texture; + std::unique_ptr preview_texture; s32 slot; bool global; }; @@ -564,13 +564,13 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn if (ssi && !ssi->screenshot_data.empty()) { li->preview_texture = g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, - HostDisplayPixelFormat::RGBA8, ssi->screenshot_data.data(), + GPUTexture::Format::RGBA8, ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false); } else { li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, - HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA, + GPUTexture::Format::RGBA8, PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); } @@ -591,7 +591,7 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, std::str if (g_host_display) { li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, - HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA, + GPUTexture::Format::RGBA8, PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); if (!li->preview_texture) Log_ErrorPrintf("Failed to upload save state image to GPU"); @@ -645,7 +645,7 @@ void SaveStateSelectorUI::Draw() { ImGui::SetCursorPosY(y_start + padding); ImGui::SetCursorPosX(padding); - ImGui::Image(reinterpret_cast(entry.preview_texture->GetHandle()), image_size); + ImGui::Image(entry.preview_texture.get(), image_size); } ImGui::SetCursorPosY(y_start + padding); diff --git a/src/frontend-common/opengl_host_display.cpp b/src/frontend-common/opengl_host_display.cpp index 30f29b0ce..0a7525ab0 100644 --- a/src/frontend-common/opengl_host_display.cpp +++ b/src/frontend-common/opengl_host_display.cpp @@ -16,36 +16,6 @@ enum : u32 TEXTURE_STREAM_BUFFER_SIZE = 16 * 1024 * 1024, }; -class OpenGLHostDisplayTexture final : public HostDisplayTexture -{ -public: - OpenGLHostDisplayTexture(GL::Texture texture, HostDisplayPixelFormat format) - : m_texture(std::move(texture)), m_format(format) - { - } - - ~OpenGLHostDisplayTexture() = default; - - void* GetHandle() const override { return const_cast(&m_texture); } - - u32 GetWidth() const override { return m_texture.GetWidth(); } - u32 GetHeight() const override { return m_texture.GetHeight(); } - u32 GetLayers() const override { return m_texture.GetLayers(); } - u32 GetLevels() const override { return m_texture.GetLevels(); } - u32 GetSamples() const override { return m_texture.GetSamples(); } - HostDisplayPixelFormat GetFormat() const override { return m_format; } - GLuint GetGLID() const { return m_texture.GetGLId(); } - - bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override; - void EndUpdate(u32 x, u32 y, u32 width, u32 height) override; - bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override; - -private: - GL::Texture m_texture; - HostDisplayPixelFormat m_format; - u32 m_map_offset = 0; -}; - OpenGLHostDisplay::OpenGLHostDisplay() = default; OpenGLHostDisplay::~OpenGLHostDisplay() @@ -74,54 +44,134 @@ void* OpenGLHostDisplay::GetRenderContext() const return m_gl_context.get(); } -static const std::tuple& GetPixelFormatMapping(bool is_gles, HostDisplayPixelFormat format) +std::unique_ptr OpenGLHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, + u32 data_stride, bool dynamic /* = false */) { - static constexpr std::array, static_cast(HostDisplayPixelFormat::Count)> - mapping = {{ - {}, // Unknown - {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8 - {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 - {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 - {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV} // RGBA5551 - }}; + std::unique_ptr tex(std::make_unique()); + if (!tex->Create(width, height, layers, levels, samples, format, data, data_stride)) + tex.reset(); - static constexpr std::array, static_cast(HostDisplayPixelFormat::Count)> - mapping_gles2 = {{ - {}, // Unknown - {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8 - {}, // BGRA8 - {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 - {} // RGBA5551 - }}; + return tex; +} - if (is_gles && !GLAD_GL_ES_VERSION_3_0) - return mapping_gles2[static_cast(format)]; +bool OpenGLHostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, + u32* out_pitch) +{ + const u32 pixel_size = texture->GetPixelSize(); + const u32 stride = Common::AlignUpPow2(width * pixel_size, 4); + const u32 size_required = stride * height; + GL::StreamBuffer* buffer = UsePBOForUploads() ? GetTextureStreamBuffer() : nullptr; + + if (buffer && size_required < buffer->GetSize()) + { + auto map = buffer->Map(4096, size_required); + m_texture_stream_buffer_offset = map.buffer_offset; + *out_buffer = map.pointer; + *out_pitch = stride; + } else - return mapping[static_cast(format)]; + { + std::vector& repack_buffer = GetTextureRepackBuffer(); + if (repack_buffer.size() < size_required) + repack_buffer.resize(size_required); + + *out_buffer = repack_buffer.data(); + *out_pitch = stride; + } + + return true; } -std::unique_ptr OpenGLHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, - u32 samples, HostDisplayPixelFormat format, - const void* data, u32 data_stride, - bool dynamic /* = false */) +void OpenGLHostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) { - if (layers != 1 || levels != 1) - return {}; + const u32 pixel_size = texture->GetPixelSize(); + const u32 stride = Common::AlignUpPow2(width * pixel_size, 4); + const u32 size_required = stride * height; + GL::Texture* gl_texture = static_cast(texture); + GL::StreamBuffer* buffer = UsePBOForUploads() ? GetTextureStreamBuffer() : nullptr; - const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), format); + const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(gl_texture->GetFormat()); + const bool whole_texture = (!gl_texture->UseTextureStorage() && x == 0 && y == 0 && width == gl_texture->GetWidth() && + height == gl_texture->GetHeight()); - // TODO: Set pack width - Assert(!data || data_stride == (width * sizeof(u32))); + gl_texture->Bind(); + if (buffer && size_required < buffer->GetSize()) + { + buffer->Unmap(size_required); + buffer->Bind(); - GL::Texture tex; - if (!tex.Create(width, height, layers, levels, samples, gl_internal_format, gl_format, gl_type, data, data_stride)) - return {}; + if (whole_texture) + { + glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, + reinterpret_cast(static_cast(m_texture_stream_buffer_offset))); + } + else + { + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, + reinterpret_cast(static_cast(m_texture_stream_buffer_offset))); + } - return std::make_unique(std::move(tex), format); + buffer->Unbind(); + } + else + { + std::vector& repack_buffer = GetTextureRepackBuffer(); + if (whole_texture) + glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data()); + else + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data()); + } } -bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, - u32 width, u32 height, void* out_data, u32 out_data_stride) +bool OpenGLHostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, + u32 pitch) +{ + GL::Texture* gl_texture = static_cast(texture); + const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(gl_texture->GetFormat()); + const u32 pixel_size = gl_texture->GetPixelSize(); + const bool is_packed_tightly = (pitch == (pixel_size * width)); + + const bool whole_texture = (!gl_texture->UseTextureStorage() && x == 0 && y == 0 && width == gl_texture->GetWidth() && + height == gl_texture->GetHeight()); + gl_texture->Bind(); + + // If we have GLES3, we can set row_length. + if (UseGLES3DrawPath() || is_packed_tightly) + { + if (!is_packed_tightly) + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / pixel_size); + + if (whole_texture) + glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data); + else + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data); + + if (!is_packed_tightly) + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + else + { + // Otherwise, we need to repack the image. + std::vector& repack_buffer = GetTextureRepackBuffer(); + const u32 packed_pitch = width * pixel_size; + const u32 repack_size = packed_pitch * height; + if (repack_buffer.size() < repack_size) + repack_buffer.resize(repack_size); + + StringUtil::StrideMemCpy(repack_buffer.data(), packed_pitch, data, pitch, packed_pitch, height); + + if (whole_texture) + glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data()); + else + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data()); + } + + return true; +} + +bool OpenGLHostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) { GLint alignment; if (out_data_stride & 1) @@ -137,14 +187,13 @@ bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP if (!m_use_gles2_draw_path) { glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length); - glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / GetDisplayPixelFormatSize(texture_format)); + glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / texture->GetPixelSize()); } - const GL::Texture* texture = static_cast(texture_handle); - const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), texture_format); + const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(texture->GetFormat()); - GL::Texture::GetTextureSubImage(texture->GetGLId(), 0, x, y, 0, width, height, 1, gl_format, gl_type, - height * out_data_stride, out_data); + GL::Texture::GetTextureSubImage(static_cast(texture)->GetGLId(), 0, x, y, 0, width, height, 1, + gl_format, gl_type, height * out_data_stride, out_data); glPixelStorei(GL_PACK_ALIGNMENT, old_alignment); if (!m_use_gles2_draw_path) @@ -152,9 +201,9 @@ bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP return true; } -bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const +bool OpenGLHostDisplay::SupportsTextureFormat(GPUTexture::Format format) const { - const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), format); + const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(format); return (gl_internal_format != static_cast(0)); } @@ -594,11 +643,10 @@ bool OpenGLHostDisplay::Render(bool skip_present) } bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) + GPUTexture::Format* out_format) { GL::Texture texture; - if (!texture.Create(width, height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr) || - !texture.CreateFramebuffer()) + if (!texture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0) || !texture.CreateFramebuffer()) { return false; } @@ -615,22 +663,21 @@ bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector if (!m_post_processing_chain.IsEmpty()) { ApplyPostProcessingChain(texture.GetGLFramebufferID(), left, height - top - draw_height, draw_width, draw_height, - m_display_texture_handle, m_display_texture_width, m_display_texture_height, - m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, - m_display_texture_view_height, width, height); + static_cast(m_display_texture), m_display_texture_view_x, + m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, + width, height); } else { - RenderDisplay(left, height - top - draw_height, draw_width, draw_height, m_display_texture_handle, - m_display_texture_width, m_display_texture_height, m_display_texture_view_x, - m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, - IsUsingLinearFiltering()); + RenderDisplay(left, height - top - draw_height, draw_width, draw_height, + static_cast(m_display_texture), m_display_texture_view_x, m_display_texture_view_y, + m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); } } out_pixels->resize(width * height); *out_stride = sizeof(u32) * width; - *out_format = HostDisplayPixelFormat::RGBA8; + *out_format = GPUTexture::Format::RGBA8; glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, out_pixels->data()); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -653,16 +700,16 @@ void OpenGLHostDisplay::RenderDisplay() if (!m_post_processing_chain.IsEmpty()) { - ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height, m_display_texture_handle, - m_display_texture_width, m_display_texture_height, m_display_texture_view_x, + ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height, + static_cast(m_display_texture), m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, GetWindowWidth(), GetWindowHeight()); return; } - RenderDisplay(left, GetWindowHeight() - top - height, width, height, m_display_texture_handle, - m_display_texture_width, m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(left, GetWindowHeight() - top - height, width, height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); } static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_width, s32 tex_view_height, @@ -689,12 +736,10 @@ static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_w glDisableVertexAttribArray(0); } -void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, - u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, - s32 texture_view_width, s32 texture_view_height, bool linear_filter) +void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, GL::Texture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, + s32 texture_view_height, bool linear_filter) { - const GL::Texture* texture = static_cast(texture_handle); - glViewport(left, bottom, width, height); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); @@ -711,10 +756,11 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh const float size_adjust = linear ? 1.0f : 0.0f; const float flip_adjust = (texture_view_height < 0) ? -1.0f : 1.0f; m_display_program.Uniform4f( - 0, (static_cast(texture_view_x) + position_adjust) / static_cast(texture_width), - (static_cast(texture_view_y) + (position_adjust * flip_adjust)) / static_cast(texture_height), - (static_cast(texture_view_width) - size_adjust) / static_cast(texture_width), - (static_cast(texture_view_height) - (size_adjust * flip_adjust)) / static_cast(texture_height)); + 0, (static_cast(texture_view_x) + position_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_y) + (position_adjust * flip_adjust)) / static_cast(texture->GetHeight()), + (static_cast(texture_view_width) - size_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_height) - (size_adjust * flip_adjust)) / + static_cast(texture->GetHeight())); glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler); glBindVertexArray(m_display_vao); glDrawArrays(GL_TRIANGLES, 0, 3); @@ -725,7 +771,7 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh texture->SetLinearFilter(linear_filter); DrawFullscreenQuadES2(m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, - m_display_texture_view_height, m_display_texture_width, m_display_texture_height); + m_display_texture_view_height, texture->GetWidth(), texture->GetHeight()); } } @@ -738,8 +784,7 @@ void OpenGLHostDisplay::RenderSoftwareCursor() RenderSoftwareCursor(left, GetWindowHeight() - top - height, width, height, m_cursor_texture.get()); } -void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, - HostDisplayTexture* texture_handle) +void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle) { glViewport(left, bottom, width, height); glEnable(GL_BLEND); @@ -749,7 +794,7 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3 glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); m_cursor_program.Bind(); - glBindTexture(GL_TEXTURE_2D, static_cast(texture_handle)->GetGLID()); + static_cast(texture_handle)->Bind(); if (!m_use_gles2_draw_path) { @@ -761,8 +806,8 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3 } else { - const s32 tex_width = static_cast(static_cast(texture_handle)->GetWidth()); - const s32 tex_height = static_cast(static_cast(texture_handle)->GetHeight()); + const s32 tex_width = static_cast(texture_handle->GetWidth()); + const s32 tex_height = static_cast(texture_handle->GetHeight()); DrawFullscreenQuadES2(0, 0, tex_width, tex_height, tex_width, tex_height); } } @@ -842,8 +887,7 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t if (m_post_processing_input_texture.GetWidth() != target_width || m_post_processing_input_texture.GetHeight() != target_height) { - if (!m_post_processing_input_texture.Create(target_width, target_height, 1, 1, 1, GL_RGBA8, GL_RGBA, - GL_UNSIGNED_BYTE) || + if (!m_post_processing_input_texture.Create(target_width, target_height, 1, 1, 1, GPUTexture::Format::RGBA8) || !m_post_processing_input_texture.CreateFramebuffer()) { return false; @@ -856,7 +900,7 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t PostProcessingStage& pps = m_post_processing_stages[i]; if (pps.output_texture.GetWidth() != target_width || pps.output_texture.GetHeight() != target_height) { - if (!pps.output_texture.Create(target_width, target_height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE) || + if (!pps.output_texture.Create(target_width, target_height, 1, 1, 1, GPUTexture::Format::RGBA8) || !pps.output_texture.CreateFramebuffer()) { return false; @@ -868,29 +912,24 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t } void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_left, s32 final_top, s32 final_width, - s32 final_height, void* texture_handle, u32 texture_width, - s32 texture_height, s32 texture_view_x, s32 texture_view_y, - s32 texture_view_width, s32 texture_view_height, u32 target_width, - u32 target_height) + s32 final_height, GL::Texture* texture, s32 texture_view_x, + s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, + u32 target_width, u32 target_height) { if (!CheckPostProcessingRenderTargets(target_width, target_height)) { - RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle, - texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, - texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture, + texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); return; } // downsample/upsample - use same viewport for remainder m_post_processing_input_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); glClear(GL_COLOR_BUFFER_BIT); - RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle, - texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height, - IsUsingLinearFiltering()); + RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture, + texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); - texture_handle = &m_post_processing_input_texture; - texture_width = m_post_processing_input_texture.GetWidth(); - texture_height = m_post_processing_input_texture.GetHeight(); + texture = &m_post_processing_input_texture; texture_view_x = final_left; texture_view_y = final_top; texture_view_width = final_width; @@ -914,12 +953,12 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_ pps.program.Bind(); - static_cast(texture_handle)->Bind(); + static_cast(texture)->Bind(); glBindSampler(0, m_display_nearest_sampler); const auto map_result = m_post_processing_ubo->Map(m_uniform_buffer_alignment, pps.uniforms_size); m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( - map_result.pointer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, + map_result.pointer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f); m_post_processing_ubo->Unmap(pps.uniforms_size); glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_post_processing_ubo->GetGLBufferId(), map_result.buffer_offset, @@ -928,7 +967,7 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_ glDrawArrays(GL_TRIANGLES, 0, 3); if (i != final_stage) - texture_handle = &pps.output_texture; + texture = &pps.output_texture; } glBindSampler(0, 0); @@ -955,7 +994,7 @@ void OpenGLHostDisplay::DestroyTimestampQueries() if (m_timestamp_query_started) { const auto EndQuery = gles ? glEndQueryEXT : glEndQuery; - EndQuery(m_timestamp_queries[m_write_timestamp_query]); + EndQuery(GL_TIME_ELAPSED); } DeleteQueries(static_cast(m_timestamp_queries.size()), m_timestamp_queries.data()); @@ -1062,121 +1101,3 @@ GL::StreamBuffer* OpenGLHostDisplay::GetTextureStreamBuffer() m_texture_stream_buffer = GL::StreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, TEXTURE_STREAM_BUFFER_SIZE); return m_texture_stream_buffer.get(); } - -bool OpenGLHostDisplayTexture::BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) -{ - const u32 pixel_size = HostDisplay::GetDisplayPixelFormatSize(m_format); - const u32 stride = Common::AlignUpPow2(width * pixel_size, 4); - const u32 size_required = stride * height; - OpenGLHostDisplay* display = static_cast(g_host_display.get()); - GL::StreamBuffer* buffer = display->UsePBOForUploads() ? display->GetTextureStreamBuffer() : nullptr; - - if (buffer && size_required < buffer->GetSize()) - { - auto map = buffer->Map(4096, size_required); - m_map_offset = map.buffer_offset; - *out_buffer = map.pointer; - *out_pitch = stride; - } - else - { - std::vector& repack_buffer = display->GetTextureRepackBuffer(); - if (repack_buffer.size() < size_required) - repack_buffer.resize(size_required); - - *out_buffer = repack_buffer.data(); - *out_pitch = stride; - } - - return true; -} - -void OpenGLHostDisplayTexture::EndUpdate(u32 x, u32 y, u32 width, u32 height) -{ - const u32 pixel_size = HostDisplay::GetDisplayPixelFormatSize(m_format); - const u32 stride = Common::AlignUpPow2(width * pixel_size, 4); - const u32 size_required = stride * height; - OpenGLHostDisplay* display = static_cast(g_host_display.get()); - GL::StreamBuffer* buffer = display->UsePBOForUploads() ? display->GetTextureStreamBuffer() : nullptr; - - const auto [gl_internal_format, gl_format, gl_type] = - GetPixelFormatMapping(display->GetGLContext()->IsGLES(), m_format); - const bool whole_texture = (!m_texture.UseTextureStorage() && x == 0 && y == 0 && width == m_texture.GetWidth() && - height == m_texture.GetHeight()); - - m_texture.Create(width, height, 1, 1, 1, gl_internal_format, gl_format, gl_type, nullptr, false, false); - m_texture.Bind(); - if (buffer && size_required < buffer->GetSize()) - { - buffer->Unmap(size_required); - buffer->Bind(); - - if (whole_texture) - { - glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, - reinterpret_cast(static_cast(m_map_offset))); - } - else - { - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, - reinterpret_cast(static_cast(m_map_offset))); - } - - buffer->Unbind(); - } - else - { - std::vector& repack_buffer = display->GetTextureRepackBuffer(); - - if (whole_texture) - glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data()); - else - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data()); - } -} - -bool OpenGLHostDisplayTexture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) -{ - OpenGLHostDisplay* display = static_cast(g_host_display.get()); - const auto [gl_internal_format, gl_format, gl_type] = - GetPixelFormatMapping(display->GetGLContext()->IsGLES(), m_format); - const u32 pixel_size = HostDisplay::GetDisplayPixelFormatSize(m_format); - const bool is_packed_tightly = (pitch == (pixel_size * width)); - - const bool whole_texture = (!m_texture.UseTextureStorage() && x == 0 && y == 0 && width == m_texture.GetWidth() && - height == m_texture.GetHeight()); - m_texture.Bind(); - - // If we have GLES3, we can set row_length. - if (!display->UseGLES3DrawPath() || is_packed_tightly) - { - if (!is_packed_tightly) - glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / pixel_size); - - if (whole_texture) - glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data); - else - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data); - - if (!is_packed_tightly) - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } - else - { - // Otherwise, we need to repack the image. - std::vector& repack_buffer = display->GetTextureRepackBuffer(); - const u32 packed_pitch = width * pixel_size; - const u32 repack_size = packed_pitch * height; - if (repack_buffer.size() < repack_size) - repack_buffer.resize(repack_size); - - StringUtil::StrideMemCpy(repack_buffer.data(), packed_pitch, data, pitch, packed_pitch, height); - - if (whole_texture) - glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data()); - else - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data()); - } - - return true; -} diff --git a/src/frontend-common/opengl_host_display.h b/src/frontend-common/opengl_host_display.h index 51e9550d0..303d30565 100644 --- a/src/frontend-common/opengl_host_display.h +++ b/src/frontend-common/opengl_host_display.h @@ -40,18 +40,21 @@ public: bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, - HostDisplayPixelFormat format, const void* data, u32 data_stride, - bool dynamic = false) override; - bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, - u32 height, void* out_data, u32 out_data_stride) override; - bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, u32 data_stride, + bool dynamic = false) override; + bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override; + void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override; + bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override; + bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) override; + bool SupportsTextureFormat(GPUTexture::Format format) const override; void SetVSync(bool enabled) override; bool Render(bool skip_present) override; bool RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) override; + GPUTexture::Format* out_format) override; bool SetGPUTimingEnabled(bool enabled) override; float GetAndResetAccumulatedGPUTime() override; @@ -80,10 +83,9 @@ protected: void RenderImGui(); void RenderSoftwareCursor(); - void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, u32 texture_width, - s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, - s32 texture_view_height, bool linear_filter); - void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, HostDisplayTexture* texture_handle); + void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, GL::Texture* texture, s32 texture_view_x, + s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter); + void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle); struct PostProcessingStage { @@ -94,9 +96,8 @@ protected: bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); void ApplyPostProcessingChain(GLuint final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, - void* texture_handle, u32 texture_width, s32 texture_height, s32 texture_view_x, - s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, u32 target_width, - u32 target_height); + GL::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, + s32 texture_view_height, u32 target_width, u32 target_height); void CreateTimestampQueries(); void DestroyTimestampQueries(); @@ -114,6 +115,7 @@ protected: std::unique_ptr m_texture_stream_buffer; std::vector m_texture_repack_buffer; + u32 m_texture_stream_buffer_offset = 0; FrontendCommon::PostProcessingChain m_post_processing_chain; GL::Texture m_post_processing_input_texture; diff --git a/src/frontend-common/vulkan_host_display.cpp b/src/frontend-common/vulkan_host_display.cpp index 934ac3127..68fae71f2 100644 --- a/src/frontend-common/vulkan_host_display.cpp +++ b/src/frontend-common/vulkan_host_display.cpp @@ -18,43 +18,6 @@ #include Log_SetChannel(VulkanHostDisplay); -class VulkanHostDisplayTexture : public HostDisplayTexture -{ -public: - VulkanHostDisplayTexture(Vulkan::Texture texture, HostDisplayPixelFormat format) - : m_texture(std::move(texture)), m_format(format) - { - } - ~VulkanHostDisplayTexture() override = default; - - void* GetHandle() const override { return const_cast(&m_texture); } - u32 GetWidth() const override { return m_texture.GetWidth(); } - u32 GetHeight() const override { return m_texture.GetHeight(); } - u32 GetLayers() const override { return m_texture.GetLayers(); } - u32 GetLevels() const override { return m_texture.GetLevels(); } - u32 GetSamples() const override { return m_texture.GetSamples(); } - HostDisplayPixelFormat GetFormat() const override { return m_format; } - - bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override - { - return m_texture.BeginUpdate(width, height, out_buffer, out_pitch); - } - - void EndUpdate(u32 x, u32 y, u32 width, u32 height) override { m_texture.EndUpdate(x, y, width, height, 0, 0); } - - bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override - { - return m_texture.Update(x, y, width, height, 0, 0, data, pitch); - } - - const Vulkan::Texture& GetTexture() const { return m_texture; } - Vulkan::Texture& GetTexture() { return m_texture; } - -private: - Vulkan::Texture m_texture; - HostDisplayPixelFormat m_format; -}; - VulkanHostDisplay::VulkanHostDisplay() = default; VulkanHostDisplay::~VulkanHostDisplay() @@ -172,56 +135,65 @@ void VulkanHostDisplay::DestroyRenderSurface() m_swap_chain.reset(); } -static constexpr std::array(HostDisplayPixelFormat::Count)> s_display_pixel_format_mapping = - {{VK_FORMAT_UNDEFINED, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16, - VK_FORMAT_A1R5G5B5_UNORM_PACK16}}; - -std::unique_ptr VulkanHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, - u32 samples, HostDisplayPixelFormat format, - const void* data, u32 data_stride, - bool dynamic /* = false */) +std::unique_ptr VulkanHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, + u32 data_stride, bool dynamic /* = false */) { - const VkFormat vk_format = s_display_pixel_format_mapping[static_cast(format)]; + const VkFormat vk_format = Vulkan::Texture::GetVkFormat(format); if (vk_format == VK_FORMAT_UNDEFINED) return {}; static constexpr VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(), - "VulkanHostDisplay::CreateTexture"); - - Vulkan::Texture texture; - if (!texture.Create(width, height, levels, layers, vk_format, static_cast(samples), - (layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - usage)) + std::unique_ptr texture(std::make_unique()); + if (!texture->Create(width, height, levels, layers, vk_format, static_cast(samples), + (layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + usage)) { return {}; } - texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + texture->TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); if (data) { - texture.Update(0, 0, width, height, 0, 0, data, data_stride); + texture->Update(0, 0, width, height, 0, 0, data, data_stride); } else { // clear it instead so we don't read uninitialized data (and keep the validation layer happy!) static constexpr VkClearColorValue ccv = {}; static constexpr VkImageSubresourceRange isr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; - vkCmdClearColorImage(g_vulkan_context->GetCurrentCommandBuffer(), texture.GetImage(), texture.GetLayout(), &ccv, 1u, - &isr); + vkCmdClearColorImage(g_vulkan_context->GetCurrentCommandBuffer(), texture->GetImage(), texture->GetLayout(), &ccv, + 1u, &isr); } - texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + texture->TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - return std::make_unique(std::move(texture), format); + return texture; } -bool VulkanHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const +bool VulkanHostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, + u32* out_pitch) { - const VkFormat vk_format = s_display_pixel_format_mapping[static_cast(format)]; + return static_cast(texture)->BeginUpdate(width, height, out_buffer, out_pitch); +} + +void VulkanHostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) +{ + static_cast(texture)->EndUpdate(x, y, width, height, 0, 0); +} + +bool VulkanHostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, + u32 pitch) +{ + return static_cast(texture)->Update(x, y, width, height, 0, 0, data, pitch); +} + +bool VulkanHostDisplay::SupportsTextureFormat(GPUTexture::Format format) const +{ + const VkFormat vk_format = Vulkan::Texture::GetVkFormat(format); if (vk_format == VK_FORMAT_UNDEFINED) return false; @@ -310,12 +282,12 @@ void VulkanHostDisplay::DestroyStagingBuffer() } } -bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, - u32 width, u32 height, void* out_data, u32 out_data_stride) +bool VulkanHostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) { - Vulkan::Texture* texture = static_cast(const_cast(texture_handle)); + Vulkan::Texture* tex = static_cast(texture); - const u32 pitch = texture->CalcUpdatePitch(width); + const u32 pitch = tex->CalcUpdatePitch(width); const u32 size = pitch * height; const u32 level = 0; if (!CheckStagingBufferSize(size)) @@ -328,16 +300,16 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP const VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer(); const Vulkan::Util::DebugScope debugScope(cmdbuf, "VulkanHostDisplay::DownloadTexture(%u,%u)", width, height); - VkImageLayout old_layout = texture->GetLayout(); + VkImageLayout old_layout = tex->GetLayout(); if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - texture->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + tex->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); VkBufferImageCopy image_copy = {}; - const VkImageAspectFlags aspect = Vulkan::Util::IsDepthFormat(static_cast(texture->GetFormat())) ? + const VkImageAspectFlags aspect = Vulkan::Util::IsDepthFormat(static_cast(tex->GetFormat())) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; image_copy.bufferOffset = 0; - image_copy.bufferRowLength = texture->CalcUpdateRowLength(pitch); + image_copy.bufferRowLength = tex->CalcUpdateRowLength(pitch); image_copy.bufferImageHeight = 0; image_copy.imageSubresource = {aspect, level, 0u, 1u}; image_copy.imageOffset = {static_cast(x), static_cast(y), 0}; @@ -349,8 +321,8 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); // do the copy - vkCmdCopyImageToBuffer(cmdbuf, texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_readback_staging_buffer, - 1, &image_copy); + vkCmdCopyImageToBuffer(cmdbuf, tex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_readback_staging_buffer, 1, + &image_copy); // flush gpu cache Vulkan::Util::BufferMemoryBarrier(cmdbuf, m_readback_staging_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, @@ -359,7 +331,7 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { - texture->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, old_layout); + tex->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, old_layout); } } @@ -674,7 +646,7 @@ bool VulkanHostDisplay::Render(bool skip_present) } bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) + GPUTexture::Format* out_format) { // in theory we could do this without a swap chain, but postprocessing assumes it for now... if (!m_swap_chain) @@ -685,26 +657,26 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector { case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_SRGB: - *out_format = HostDisplayPixelFormat::RGBA8; + *out_format = GPUTexture::Format::RGBA8; *out_stride = sizeof(u32) * width; out_pixels->resize(width * height); break; case VK_FORMAT_B8G8R8A8_UNORM: case VK_FORMAT_B8G8R8A8_SRGB: - *out_format = HostDisplayPixelFormat::BGRA8; + *out_format = GPUTexture::Format::BGRA8; *out_stride = sizeof(u32) * width; out_pixels->resize(width * height); break; case VK_FORMAT_A1R5G5B5_UNORM_PACK16: - *out_format = HostDisplayPixelFormat::RGBA5551; + *out_format = GPUTexture::Format::RGBA5551; *out_stride = sizeof(u16) * width; out_pixels->resize(((width * height) + 1) / 2); break; case VK_FORMAT_R5G6B5_UNORM_PACK16: - *out_format = HostDisplayPixelFormat::RGB565; + *out_format = GPUTexture::Format::RGB565; *out_stride = sizeof(u16) * width; out_pixels->resize(((width * height) + 1) / 2); break; @@ -746,22 +718,22 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector if (!m_post_processing_chain.IsEmpty()) { - ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, - m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, width, height); + ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, width, height); } else { BeginSwapChainRenderPass(fb, width, height); - RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, - m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(left, top, draw_width, draw_height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); } vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer()); Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer()); tex.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - DownloadTexture(&tex, *out_format, 0, 0, width, height, out_pixels->data(), *out_stride); + DownloadTexture(&tex, 0, 0, width, height, out_pixels->data(), *out_stride); // destroying these immediately should be safe since nothing's going to access them, and it's not part of the command // stream @@ -800,27 +772,27 @@ void VulkanHostDisplay::RenderDisplay() if (!m_post_processing_chain.IsEmpty()) { - ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height, m_display_texture_handle, - m_display_texture_width, m_display_texture_height, m_display_texture_view_x, + ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height, + static_cast(m_display_texture), m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); return; } BeginSwapChainRenderPass(m_swap_chain->GetCurrentFramebuffer(), m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); - RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height, - m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, - m_display_texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(left, top, width, height, static_cast(m_display_texture), m_display_texture_view_x, + m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, + IsUsingLinearFiltering()); } -void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, - s32 texture_height, s32 texture_view_x, s32 texture_view_y, - s32 texture_view_width, s32 texture_view_height, bool linear_filter) +void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, Vulkan::Texture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, + s32 texture_view_height, bool linear_filter) { VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); const Vulkan::Util::DebugScope debugScope( cmdbuffer, "VulkanHostDisplay::RenderDisplay: {%u,%u} %ux%u | %ux%u | {%u,%u} %ux%u", left, top, width, height, - texture_height, texture_width, texture_view_x, texture_view_y, texture_view_width, texture_view_height); + texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width, texture_view_height); VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_descriptor_set_layout); if (ds == VK_NULL_HANDLE) @@ -830,19 +802,19 @@ void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, } { - const Vulkan::Texture* vktex = static_cast(texture_handle); Vulkan::DescriptorSetUpdateBuilder dsupdate; dsupdate.AddCombinedImageSamplerDescriptorWrite( - ds, 0, vktex->GetView(), linear_filter ? m_linear_sampler : m_point_sampler, vktex->GetLayout()); + ds, 0, texture->GetView(), linear_filter ? m_linear_sampler : m_point_sampler, texture->GetLayout()); dsupdate.Update(g_vulkan_context->GetDevice()); } const float position_adjust = IsUsingLinearFiltering() ? 0.5f : 0.0f; const float size_adjust = IsUsingLinearFiltering() ? 1.0f : 0.0f; - const PushConstants pc{(static_cast(texture_view_x) + position_adjust) / static_cast(texture_width), - (static_cast(texture_view_y) + position_adjust) / static_cast(texture_height), - (static_cast(texture_view_width) - size_adjust) / static_cast(texture_width), - (static_cast(texture_view_height) - size_adjust) / static_cast(texture_height)}; + const PushConstants pc{ + (static_cast(texture_view_x) + position_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_y) + position_adjust) / static_cast(texture->GetHeight()), + (static_cast(texture_view_width) - size_adjust) / static_cast(texture->GetWidth()), + (static_cast(texture_view_height) - size_adjust) / static_cast(texture->GetHeight())}; vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_display_pipeline); vkCmdPushConstants(cmdbuffer, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pc), &pc); @@ -867,7 +839,7 @@ void VulkanHostDisplay::RenderSoftwareCursor() RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get()); } -void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture) +void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture) { VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); const Vulkan::Util::DebugScope debugScope(cmdbuffer, "VulkanHostDisplay::RenderSoftwareCursor: {%u,%u} %ux%u", left, @@ -882,8 +854,8 @@ void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 h { Vulkan::DescriptorSetUpdateBuilder dsupdate; - dsupdate.AddCombinedImageSamplerDescriptorWrite( - ds, 0, static_cast(texture)->GetTexture().GetView(), m_linear_sampler); + dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 0, static_cast(texture)->GetView(), + m_linear_sampler); dsupdate.Update(g_vulkan_context->GetDevice()); } @@ -1118,10 +1090,9 @@ bool VulkanHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t } void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top, - s32 final_width, s32 final_height, void* texture_handle, - u32 texture_width, s32 texture_height, s32 texture_view_x, - s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, - u32 target_width, u32 target_height) + s32 final_width, s32 final_height, Vulkan::Texture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, + s32 texture_view_height, u32 target_width, u32 target_height) { VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); const Vulkan::Util::DebugScope post_scope(cmdbuffer, "VulkanHostDisplay::ApplyPostProcessingChain"); @@ -1129,23 +1100,21 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi if (!CheckPostProcessingRenderTargets(target_width, target_height)) { BeginSwapChainRenderPass(target_fb, target_width, target_height); - RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height, - texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y, + texture_view_width, texture_view_height, IsUsingLinearFiltering()); return; } // downsample/upsample - use same viewport for remainder m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); BeginSwapChainRenderPass(m_post_processing_input_framebuffer, target_width, target_height); - RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height, - texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); + RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y, + texture_view_width, texture_view_height, IsUsingLinearFiltering()); vkCmdEndRenderPass(cmdbuffer); Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer()); m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - texture_handle = &m_post_processing_input_texture; - texture_width = m_post_processing_input_texture.GetWidth(); - texture_height = m_post_processing_input_texture.GetHeight(); + texture = &m_post_processing_input_texture; texture_view_x = final_left; texture_view_y = final_top; texture_view_width = final_width; @@ -1177,17 +1146,16 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi return; } - const Vulkan::Texture* vktex = static_cast(texture_handle); Vulkan::DescriptorSetUpdateBuilder dsupdate; - dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 1, vktex->GetView(), m_point_sampler, vktex->GetLayout()); + dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 1, texture->GetView(), m_point_sampler, texture->GetLayout()); if (use_push_constants) { u8 buffer[FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD]; Assert(pps.uniforms_size <= sizeof(buffer)); m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( - buffer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height, - GetWindowWidth(), GetWindowHeight(), 0.0f); + buffer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width, + texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f); vkCmdPushConstants(cmdbuffer, m_post_process_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, pps.uniforms_size, buffer); @@ -1206,8 +1174,8 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi const u32 offset = m_post_processing_ubo.GetCurrentOffset(); m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( - m_post_processing_ubo.GetCurrentHostPointer(), texture_width, texture_height, texture_view_x, texture_view_y, - texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f); + m_post_processing_ubo.GetCurrentHostPointer(), texture->GetWidth(), texture->GetHeight(), texture_view_x, + texture_view_y, texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f); m_post_processing_ubo.CommitMemory(pps.uniforms_size); dsupdate.AddBufferDescriptorWrite(ds, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, @@ -1226,7 +1194,7 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi vkCmdEndRenderPass(cmdbuffer); Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer()); pps.output_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - texture_handle = &pps.output_texture; + texture = &pps.output_texture; } } } diff --git a/src/frontend-common/vulkan_host_display.h b/src/frontend-common/vulkan_host_display.h index a9a57db91..1ed68646c 100644 --- a/src/frontend-common/vulkan_host_display.h +++ b/src/frontend-common/vulkan_host_display.h @@ -30,7 +30,7 @@ public: bool threaded_presentation) override; bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device, bool threaded_presentation) override; - + bool MakeRenderContextCurrent() override; bool DoneRenderContextCurrent() override; @@ -44,18 +44,21 @@ public: bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, - HostDisplayPixelFormat format, const void* data, u32 data_stride, - bool dynamic = false) override; - bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, - u32 height, void* out_data, u32 out_data_stride) override; - bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Format format, const void* data, u32 data_stride, + bool dynamic = false) override; + bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override; + void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override; + bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override; + bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) override; + bool SupportsTextureFormat(GPUTexture::Format format) const override; void SetVSync(bool enabled) override; bool Render(bool skip_present) override; bool RenderScreenshot(u32 width, u32 height, std::vector* out_pixels, u32* out_stride, - HostDisplayPixelFormat* out_format) override; + GPUTexture::Format* out_format) override; bool SetGPUTimingEnabled(bool enabled) override; float GetAndResetAccumulatedGPUTime() override; @@ -85,9 +88,8 @@ protected: bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); void ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top, s32 final_width, - s32 final_height, void* texture_handle, u32 texture_width, s32 texture_height, - s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, - u32 target_width, u32 target_height); + s32 final_height, Vulkan::Texture* texture, s32 texture_view_x, s32 texture_view_y, + s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height); VkRenderPass GetRenderPassForDisplay() const; @@ -106,10 +108,9 @@ protected: void RenderImGui(); void RenderSoftwareCursor(); - void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, - s32 texture_height, s32 texture_view_x, 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, HostDisplayTexture* texture_handle); + void RenderDisplay(s32 left, s32 top, s32 width, s32 height, Vulkan::Texture* texture, s32 texture_view_x, + 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_handle); std::unique_ptr m_swap_chain;