HostDisplay: Common texture base class for all APIs

This commit is contained in:
Connor McLaughlin 2022-10-03 16:44:34 +10:00
parent 12d400b76a
commit a9038133c8
50 changed files with 1428 additions and 1566 deletions

View File

@ -15,6 +15,8 @@ add_library(common
fifo_queue.h fifo_queue.h
file_system.cpp file_system.cpp
file_system.h file_system.h
gpu_texture.cpp
gpu_texture.h
image.cpp image.cpp
image.h image.h
hash_combine.h hash_combine.h

View File

@ -46,6 +46,7 @@
<ClInclude Include="gl\texture.h"> <ClInclude Include="gl\texture.h">
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
</ClInclude> </ClInclude>
<ClInclude Include="gpu_texture.h" />
<ClInclude Include="hash_combine.h" /> <ClInclude Include="hash_combine.h" />
<ClInclude Include="heap_array.h" /> <ClInclude Include="heap_array.h" />
<ClInclude Include="http_downloader.h" /> <ClInclude Include="http_downloader.h" />
@ -142,6 +143,7 @@
<ClCompile Include="gl\texture.cpp"> <ClCompile Include="gl\texture.cpp">
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="gpu_texture.cpp" />
<ClCompile Include="http_downloader.cpp" /> <ClCompile Include="http_downloader.cpp" />
<ClCompile Include="http_downloader_winhttp.cpp" /> <ClCompile Include="http_downloader_winhttp.cpp" />
<ClCompile Include="image.cpp" /> <ClCompile Include="image.cpp" />

View File

@ -129,6 +129,7 @@
<ClInclude Include="scoped_guard.h" /> <ClInclude Include="scoped_guard.h" />
<ClInclude Include="build_timestamp.h" /> <ClInclude Include="build_timestamp.h" />
<ClInclude Include="sha1_digest.h" /> <ClInclude Include="sha1_digest.h" />
<ClInclude Include="gpu_texture.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="gl\program.cpp"> <ClCompile Include="gl\program.cpp">
@ -233,6 +234,7 @@
<ClCompile Include="memory_settings_interface.cpp" /> <ClCompile Include="memory_settings_interface.cpp" />
<ClCompile Include="threading.cpp" /> <ClCompile Include="threading.cpp" />
<ClCompile Include="sha1_digest.cpp" /> <ClCompile Include="sha1_digest.cpp" />
<ClCompile Include="gpu_texture.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Natvis Include="bitfield.natvis" /> <Natvis Include="bitfield.natvis" />

View File

@ -1,38 +1,63 @@
#include "texture.h" #include "texture.h"
#include "../log.h" #include "../log.h"
#include <array>
Log_SetChannel(D3D11); Log_SetChannel(D3D11);
namespace D3D11 { static constexpr std::array<DXGI_FORMAT, static_cast<u32>(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<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, D3D11::Texture::Texture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
ComPtr<ID3D11RenderTargetView> rtv) ComPtr<ID3D11RenderTargetView> rtv)
: m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv(std::move(rtv)) : m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv(std::move(rtv))
{ {
const D3D11_TEXTURE2D_DESC desc = GetDesc(); const D3D11_TEXTURE2D_DESC desc = GetDesc();
m_width = static_cast<u16>(desc.Width); m_width = static_cast<u16>(desc.Width);
m_height = static_cast<u16>(desc.Height); m_height = static_cast<u16>(desc.Height);
m_layers = static_cast<u16>(desc.ArraySize); m_layers = static_cast<u8>(desc.ArraySize);
m_levels = static_cast<u8>(desc.MipLevels); m_levels = static_cast<u8>(desc.MipLevels);
m_samples = static_cast<u8>(desc.SampleDesc.Count); m_samples = static_cast<u8>(desc.SampleDesc.Count);
m_format = LookupBaseFormat(desc.Format);
m_dynamic = (desc.Usage == D3D11_USAGE_DYNAMIC);
} }
Texture::~Texture() D3D11::Texture::~Texture()
{ {
Destroy(); Destroy();
} }
D3D11_TEXTURE2D_DESC Texture::GetDesc() const DXGI_FORMAT D3D11::Texture::GetDXGIFormat(Format format)
{
return s_dxgi_mapping[static_cast<u8>(format)];
}
GPUTexture::Format D3D11::Texture::LookupBaseFormat(DXGI_FORMAT dformat)
{
for (u32 i = 0; i < static_cast<u32>(s_dxgi_mapping.size()); i++)
{
if (s_dxgi_mapping[i] == dformat)
return static_cast<Format>(i);
}
return GPUTexture::Format::Unknown;
}
D3D11_TEXTURE2D_DESC D3D11::Texture::GetDesc() const
{ {
D3D11_TEXTURE2D_DESC desc; D3D11_TEXTURE2D_DESC desc;
m_texture->GetDesc(&desc); m_texture->GetDesc(&desc);
return desc; return desc;
} }
bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, bool D3D11::Texture::IsValid() const
DXGI_FORMAT format, u32 bind_flags, const void* initial_data /* = nullptr */, {
u32 initial_data_stride /* = 0 */, bool dynamic /* = false */) return static_cast<bool>(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 || 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)) 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; 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, dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0,
samples, 0, 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_rtv = std::move(rtv);
m_width = static_cast<u16>(width); m_width = static_cast<u16>(width);
m_height = static_cast<u16>(height); m_height = static_cast<u16>(height);
m_layers = static_cast<u16>(layers); m_layers = static_cast<u8>(layers);
m_levels = static_cast<u8>(levels); m_levels = static_cast<u8>(levels);
m_samples = static_cast<u8>(samples); m_samples = static_cast<u8>(samples);
m_format = format;
m_dynamic = dynamic;
return true; return true;
} }
bool Texture::Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture) bool D3D11::Texture::Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture)
{ {
D3D11_TEXTURE2D_DESC desc; D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc); texture->GetDesc(&desc);
@ -140,22 +167,18 @@ bool Texture::Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture)
m_rtv = std::move(rtv); m_rtv = std::move(rtv);
m_width = static_cast<u16>(desc.Width); m_width = static_cast<u16>(desc.Width);
m_height = static_cast<u16>(desc.Height); m_height = static_cast<u16>(desc.Height);
m_layers = static_cast<u16>(desc.ArraySize); m_layers = static_cast<u8>(desc.ArraySize);
m_levels = static_cast<u8>(desc.MipLevels); m_levels = static_cast<u8>(desc.MipLevels);
m_samples = static_cast<u8>(desc.SampleDesc.Count); m_samples = static_cast<u8>(desc.SampleDesc.Count);
m_dynamic = (desc.Usage == D3D11_USAGE_DYNAMIC);
return true; return true;
} }
void Texture::Destroy() void D3D11::Texture::Destroy()
{ {
m_rtv.Reset(); m_rtv.Reset();
m_srv.Reset(); m_srv.Reset();
m_texture.Reset(); m_texture.Reset();
m_width = 0; m_dynamic = false;
m_height = 0; ClearBaseProperties();
m_layers = 0;
m_levels = 0;
m_samples = 0;
} }
} // namespace D3D11

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "../types.h" #include "../gpu_texture.h"
#include "../windows_headers.h" #include "../windows_headers.h"
#include <d3d11.h> #include <d3d11.h>
#include <wrl/client.h> #include <wrl/client.h>
namespace D3D11 { namespace D3D11 {
class Texture
class Texture final : public GPUTexture
{ {
public: public:
template<typename T> template<typename T>
@ -15,27 +16,27 @@ public:
Texture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, ComPtr<ID3D11RenderTargetView> rtv); Texture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, ComPtr<ID3D11RenderTargetView> rtv);
~Texture(); ~Texture();
static DXGI_FORMAT GetDXGIFormat(Format format);
static Format LookupBaseFormat(DXGI_FORMAT dformat);
ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); }
ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); }
ALWAYS_INLINE ID3D11RenderTargetView* GetD3DRTV() const { return m_rtv.Get(); } ALWAYS_INLINE ID3D11RenderTargetView* GetD3DRTV() const { return m_rtv.Get(); }
ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); } ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); }
ALWAYS_INLINE ID3D11RenderTargetView* const* GetD3DRTVArray() const { return m_rtv.GetAddressOf(); } ALWAYS_INLINE ID3D11RenderTargetView* const* GetD3DRTVArray() const { return m_rtv.GetAddressOf(); }
ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return GetDXGIFormat(m_format); }
ALWAYS_INLINE u16 GetWidth() const { return m_width; } ALWAYS_INLINE bool IsDynamic() const { return m_dynamic; }
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 operator ID3D11Texture2D*() const { return m_texture.Get(); } ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); }
ALWAYS_INLINE operator ID3D11ShaderResourceView*() const { return m_srv.Get(); } ALWAYS_INLINE operator ID3D11ShaderResourceView*() const { return m_srv.Get(); }
ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); } ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); }
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); } ALWAYS_INLINE operator bool() const { return static_cast<bool>(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); u32 bind_flags, const void* initial_data = nullptr, u32 initial_data_stride = 0, bool dynamic = false);
bool Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture); bool Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture);
@ -45,10 +46,7 @@ private:
ComPtr<ID3D11Texture2D> m_texture; ComPtr<ID3D11Texture2D> m_texture;
ComPtr<ID3D11ShaderResourceView> m_srv; ComPtr<ID3D11ShaderResourceView> m_srv;
ComPtr<ID3D11RenderTargetView> m_rtv; ComPtr<ID3D11RenderTargetView> m_rtv;
u16 m_width; bool m_dynamic = false;
u16 m_height;
u16 m_layers;
u8 m_levels;
u8 m_samples;
}; };
} // namespace D3D11 } // namespace D3D11

View File

@ -8,79 +8,111 @@
#include "util.h" #include "util.h"
Log_SetChannel(D3D12); Log_SetChannel(D3D12);
namespace D3D12 { static constexpr std::array<DXGI_FORMAT, static_cast<u32>(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(); const D3D12_RESOURCE_DESC desc = GetDesc();
m_width = static_cast<u32>(desc.Width); m_width = static_cast<u16>(desc.Width);
m_height = desc.Height; m_height = static_cast<u16>(desc.Height);
m_samples = desc.SampleDesc.Count; m_layers = static_cast<u8>(desc.DepthOrArraySize);
m_format = desc.Format; m_levels = static_cast<u8>(desc.MipLevels);
m_samples = static_cast<u8>(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_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_rtv_or_dsv_descriptor(texture.m_rtv_or_dsv_descriptor), m_is_depth_view(texture.m_is_depth_view)
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_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_srv_descriptor = {};
texture.m_rtv_or_dsv_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_state = D3D12_RESOURCE_STATE_COMMON;
texture.m_is_depth_view = false; texture.m_is_depth_view = false;
texture.ClearBaseProperties();
} }
Texture::~Texture() DXGI_FORMAT D3D12::Texture::GetDXGIFormat(Format format)
{
return s_dxgi_mapping[static_cast<u8>(format)];
}
GPUTexture::Format D3D12::Texture::LookupBaseFormat(DXGI_FORMAT dformat)
{
for (u32 i = 0; i < static_cast<u32>(s_dxgi_mapping.size()); i++)
{
if (s_dxgi_mapping[i] == dformat)
return static_cast<Format>(i);
}
return GPUTexture::Format::Unknown;
}
D3D12::Texture::~Texture()
{ {
Destroy(); Destroy();
} }
Texture& Texture::operator=(Texture&& texture) D3D12::Texture& D3D12::Texture::operator=(Texture&& texture)
{ {
Destroy(); 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_resource = std::move(texture.m_resource);
m_srv_descriptor = texture.m_srv_descriptor; m_srv_descriptor = texture.m_srv_descriptor;
m_rtv_or_dsv_descriptor = texture.m_rtv_or_dsv_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_state = texture.m_state;
m_is_depth_view = texture.m_is_depth_view; m_is_depth_view = texture.m_is_depth_view;
texture.ClearBaseProperties();
texture.m_srv_descriptor = {}; texture.m_srv_descriptor = {};
texture.m_rtv_or_dsv_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_state = D3D12_RESOURCE_STATE_COMMON;
texture.m_is_depth_view = false; texture.m_is_depth_view = false;
return *this; return *this;
} }
D3D12_RESOURCE_DESC Texture::GetDesc() const D3D12_RESOURCE_DESC D3D12::Texture::GetDesc() const
{ {
return m_resource->GetDesc(); return m_resource->GetDesc();
} }
bool Texture::Create(u32 width, u32 height, u32 samples, DXGI_FORMAT format, DXGI_FORMAT srv_format, bool D3D12::Texture::IsValid() const
DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags) {
return static_cast<bool>(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}; 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 = {}; D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Width = width; desc.Width = width;
desc.Height = height; desc.Height = static_cast<u16>(height);
desc.DepthOrArraySize = 1; desc.DepthOrArraySize = static_cast<u16>(layers);
desc.MipLevels = 1; desc.MipLevels = static_cast<u16>(levels);
desc.Format = format; desc.Format = format;
desc.SampleDesc.Count = samples; desc.SampleDesc.Count = samples;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; 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_resource = std::move(resource);
m_srv_descriptor = std::move(srv_descriptor); m_srv_descriptor = std::move(srv_descriptor);
m_rtv_or_dsv_descriptor = std::move(rtv_descriptor); m_rtv_or_dsv_descriptor = std::move(rtv_descriptor);
m_width = width; m_width = static_cast<u16>(width);
m_height = height; m_height = static_cast<u16>(height);
m_samples = samples; m_layers = static_cast<u8>(layers);
m_format = format; m_levels = static_cast<u8>(levels);
m_samples = static_cast<u8>(samples);
m_format = LookupBaseFormat(format);
m_state = state; m_state = state;
m_is_depth_view = is_depth_view; m_is_depth_view = is_depth_view;
return true; return true;
} }
bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, bool D3D12::Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state) DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state)
{ {
const D3D12_RESOURCE_DESC desc(texture->GetDesc()); const D3D12_RESOURCE_DESC desc(texture->GetDesc());
@ -168,6 +202,8 @@ bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI
return false; return false;
} }
m_is_depth_view = false;
if (rtv_format != DXGI_FORMAT_UNKNOWN) if (rtv_format != DXGI_FORMAT_UNKNOWN)
{ {
Assert(dsv_format == DXGI_FORMAT_UNKNOWN); Assert(dsv_format == DXGI_FORMAT_UNKNOWN);
@ -184,20 +220,24 @@ bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false; return false;
} }
m_is_depth_view = true;
} }
m_resource = std::move(texture); m_resource = std::move(texture);
m_srv_descriptor = std::move(srv_descriptor); m_srv_descriptor = std::move(srv_descriptor);
m_rtv_or_dsv_descriptor = std::move(rtv_descriptor); m_rtv_or_dsv_descriptor = std::move(rtv_descriptor);
m_width = static_cast<u32>(desc.Width); m_width = static_cast<u16>(desc.Width);
m_height = desc.Height; m_height = static_cast<u16>(desc.Height);
m_samples = desc.SampleDesc.Count; m_layers = static_cast<u8>(desc.DepthOrArraySize);
m_format = desc.Format; m_levels = static_cast<u8>(desc.MipLevels);
m_samples = static_cast<u8>(desc.SampleDesc.Count);
m_format = LookupBaseFormat(desc.Format);
m_state = state; m_state = state;
return true; return true;
} }
void Texture::Destroy(bool defer /* = true */) void D3D12::Texture::Destroy(bool defer /* = true */)
{ {
if (defer) if (defer)
{ {
@ -220,14 +260,11 @@ void Texture::Destroy(bool defer /* = true */)
m_resource.Reset(); m_resource.Reset();
} }
m_width = 0; ClearBaseProperties();
m_height = 0;
m_samples = 0;
m_format = DXGI_FORMAT_UNKNOWN;
m_is_depth_view = false; 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) if (m_state == state)
return; return;
@ -236,9 +273,9 @@ void Texture::TransitionToState(D3D12_RESOURCE_STATES state) const
m_state = state; 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; const u32 upload_size = copy_pitch * height;
if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) 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; 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; const u32 upload_size = copy_pitch * height;
StreamBuffer& sb = g_d3d12_context->GetTextureStreamBuffer(); 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); 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; D3D12_TEXTURE_COPY_LOCATION src;
src.pResource = buffer; 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.Height = height;
src.PlacedFootprint.Footprint.Depth = 1; src.PlacedFootprint.Footprint.Depth = 1;
src.PlacedFootprint.Footprint.RowPitch = pitch; src.PlacedFootprint.Footprint.RowPitch = pitch;
src.PlacedFootprint.Footprint.Format = m_format; src.PlacedFootprint.Footprint.Format = GetDXGIFormat();
D3D12_TEXTURE_COPY_LOCATION dst; D3D12_TEXTURE_COPY_LOCATION dst;
dst.pResource = m_resource.Get(); 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); 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_pitch = Common::AlignUpPow2(width * texel_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = upload_pitch * height; const u32 upload_size = upload_pitch * height;
if (upload_size >= g_d3d12_context->GetTextureStreamBuffer().GetSize()) if (upload_size >= g_d3d12_context->GetTextureStreamBuffer().GetSize())
{ {
StagingTexture st; 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; return false;
D3D12_RESOURCE_STATES old_state = m_state; 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; 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<const u8*>(src_data); const u8* src_ptr = static_cast<const u8*>(src_data);
u8* dst_ptr = static_cast<u8*>(dst_data); u8* dst_ptr = static_cast<u8*>(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)) if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh))
{ {
@ -362,7 +401,8 @@ bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format,
return true; 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)) if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh))
{ {
@ -377,7 +417,8 @@ bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format,
return true; 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)) 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); g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
return true; return true;
} }
} // namespace D3D12

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "../types.h" #include "../gpu_texture.h"
#include "../windows_headers.h" #include "../windows_headers.h"
#include "descriptor_heap_manager.h" #include "descriptor_heap_manager.h"
#include <d3d12.h> #include <d3d12.h>
@ -9,7 +9,7 @@ namespace D3D12 {
class StreamBuffer; class StreamBuffer;
class Texture final class Texture final : public GPUTexture
{ {
public: public:
template<typename T> template<typename T>
@ -21,21 +21,21 @@ public:
Texture(const Texture&) = delete; Texture(const Texture&) = delete;
~Texture(); ~Texture();
static DXGI_FORMAT GetDXGIFormat(Format format);
static Format LookupBaseFormat(DXGI_FORMAT dformat);
ALWAYS_INLINE ID3D12Resource* GetResource() const { return m_resource.Get(); } ALWAYS_INLINE ID3D12Resource* GetResource() const { return m_resource.Get(); }
ALWAYS_INLINE const DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; } ALWAYS_INLINE const DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
ALWAYS_INLINE const DescriptorHandle& GetRTVOrDSVDescriptor() const { return m_rtv_or_dsv_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 D3D12_RESOURCE_STATES GetState() const { return m_state; }
ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return GetDXGIFormat(m_format); }
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 operator ID3D12Resource*() const { return m_resource.Get(); } ALWAYS_INLINE operator ID3D12Resource*() const { return m_resource.Get(); }
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_resource); } ALWAYS_INLINE operator bool() const { return static_cast<bool>(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); DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags);
bool Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, bool Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format,
D3D12_RESOURCE_STATES state); D3D12_RESOURCE_STATES state);
@ -68,10 +68,6 @@ private:
ComPtr<ID3D12Resource> m_resource; ComPtr<ID3D12Resource> m_resource;
DescriptorHandle m_srv_descriptor = {}; DescriptorHandle m_srv_descriptor = {};
DescriptorHandle m_rtv_or_dsv_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; mutable D3D12_RESOURCE_STATES m_state = D3D12_RESOURCE_STATE_COMMON;

View File

@ -1,51 +1,78 @@
#include "texture.h" #include "texture.h"
#include "../assert.h" #include "../assert.h"
#include "../log.h" #include "../log.h"
#include <array>
#include <limits> #include <limits>
#include <tuple>
Log_SetChannel(GL); Log_SetChannel(GL);
namespace GL { const std::tuple<GLenum, GLenum, GLenum>& GL::Texture::GetPixelFormatMapping(GPUTexture::Format format)
static constexpr u32 MAX_DIMENSIONS = std::numeric_limits<u16>::max();
static constexpr u8 MAX_LEVELS = std::numeric_limits<u8>::max();
static constexpr u8 MAX_SAMPLES = std::numeric_limits<u8>::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)
{ {
moved.m_id = 0; static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(GPUTexture::Format::Count)> mapping =
moved.m_width = 0; {{
moved.m_height = 0; {}, // Unknown
moved.m_samples = 0; {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
moved.m_fbo_id = 0; {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<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(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<u32>(format)];
else
return mapping_gles2[static_cast<u32>(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(); 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); 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()); return UseTextureStorage(IsMultisampled());
} }
bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GLenum internal_format, GLenum format, bool GL::Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Format format,
GLenum type, const void* data /* = nullptr */, bool linear_filter /* = false */, const void* data /* = nullptr */, u32 data_pitch /* = 0 */, bool linear /* = true */,
bool wrap /* = false */) bool wrap /* = true */)
{ {
glGetError(); glGetError();
if (width > MAX_DIMENSIONS || height > MAX_DIMENSIONS || layers > MAX_DIMENSIONS || levels > MAX_DIMENSIONS || if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES)
samples > MAX_SAMPLES)
{ {
Log_ErrorPrintf("Invalid dimensions: %ux%ux%u %u %u", width, height, layers, levels, samples); Log_ErrorPrintf("Invalid dimensions: %ux%ux%u %u %u", width, height, layers, levels, samples);
return false; 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) : 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)); ((layers > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D));
const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(format);
GLuint id; GLuint id;
glGenTextures(1, &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 (UseTextureStorage(true))
{ {
if (layers > 1) 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 else
glTexStorage2DMultisample(target, samples, internal_format, width, height, GL_FALSE); glTexStorage2DMultisample(target, samples, gl_internal_format, width, height, GL_FALSE);
} }
else else
{ {
if (layers > 1) 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 else
glTexImage2DMultisample(target, samples, internal_format, width, height, GL_FALSE); glTexImage2DMultisample(target, samples, gl_internal_format, width, height, GL_FALSE);
} }
} }
else else
@ -93,17 +121,17 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
if (UseTextureStorage(false)) if (UseTextureStorage(false))
{ {
if (layers > 1) if (layers > 1)
glTexStorage3D(target, levels, internal_format, width, height, layers); glTexStorage3D(target, levels, gl_internal_format, width, height, layers);
else else
glTexStorage2D(target, levels, internal_format, width, height); glTexStorage2D(target, levels, gl_internal_format, width, height);
if (data) if (data)
{ {
// TODO: Fix data for mipmaps here. // TODO: Fix data for mipmaps here.
if (layers > 1) 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 else
glTexSubImage2D(target, 0, 0, 0, width, height, format, type, data); glTexSubImage2D(target, 0, 0, 0, width, height, gl_format, gl_type, data);
} }
} }
else else
@ -112,17 +140,17 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
{ {
// TODO: Fix data pointer here. // TODO: Fix data pointer here.
if (layers > 1) 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 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_BASE_LEVEL, 0);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels);
} }
glTexParameteri(target, GL_TEXTURE_MIN_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_filter ? 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_S, wrap ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, 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_id = id;
m_width = static_cast<u16>(width); m_width = static_cast<u16>(width);
m_height = static_cast<u16>(height); m_height = static_cast<u16>(height);
m_layers = static_cast<u16>(layers); m_layers = static_cast<u8>(layers);
m_levels = static_cast<u8>(levels); m_levels = static_cast<u8>(levels);
m_samples = static_cast<u8>(samples); m_samples = static_cast<u8>(samples);
m_format = format;
return true; 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 && Assert(IsValid() && width < MAX_WIDTH && height < MAX_HEIGHT && m_layers == 1 && m_samples == 1 && m_levels == 1);
m_levels == 1);
const bool size_changed = (width != m_width || height != m_height); 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()); 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); 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, void GL::Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type,
const void* data) const void* data)
{ {
Assert(IsValid() && !IsMultisampled()); 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); 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()); Assert(!IsMultisampled());
@ -220,7 +248,17 @@ void Texture::SetLinearFilter(bool enabled) const
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, enabled ? GL_LINEAR : GL_NEAREST); 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()) if (!IsValid())
return false; return false;
@ -244,7 +282,7 @@ bool Texture::CreateFramebuffer()
return true; return true;
} }
void Texture::Destroy() void GL::Texture::Destroy()
{ {
if (m_fbo_id != 0) if (m_fbo_id != 0)
{ {
@ -257,54 +295,46 @@ void Texture::Destroy()
m_id = 0; m_id = 0;
} }
m_width = 0; ClearBaseProperties();
m_height = 0;
m_layers = 0;
m_levels = 0;
m_samples = 0;
} }
void Texture::Bind() const void GL::Texture::Bind() const
{ {
glBindTexture(GetGLTarget(), m_id); 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); DebugAssert(m_fbo_id != 0);
glBindFramebuffer(target, m_fbo_id); glBindFramebuffer(target, m_fbo_id);
} }
void Texture::Unbind() const void GL::Texture::Unbind() const
{ {
glBindTexture(GetGLTarget(), 0); glBindTexture(GetGLTarget(), 0);
} }
Texture& Texture::operator=(Texture&& moved) GL::Texture& GL::Texture::operator=(Texture&& moved)
{ {
Destroy(); Destroy();
m_id = moved.m_id; m_id = moved.m_id;
m_fbo_id = moved.m_fbo_id;
m_width = moved.m_width; m_width = moved.m_width;
m_height = moved.m_height; m_height = moved.m_height;
m_layers = moved.m_layers; m_layers = moved.m_layers;
m_levels = moved.m_levels; m_levels = moved.m_levels;
m_samples = moved.m_samples; m_samples = moved.m_samples;
m_fbo_id = moved.m_fbo_id;
moved.m_id = 0; 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.m_fbo_id = 0;
moved.ClearBaseProperties();
return *this; return *this;
} }
void Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, 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 width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
GLsizei bufSize, void* pixels) GLsizei bufSize, void* pixels)
{ {
if (GLAD_GL_VERSION_4_5 || GLAD_GL_ARB_get_texture_sub_image) 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); glBindFramebuffer(target, old_read_fbo);
glDeleteFramebuffers(1, &temp_fbo); glDeleteFramebuffers(1, &temp_fbo);
} }
} // namespace GL

View File

@ -1,9 +1,11 @@
#pragma once #pragma once
#include "../types.h" #include "../gpu_texture.h"
#include "loader.h" #include "loader.h"
#include <tuple>
namespace GL { namespace GL {
class Texture
class Texture final : public GPUTexture
{ {
public: public:
Texture(); Texture();
@ -11,29 +13,25 @@ public:
~Texture(); ~Texture();
static bool UseTextureStorage(bool multisampled); static bool UseTextureStorage(bool multisampled);
static const std::tuple<GLenum, GLenum, GLenum>& 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 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 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, void ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type,
const void* data); const void* data);
bool CreateFramebuffer(); bool CreateFramebuffer();
void Destroy();
bool UseTextureStorage() const; bool UseTextureStorage() const;
void SetLinearFilter(bool enabled) const;
ALWAYS_INLINE bool IsValid() const { return m_id != 0; } void SetLinearFilter(bool enabled) const;
ALWAYS_INLINE bool IsTextureArray() const { return m_layers > 1; } void SetWrap(bool enabled) const;
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; }
ALWAYS_INLINE GLuint GetGLFramebufferID() const { return m_fbo_id; } ALWAYS_INLINE GLuint GetGLFramebufferID() const { return m_fbo_id; }
ALWAYS_INLINE GLenum GetGLTarget() const ALWAYS_INLINE GLenum GetGLTarget() const
@ -56,12 +54,6 @@ public:
private: private:
GLuint m_id = 0; 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; GLuint m_fbo_id = 0;
}; };

145
src/common/gpu_texture.cpp Normal file
View File

@ -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<u32>& 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<u32*>(reinterpret_cast<u8*>(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<u32> temp(width * height);
for (u32 y = 0; y < height; y++)
{
const u8* pixels_in = reinterpret_cast<u8*>(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<u32> temp(width * height);
for (u32 y = 0; y < height; y++)
{
const u8* pixels_in = reinterpret_cast<u8*>(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<u32>(format));
return false;
}
}
void GPUTexture::FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride)
{
std::vector<u32> 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);
}
}

68
src/common/gpu_texture.h Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include "types.h"
#include <algorithm>
#include <vector>
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<u32>(m_width >> level, 1u); }
ALWAYS_INLINE u32 GetMipHeight(u32 level) const { return std::max<u32>(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<u32>& texture_data, u32& texture_data_stride,
GPUTexture::Format format);
static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& 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;
};

View File

@ -8,22 +8,26 @@
#include <algorithm> #include <algorithm>
Log_SetChannel(Texture); Log_SetChannel(Texture);
static constexpr std::array<VkFormat, static_cast<u32>(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, static constexpr VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
Vulkan::Texture::Texture() = default; Vulkan::Texture::Texture() = default;
Vulkan::Texture::Texture(Texture&& move) 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_view_type(move.m_view_type), m_layout(move.m_layout), m_image(move.m_image), m_allocation(move.m_allocation),
m_format(move.m_format), m_samples(move.m_samples), m_view_type(move.m_view_type), m_layout(move.m_layout), m_view(move.m_view)
m_image(move.m_image), m_allocation(move.m_allocation), m_view(move.m_view)
{ {
move.m_width = 0; m_width = move.m_width;
move.m_height = 0; m_height = move.m_height;
move.m_levels = 0; m_layers = move.m_layers;
move.m_layers = 0; m_levels = move.m_levels;
move.m_format = VK_FORMAT_UNDEFINED; m_samples = move.m_samples;
move.m_samples = VK_SAMPLE_COUNT_1_BIT;
move.ClearBaseProperties();
move.m_view_type = VK_IMAGE_VIEW_TYPE_2D; move.m_view_type = VK_IMAGE_VIEW_TYPE_2D;
move.m_layout = VK_IMAGE_LAYOUT_UNDEFINED; move.m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
move.m_image = VK_NULL_HANDLE; move.m_image = VK_NULL_HANDLE;
@ -37,6 +41,26 @@ Vulkan::Texture::~Texture()
Destroy(true); Destroy(true);
} }
VkFormat Vulkan::Texture::GetVkFormat(Format format)
{
return s_vk_mapping[static_cast<u8>(format)];
}
GPUTexture::Format Vulkan::Texture::LookupBaseFormat(VkFormat vformat)
{
for (u32 i = 0; i < static_cast<u32>(s_vk_mapping.size()); i++)
{
if (s_vk_mapping[i] == vformat)
return static_cast<Format>(i);
}
return GPUTexture::Format::Unknown;
}
bool Vulkan::Texture::IsValid() const
{
return (m_image != VK_NULL_HANDLE);
}
Vulkan::Texture& Vulkan::Texture::operator=(Texture&& move) Vulkan::Texture& Vulkan::Texture::operator=(Texture&& move)
{ {
if (IsValid()) if (IsValid())
@ -129,12 +153,12 @@ bool Vulkan::Texture::Create(u32 width, u32 height, u32 levels, u32 layers, VkFo
if (IsValid()) if (IsValid())
Destroy(true); Destroy(true);
m_width = width; m_width = static_cast<u16>(width);
m_height = height; m_height = static_cast<u16>(height);
m_levels = levels; m_levels = static_cast<u8>(levels);
m_layers = layers; m_layers = static_cast<u8>(layers);
m_format = format; m_samples = static_cast<u8>(samples);
m_samples = samples; m_format = LookupBaseFormat(format);
m_view_type = view_type; m_view_type = view_type;
m_image = image; m_image = image;
m_allocation = allocation; m_allocation = allocation;
@ -171,12 +195,12 @@ bool Vulkan::Texture::Adopt(VkImage existing_image, VkImageViewType view_type, u
if (IsValid()) if (IsValid())
Destroy(true); Destroy(true);
m_width = width; m_width = static_cast<u16>(width);
m_height = height; m_height = static_cast<u16>(height);
m_levels = levels; m_levels = static_cast<u8>(levels);
m_layers = layers; m_layers = static_cast<u8>(layers);
m_format = format; m_format = LookupBaseFormat(format);
m_samples = samples; m_samples = static_cast<u8>(samples);
m_view_type = view_type; m_view_type = view_type;
m_image = existing_image; m_image = existing_image;
m_view = view; m_view = view;
@ -206,11 +230,7 @@ void Vulkan::Texture::Destroy(bool defer /* = true */)
m_allocation = VK_NULL_HANDLE; m_allocation = VK_NULL_HANDLE;
} }
m_width = 0; ClearBaseProperties();
m_height = 0;
m_levels = 0;
m_layers = 0;
m_format = VK_FORMAT_UNDEFINED;
m_samples = VK_SAMPLE_COUNT_1_BIT; m_samples = VK_SAMPLE_COUNT_1_BIT;
m_view_type = VK_IMAGE_VIEW_TYPE_2D; m_view_type = VK_IMAGE_VIEW_TYPE_2D;
m_layout = VK_IMAGE_LAYOUT_UNDEFINED; 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 srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image m_image, // VkImage image
{static_cast<VkImageAspectFlags>(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : {static_cast<VkImageAspectFlags>(IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
VK_IMAGE_ASPECT_COLOR_BIT),
start_level, num_levels, start_layer, num_layers} // VkImageSubresourceRange subresourceRange 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 u32 Vulkan::Texture::CalcUpdatePitch(u32 width) const
{ {
return Common::AlignUp(width * Vulkan::Util::GetTexelSize(m_format), return Common::AlignUp(width * GetPixelSize(), g_vulkan_context->GetBufferCopyRowPitchAlignment());
g_vulkan_context->GetBufferCopyRowPitchAlignment());
} }
u32 Vulkan::Texture::CalcUpdateRowLength(u32 pitch) const 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) bool Vulkan::Texture::BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch)

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "../types.h" #include "../gpu_texture.h"
#include "loader.h" #include "loader.h"
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
namespace Vulkan { namespace Vulkan {
class Texture
class Texture final : public GPUTexture
{ {
public: public:
Texture(); Texture();
@ -16,7 +17,10 @@ public:
Texture& operator=(Texture&& move); Texture& operator=(Texture&& move);
Texture& operator=(const Texture&) = delete; 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. /// An image is considered owned/managed if we control the memory.
ALWAYS_INLINE bool IsOwned() const { return (m_allocation != VK_NULL_HANDLE); } 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 GetHeight() const { return m_height; }
ALWAYS_INLINE u32 GetLevels() const { return m_levels; } ALWAYS_INLINE u32 GetLevels() const { return m_levels; }
ALWAYS_INLINE u32 GetLayers() const { return m_layers; } ALWAYS_INLINE u32 GetLayers() const { return m_layers; }
ALWAYS_INLINE u32 GetMipWidth(u32 level) const { return std::max<u32>(m_width >> level, 1u); }
ALWAYS_INLINE u32 GetMipHeight(u32 level) const { return std::max<u32>(m_height >> level, 1u); } ALWAYS_INLINE VkFormat GetVkFormat() const { return GetVkFormat(m_format); }
ALWAYS_INLINE VkFormat GetFormat() const { return m_format; } ALWAYS_INLINE VkSampleCountFlagBits GetVkSamples() const { return static_cast<VkSampleCountFlagBits>(m_samples); }
ALWAYS_INLINE VkSampleCountFlagBits GetSamples() const { return m_samples; }
ALWAYS_INLINE VkImageLayout GetLayout() const { return m_layout; } ALWAYS_INLINE VkImageLayout GetLayout() const { return m_layout; }
ALWAYS_INLINE VkImageViewType GetViewType() const { return m_view_type; } ALWAYS_INLINE VkImageViewType GetViewType() const { return m_view_type; }
ALWAYS_INLINE VkImage GetImage() const { return m_image; } 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); bool Update(u32 x, u32 y, u32 width, u32 height, u32 level, u32 layer, const void* data, u32 data_pitch);
private: 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; VkImageViewType m_view_type = VK_IMAGE_VIEW_TYPE_2D;
VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;

View File

@ -163,7 +163,7 @@ void GPU::SoftReset()
UpdateGPUIdle(); 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()) if (sw.IsReading())
{ {

View File

@ -15,7 +15,7 @@
class StateWrapper; class StateWrapper;
class HostDisplay; class HostDisplay;
class HostDisplayTexture; class GPUTexture;
class TimingEvent; class TimingEvent;
class Timers; class Timers;
@ -83,7 +83,7 @@ public:
virtual bool Initialize(); virtual bool Initialize();
virtual void Reset(bool clear_vram); 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. // Graphics API state reset/restore - call when drawing the UI etc.
virtual void ResetGraphicsAPIState(); virtual void ResetGraphicsAPIState();

View File

@ -123,7 +123,7 @@ void GPU_HW::Reset(bool clear_vram)
SetFullVRAMDirtyRectangle(); 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)) if (!GPU::DoState(sw, host_texture, update_display))
return false; return false;

View File

@ -37,7 +37,7 @@ public:
virtual bool Initialize() override; virtual bool Initialize() override;
virtual void Reset(bool clear_vram) 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; void UpdateResolutionScale() override final;
std::tuple<u32, u32> GetEffectiveDisplayResolution(bool scaled = true) override final; std::tuple<u32, u32> GetEffectiveDisplayResolution(bool scaled = true) override final;

View File

@ -99,13 +99,13 @@ void GPU_HW_D3D11::Reset(bool clear_vram)
ClearFramebuffer(); 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) if (host_texture)
{ {
ComPtr<ID3D11Resource> resource; ComPtr<ID3D11Resource> resource;
HostDisplayTexture* tex = *host_texture; D3D11::Texture* tex = static_cast<D3D11::Texture*>(*host_texture);
if (sw.IsReading()) if (sw.IsReading())
{ {
if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || 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; return false;
} }
static_cast<ID3D11ShaderResourceView*>(tex->GetHandle())->GetResource(resource.GetAddressOf()); m_context->CopySubresourceRegion(m_vram_texture.GetD3DTexture(), 0, 0, 0, 0, tex->GetD3DTexture(), 0, nullptr);
m_context->CopySubresourceRegion(m_vram_texture.GetD3DTexture(), 0, 0, 0, 0, resource.Get(), 0, nullptr);
} }
else else
{ {
@ -124,17 +123,17 @@ bool GPU_HW_D3D11::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{ {
delete tex; delete tex;
tex = g_host_display tex = static_cast<D3D11::Texture*>(g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) 1, m_vram_texture.GetSamples(), GPUTexture::Format::RGBA8,
.release(); nullptr, 0, false)
.release());
*host_texture = tex; *host_texture = tex;
if (!tex) if (!tex)
return false; return false;
} }
static_cast<ID3D11ShaderResourceView*>(tex->GetHandle())->GetResource(resource.GetAddressOf()); m_context->CopySubresourceRegion(tex->GetD3DTexture(), 0, 0, 0, 0, m_vram_texture.GetD3DTexture(), 0, nullptr);
m_context->CopySubresourceRegion(resource.Get(), 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 // scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale; const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
const u32 texture_height = VRAM_HEIGHT * m_resolution_scale; const u32 texture_height = VRAM_HEIGHT * m_resolution_scale;
const u16 samples = static_cast<u16>(m_multisamples); const u8 samples = static_cast<u8>(m_multisamples);
const DXGI_FORMAT texture_format = DXGI_FORMAT_R8G8B8A8_UNORM; const GPUTexture::Format texture_format = GPUTexture::Format::RGBA8;
const DXGI_FORMAT depth_format = DXGI_FORMAT_D16_UNORM; 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, 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) || D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) ||
@ -275,8 +274,9 @@ bool GPU_HW_D3D11::CreateFramebuffer()
return false; return false;
} }
const CD3D11_DEPTH_STENCIL_VIEW_DESC depth_view_desc( const CD3D11_DEPTH_STENCIL_VIEW_DESC depth_view_desc(samples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS :
samples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D, depth_format); D3D11_DSV_DIMENSION_TEXTURE2D,
D3D11::Texture::GetDXGIFormat(depth_format));
HRESULT hr = HRESULT hr =
m_device->CreateDepthStencilView(m_vram_depth_texture, &depth_view_desc, m_vram_depth_view.GetAddressOf()); m_device->CreateDepthStencilView(m_vram_depth_texture, &depth_view_desc, m_vram_depth_view.GetAddressOf());
if (FAILED(hr)) 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<u16>(levels), 1, if (!m_downsample_texture.Create(m_device.Get(), texture_width, texture_height, 1, static_cast<u16>(levels), 1,
texture_format, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) || texture_format, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) ||
!m_downsample_weight_texture.Create(m_device.Get(), texture_width >> (levels - 1), !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)) D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET))
{ {
return false; return false;
@ -299,9 +299,9 @@ bool GPU_HW_D3D11::CreateFramebuffer()
for (u32 i = 0; i < levels; i++) for (u32 i = 0; i < levels; i++)
{ {
const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(m_downsample_texture, D3D11_SRV_DIMENSION_TEXTURE2D, const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(m_downsample_texture, D3D11_SRV_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, texture_format, const CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(m_downsample_texture, D3D11_RTV_DIMENSION_TEXTURE2D,
i, 1); m_downsample_texture.GetDXGIFormat(), i, 1);
hr = m_device->CreateShaderResourceView(m_downsample_texture, &srv_desc, hr = m_device->CreateShaderResourceView(m_downsample_texture, &srv_desc,
m_downsample_mip_views[i].first.GetAddressOf()); 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()) m_vram_replacement_texture.GetHeight() < tex->GetHeight())
{ {
if (!m_vram_replacement_texture.Create(m_device.Get(), tex->GetWidth(), tex->GetHeight(), 1, 1, 1, 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)) tex->GetPitch(), true))
{ {
return false; return false;
@ -841,15 +841,12 @@ void GPU_HW_D3D11::UpdateDisplay()
if (IsUsingMultisampling()) if (IsUsingMultisampling())
{ {
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, 0, m_vram_read_texture.GetWidth(),
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, m_vram_read_texture.GetHeight());
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight());
} }
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
@ -889,8 +886,7 @@ void GPU_HW_D3D11::UpdateDisplay()
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y,
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
} }
} }
@ -916,15 +912,9 @@ void GPU_HW_D3D11::UpdateDisplay()
DrawUtilityShader(display_pixel_shader, uniforms, sizeof(uniforms)); DrawUtilityShader(display_pixel_shader, uniforms, sizeof(uniforms));
if (IsUsingDownsampling()) if (IsUsingDownsampling())
{
DownsampleFramebuffer(m_display_texture, 0, 0, scaled_display_width, scaled_display_height); DownsampleFramebuffer(m_display_texture, 0, 0, scaled_display_width, scaled_display_height);
}
else else
{ g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height);
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);
}
RestoreGraphicsAPIState(); 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)); DrawUtilityShader(m_vram_read_pixel_shader.Get(), uniforms, sizeof(uniforms));
// Stage the readback and copy it into our shadow buffer. // Stage the readback and copy it into our shadow buffer.
g_host_display->DownloadTexture( g_host_display->DownloadTexture(&m_vram_encoding_texture, 0, 0, encoded_width, encoded_height,
&m_vram_encoding_texture, HostDisplayPixelFormat::RGBA8, 0, 0, encoded_width, encoded_height, reinterpret_cast<u32*>(&m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left]),
reinterpret_cast<u32*>(&m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left]), VRAM_WIDTH * sizeof(u16)); VRAM_WIDTH * sizeof(u16));
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
} }
@ -1080,7 +1070,7 @@ void GPU_HW_D3D11::UpdateVRAMReadTexture()
if (m_vram_texture.IsMultisampled()) if (m_vram_texture.IsMultisampled())
{ {
m_context->ResolveSubresource(m_vram_read_texture.GetD3DTexture(), 0, m_vram_texture.GetD3DTexture(), 0, m_context->ResolveSubresource(m_vram_read_texture.GetD3DTexture(), 0, m_vram_texture.GetD3DTexture(), 0,
m_vram_texture.GetFormat()); m_vram_texture.GetDXGIFormat());
} }
else else
{ {
@ -1191,8 +1181,7 @@ void GPU_HW_D3D11::DownsampleFramebufferAdaptive(D3D11::Texture& source, u32 lef
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_display_texture, left, top, width, height);
m_display_texture.GetHeight(), left, top, width, height);
} }
void GPU_HW_D3D11::DownsampleFramebufferBoxFilter(D3D11::Texture& source, u32 left, u32 top, u32 width, u32 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(); RestoreGraphicsAPIState();
g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height);
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top,
ds_width, ds_height);
} }
std::unique_ptr<GPU> GPU::CreateHardwareD3D11Renderer() std::unique_ptr<GPU> GPU::CreateHardwareD3D11Renderer()

View File

@ -23,7 +23,7 @@ public:
bool Initialize() override; bool Initialize() override;
void Reset(bool clear_vram) 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 ResetGraphicsAPIState() override;
void RestoreGraphicsAPIState() override; void RestoreGraphicsAPIState() override;

View File

@ -319,16 +319,16 @@ bool GPU_HW_D3D12::CreateFramebuffer()
const DXGI_FORMAT texture_format = DXGI_FORMAT_R8G8B8A8_UNORM; const DXGI_FORMAT texture_format = DXGI_FORMAT_R8G8B8A8_UNORM;
const DXGI_FORMAT depth_format = DXGI_FORMAT_D16_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) || texture_format, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ||
!m_vram_depth_texture.Create( !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) || 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, !m_vram_read_texture.Create(texture_width, texture_height, 1, 1, 1, texture_format, texture_format,
DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE) || 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_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) || 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) || DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ||
!m_vram_readback_staging_texture.Create(VRAM_WIDTH / 2, VRAM_HEIGHT, texture_format, false)) !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<GPUTextureMode>(texture_mode) != GPUTextureMode::Disabled); const bool textured = (static_cast<GPUTextureMode>(texture_mode) != GPUTextureMode::Disabled);
gpbuilder.SetRootSignature(m_batch_root_signature.Get()); gpbuilder.SetRootSignature(m_batch_root_signature.Get());
gpbuilder.SetRenderTarget(0, m_vram_texture.GetFormat()); gpbuilder.SetRenderTarget(0, m_vram_texture.GetDXGIFormat());
gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetFormat()); gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetDXGIFormat());
gpbuilder.AddVertexAttribute("ATTR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(BatchVertex, x)); gpbuilder.AddVertexAttribute("ATTR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(BatchVertex, x));
gpbuilder.AddVertexAttribute("ATTR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(BatchVertex, color)); gpbuilder.AddVertexAttribute("ATTR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(BatchVertex, color));
@ -547,16 +547,16 @@ bool GPU_HW_D3D12::CompilePipelines()
// common state // common state
gpbuilder.SetRootSignature(m_single_sampler_root_signature.Get()); gpbuilder.SetRootSignature(m_single_sampler_root_signature.Get());
gpbuilder.SetRenderTarget(0, m_vram_texture.GetFormat()); gpbuilder.SetRenderTarget(0, m_vram_texture.GetDXGIFormat());
gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetFormat()); gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetDXGIFormat());
gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE); gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
gpbuilder.SetNoCullRasterizationState(); gpbuilder.SetNoCullRasterizationState();
gpbuilder.SetNoDepthTestState(); gpbuilder.SetNoDepthTestState();
gpbuilder.SetNoBlendingState(); gpbuilder.SetNoBlendingState();
gpbuilder.SetVertexShader(fullscreen_quad_vertex_shader.Get()); gpbuilder.SetVertexShader(fullscreen_quad_vertex_shader.Get());
gpbuilder.SetMultisamples(m_multisamples); gpbuilder.SetMultisamples(m_multisamples);
gpbuilder.SetRenderTarget(0, m_vram_texture.GetFormat()); gpbuilder.SetRenderTarget(0, m_vram_texture.GetDXGIFormat());
gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetFormat()); gpbuilder.SetDepthStencilFormat(m_vram_depth_texture.GetDXGIFormat());
// VRAM fill // VRAM fill
for (u8 wrapped = 0; wrapped < 2; wrapped++) for (u8 wrapped = 0; wrapped < 2; wrapped++)
@ -663,7 +663,7 @@ bool GPU_HW_D3D12::CompilePipelines()
gpbuilder.SetNoCullRasterizationState(); gpbuilder.SetNoCullRasterizationState();
gpbuilder.SetNoDepthTestState(); gpbuilder.SetNoDepthTestState();
gpbuilder.SetNoBlendingState(); gpbuilder.SetNoBlendingState();
gpbuilder.SetRenderTarget(0, m_vram_readback_texture.GetFormat()); gpbuilder.SetRenderTarget(0, m_vram_readback_texture.GetDXGIFormat());
gpbuilder.ClearDepthStencilFormat(); gpbuilder.ClearDepthStencilFormat();
m_vram_readback_pipeline = gpbuilder.Create(g_d3d12_context->GetDevice(), shader_cache, false); 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.SetNoCullRasterizationState();
gpbuilder.SetNoDepthTestState(); gpbuilder.SetNoDepthTestState();
gpbuilder.SetNoBlendingState(); 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++) 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() || if (m_vram_write_replacement_texture.GetWidth() < tex->GetWidth() ||
m_vram_write_replacement_texture.GetHeight() < tex->GetHeight()) 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, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
D3D12_RESOURCE_FLAG_NONE)) D3D12_RESOURCE_FLAG_NONE))
{ {
@ -867,16 +867,13 @@ void GPU_HW_D3D12::UpdateDisplay()
if (IsUsingMultisampling()) if (IsUsingMultisampling())
{ {
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, 0, m_vram_read_texture.GetWidth(),
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, m_vram_read_texture.GetHeight());
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
} }
else else
{ {
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight());
} }
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
@ -908,8 +905,7 @@ void GPU_HW_D3D12::UpdateDisplay()
(scaled_vram_offset_y + scaled_display_height) <= m_vram_texture.GetHeight()) (scaled_vram_offset_y + scaled_display_height) <= m_vram_texture.GetHeight())
{ {
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y,
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
} }
else else
@ -936,9 +932,7 @@ void GPU_HW_D3D12::UpdateDisplay()
m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height);
m_display_texture.GetHeight(), 0, 0, scaled_display_width,
scaled_display_height);
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
} }
@ -1150,7 +1144,7 @@ void GPU_HW_D3D12::UpdateVRAMReadTexture()
{ {
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RESOLVE_SOURCE); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
m_vram_read_texture.TransitionToState(D3D12_RESOURCE_STATE_RESOLVE_DEST); 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 else
{ {

View File

@ -108,11 +108,11 @@ void GPU_HW_OpenGL::Reset(bool clear_vram)
ClearFramebuffer(); 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) if (host_texture)
{ {
HostDisplayTexture* tex = *host_texture; GPUTexture* tex = *host_texture;
if (sw.IsReading()) if (sw.IsReading())
{ {
if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || 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; return false;
} }
CopyFramebufferForState( CopyFramebufferForState(m_vram_texture.GetGLTarget(), static_cast<GL::Texture*>(tex)->GetGLId(), 0, 0, 0,
m_vram_texture.GetGLTarget(), static_cast<GLuint>(reinterpret_cast<uintptr_t>(tex->GetHandle())), 0, 0, 0, m_vram_texture.GetGLId(), m_vram_fbo_id, 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetGLId(), m_vram_fbo_id, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); m_vram_texture.GetHeight());
} }
else else
{ {
@ -134,7 +134,7 @@ bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
tex = g_host_display tex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, ->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(); .release();
*host_texture = tex; *host_texture = tex;
if (!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, CopyFramebufferForState(m_vram_texture.GetGLTarget(), m_vram_texture.GetGLId(), m_vram_fbo_id, 0, 0,
static_cast<GLuint>(reinterpret_cast<uintptr_t>(tex->GetHandle())), 0, 0, 0, static_cast<GL::Texture*>(tex)->GetGLId(), 0, 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); m_vram_texture.GetHeight());
} }
} }
@ -285,17 +285,11 @@ void GPU_HW_OpenGL::UnmapBatchVertexPointer(u32 used_vertices)
DebugAssert(m_batch_start_vertex_ptr); DebugAssert(m_batch_start_vertex_ptr);
m_vertex_stream_buffer->Unmap(used_vertices * sizeof(BatchVertex)); m_vertex_stream_buffer->Unmap(used_vertices * sizeof(BatchVertex));
m_vertex_stream_buffer->Bind();
m_batch_start_vertex_ptr = nullptr; m_batch_start_vertex_ptr = nullptr;
m_batch_end_vertex_ptr = nullptr; m_batch_end_vertex_ptr = nullptr;
m_batch_current_vertex_ptr = nullptr; m_batch_current_vertex_ptr = nullptr;
} }
std::tuple<s32, s32> GPU_HW_OpenGL::ConvertToFramebufferCoordinates(s32 x, s32 y)
{
return std::make_tuple(x, static_cast<s32>(static_cast<s32>(VRAM_HEIGHT) - y));
}
void GPU_HW_OpenGL::SetCapabilities() void GPU_HW_OpenGL::SetCapabilities()
{ {
GLint max_texture_size = VRAM_WIDTH; 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 texture_height = VRAM_HEIGHT * m_resolution_scale;
const u32 multisamples = m_multisamples; const u32 multisamples = m_multisamples;
if (!m_vram_texture.Create(texture_width, texture_height, 1, 1, multisamples, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, if (!m_vram_texture.Create(texture_width, texture_height, 1, 1, multisamples, GPUTexture::Format::RGBA8, nullptr, 0,
nullptr, false, true) || true, true) ||
!m_vram_depth_texture.Create(texture_width, texture_height, 1, 1, multisamples, GL_DEPTH_COMPONENT16, !m_vram_depth_texture.Create(texture_width, texture_height, 1, 1, multisamples, GPUTexture::Format::D16, nullptr,
GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr, false) || 0, false, true) ||
!m_vram_read_texture.Create(texture_width, texture_height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, !m_vram_read_texture.Create(texture_width, texture_height, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0, false,
false, true) || true) ||
!m_vram_read_texture.CreateFramebuffer() || !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, !m_vram_encoding_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0, false,
false) || true) ||
!m_vram_encoding_texture.CreateFramebuffer() || !m_vram_encoding_texture.CreateFramebuffer() ||
!m_display_texture.Create(GPU_MAX_DISPLAY_WIDTH * m_resolution_scale, GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, !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()) !m_display_texture.CreateFramebuffer())
{ {
return false; return false;
@ -425,7 +419,7 @@ bool GPU_HW_OpenGL::CreateFramebuffer()
if (m_downsample_mode == GPUDownsampleMode::Box) 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()) !m_downsample_texture.CreateFramebuffer())
{ {
return false; 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.IsValid())
{ {
if (!m_vram_write_replacement_texture.Create(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GL_RGBA8, GL_RGBA, if (!m_vram_write_replacement_texture.Create(tex->GetWidth(), tex->GetHeight(), 1, 1, 1,
GL_UNSIGNED_BYTE, tex->GetPixels(), true) || GPUTexture::Format::RGBA8) ||
!m_vram_write_replacement_texture.CreateFramebuffer()) !m_vram_write_replacement_texture.CreateFramebuffer())
{ {
m_vram_write_replacement_texture.Destroy(); m_vram_write_replacement_texture.Destroy();
@ -795,7 +789,6 @@ bool GPU_HW_OpenGL::BlitVRAMReplacementTexture(const TextureReplacementTexture*
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
m_vram_write_replacement_texture.BindFramebuffer(GL_READ_FRAMEBUFFER); 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, glBlitFramebuffer(0, tex->GetHeight(), tex->GetWidth(), 0, dst_x, dst_y, dst_x + width, dst_y + height,
GL_COLOR_BUFFER_BIT, GL_LINEAR); GL_COLOR_BUFFER_BIT, GL_LINEAR);
@ -826,7 +819,7 @@ void GPU_HW_OpenGL::SetScissorFromDrawingArea()
const int width = right - left; const int width = right - left;
const int height = bottom - top; const int height = bottom - top;
const int x = left; 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); Log_DebugPrintf("SetScissor: (%d-%d, %d-%d)", x, x + width, y, y + height);
glScissor(x, y, width, height); glScissor(x, y, width, height);
@ -867,16 +860,13 @@ void GPU_HW_OpenGL::UpdateDisplay()
{ {
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
g_host_display->SetDisplayTexture( g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, m_vram_read_texture.GetHeight(),
&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, m_vram_read_texture.GetWidth(), m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
static_cast<s32>(m_vram_read_texture.GetHeight()), 0, m_vram_read_texture.GetHeight(),
m_vram_read_texture.GetWidth(), -static_cast<s32>(m_vram_read_texture.GetHeight()));
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, 0, m_vram_texture.GetHeight(), m_vram_texture.GetWidth(),
static_cast<s32>(m_vram_texture.GetHeight()), 0, m_vram_texture.GetHeight(), m_vram_texture.GetHeight());
m_vram_texture.GetWidth(), -static_cast<s32>(m_vram_texture.GetHeight()));
} }
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
@ -914,10 +904,8 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y,
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_display_width, scaled_display_height);
m_vram_texture.GetHeight() - scaled_vram_offset_y, scaled_display_width,
-static_cast<s32>(scaled_display_height));
} }
} }
else else
@ -936,14 +924,11 @@ void GPU_HW_OpenGL::UpdateDisplay()
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast<GLsizei>(attachments.size()), attachments.data()); glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast<GLsizei>(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 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_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 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, const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
reinterpret_field_offset}; reinterpret_crop_left, reinterpret_field_offset};
UploadUniformBuffer(uniforms, sizeof(uniforms)); UploadUniformBuffer(uniforms, sizeof(uniforms));
m_batch_ubo_dirty = true; m_batch_ubo_dirty = true;
@ -960,10 +945,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height);
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0,
scaled_display_height, scaled_display_width,
-static_cast<s32>(scaled_display_height));
} }
// restore state // 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(); const u32 encoded_height = copy_rect.GetHeight();
// Encode the 24-bit texture as 16-bit. // 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(), const u32 uniforms[4] = {copy_rect.left, copy_rect.top, copy_rect.GetWidth(), copy_rect.GetHeight()};
copy_rect.GetHeight()};
m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture.Bind(); m_vram_texture.Bind();
m_vram_read_program.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); GPU_HW::FillVRAM(x, y, width, height, color);
const Common::Rectangle<u32> bounds(GetVRAMTransferBounds(x, y, width, height)); const Common::Rectangle<u32> bounds(GetVRAMTransferBounds(x, y, width, height));
glScissor(bounds.left * m_resolution_scale, glScissor(bounds.left * m_resolution_scale, bounds.top * m_resolution_scale, width * m_resolution_scale,
m_vram_texture.GetHeight() - (bounds.top * m_resolution_scale) - (height * m_resolution_scale), height * m_resolution_scale);
width * m_resolution_scale, height * m_resolution_scale);
// fast path when not using interlaced rendering // fast path when not using interlaced rendering
const bool wrapped = IsVRAMFillOversized(x, y, width, height); 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 // the viewport should already be set to the full vram, so just adjust the scissor
const Common::Rectangle<u32> scaled_bounds = bounds * m_resolution_scale; const Common::Rectangle<u32> scaled_bounds = bounds * m_resolution_scale;
glScissor(scaled_bounds.left, m_vram_texture.GetHeight() - scaled_bounds.top - scaled_bounds.GetHeight(), glScissor(scaled_bounds.left, scaled_bounds.top, scaled_bounds.GetWidth(), scaled_bounds.GetHeight());
scaled_bounds.GetWidth(), scaled_bounds.GetHeight());
glBindVertexArray(m_attributeless_vao_id); glBindVertexArray(m_attributeless_vao_id);
glDrawArrays(GL_TRIANGLES, 0, 3); 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)); 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 u32 source_stride = width * sizeof(u16);
const u8* source_ptr = static_cast<const u8*>(data) + (source_stride * (height - 1)); const u8* source_ptr = static_cast<const u8*>(data);
const u16 mask_or = set_mask ? 0x8000 : 0x0000; const u16 mask_or = set_mask ? 0x8000 : 0x0000;
u32* dest_ptr = static_cast<u32*>(map_result.pointer); u32* dest_ptr = static_cast<u32*>(map_result.pointer);
for (u32 row = 0; row < height; row++) 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); *(dest_ptr++) = VRAMRGBA5551ToRGBA8888(src_col | mask_or);
} }
source_ptr -= source_stride; source_ptr += source_stride;
} }
m_texture_stream_buffer->Unmap(num_pixels * sizeof(u32)); 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 else
m_vram_texture.Bind(); m_vram_texture.Bind();
// lower-left origin flip happens here
const u32 flipped_y = VRAM_HEIGHT - y - height;
// update texture data // 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<void*>(static_cast<uintptr_t>(map_result.buffer_offset))); reinterpret_cast<void*>(static_cast<uintptr_t>(map_result.buffer_offset)));
m_texture_stream_buffer->Unbind(); 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_height = height * m_resolution_scale;
const u32 scaled_x = x * m_resolution_scale; const u32 scaled_x = x * m_resolution_scale;
const u32 scaled_y = y * 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); glDisable(GL_SCISSOR_TEST);
m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y, glBlitFramebuffer(x, y, x + width, y + height, scaled_x, scaled_y, scaled_x + scaled_width,
scaled_x + scaled_width, scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); scaled_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); 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(); UpdateVRAMReadTexture();
IncludeVRAMDirtyRectangle(dst_bounds); IncludeVRAMDirtyRectangle(dst_bounds);
VRAMCopyUBOData uniforms = GetVRAMCopyUBOData(src_x, src_y, dst_x, dst_y, width, height); const 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;
UploadUniformBuffer(&uniforms, sizeof(uniforms)); UploadUniformBuffer(&uniforms, sizeof(uniforms));
glDisable(GL_SCISSOR_TEST); 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); SetDepthFunc((m_GPUSTAT.check_mask_before_draw && !m_pgxp_depth_buffer) ? GL_GEQUAL : GL_ALWAYS);
const Common::Rectangle<u32> dst_bounds_scaled(dst_bounds * m_resolution_scale); const Common::Rectangle<u32> dst_bounds_scaled(dst_bounds * m_resolution_scale);
glViewport(dst_bounds_scaled.left, glViewport(dst_bounds_scaled.left, dst_bounds_scaled.top, dst_bounds_scaled.GetWidth(),
m_vram_texture.GetHeight() - dst_bounds_scaled.top - dst_bounds_scaled.GetHeight(), dst_bounds_scaled.GetHeight());
dst_bounds_scaled.GetWidth(), dst_bounds_scaled.GetHeight());
m_vram_read_texture.Bind(); m_vram_read_texture.Bind();
m_vram_copy_program.Bind(); m_vram_copy_program.Bind();
glBindVertexArray(m_attributeless_vao_id); 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; width *= m_resolution_scale;
height *= 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) if (GLAD_GL_VERSION_4_3)
{ {
glCopyImageSubData(m_vram_texture.GetGLId(), m_vram_texture.GetGLTarget(), 0, src_x, src_y, 0, 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 width = scaled_rect.GetWidth();
const u32 height = scaled_rect.GetHeight(); const u32 height = scaled_rect.GetHeight();
const u32 x = scaled_rect.left; 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(); const bool multisampled = m_vram_texture.IsMultisampled();
if (!multisampled && GLAD_GL_VERSION_4_3) 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_BLEND);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_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); glBindVertexArray(m_attributeless_vao_id);
source.Bind(); source.Bind();
m_downsample_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_downsample_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
@ -1353,9 +1319,7 @@ void GPU_HW_OpenGL::DownsampleFramebufferBoxFilter(GL::Texture& source, u32 left
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height);
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left,
m_downsample_texture.GetHeight() - ds_top, ds_width, -static_cast<s32>(ds_height));
} }
std::unique_ptr<GPU> GPU::CreateHardwareOpenGLRenderer() std::unique_ptr<GPU> GPU::CreateHardwareOpenGLRenderer()

View File

@ -20,7 +20,7 @@ public:
bool Initialize() override; bool Initialize() override;
void Reset(bool clear_vram) 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 ResetGraphicsAPIState() override;
void RestoreGraphicsAPIState() override; void RestoreGraphicsAPIState() override;
@ -55,8 +55,6 @@ private:
ALWAYS_INLINE bool IsGLES() const { return (m_render_api == RenderAPI::OpenGLES); } ALWAYS_INLINE bool IsGLES() const { return (m_render_api == RenderAPI::OpenGLES); }
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities(); void SetCapabilities();
bool CreateFramebuffer(); bool CreateFramebuffer();
void ClearFramebuffer(); void ClearFramebuffer();

View File

@ -25,25 +25,6 @@ void GPU_HW_ShaderGen::WriteCommonFunctions(std::stringstream& ss)
ss << "CONSTANT uint MULTISAMPLES = " << m_multisamples << "u;\n"; ss << "CONSTANT uint MULTISAMPLES = " << m_multisamples << "u;\n";
ss << "CONSTANT bool PER_SAMPLE_SHADING = " << (m_per_sample_shading ? "true" : "false") << ";\n"; ss << "CONSTANT bool PER_SAMPLE_SHADING = " << (m_per_sample_shading ? "true" : "false") << ";\n";
ss << R"( 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 RGBA8ToRGBA5551(float4 v)
{ {
uint r = uint(roundEven(v.r * 31.0)); uint r = uint(roundEven(v.r * 31.0));
@ -85,23 +66,6 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured)
WriteCommonFunctions(ss); WriteCommonFunctions(ss);
WriteBatchUniformBuffer(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 (textured)
{ {
if (m_uv_limits) if (m_uv_limits)
@ -145,14 +109,12 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured)
#endif #endif
#if API_OPENGL || API_OPENGL_ES #if API_OPENGL || API_OPENGL_ES
pos_y += POS_EPSILON;
// 0..1 to -1..1 depth range. // 0..1 to -1..1 depth range.
pos_z = (pos_z * 2.0) - 1.0; pos_z = (pos_z * 2.0) - 1.0;
#endif #endif
// NDC space Y flip in Vulkan. // NDC space Y flip in Vulkan.
#if API_VULKAN #if API_OPENGL || API_OPENGL_ES || API_VULKAN
pos_y = -pos_y; pos_y = -pos_y;
#endif #endif
@ -767,7 +729,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
#endif #endif
// fixup coords // 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 // load colour/palette
float4 texel = SAMPLE_TEXTURE(samp0, float2(vicoord) * RCP_VRAM_SIZE); float4 texel = SAMPLE_TEXTURE(samp0, float2(vicoord) * RCP_VRAM_SIZE);
@ -783,12 +745,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
#endif #endif
// sample palette // 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); return SAMPLE_TEXTURE(samp0, float2(palette_icoord) * RCP_VRAM_SIZE);
#else #else
// Direct texturing. Render-to-texture effects. Use upscaled coordinates. // Direct texturing. Render-to-texture effects. Use upscaled coordinates.
uint2 icoord = ApplyUpscaledTextureWindow(FloatToIntegerCoords(coords)); 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); return SAMPLE_TEXTURE(samp0, float2(direct_icoord) * RCP_VRAM_SIZE);
#endif #endif
} }
@ -831,7 +793,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
float oalpha; float oalpha;
#if INTERLACING #if INTERLACING
if ((fixYCoord(uint(v_pos.y)) & 1u) == u_interlaced_displayed_field) if ((uint(v_pos.y) & 1u) == u_interlaced_displayed_field)
discard; discard;
#endif #endif
@ -1097,7 +1059,7 @@ float3 SampleVRAM24Smoothed(uint2 icoords)
uint2 icoords = uint2(v_pos.xy) + uint2(u_crop_left, 0u); uint2 icoords = uint2(v_pos.xy) + uint2(u_crop_left, 0u);
#if INTERLACED #if INTERLACED
if ((fixYCoord(icoords.y) & 1u) != u_field_offset) if ((icoords.y & 1u) != u_field_offset)
discard; discard;
#if !INTERLEAVED #if !INTERLEAVED
@ -1167,13 +1129,6 @@ uint SampleVRAM(uint2 coords)
ss << R"( ss << R"(
{ {
uint2 sample_coords = uint2(uint(v_pos.x) * 2u, uint(v_pos.y)); 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; 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. // 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); DeclareFragmentEntryPoint(ss, 0, 1, {}, true, 1, true);
ss << R"( 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 // make sure it's not oversized and out of range
if ((coords.x < u_base_coords.x && coords.x >= u_end_coords.x) || 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"( ss << R"(
{ {
#if INTERLACED || WRAPPED #if INTERLACED || WRAPPED
uint2 dst_coords = uint2(uint(v_pos.x), fixYCoord(uint(v_pos.y))); uint2 dst_coords = uint2(v_pos.xy);
#endif #endif
#if INTERLACED #if INTERLACED

View File

@ -102,7 +102,7 @@ void GPU_HW_Vulkan::Reset(bool clear_vram)
ClearFramebuffer(); 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) if (host_texture)
{ {
@ -119,7 +119,7 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
if (sw.IsReading()) if (sw.IsReading())
{ {
Vulkan::Texture* tex = static_cast<Vulkan::Texture*>((*host_texture)->GetHandle()); Vulkan::Texture* tex = static_cast<Vulkan::Texture*>(*host_texture);
if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() ||
tex->GetSamples() != m_vram_texture.GetSamples()) tex->GetSamples() != m_vram_texture.GetSamples())
{ {
@ -137,22 +137,22 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
} }
else else
{ {
HostDisplayTexture* htex = *host_texture; Vulkan::Texture* tex = static_cast<Vulkan::Texture*>(*host_texture);
if (!htex || htex->GetWidth() != m_vram_texture.GetWidth() || htex->GetHeight() != m_vram_texture.GetHeight() || if (!tex || tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() ||
htex->GetSamples() != static_cast<u32>(m_vram_texture.GetSamples())) tex->GetSamples() != static_cast<u32>(m_vram_texture.GetSamples()))
{ {
delete htex; delete tex;
htex = g_host_display tex = static_cast<Vulkan::Texture*>(g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) 1, m_vram_texture.GetSamples(), GPUTexture::Format::RGBA8,
.release(); nullptr, 0, false)
*host_texture = htex; .release());
if (!htex) *host_texture = tex;
if (!tex)
return false; return false;
} }
Vulkan::Texture* tex = static_cast<Vulkan::Texture*>(htex->GetHandle());
if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() || if (tex->GetWidth() != m_vram_texture.GetWidth() || tex->GetHeight() != m_vram_texture.GetHeight() ||
tex->GetSamples() != m_vram_texture.GetSamples()) tex->GetSamples() != m_vram_texture.GetSamples())
{ {
@ -612,13 +612,13 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
m_vram_update_depth_render_pass = m_vram_update_depth_render_pass =
g_vulkan_context->GetRenderPass(VK_FORMAT_UNDEFINED, depth_format, samples, VK_ATTACHMENT_LOAD_OP_DONT_CARE); 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_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 = m_display_discard_render_pass =
g_vulkan_context->GetRenderPass(m_display_texture.GetFormat(), VK_FORMAT_UNDEFINED, m_display_texture.GetSamples(), g_vulkan_context->GetRenderPass(m_display_texture.GetVkFormat(), VK_FORMAT_UNDEFINED,
VK_ATTACHMENT_LOAD_OP_DONT_CARE); m_display_texture.GetVkSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE);
m_vram_readback_render_pass = m_vram_readback_render_pass =
g_vulkan_context->GetRenderPass(m_vram_readback_texture.GetFormat(), VK_FORMAT_UNDEFINED, g_vulkan_context->GetRenderPass(m_vram_readback_texture.GetVkFormat(), VK_FORMAT_UNDEFINED,
m_vram_readback_texture.GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); 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 || 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) 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_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); VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR);
m_downsample_weight_render_pass = g_vulkan_context->GetRenderPass( m_downsample_weight_render_pass =
m_downsample_weight_texture.GetFormat(), VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR); 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) if (m_downsample_render_pass == VK_NULL_HANDLE || m_downsample_weight_render_pass == VK_NULL_HANDLE)
return false; return false;
@ -725,7 +726,7 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
0, 0,
m_downsample_texture.GetImage(), m_downsample_texture.GetImage(),
VK_IMAGE_VIEW_TYPE_2D, 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_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
{VK_IMAGE_ASPECT_COLOR_BIT, i, 1u, 0u, 1u}}; {VK_IMAGE_ASPECT_COLOR_BIT, i, 1u, 0u, 1u}};
@ -776,7 +777,7 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
return false; 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); VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR);
m_downsample_mip_views.resize(1); m_downsample_mip_views.resize(1);
@ -1433,15 +1434,12 @@ void GPU_HW_Vulkan::UpdateDisplay()
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
} }
g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_vram_read_texture, 0, 0, m_vram_read_texture.GetWidth(),
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, m_vram_read_texture.GetHeight());
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight());
} }
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
@ -1479,8 +1477,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, scaled_vram_offset_x, scaled_vram_offset_y,
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
} }
} }
@ -1526,9 +1523,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
} }
else else
{ {
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_display_texture, 0, 0, scaled_display_width, scaled_display_height);
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0,
scaled_display_width, scaled_display_height);
RestoreGraphicsAPIState(); 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); 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). // 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, g_host_display->DownloadTexture(&m_vram_readback_texture, 0, 0, encoded_width, encoded_height,
encoded_height, &m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left], &m_vram_shadow[copy_rect.top * VRAM_WIDTH + copy_rect.left],
VRAM_WIDTH * sizeof(u16)); VRAM_WIDTH * sizeof(u16));
} }
@ -1890,9 +1885,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferBoxFilter(Vulkan::Texture& source, u32
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height);
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top,
ds_width, ds_height);
} }
void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 left, u32 top, u32 width, u32 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(); RestoreGraphicsAPIState();
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_display_texture, left, top, width, height);
m_display_texture.GetHeight(), left, top, width, height);
} }
std::unique_ptr<GPU> GPU::CreateHardwareVulkanRenderer() std::unique_ptr<GPU> GPU::CreateHardwareVulkanRenderer()

View File

@ -18,7 +18,7 @@ public:
bool Initialize() override; bool Initialize() override;
void Reset(bool clear_vram) 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 ResetGraphicsAPIState() override;
void RestoreGraphicsAPIState() override; void RestoreGraphicsAPIState() override;

View File

@ -59,22 +59,22 @@ bool GPU_SW::Initialize()
if (!GPU::Initialize() || !m_backend.Initialize(false)) if (!GPU::Initialize() || !m_backend.Initialize(false))
return false; return false;
static constexpr auto formats_for_16bit = make_array(HostDisplayPixelFormat::RGB565, HostDisplayPixelFormat::RGBA5551, static constexpr auto formats_for_16bit = make_array(GPUTexture::Format::RGB565, GPUTexture::Format::RGBA5551,
HostDisplayPixelFormat::RGBA8, HostDisplayPixelFormat::BGRA8); GPUTexture::Format::RGBA8, GPUTexture::Format::BGRA8);
static constexpr auto formats_for_24bit = static constexpr auto formats_for_24bit =
make_array(HostDisplayPixelFormat::RGBA8, HostDisplayPixelFormat::BGRA8, HostDisplayPixelFormat::RGB565, make_array(GPUTexture::Format::RGBA8, GPUTexture::Format::BGRA8, GPUTexture::Format::RGB565,
HostDisplayPixelFormat::RGBA5551); GPUTexture::Format::RGBA5551);
for (const HostDisplayPixelFormat format : formats_for_16bit) 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; m_16bit_display_format = format;
break; 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; m_24bit_display_format = format;
break; break;
@ -84,7 +84,7 @@ bool GPU_SW::Initialize()
return true; 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 // ignore the host texture for software mode, since we want to save vram here
return GPU::DoState(sw, nullptr, update_display); return GPU::DoState(sw, nullptr, update_display);
@ -103,7 +103,7 @@ void GPU_SW::UpdateSettings()
m_backend.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 || if (!m_display_texture || m_display_texture->GetWidth() != width || m_display_texture->GetHeight() != height ||
m_display_texture->GetFormat() != format) m_display_texture->GetFormat() != format)
@ -118,32 +118,32 @@ HostDisplayTexture* GPU_SW::GetDisplayTexture(u32 width, u32 height, HostDisplay
return m_display_texture.get(); return m_display_texture.get();
} }
template<HostDisplayPixelFormat out_format, typename out_type> template<GPUTexture::Format out_format, typename out_type>
static void CopyOutRow16(const u16* src_ptr, out_type* dst_ptr, u32 width); static void CopyOutRow16(const u16* src_ptr, out_type* dst_ptr, u32 width);
template<HostDisplayPixelFormat out_format, typename out_type> template<GPUTexture::Format out_format, typename out_type>
static out_type VRAM16ToOutput(u16 value); static out_type VRAM16ToOutput(u16 value);
template<> template<>
ALWAYS_INLINE u16 VRAM16ToOutput<HostDisplayPixelFormat::RGBA5551, u16>(u16 value) ALWAYS_INLINE u16 VRAM16ToOutput<GPUTexture::Format::RGBA5551, u16>(u16 value)
{ {
return (value & 0x3E0) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 10); return (value & 0x3E0) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 10);
} }
template<> template<>
ALWAYS_INLINE u16 VRAM16ToOutput<HostDisplayPixelFormat::RGB565, u16>(u16 value) ALWAYS_INLINE u16 VRAM16ToOutput<GPUTexture::Format::RGB565, u16>(u16 value)
{ {
return ((value & 0x3E0) << 1) | ((value & 0x20) << 1) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 11); return ((value & 0x3E0) << 1) | ((value & 0x20) << 1) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 11);
} }
template<> template<>
ALWAYS_INLINE u32 VRAM16ToOutput<HostDisplayPixelFormat::RGBA8, u32>(u16 value) ALWAYS_INLINE u32 VRAM16ToOutput<GPUTexture::Format::RGBA8, u32>(u16 value)
{ {
return VRAMRGBA5551ToRGBA8888(value); return VRAMRGBA5551ToRGBA8888(value);
} }
template<> template<>
ALWAYS_INLINE u32 VRAM16ToOutput<HostDisplayPixelFormat::BGRA8, u32>(u16 value) ALWAYS_INLINE u32 VRAM16ToOutput<GPUTexture::Format::BGRA8, u32>(u16 value)
{ {
const u32 value32 = ZeroExtend32(value); const u32 value32 = ZeroExtend32(value);
const u32 r = VRAMConvert5To8(value32 & 31u); const u32 r = VRAMConvert5To8(value32 & 31u);
@ -153,7 +153,7 @@ ALWAYS_INLINE u32 VRAM16ToOutput<HostDisplayPixelFormat::BGRA8, u32>(u16 value)
} }
template<> template<>
ALWAYS_INLINE void CopyOutRow16<HostDisplayPixelFormat::RGBA5551, u16>(const u16* src_ptr, u16* dst_ptr, u32 width) ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::RGBA5551, u16>(const u16* src_ptr, u16* dst_ptr, u32 width)
{ {
u32 col = 0; u32 col = 0;
@ -188,11 +188,11 @@ ALWAYS_INLINE void CopyOutRow16<HostDisplayPixelFormat::RGBA5551, u16>(const u16
#endif #endif
for (; col < width; col++) for (; col < width; col++)
*(dst_ptr++) = VRAM16ToOutput<HostDisplayPixelFormat::RGBA5551, u16>(*(src_ptr++)); *(dst_ptr++) = VRAM16ToOutput<GPUTexture::Format::RGBA5551, u16>(*(src_ptr++));
} }
template<> template<>
ALWAYS_INLINE void CopyOutRow16<HostDisplayPixelFormat::RGB565, u16>(const u16* src_ptr, u16* dst_ptr, u32 width) ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::RGB565, u16>(const u16* src_ptr, u16* dst_ptr, u32 width)
{ {
u32 col = 0; u32 col = 0;
@ -229,39 +229,39 @@ ALWAYS_INLINE void CopyOutRow16<HostDisplayPixelFormat::RGB565, u16>(const u16*
#endif #endif
for (; col < width; col++) for (; col < width; col++)
*(dst_ptr++) = VRAM16ToOutput<HostDisplayPixelFormat::RGB565, u16>(*(src_ptr++)); *(dst_ptr++) = VRAM16ToOutput<GPUTexture::Format::RGB565, u16>(*(src_ptr++));
} }
template<> template<>
ALWAYS_INLINE void CopyOutRow16<HostDisplayPixelFormat::RGBA8, u32>(const u16* src_ptr, u32* dst_ptr, u32 width) ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::RGBA8, u32>(const u16* src_ptr, u32* dst_ptr, u32 width)
{ {
for (u32 col = 0; col < width; col++) for (u32 col = 0; col < width; col++)
*(dst_ptr++) = VRAM16ToOutput<HostDisplayPixelFormat::RGBA8, u32>(*(src_ptr++)); *(dst_ptr++) = VRAM16ToOutput<GPUTexture::Format::RGBA8, u32>(*(src_ptr++));
} }
template<> template<>
ALWAYS_INLINE void CopyOutRow16<HostDisplayPixelFormat::BGRA8, u32>(const u16* src_ptr, u32* dst_ptr, u32 width) ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::BGRA8, u32>(const u16* src_ptr, u32* dst_ptr, u32 width)
{ {
for (u32 col = 0; col < width; col++) for (u32 col = 0; col < width; col++)
*(dst_ptr++) = VRAM16ToOutput<HostDisplayPixelFormat::BGRA8, u32>(*(src_ptr++)); *(dst_ptr++) = VRAM16ToOutput<GPUTexture::Format::BGRA8, u32>(*(src_ptr++));
} }
template<HostDisplayPixelFormat display_format> template<GPUTexture::Format display_format>
void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved) void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved)
{ {
u8* dst_ptr; u8* dst_ptr;
u32 dst_stride; u32 dst_stride;
using OutputPixelType = std::conditional_t< 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) if (!texture)
return; return;
if (!interlaced) if (!interlaced)
{ {
if (!texture->BeginUpdate(width, height, reinterpret_cast<void**>(&dst_ptr), &dst_stride)) if (!g_host_display->BeginTextureUpdate(texture, width, height, reinterpret_cast<void**>(&dst_ptr), &dst_stride))
return; return;
} }
else else
@ -309,36 +309,36 @@ void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field
} }
if (!interlaced) if (!interlaced)
texture->EndUpdate(0, 0, width, height); g_host_display->EndTextureUpdate(texture, 0, 0, width, height);
else 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) bool interlaced, bool interleaved)
{ {
switch (display_format) switch (display_format)
{ {
case HostDisplayPixelFormat::RGBA5551: case GPUTexture::Format::RGBA5551:
CopyOut15Bit<HostDisplayPixelFormat::RGBA5551>(src_x, src_y, width, height, field, interlaced, interleaved); CopyOut15Bit<GPUTexture::Format::RGBA5551>(src_x, src_y, width, height, field, interlaced, interleaved);
break; break;
case HostDisplayPixelFormat::RGB565: case GPUTexture::Format::RGB565:
CopyOut15Bit<HostDisplayPixelFormat::RGB565>(src_x, src_y, width, height, field, interlaced, interleaved); CopyOut15Bit<GPUTexture::Format::RGB565>(src_x, src_y, width, height, field, interlaced, interleaved);
break; break;
case HostDisplayPixelFormat::RGBA8: case GPUTexture::Format::RGBA8:
CopyOut15Bit<HostDisplayPixelFormat::RGBA8>(src_x, src_y, width, height, field, interlaced, interleaved); CopyOut15Bit<GPUTexture::Format::RGBA8>(src_x, src_y, width, height, field, interlaced, interleaved);
break; break;
case HostDisplayPixelFormat::BGRA8: case GPUTexture::Format::BGRA8:
CopyOut15Bit<HostDisplayPixelFormat::BGRA8>(src_x, src_y, width, height, field, interlaced, interleaved); CopyOut15Bit<GPUTexture::Format::BGRA8>(src_x, src_y, width, height, field, interlaced, interleaved);
break; break;
default: default:
break; break;
} }
} }
template<HostDisplayPixelFormat display_format> template<GPUTexture::Format display_format>
void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced, void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced,
bool interleaved) 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; u32 dst_stride;
using OutputPixelType = std::conditional_t< 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) if (!texture)
return; return;
if (!interlaced) if (!interlaced)
{ {
if (!texture->BeginUpdate(width, height, reinterpret_cast<void**>(&dst_ptr), &dst_stride)) if (!g_host_display->BeginTextureUpdate(texture, width, height, reinterpret_cast<void**>(&dst_ptr), &dst_stride))
return; return;
} }
else 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); const u32 src_stride = (VRAM_WIDTH << interleaved_shift) * sizeof(u16);
for (u32 row = 0; row < rows; row++) 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; const u8* src_row_ptr = src_ptr;
u8* dst_row_ptr = reinterpret_cast<u8*>(dst_ptr); u8* dst_row_ptr = reinterpret_cast<u8*>(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; *(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; const u8* src_row_ptr = src_ptr;
u8* dst_row_ptr = reinterpret_cast<u8*>(dst_ptr); u8* dst_row_ptr = reinterpret_cast<u8*>(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; 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; const u8* src_row_ptr = src_ptr;
u16* dst_row_ptr = reinterpret_cast<u16*>(dst_ptr); u16* dst_row_ptr = reinterpret_cast<u16*>(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; 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; const u8* src_row_ptr = src_ptr;
u16* dst_row_ptr = reinterpret_cast<u16*>(dst_ptr); u16* dst_row_ptr = reinterpret_cast<u16*>(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<u8>(col & 1u) * 8; const u8 shift = static_cast<u8>(col & 1u) * 8;
const u32 rgb = (((ZeroExtend32(s1) << 16) | ZeroExtend32(s0)) >> shift); 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; *(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; *(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); *(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); *(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) if (!interlaced)
texture->EndUpdate(0, 0, width, height); g_host_display->EndTextureUpdate(texture, 0, 0, width, height);
else 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) u32 height, u32 field, bool interlaced, bool interleaved)
{ {
switch (display_format) switch (display_format)
{ {
case HostDisplayPixelFormat::RGBA5551: case GPUTexture::Format::RGBA5551:
CopyOut24Bit<HostDisplayPixelFormat::RGBA5551>(src_x, src_y, skip_x, width, height, field, interlaced, CopyOut24Bit<GPUTexture::Format::RGBA5551>(src_x, src_y, skip_x, width, height, field, interlaced,
interleaved); interleaved);
break; break;
case HostDisplayPixelFormat::RGB565: case GPUTexture::Format::RGB565:
CopyOut24Bit<HostDisplayPixelFormat::RGB565>(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); CopyOut24Bit<GPUTexture::Format::RGB565>(src_x, src_y, skip_x, width, height, field, interlaced, interleaved);
break; break;
case HostDisplayPixelFormat::RGBA8: case GPUTexture::Format::RGBA8:
CopyOut24Bit<HostDisplayPixelFormat::RGBA8>(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); CopyOut24Bit<GPUTexture::Format::RGBA8>(src_x, src_y, skip_x, width, height, field, interlaced, interleaved);
break; break;
case HostDisplayPixelFormat::BGRA8: case GPUTexture::Format::BGRA8:
CopyOut24Bit<HostDisplayPixelFormat::BGRA8>(src_x, src_y, skip_x, width, height, field, interlaced, interleaved); CopyOut24Bit<GPUTexture::Format::BGRA8>(src_x, src_y, skip_x, width, height, field, interlaced, interleaved);
break; break;
default: default:
break; break;

View File

@ -12,7 +12,7 @@ namespace Threading
class Thread; class Thread;
} }
class HostDisplayTexture; class GPUTexture;
class GPU_SW final : public GPU class GPU_SW final : public GPU
{ {
@ -26,7 +26,7 @@ public:
const Threading::Thread* GetSWThread() const override; const Threading::Thread* GetSWThread() const override;
bool Initialize() 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 Reset(bool clear_vram) override;
void UpdateSettings() 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 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; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;
template<HostDisplayPixelFormat display_format> template<GPUTexture::Format display_format>
void CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field, bool interlaced, bool interleaved); 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); bool interlaced, bool interleaved);
template<HostDisplayPixelFormat display_format> template<GPUTexture::Format display_format>
void CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced, void CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u32 field, bool interlaced,
bool interleaved); 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); u32 field, bool interlaced, bool interleaved);
void ClearDisplay() override; void ClearDisplay() override;
@ -55,12 +55,12 @@ protected:
void FillBackendCommandParameters(GPUBackendCommand* cmd) const; void FillBackendCommandParameters(GPUBackendCommand* cmd) const;
void FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) 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<u8, GPU_MAX_DISPLAY_WIDTH * GPU_MAX_DISPLAY_HEIGHT * sizeof(u32)> m_display_texture_buffer; HeapArray<u8, GPU_MAX_DISPLAY_WIDTH * GPU_MAX_DISPLAY_HEIGHT * sizeof(u32)> m_display_texture_buffer;
HostDisplayPixelFormat m_16bit_display_format = HostDisplayPixelFormat::RGB565; GPUTexture::Format m_16bit_display_format = GPUTexture::Format::RGB565;
HostDisplayPixelFormat m_24bit_display_format = HostDisplayPixelFormat::RGBA8; GPUTexture::Format m_24bit_display_format = GPUTexture::Format::RGBA8;
std::unique_ptr<HostDisplayTexture> m_display_texture; std::unique_ptr<GPUTexture> m_display_texture;
GPU_SW_Backend m_backend; GPU_SW_Backend m_backend;
}; };

View File

@ -18,27 +18,6 @@ Log_SetChannel(HostDisplay);
std::unique_ptr<HostDisplay> g_host_display; std::unique_ptr<HostDisplay> 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; HostDisplay::~HostDisplay() = default;
RenderAPI HostDisplay::GetPreferredAPI() RenderAPI HostDisplay::GetPreferredAPI()
@ -50,6 +29,18 @@ RenderAPI HostDisplay::GetPreferredAPI()
#endif #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) bool HostDisplay::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
{ {
if (!mode.empty()) if (!mode.empty())
@ -126,23 +117,6 @@ bool HostDisplay::ShouldSkipDisplayingFrame()
return false; 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) bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
{ {
if (m_window_info.surface_refresh_rate > 0.0f) if (m_window_info.surface_refresh_rate > 0.0f)
@ -164,7 +138,7 @@ float HostDisplay::GetAndResetAccumulatedGPUTime()
return 0.0f; return 0.0f;
} }
void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/) void HostDisplay::SetSoftwareCursor(std::unique_ptr<GPUTexture> texture, float scale /*= 1.0f*/)
{ {
m_cursor_texture = std::move(texture); m_cursor_texture = std::move(texture);
m_cursor_texture_scale = scale; m_cursor_texture_scale = scale;
@ -172,8 +146,8 @@ void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture,
bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/) bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/)
{ {
std::unique_ptr<HostDisplayTexture> tex = std::unique_ptr<GPUTexture> tex =
CreateTexture(width, height, 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixels, stride, false); CreateTexture(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, pixels, stride, false);
if (!tex) if (!tex)
return false; return false;
@ -198,8 +172,8 @@ bool HostDisplay::SetSoftwareCursor(const char* path, float scale /*= 1.0f*/)
return false; return false;
} }
std::unique_ptr<HostDisplayTexture> tex = std::unique_ptr<GPUTexture> tex =
CreateTexture(static_cast<u32>(width), static_cast<u32>(height), 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixel_data, CreateTexture(static_cast<u32>(width), static_cast<u32>(height), 1, 1, 1, GPUTexture::Format::RGBA8, pixel_data,
sizeof(u32) * static_cast<u32>(width), false); sizeof(u32) * static_cast<u32>(width), false);
stbi_image_free(pixel_data); stbi_image_free(pixel_data);
if (!tex) if (!tex)
@ -371,106 +345,10 @@ std::tuple<float, float> HostDisplay::ConvertWindowCoordinatesToDisplayCoordinat
return std::make_tuple(display_x, display_y); return std::make_tuple(display_x, display_y);
} }
bool HostDisplay::ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data,
u32& texture_data_stride, HostDisplayPixelFormat format)
{
switch (format)
{
case HostDisplayPixelFormat::BGRA8:
{
for (u32 y = 0; y < height; y++)
{
u32* pixels = reinterpret_cast<u32*>(reinterpret_cast<u8*>(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<u32> temp(width * height);
for (u32 y = 0; y < height; y++)
{
const u8* pixels_in = reinterpret_cast<u8*>(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<u32> temp(width * height);
for (u32 y = 0; y < height; y++)
{
const u8* pixels_in = reinterpret_cast<u8*>(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<u32>(format));
return false;
}
}
void HostDisplay::FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride)
{
std::vector<u32> 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, 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, bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height,
std::vector<u32> texture_data, u32 texture_data_stride, std::vector<u32> texture_data, u32 texture_data_stride,
HostDisplayPixelFormat texture_format) GPUTexture::Format texture_format)
{ {
const char* extension = std::strrchr(filename.c_str(), '.'); const char* extension = std::strrchr(filename.c_str(), '.');
@ -480,7 +358,7 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil
return false; 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; return false;
if (clear_alpha) if (clear_alpha)
@ -490,7 +368,7 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil
} }
if (flip_y) 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)) 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; return true;
} }
bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, bool HostDisplay::WriteTextureToFile(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, std::string filename,
HostDisplayPixelFormat format, std::string filename, bool clear_alpha /* = true */, bool clear_alpha /* = true */, bool flip_y /* = false */,
bool flip_y /* = false */, u32 resize_width /* = 0 */, u32 resize_height /* = 0 */, u32 resize_width /* = 0 */, u32 resize_height /* = 0 */,
bool compress_on_thread /* = false */) bool compress_on_thread /* = false */)
{ {
std::vector<u32> texture_data(width * height); std::vector<u32> texture_data(width * height);
u32 texture_data_stride = Common::AlignUpPow2(GetDisplayPixelFormatSize(format) * width, 4); u32 texture_data_stride = Common::AlignUpPow2(GPUTexture::GetPixelSize(texture->GetFormat()) * width, 4);
if (!DownloadTexture(texture_handle, format, x, y, width, height, texture_data.data(), texture_data_stride)) if (!DownloadTexture(texture, x, y, width, height, texture_data.data(), texture_data_stride))
{ {
Log_ErrorPrintf("Texture download failed"); Log_ErrorPrintf("Texture download failed");
return false; 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, 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, 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), 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), clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data),
texture_data_stride, format); texture_data_stride, texture->GetFormat());
compress_thread.detach(); compress_thread.detach();
return true; 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 HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_resolution /* = true */,
bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = false */) bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = false */)
{ {
if (!m_display_texture_handle) if (!m_display_texture)
return false; return false;
s32 resize_width = 0; s32 resize_width = 0;
@ -612,18 +490,19 @@ bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_reso
if (flip_y) if (flip_y)
{ {
read_height = -m_display_texture_view_height; 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, return WriteTextureToFile(m_display_texture, m_display_texture_view_x, read_y, m_display_texture_view_width,
read_height, m_display_texture_format, std::move(filename), true, flip_y, read_height, std::move(filename), true, flip_y, static_cast<u32>(resize_width),
static_cast<u32>(resize_width), static_cast<u32>(resize_height), compress_on_thread); static_cast<u32>(resize_height), compress_on_thread);
} }
bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resize_width /* = 0 */, bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resize_width /* = 0 */,
u32 resize_height /* = 0 */, bool clear_alpha /* = true */) u32 resize_height /* = 0 */, bool clear_alpha /* = true */)
{ {
if (!m_display_texture_handle) if (!m_display_texture)
return false; return false;
const bool flip_y = (m_display_texture_view_height < 0); const bool flip_y = (m_display_texture_view_height < 0);
@ -634,22 +513,25 @@ bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resi
if (flip_y) if (flip_y)
{ {
read_height = -m_display_texture_view_height; 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<u32>(read_width); u32 width = static_cast<u32>(read_width);
u32 height = static_cast<u32>(read_height); u32 height = static_cast<u32>(read_height);
std::vector<u32> texture_data(width * height); std::vector<u32> texture_data(width * height);
u32 texture_data_stride = Common::AlignUpPow2(GetDisplayPixelFormatSize(m_display_texture_format) * width, 4); u32 texture_data_stride = Common::AlignUpPow2(m_display_texture->GetPixelSize() * width, 4);
if (!DownloadTexture(m_display_texture_handle, m_display_texture_format, read_x, read_y, width, height, if (!DownloadTexture(m_display_texture, read_x, read_y, width, height, texture_data.data(), texture_data_stride))
texture_data.data(), texture_data_stride))
{ {
Log_ErrorPrintf("Failed to download texture from GPU."); Log_ErrorPrintf("Failed to download texture from GPU.");
return false; 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; return false;
}
if (clear_alpha) if (clear_alpha)
{ {
@ -704,7 +586,7 @@ bool HostDisplay::WriteScreenshotToFile(std::string filename, bool compress_on_t
std::vector<u32> pixels; std::vector<u32> pixels;
u32 pixels_stride; u32 pixels_stride;
HostDisplayPixelFormat pixels_format; GPUTexture::Format pixels_format;
if (!RenderScreenshot(width, height, &pixels, &pixels_stride, &pixels_format)) if (!RenderScreenshot(width, height, &pixels, &pixels_stride, &pixels_format))
{ {
Log_ErrorPrintf("Failed to render %ux%u screenshot", width, height); Log_ErrorPrintf("Failed to render %ux%u screenshot", width, height);

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "common/gpu_texture.h"
#include "common/rectangle.h" #include "common/rectangle.h"
#include "common/window_info.h" #include "common/window_info.h"
#include "types.h" #include "types.h"
@ -18,35 +19,6 @@ enum class RenderAPI : u32
OpenGLES 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. // Interface to the frontend's renderer.
class HostDisplay class HostDisplay
{ {
@ -89,7 +61,7 @@ public:
m_mouse_position_y = y; 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 GetDisplayTopMargin() const { return m_display_top_margin; }
ALWAYS_INLINE s32 GetDisplayWidth() const { return m_display_width; } ALWAYS_INLINE s32 GetDisplayWidth() const { return m_display_width; }
ALWAYS_INLINE s32 GetDisplayHeight() const { return m_display_height; } 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; 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. /// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below.
virtual std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, virtual std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
HostDisplayPixelFormat format, const void* data, GPUTexture::Format format, const void* data, u32 data_stride,
u32 data_stride, bool dynamic = false) = 0; bool dynamic = false) = 0;
virtual bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, virtual bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) = 0;
u32 width, u32 height, void* out_data, u32 out_data_stride) = 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. /// Returns false if the window was completely occluded.
virtual bool Render(bool skip_present) = 0; virtual bool Render(bool skip_present) = 0;
/// Renders the display with postprocessing to the specified image. /// Renders the display with postprocessing to the specified image.
virtual bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, virtual bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) = 0; GPUTexture::Format* out_format) = 0;
virtual void SetVSync(bool enabled) = 0; virtual void SetVSync(bool enabled) = 0;
@ -150,9 +127,7 @@ public:
void ClearDisplayTexture() void ClearDisplayTexture()
{ {
m_display_texture_handle = nullptr; m_display_texture = nullptr;
m_display_texture_width = 0;
m_display_texture_height = 0;
m_display_texture_view_x = 0; m_display_texture_view_x = 0;
m_display_texture_view_y = 0; m_display_texture_view_y = 0;
m_display_texture_view_width = 0; m_display_texture_view_width = 0;
@ -160,13 +135,9 @@ public:
m_display_changed = true; m_display_changed = true;
} }
void SetDisplayTexture(void* texture_handle, HostDisplayPixelFormat texture_format, s32 texture_width, void SetDisplayTexture(GPUTexture* texture, s32 view_x, s32 view_y, s32 view_width, s32 view_height)
s32 texture_height, s32 view_x, s32 view_y, s32 view_width, s32 view_height)
{ {
m_display_texture_handle = texture_handle; m_display_texture = texture;
m_display_texture_format = texture_format;
m_display_texture_width = texture_width;
m_display_texture_height = texture_height;
m_display_texture_view_x = view_x; m_display_texture_view_x = view_x;
m_display_texture_view_y = view_y; m_display_texture_view_y = view_y;
m_display_texture_view_width = view_width; m_display_texture_view_width = view_width;
@ -196,12 +167,7 @@ public:
m_display_changed = true; m_display_changed = true;
} }
static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format); virtual bool SupportsTextureFormat(GPUTexture::Format format) const = 0;
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
HostDisplayPixelFormat format);
static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride);
virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0;
virtual bool GetHostRefreshRate(float* refresh_rate); virtual bool GetHostRefreshRate(float* refresh_rate);
@ -215,7 +181,7 @@ public:
void SetDisplayAlignment(Alignment alignment) { m_display_alignment = alignment; } void SetDisplayAlignment(Alignment alignment) { m_display_alignment = alignment; }
/// Sets the software cursor to the specified texture. Ownership of the texture is transferred. /// Sets the software cursor to the specified texture. Ownership of the texture is transferred.
void SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale = 1.0f); void SetSoftwareCursor(std::unique_ptr<GPUTexture> texture, float scale = 1.0f);
/// Sets the software cursor to the specified image. /// Sets the software cursor to the specified image.
bool SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale = 1.0f); 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; 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. /// 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, bool WriteTextureToFile(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, std::string filename,
HostDisplayPixelFormat format, std::string filename, bool clear_alpha = true, bool clear_alpha = true, bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0,
bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0,
bool compress_on_thread = false); bool compress_on_thread = false);
/// Helper function to save current display texture to PNG. /// Helper function to save current display texture to PNG.
@ -253,7 +218,7 @@ public:
protected: protected:
ALWAYS_INLINE bool HasSoftwareCursor() const { return static_cast<bool>(m_cursor_texture); } ALWAYS_INLINE bool HasSoftwareCursor() const { return static_cast<bool>(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; bool IsUsingLinearFiltering() const;
@ -280,10 +245,7 @@ protected:
float m_display_aspect_ratio = 1.0f; float m_display_aspect_ratio = 1.0f;
float m_display_frame_interval = 0.0f; float m_display_frame_interval = 0.0f;
void* m_display_texture_handle = nullptr; GPUTexture* m_display_texture = nullptr;
HostDisplayPixelFormat m_display_texture_format = HostDisplayPixelFormat::Count;
s32 m_display_texture_width = 0;
s32 m_display_texture_height = 0;
s32 m_display_texture_view_x = 0; s32 m_display_texture_view_x = 0;
s32 m_display_texture_view_y = 0; s32 m_display_texture_view_y = 0;
s32 m_display_texture_view_width = 0; s32 m_display_texture_view_width = 0;
@ -292,7 +254,7 @@ protected:
s32 m_display_top_margin = 0; s32 m_display_top_margin = 0;
Alignment m_display_alignment = Alignment::Center; Alignment m_display_alignment = Alignment::Center;
std::unique_ptr<HostDisplayTexture> m_cursor_texture; std::unique_ptr<GPUTexture> m_cursor_texture;
float m_cursor_texture_scale = 1.0f; float m_cursor_texture_scale = 1.0f;
bool m_display_changed = false; 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 /// 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. /// 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. /// Presents the frame to the display, and renders OSD elements.
//void EndPresentFrame(); // void EndPresentFrame();
/// Provided by the host; renders the display. /// Provided by the host; renders the display.
void RenderDisplay(bool skip_present); void RenderDisplay(bool skip_present);

View File

@ -72,7 +72,7 @@ SystemBootParameters::~SystemBootParameters() = default;
struct MemorySaveState struct MemorySaveState
{ {
std::unique_ptr<HostDisplayTexture> vram_texture; std::unique_ptr<GPUTexture> vram_texture;
std::unique_ptr<GrowableMemoryByteStream> state_stream; std::unique_ptr<GrowableMemoryByteStream> state_stream;
}; };
@ -97,7 +97,7 @@ static void ClearRunningGame();
static void DestroySystem(); static void DestroySystem();
static std::string GetMediaPathFromSaveState(const char* path); static std::string GetMediaPathFromSaveState(const char* path);
static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display); 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 void DoRunFrame();
static bool CreateGPU(GPURenderer renderer); static bool CreateGPU(GPURenderer renderer);
static bool SaveUndoLoadState(); 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 else
{ {
@ -1549,7 +1550,7 @@ bool System::CreateGPU(GPURenderer renderer)
return true; 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")) if (!sw.DoMarker("System"))
return false; return false;
@ -1917,11 +1918,11 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 *
std::vector<u32> screenshot_buffer; std::vector<u32> screenshot_buffer;
u32 screenshot_stride; u32 screenshot_stride;
HostDisplayPixelFormat screenshot_format; GPUTexture::Format screenshot_format;
if (g_host_display->RenderScreenshot(screenshot_width, screenshot_height, &screenshot_buffer, &screenshot_stride, if (g_host_display->RenderScreenshot(screenshot_width, screenshot_height, &screenshot_buffer, &screenshot_stride,
&screenshot_format) && &screenshot_format) &&
g_host_display->ConvertTextureDataToRGBA8(screenshot_width, screenshot_height, screenshot_buffer, GPUTexture::ConvertTextureDataToRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride,
screenshot_stride, screenshot_format)) screenshot_format))
{ {
if (screenshot_stride != (screenshot_width * sizeof(u32))) 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()) if (g_host_display->UsesLowerLeftOrigin())
{ {
g_host_display->FlipTextureDataRGBA8(screenshot_width, screenshot_height, screenshot_buffer, GPUTexture::FlipTextureDataRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride);
screenshot_stride);
} }
header.offset_to_screenshot = static_cast<u32>(state->GetPosition()); header.offset_to_screenshot = static_cast<u32>(state->GetPosition());
@ -3336,7 +3336,7 @@ bool System::LoadMemoryState(const MemorySaveState& mss)
mss.state_stream->SeekAbsolute(0); mss.state_stream->SeekAbsolute(0);
StateWrapper sw(mss.state_stream.get(), StateWrapper::Mode::Read, SAVE_STATE_VERSION); 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)) if (!DoState(sw, &host_texture, true, true))
{ {
Host::ReportErrorAsync("Error", "Failed to load memory save state, resetting."); Host::ReportErrorAsync("Error", "Failed to load memory save state, resetting.");
@ -3354,7 +3354,7 @@ bool System::SaveMemoryState(MemorySaveState* mss)
else else
mss->state_stream->SeekAbsolute(0); 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); StateWrapper sw(mss->state_stream.get(), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
if (!DoState(sw, &host_texture, false, true)) if (!DoState(sw, &host_texture, false, true))
{ {

View File

@ -327,8 +327,8 @@ LRESULT CALLBACK Win32NoGUIPlatform::WndProc(HWND hwnd, UINT msg, WPARAM wParam,
{ {
const WCHAR utf16[1] = {static_cast<WCHAR>(wParam)}; const WCHAR utf16[1] = {static_cast<WCHAR>(wParam)};
char utf8[8] = {}; char utf8[8] = {};
const int utf8_len = const int utf8_len = WideCharToMultiByte(CP_UTF8, 0, utf16, static_cast<int>(std::size(utf16)), utf8,
WideCharToMultiByte(CP_UTF8, 0, utf16, std::size(utf16), utf8, sizeof(utf8) - 1, nullptr, nullptr); static_cast<int>(sizeof(utf8)) - 1, nullptr, nullptr);
if (utf8_len > 0) if (utf8_len > 0)
{ {
utf8[utf8_len] = 0; utf8[utf8_len] = 0;

View File

@ -128,38 +128,38 @@ bool RegTestHostDisplay::SetPostProcessingChain(const std::string_view& config)
return false; return false;
} }
std::unique_ptr<HostDisplayTexture> RegTestHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, std::unique_ptr<GPUTexture> RegTestHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels,
u32 samples, HostDisplayPixelFormat format, u32 samples, GPUTexture::Format format,
const void* data, u32 data_stride, const void* data, u32 data_stride,
bool dynamic /* = false */) bool dynamic /* = false */)
{ {
return nullptr; 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) 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) 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 u32 input_stride = Common::AlignUpPow2(width * pixel_size, 4);
const u8* input_start = static_cast<const u8*>(texture_handle) + (x * pixel_size); const u8* input_start = static_cast<const u8*>(texture_handle) + (x * pixel_size);
StringUtil::StrideMemCpy(out_data, out_data_stride, input_start, input_stride, width * pixel_size, height); StringUtil::StrideMemCpy(out_data, out_data_stride, input_start, input_stride, width * pixel_size, height);
return true; 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) 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; const u32 required_size = height * pitch;
if (m_frame_buffer.size() != (required_size / 4)) 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, Common::RGBA8Image image(m_display_texture_width, m_display_texture_height,
static_cast<const u32*>(m_display_texture_handle)); static_cast<const u32*>(m_display_texture));
// set alpha channel on all pixels // set alpha channel on all pixels
u32* pixels = image.GetPixels(); u32* pixels = image.GetPixels();
@ -214,7 +214,7 @@ bool RegTestHostDisplay::Render()
} }
bool RegTestHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool RegTestHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) GPUTexture::Format* out_format)
{ {
return false; return false;
} }

View File

@ -43,28 +43,28 @@ public:
void DestroyImGuiContext() override; void DestroyImGuiContext() override;
bool UpdateImGuiFontTexture() override; bool UpdateImGuiFontTexture() override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
HostDisplayPixelFormat format, const void* data, u32 data_stride, GPUTexture::Format format, const void* data, u32 data_stride,
bool dynamic = false) override; 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; 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; u32 height, void* out_data, u32 out_data_stride) override;
void SetVSync(bool enabled) override; void SetVSync(bool enabled) override;
bool Render() override; bool Render() override;
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* 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; u32* out_pitch) override;
void EndSetDisplayPixels() override; void EndSetDisplayPixels() override;
private: private:
std::vector<u32> m_frame_buffer; std::vector<u32> 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; u32 m_frame_buffer_pitch = 0;
}; };

View File

@ -412,9 +412,9 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoBackground)) ImGuiWindowFlags_NoBackground))
{ {
HostDisplayTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png"); GPUTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png");
if (tex) if (tex)
ImGui::Image(tex->GetHandle(), ImVec2(logo_width, logo_height)); ImGui::Image(tex, ImVec2(logo_width, logo_height));
} }
ImGui::End(); ImGui::End();

View File

@ -21,69 +21,6 @@ Log_SetChannel(D3D11HostDisplay);
#pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.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<D3D11::Texture*>(&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<ID3D11DeviceContext*>(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<ID3D11DeviceContext*>(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<ID3D11DeviceContext*>(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() = default;
D3D11HostDisplay::~D3D11HostDisplay() D3D11HostDisplay::~D3D11HostDisplay()
@ -120,34 +57,61 @@ bool D3D11HostDisplay::HasRenderSurface() const
return static_cast<bool>(m_swap_chain); return static_cast<bool>(m_swap_chain);
} }
static constexpr std::array<DXGI_FORMAT, static_cast<u32>(HostDisplayPixelFormat::Count)> std::unique_ptr<GPUTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
s_display_pixel_format_mapping = {{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, GPUTexture::Format format, const void* data,
DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM}}; u32 data_stride, bool dynamic /* = false */)
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels,
u32 samples, HostDisplayPixelFormat format,
const void* data, u32 data_stride,
bool dynamic /* = false */)
{ {
if (layers != 1) std::unique_ptr<D3D11::Texture> tex(std::make_unique<D3D11::Texture>());
return {}; if (!tex->Create(m_device.Get(), width, height, layers, levels, samples, format, D3D11_BIND_SHADER_RESOURCE, data,
data_stride, dynamic))
D3D11::Texture tex;
if (!tex.Create(m_device.Get(), width, height, layers, levels, samples,
s_display_pixel_format_mapping[static_cast<u32>(format)], D3D11_BIND_SHADER_RESOURCE, data,
data_stride, dynamic))
{ {
return {}; tex.reset();
} }
return std::make_unique<D3D11HostDisplayTexture>(std::move(tex), format, dynamic); return tex;
} }
bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, bool D3D11HostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch)
u32 width, u32 height, void* out_data, u32 out_data_stride)
{ {
const D3D11::Texture* tex = static_cast<const D3D11::Texture*>(texture_handle); D3D11::Texture* tex = static_cast<D3D11::Texture*>(texture);
if (!CheckStagingBufferSize(width, height, tex->GetFormat())) 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<D3D11::Texture*>(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<D3D11::Texture*>(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<const D3D11::Texture*>(texture);
if (!CheckStagingBufferSize(width, height, tex->GetDXGIFormat()))
return false; return false;
const CD3D11_BOX box(static_cast<LONG>(x), static_cast<LONG>(y), 0, static_cast<LONG>(x + width), const CD3D11_BOX box(static_cast<LONG>(x), static_cast<LONG>(y), 0, static_cast<LONG>(x + width),
@ -162,7 +126,7 @@ bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPi
return false; 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); StringUtil::StrideMemCpy(out_data, out_data_stride, sr.pData, sr.RowPitch, copy_size, height);
m_context->Unmap(m_readback_staging_texture.Get(), 0); m_context->Unmap(m_readback_staging_texture.Get(), 0);
return true; return true;
@ -195,9 +159,9 @@ void D3D11HostDisplay::DestroyStagingBuffer()
m_readback_staging_texture_format = DXGI_FORMAT_UNKNOWN; 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<u32>(format)]; const DXGI_FORMAT dfmt = D3D11::Texture::GetDXGIFormat(format);
if (dfmt == DXGI_FORMAT_UNKNOWN) if (dfmt == DXGI_FORMAT_UNKNOWN)
return false; return false;
@ -767,13 +731,12 @@ bool D3D11HostDisplay::Render(bool skip_present)
} }
bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) GPUTexture::Format* out_format)
{ {
static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8;
static constexpr HostDisplayPixelFormat hdformat = HostDisplayPixelFormat::RGBA8;
D3D11::Texture render_texture; 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; return false;
static constexpr std::array<float, 4> clear_color = {}; static constexpr std::array<float, 4> clear_color = {};
@ -786,24 +749,24 @@ bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
if (!m_post_processing_chain.IsEmpty()) if (!m_post_processing_chain.IsEmpty())
{ {
ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height, m_display_texture_handle, ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height,
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
width, height); width, height);
} }
else else
{ {
RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, RenderDisplay(left, top, draw_width, draw_height, static_cast<D3D11::Texture*>(m_display_texture),
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); m_display_texture_view_height, IsUsingLinearFiltering());
} }
} }
m_context->OMSetRenderTargets(0, nullptr, nullptr); m_context->OMSetRenderTargets(0, nullptr, nullptr);
const u32 stride = GetDisplayPixelFormatSize(hdformat) * width; const u32 stride = GPUTexture::GetPixelSize(hdformat) * width;
out_pixels->resize(width * height); 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; return false;
*out_stride = stride; *out_stride = stride;
@ -826,36 +789,36 @@ void D3D11HostDisplay::RenderDisplay()
if (!m_post_processing_chain.IsEmpty()) if (!m_post_processing_chain.IsEmpty())
{ {
ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height, m_display_texture_handle, ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height,
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
GetWindowWidth(), GetWindowHeight()); GetWindowWidth(), GetWindowHeight());
return; return;
} }
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height, RenderDisplay(left, top, width, height, static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
m_display_texture_view_height, IsUsingLinearFiltering()); IsUsingLinearFiltering());
} }
void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, D3D11::Texture* texture,
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_height, bool linear_filter) s32 texture_view_height, bool linear_filter)
{ {
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0); m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0); m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0);
m_context->PSSetShaderResources(0, 1, static_cast<D3D11::Texture*>(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()); m_context->PSSetSamplers(0, 1, linear_filter ? m_linear_sampler.GetAddressOf() : m_point_sampler.GetAddressOf());
const bool linear = IsUsingLinearFiltering(); const bool linear = IsUsingLinearFiltering();
const float position_adjust = linear ? 0.5f : 0.0f; const float position_adjust = linear ? 0.5f : 0.0f;
const float size_adjust = linear ? 1.0f : 0.0f; const float size_adjust = linear ? 1.0f : 0.0f;
const float uniforms[4] = { const float uniforms[4] = {
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width), (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height), (static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width), (static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture_height)}; (static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
const auto map = m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), sizeof(uniforms)); 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)); std::memcpy(map.pointer, uniforms, sizeof(uniforms));
m_display_uniform_buffer.Unmap(m_context.Get(), 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()); RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
} }
void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle)
HostDisplayTexture* texture_handle)
{ {
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0); m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
m_context->PSSetShader(m_display_alpha_pixel_shader.Get(), nullptr, 0); m_context->PSSetShader(m_display_alpha_pixel_shader.Get(), nullptr, 0);
m_context->PSSetShaderResources(0, 1, static_cast<D3D11HostDisplayTexture*>(texture_handle)->GetD3DSRVArray()); m_context->PSSetShaderResources(0, 1, static_cast<D3D11::Texture*>(texture_handle)->GetD3DSRVArray());
m_context->PSSetSamplers(0, 1, m_linear_sampler.GetAddressOf()); m_context->PSSetSamplers(0, 1, m_linear_sampler.GetAddressOf());
const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f}; 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()); 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; const u32 bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
if (m_post_processing_input_texture.GetWidth() != target_width || 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, void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top,
s32 final_width, s32 final_height, void* texture_handle, s32 final_width, s32 final_height, D3D11::Texture* texture,
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, s32 texture_view_height, u32 target_width, u32 target_height)
u32 target_width, u32 target_height)
{ {
static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f}; static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
if (!CheckPostProcessingRenderTargets(target_width, target_height)) if (!CheckPostProcessingRenderTargets(target_width, target_height))
{ {
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height, RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); texture_view_width, texture_view_height, IsUsingLinearFiltering());
return; return;
} }
// downsample/upsample - use same viewport for remainder // downsample/upsample - use same viewport for remainder
m_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), clear_color.data()); m_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), clear_color.data());
m_context->OMSetRenderTargets(1, m_post_processing_input_texture.GetD3DRTVArray(), nullptr); 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, RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); texture_view_width, texture_view_height, IsUsingLinearFiltering());
texture_handle = &m_post_processing_input_texture; texture = &m_post_processing_input_texture;
texture_width = m_post_processing_input_texture.GetWidth();
texture_height = m_post_processing_input_texture.GetHeight();
texture_view_x = final_left; texture_view_x = final_left;
texture_view_y = final_top; texture_view_y = final_top;
texture_view_width = final_width; texture_view_width = final_width;
@ -1125,13 +1084,13 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0); m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0);
m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0); m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0);
m_context->PSSetShaderResources(0, 1, static_cast<D3D11::Texture*>(texture_handle)->GetD3DSRVArray()); m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray());
m_context->PSSetSamplers(0, 1, m_point_sampler.GetAddressOf()); m_context->PSSetSamplers(0, 1, m_point_sampler.GetAddressOf());
const auto map = const auto map =
m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), pps.uniforms_size); m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), pps.uniforms_size);
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( 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); texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
m_display_uniform_buffer.Unmap(m_context.Get(), pps.uniforms_size); m_display_uniform_buffer.Unmap(m_context.Get(), pps.uniforms_size);
m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray()); 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); m_context->Draw(3, 0);
if (i != final_stage) if (i != final_stage)
texture_handle = &pps.output_texture; texture = &pps.output_texture;
} }
ID3D11ShaderResourceView* null_srv = nullptr; ID3D11ShaderResourceView* null_srv = nullptr;

View File

@ -47,12 +47,15 @@ public:
bool SetPostProcessingChain(const std::string_view& config) override; bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
HostDisplayPixelFormat format, const void* data, u32 data_stride, GPUTexture::Format format, const void* data, u32 data_stride,
bool dynamic = false) override; bool dynamic = false) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
u32 height, void* out_data, u32 out_data_stride) override; void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const 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; bool GetHostRefreshRate(float* refresh_rate) override;
@ -63,7 +66,7 @@ public:
bool Render(bool skip_present) override; bool Render(bool skip_present) override;
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) override; GPUTexture::Format* out_format) override;
static AdapterAndModeList StaticGetAdapterAndModeList(); static AdapterAndModeList StaticGetAdapterAndModeList();
@ -90,10 +93,9 @@ protected:
void RenderSoftwareCursor(); void RenderSoftwareCursor();
void RenderImGui(); void RenderImGui();
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, void RenderDisplay(s32 left, s32 top, s32 width, s32 height, D3D11::Texture* texture, s32 texture_view_x,
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
s32 texture_view_height, bool linear_filter); void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle);
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
struct PostProcessingStage struct PostProcessingStage
{ {
@ -105,9 +107,8 @@ protected:
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
void ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width, 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 final_height, D3D11::Texture* texture, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height);
u32 target_width, u32 target_height);
bool CreateTimestampQueries(); bool CreateTimestampQueries();
void DestroyTimestampQueries(); void DestroyTimestampQueries();

View File

@ -15,51 +15,6 @@
#include <dxgi1_5.h> #include <dxgi1_5.h>
Log_SetChannel(D3D12HostDisplay); Log_SetChannel(D3D12HostDisplay);
static constexpr std::array<DXGI_FORMAT, static_cast<u32>(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<D3D12::Texture*>(&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<u32>(s_display_pixel_format_mapping.size()); i++)
{
if (m_texture.GetFormat() == s_display_pixel_format_mapping[i])
return static_cast<HostDisplayPixelFormat>(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() = default;
D3D12HostDisplay::~D3D12HostDisplay() D3D12HostDisplay::~D3D12HostDisplay()
@ -98,47 +53,62 @@ bool D3D12HostDisplay::HasRenderSurface() const
return static_cast<bool>(m_swap_chain); return static_cast<bool>(m_swap_chain);
} }
std::unique_ptr<HostDisplayTexture> D3D12HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, std::unique_ptr<GPUTexture> D3D12HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
u32 samples, HostDisplayPixelFormat format, GPUTexture::Format format, const void* data,
const void* data, u32 data_stride, u32 data_stride, bool dynamic /* = false */)
bool dynamic /* = false */)
{ {
if (layers != 1) const DXGI_FORMAT dformat = D3D12::Texture::GetDXGIFormat(format);
if (dformat == DXGI_FORMAT_UNKNOWN)
return {}; return {};
const DXGI_FORMAT dxgi_format = s_display_pixel_format_mapping[static_cast<u32>(format)]; std::unique_ptr<D3D12::Texture> tex(std::make_unique<D3D12::Texture>());
D3D12::Texture tex; if (!tex->Create(width, height, layers, levels, samples, dformat, dformat, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
if (!tex.Create(width, height, samples, dxgi_format, dxgi_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE))
D3D12_RESOURCE_FLAG_NONE))
{ {
return {}; 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 {};
return std::make_unique<D3D12HostDisplayTexture>(std::move(tex)); return tex;
} }
bool D3D12HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, bool D3D12HostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch)
u32 width, u32 height, void* out_data, u32 out_data_stride)
{ {
const D3D12::Texture* texture = static_cast<const D3D12::Texture*>(texture_handle); return static_cast<D3D12::Texture*>(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<D3D12::Texture*>(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<const D3D12::Texture*>(texture);
if (!m_readback_staging_texture.EnsureSize(width, height, tex->GetDXGIFormat(), false))
return false; return false;
const D3D12_RESOURCE_STATES old_state = texture->GetState(); const D3D12_RESOURCE_STATES old_state = tex->GetState();
texture->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE); tex->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
m_readback_staging_texture.CopyFromTexture(texture->GetResource(), 0, x, y, 0, 0, width, height); m_readback_staging_texture.CopyFromTexture(tex->GetResource(), 0, x, y, 0, 0, width, height);
texture->TransitionToState(old_state); tex->TransitionToState(old_state);
return m_readback_staging_texture.ReadPixels(0, 0, width, height, out_data, out_data_stride); 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<u32>(format)]; const DXGI_FORMAT dfmt = D3D12::Texture::GetDXGIFormat(format);
if (dfmt == DXGI_FORMAT_UNKNOWN) if (dfmt == DXGI_FORMAT_UNKNOWN)
return false; return false;
@ -654,13 +624,13 @@ bool D3D12HostDisplay::Render(bool skip_present)
} }
bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) GPUTexture::Format* out_format)
{ {
static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; 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; 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) || D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ||
!m_readback_staging_texture.EnsureSize(width, height, format, false)) !m_readback_staging_texture.EnsureSize(width, height, format, false))
{ {
@ -676,9 +646,9 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
if (HasDisplayTexture()) if (HasDisplayTexture())
{ {
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0); 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, RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast<D3D12::Texture*>(m_display_texture),
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); m_display_texture_view_height, IsUsingLinearFiltering());
} }
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr); cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr);
@ -728,23 +698,22 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist)
// return; // return;
// } // }
RenderDisplay(cmdlist, left, top, width, height, m_display_texture_handle, m_display_texture_width, RenderDisplay(cmdlist, left, top, width, height, static_cast<D3D12::Texture*>(m_display_texture),
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); m_display_texture_view_height, IsUsingLinearFiltering());
} }
void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, 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, D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, s32 texture_view_width, s32 texture_view_height, bool linear_filter)
bool linear_filter)
{ {
const float position_adjust = linear_filter ? 0.5f : 0.0f; const float position_adjust = linear_filter ? 0.5f : 0.0f;
const float size_adjust = linear_filter ? 1.0f : 0.0f; const float size_adjust = linear_filter ? 1.0f : 0.0f;
const float uniforms[4] = { const float uniforms[4] = {
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width), (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height), (static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width), (static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture_height)}; (static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)) if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
Panic("Failed to reserve UBO space"); 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->SetGraphicsRootSignature(m_display_root_signature.Get());
cmdlist->SetPipelineState(m_display_pipeline.Get()); cmdlist->SetPipelineState(m_display_pipeline.Get());
cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset); cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset);
cmdlist->SetGraphicsRootDescriptorTable(1, reinterpret_cast<D3D12::Texture*>(texture_handle)->GetSRVDescriptor()); cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor());
cmdlist->SetGraphicsRootDescriptorTable(2, linear_filter ? m_linear_sampler : m_point_sampler); cmdlist->SetGraphicsRootDescriptorTable(2, linear_filter ? m_linear_sampler : m_point_sampler);
D3D12::SetViewportAndScissor(cmdlist, left, top, width, height); 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, 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}; 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)) 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->SetPipelineState(m_display_pipeline.Get());
cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset); cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset);
cmdlist->SetGraphicsRootDescriptorTable( cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12::Texture*>(texture_handle)->GetRTVOrDSVDescriptor());
1, static_cast<D3D12HostDisplayTexture*>(texture_handle)->GetTexture().GetRTVOrDSVDescriptor());
cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler); cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler);
D3D12::SetViewportAndScissor(cmdlist, left, top, width, height); D3D12::SetViewportAndScissor(cmdlist, left, top, width, height);

View File

@ -49,12 +49,15 @@ public:
bool SetPostProcessingChain(const std::string_view& config) override; bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
HostDisplayPixelFormat format, const void* data, u32 data_stride, GPUTexture::Format format, const void* data, u32 data_stride,
bool dynamic = false) override; bool dynamic = false) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
u32 height, void* out_data, u32 out_data_stride) override; void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const 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; bool GetHostRefreshRate(float* refresh_rate) override;
@ -62,7 +65,7 @@ public:
bool Render(bool skip_present) override; bool Render(bool skip_present) override;
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) override; GPUTexture::Format* out_format) override;
bool SetGPUTimingEnabled(bool enabled) override; bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override; float GetAndResetAccumulatedGPUTime() override;
@ -93,11 +96,11 @@ protected:
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist); void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist);
void RenderImGui(ID3D12GraphicsCommandList* cmdlist); void RenderImGui(ID3D12GraphicsCommandList* cmdlist);
void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, void* texture_handle, void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_width, s32 texture_view_height, bool linear_filter); s32 texture_view_height, bool linear_filter);
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
HostDisplayTexture* texture_handle); GPUTexture* texture_handle);
ComPtr<IDXGIFactory> m_dxgi_factory; ComPtr<IDXGIFactory> m_dxgi_factory;
ComPtr<IDXGISwapChain> m_swap_chain; ComPtr<IDXGISwapChain> m_swap_chain;

View File

@ -218,14 +218,14 @@ static std::deque<AsyncOpEntry> s_async_ops;
static bool LoadResources(); static bool LoadResources();
static void DestroyResources(); static void DestroyResources();
static std::shared_ptr<HostDisplayTexture> s_app_icon_texture; static std::shared_ptr<GPUTexture> s_app_icon_texture;
static std::array<std::shared_ptr<HostDisplayTexture>, static_cast<u32>(GameDatabase::CompatibilityRating::Count)> static std::array<std::shared_ptr<GPUTexture>, static_cast<u32>(GameDatabase::CompatibilityRating::Count)>
s_game_compatibility_textures; s_game_compatibility_textures;
static std::shared_ptr<HostDisplayTexture> s_fallback_disc_texture; static std::shared_ptr<GPUTexture> s_fallback_disc_texture;
static std::shared_ptr<HostDisplayTexture> s_fallback_exe_texture; static std::shared_ptr<GPUTexture> s_fallback_exe_texture;
static std::shared_ptr<HostDisplayTexture> s_fallback_psf_texture; static std::shared_ptr<GPUTexture> s_fallback_psf_texture;
static std::shared_ptr<HostDisplayTexture> s_fallback_playlist_texture; static std::shared_ptr<GPUTexture> s_fallback_playlist_texture;
static std::vector<std::unique_ptr<HostDisplayTexture>> s_cleanup_textures; static std::vector<std::unique_ptr<GPUTexture>> s_cleanup_textures;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Landing // Landing
@ -375,7 +375,7 @@ struct SaveStateListEntry
std::string title; std::string title;
std::string summary; std::string summary;
std::string path; std::string path;
std::unique_ptr<HostDisplayTexture> preview_texture; std::unique_ptr<GPUTexture> preview_texture;
time_t timestamp; time_t timestamp;
s32 slot; s32 slot;
bool global; bool global;
@ -415,9 +415,9 @@ static void HandleGameListOptions(const GameList::Entry* entry);
static void DrawGameListSettingsPage(const ImVec2& heading_size); static void DrawGameListSettingsPage(const ImVec2& heading_size);
static void SwitchToGameList(); static void SwitchToGameList();
static void PopulateGameListEntryList(); static void PopulateGameListEntryList();
static HostDisplayTexture* GetTextureForGameListEntryType(GameList::EntryType type); static GPUTexture* GetTextureForGameListEntryType(GameList::EntryType type);
static HostDisplayTexture* GetGameListCover(const GameList::Entry* entry); static GPUTexture* GetGameListCover(const GameList::Entry* entry);
static HostDisplayTexture* GetCoverForCurrentGame(); static GPUTexture* GetCoverForCurrentGame();
// Lazily populated cover images. // Lazily populated cover images.
static std::unordered_map<std::string, std::string> s_cover_image_map; static std::unordered_map<std::string, std::string> s_cover_image_map;
@ -717,7 +717,7 @@ void FullscreenUI::Render()
if (!s_initialized) if (!s_initialized)
return; return;
for (std::unique_ptr<HostDisplayTexture>& tex : s_cleanup_textures) for (std::unique_ptr<GPUTexture>& tex : s_cleanup_textures)
tex.reset(); tex.reset();
s_cleanup_textures.clear(); s_cleanup_textures.clear();
ImGuiFullscreen::UploadAsyncTextures(); ImGuiFullscreen::UploadAsyncTextures();
@ -1077,7 +1077,7 @@ void FullscreenUI::DrawLandingWindow()
const float image_size = LayoutScale(380.f); const float image_size = LayoutScale(380.f);
ImGui::SetCursorPos(ImVec2((ImGui::GetWindowWidth() * 0.5f) - (image_size * 0.5f), ImGui::SetCursorPos(ImVec2((ImGui::GetWindowWidth() * 0.5f) - (image_size * 0.5f),
(ImGui::GetWindowHeight() * 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(); EndFullscreenColumnWindow();
@ -3885,7 +3885,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
const ImVec2 image_min(display_size.x - LayoutScale(20.0f + 50.0f) - rp_height, const ImVec2 image_min(display_size.x - LayoutScale(20.0f + 50.0f) - rp_height,
display_size.y - 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); 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)); 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(); li->preview_texture.reset();
if (ssi && !ssi->screenshot_data.empty()) if (ssi && !ssi->screenshot_data.empty())
{ {
li->preview_texture = g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, li->preview_texture =
HostDisplayPixelFormat::RGBA8, ssi->screenshot_data.data(), g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, GPUTexture::Format::RGBA8,
sizeof(u32) * ssi->screenshot_width, false); ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false);
} }
else else
{ {
li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, li->preview_texture =
HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA, g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, GPUTexture::Format::RGBA8,
sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
} }
if (!li->preview_texture) if (!li->preview_texture)
@ -4254,8 +4254,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading, bool fullscreen)
ImVec2 pos(bb.Min); ImVec2 pos(bb.Min);
// use aspect ratio of screenshot to determine height // use aspect ratio of screenshot to determine height
const HostDisplayTexture* image = const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
const float image_height = const float image_height =
max_image_width / (static_cast<float>(image->GetWidth()) / static_cast<float>(image->GetHeight())); max_image_width / (static_cast<float>(image->GetWidth()) / static_cast<float>(image->GetHeight()));
const float image_margin = (max_image_height - image_height) / 2.0f; 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::PopFont();
ImGui::GetWindowDrawList()->AddImage(static_cast<ImTextureID>(entry.preview_texture ? ImGui::GetWindowDrawList()->AddImage(
entry.preview_texture->GetHandle() : static_cast<ImTextureID>(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()),
GetPlaceholderTexture()->GetHandle()), image_bb.Min, image_bb.Max);
image_bb.Min, image_bb.Max);
if (pressed) 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?", 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()); TimeToPrintableString(entry.timestamp).c_str());
const HostDisplayTexture* image = const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
const float image_height = LayoutScale(250.0f); const float image_height = LayoutScale(250.0f);
const float image_width = const float image_width =
image_height * (static_cast<float>(image->GetWidth()) / static_cast<float>(image->GetHeight())); image_height * (static_cast<float>(image->GetWidth()) / static_cast<float>(image->GetHeight()));
const ImVec2 pos(ImGui::GetCursorScreenPos() + const ImVec2 pos(ImGui::GetCursorScreenPos() +
ImVec2((ImGui::GetCurrentWindow()->WorkRect.GetWidth() - image_width) * 0.5f, LayoutScale(20.0f))); ImVec2((ImGui::GetCurrentWindow()->WorkRect.GetWidth() - image_width) * 0.5f, LayoutScale(20.0f)));
const ImRect image_bb(pos, pos + ImVec2(image_width, image_height)); const ImRect image_bb(pos, pos + ImVec2(image_width, image_height));
ImGui::GetWindowDrawList()->AddImage(static_cast<ImTextureID>(entry.preview_texture ? ImGui::GetWindowDrawList()->AddImage(
entry.preview_texture->GetHandle() : static_cast<ImTextureID>(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()),
GetPlaceholderTexture()->GetHandle()), image_bb.Min, image_bb.Max);
image_bb.Min, image_bb.Max);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + image_height + LayoutScale(40.0f)); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + image_height + LayoutScale(40.0f));
@ -4564,7 +4560,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
if (!visible) if (!visible)
continue; continue;
HostDisplayTexture* cover_texture = GetGameListCover(entry); GPUTexture* cover_texture = GetGameListCover(entry);
if (entry->serial.empty()) 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<float>(cover_texture->GetWidth()), CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(cover_texture->GetWidth()),
static_cast<float>(cover_texture->GetHeight())))); static_cast<float>(cover_texture->GetHeight()))));
ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), image_rect.Min, image_rect.Max, ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f),
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); 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 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); 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)) 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); selected_entry ? GetGameListCover(selected_entry) : GetTextureForGameListEntryType(GameList::EntryType::Count);
if (cover_texture) if (cover_texture)
{ {
@ -4632,8 +4628,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
static_cast<float>(cover_texture->GetHeight())))); static_cast<float>(cover_texture->GetHeight()))));
ImGui::SetCursorPos(LayoutScale(ImVec2(90.0f, 50.0f)) + image_rect.Min); ImGui::SetCursorPos(LayoutScale(ImVec2(90.0f, 50.0f)) + image_rect.Min);
ImGui::Image(selected_entry ? GetGameListCover(selected_entry)->GetHandle() : ImGui::Image(selected_entry ? GetGameListCover(selected_entry) :
GetTextureForGameListEntryType(GameList::EntryType::Count)->GetHandle(), GetTextureForGameListEntryType(GameList::EntryType::Count),
image_rect.GetSize()); image_rect.GetSize());
} }
@ -4683,7 +4679,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
fmt::format("fullscreenui/{}.png", Settings::GetDiscRegionName(selected_entry->region))); fmt::format("fullscreenui/{}.png", Settings::GetDiscRegionName(selected_entry->region)));
ImGui::TextUnformatted("Region: "); ImGui::TextUnformatted("Region: ");
ImGui::SameLine(); 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::SameLine();
ImGui::Text(" (%s)", Settings::GetDiscRegionDisplayName(selected_entry->region)); ImGui::Text(" (%s)", Settings::GetDiscRegionDisplayName(selected_entry->region));
} }
@ -4701,7 +4697,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
ImGui::SameLine(); ImGui::SameLine();
if (selected_entry->compatibility != GameDatabase::CompatibilityRating::Unknown) if (selected_entry->compatibility != GameDatabase::CompatibilityRating::Unknown)
{ {
ImGui::Image(s_game_compatibility_textures[static_cast<u32>(selected_entry->compatibility)]->GetHandle(), ImGui::Image(s_game_compatibility_textures[static_cast<u32>(selected_entry->compatibility)].get(),
LayoutScale(64.0f, 16.0f)); LayoutScale(64.0f, 16.0f));
ImGui::SameLine(); ImGui::SameLine();
} }
@ -4801,13 +4797,13 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
bb.Min += style.FramePadding; bb.Min += style.FramePadding;
bb.Max -= style.FramePadding; bb.Max -= style.FramePadding;
const HostDisplayTexture* const cover_texture = GetGameListCover(entry); GPUTexture* const cover_texture = GetGameListCover(entry);
const ImRect image_rect( const ImRect image_rect(
CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(cover_texture->GetWidth()), CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(cover_texture->GetWidth()),
static_cast<float>(cover_texture->GetHeight())))); static_cast<float>(cover_texture->GetHeight()))));
ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), image_rect.Min, image_rect.Max, ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f),
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); 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 ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
const std::string_view title( const std::string_view title(
@ -5111,7 +5107,7 @@ void FullscreenUI::SwitchToGameList()
QueueResetFocus(); QueueResetFocus();
} }
HostDisplayTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry) GPUTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry)
{ {
// lookup and grab cover image // lookup and grab cover image
auto cover_it = s_cover_image_map.find(entry->path); 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; 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); return tex ? tex : GetTextureForGameListEntryType(entry->type);
} }
HostDisplayTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type) GPUTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type)
{ {
switch (type) switch (type)
{ {
@ -5144,7 +5140,7 @@ HostDisplayTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::Entry
} }
} }
HostDisplayTexture* FullscreenUI::GetCoverForCurrentGame() GPUTexture* FullscreenUI::GetCoverForCurrentGame()
{ {
auto lock = GameList::GetLock(); auto lock = GameList::GetLock();
@ -5360,11 +5356,11 @@ void FullscreenUI::DrawAchievement(const Achievements::Achievement& cheevo)
const std::string& badge_path = Achievements::GetAchievementBadgePath(cheevo); const std::string& badge_path = Achievements::GetAchievementBadgePath(cheevo);
if (!badge_path.empty()) if (!badge_path.empty())
{ {
HostDisplayTexture* badge = GetCachedTextureAsync(badge_path.c_str()); GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str());
if (badge) if (badge)
{ {
ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f), ImGui::GetWindowDrawList()->AddImage(badge, bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); IM_COL32(255, 255, 255, 255));
} }
} }
@ -5463,11 +5459,11 @@ void FullscreenUI::DrawAchievementsWindow()
const std::string& icon_path = Achievements::GetGameIcon(); const std::string& icon_path = Achievements::GetGameIcon();
if (!icon_path.empty()) if (!icon_path.empty())
{ {
HostDisplayTexture* badge = GetCachedTexture(icon_path.c_str()); GPUTexture* badge = GetCachedTexture(icon_path.c_str());
if (badge) if (badge)
{ {
ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), icon_min, icon_max, ImVec2(0.0f, 0.0f), ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); IM_COL32(255, 255, 255, 255));
} }
} }
@ -5602,12 +5598,12 @@ void FullscreenUI::DrawPrimedAchievements()
if (badge_path.empty()) if (badge_path.empty())
return true; return true;
HostDisplayTexture* badge = GetCachedTextureAsync(badge_path.c_str()); GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str());
if (!badge) if (!badge)
return true; return true;
ImDrawList* dl = ImGui::GetBackgroundDrawList(); ImDrawList* dl = ImGui::GetBackgroundDrawList();
dl->AddImage(badge->GetHandle(), position, position + image_size); dl->AddImage(badge, position, position + image_size);
position.x -= x_advance; position.x -= x_advance;
return true; return true;
}); });
@ -5786,11 +5782,11 @@ void FullscreenUI::DrawLeaderboardsWindow()
const std::string& icon_path = Achievements::GetGameIcon(); const std::string& icon_path = Achievements::GetGameIcon();
if (!icon_path.empty()) if (!icon_path.empty())
{ {
HostDisplayTexture* badge = GetCachedTexture(icon_path.c_str()); GPUTexture* badge = GetCachedTexture(icon_path.c_str());
if (badge) if (badge)
{ {
ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), icon_min, icon_max, ImVec2(0.0f, 0.0f), ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); IM_COL32(255, 255, 255, 255));
} }
} }

View File

@ -4,7 +4,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
class HostDisplayTexture; class GPUTexture;
struct Settings; struct Settings;

View File

@ -32,7 +32,7 @@ namespace ImGuiFullscreen {
using MessageDialogCallbackVariant = std::variant<InfoMessageDialogCallback, ConfirmMessageDialogCallback>; using MessageDialogCallbackVariant = std::variant<InfoMessageDialogCallback, ConfirmMessageDialogCallback>;
static std::optional<Common::RGBA8Image> LoadTextureImage(const char* path); static std::optional<Common::RGBA8Image> LoadTextureImage(const char* path);
static std::shared_ptr<HostDisplayTexture> UploadTexture(const char* path, const Common::RGBA8Image& image); static std::shared_ptr<GPUTexture> UploadTexture(const char* path, const Common::RGBA8Image& image);
static void TextureLoaderThread(); static void TextureLoaderThread();
static void DrawFileSelector(); static void DrawFileSelector();
@ -78,8 +78,8 @@ static u32 s_menu_button_index = 0;
static u32 s_close_button_state = 0; static u32 s_close_button_state = 0;
static bool s_focus_reset_queued = false; static bool s_focus_reset_queued = false;
static LRUCache<std::string, std::shared_ptr<HostDisplayTexture>> s_texture_cache(128, true); static LRUCache<std::string, std::shared_ptr<GPUTexture>> s_texture_cache(128, true);
static std::shared_ptr<HostDisplayTexture> s_placeholder_texture; static std::shared_ptr<GPUTexture> s_placeholder_texture;
static std::atomic_bool s_texture_load_thread_quit{false}; static std::atomic_bool s_texture_load_thread_quit{false};
static std::mutex s_texture_load_mutex; static std::mutex s_texture_load_mutex;
static std::condition_variable s_texture_load_cv; static std::condition_variable s_texture_load_cv;
@ -231,7 +231,7 @@ void ImGuiFullscreen::Shutdown()
s_file_selector_items.clear(); s_file_selector_items.clear();
} }
const std::shared_ptr<HostDisplayTexture>& ImGuiFullscreen::GetPlaceholderTexture() const std::shared_ptr<GPUTexture>& ImGuiFullscreen::GetPlaceholderTexture()
{ {
return s_placeholder_texture; return s_placeholder_texture;
} }
@ -262,10 +262,10 @@ std::optional<Common::RGBA8Image> ImGuiFullscreen::LoadTextureImage(const char*
return image; return image;
} }
std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image) std::shared_ptr<GPUTexture> ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image)
{ {
std::unique_ptr<HostDisplayTexture> texture = std::unique_ptr<GPUTexture> texture =
g_host_display->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, HostDisplayPixelFormat::RGBA8, g_host_display->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Format::RGBA8,
image.GetPixels(), image.GetPitch()); image.GetPixels(), image.GetPitch());
if (!texture) if (!texture)
{ {
@ -274,16 +274,16 @@ std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::UploadTexture(const char* p
} }
Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight()); Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight());
return std::shared_ptr<HostDisplayTexture>(std::move(texture)); return std::shared_ptr<GPUTexture>(std::move(texture));
} }
std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::LoadTexture(const std::string_view& path) std::shared_ptr<GPUTexture> ImGuiFullscreen::LoadTexture(const std::string_view& path)
{ {
std::string path_str(path); std::string path_str(path);
std::optional<Common::RGBA8Image> image(LoadTextureImage(path_str.c_str())); std::optional<Common::RGBA8Image> image(LoadTextureImage(path_str.c_str()));
if (image.has_value()) if (image.has_value())
{ {
std::shared_ptr<HostDisplayTexture> ret(UploadTexture(path_str.c_str(), image.value())); std::shared_ptr<GPUTexture> ret(UploadTexture(path_str.c_str(), image.value()));
if (ret) if (ret)
return ret; return ret;
} }
@ -291,21 +291,21 @@ std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::LoadTexture(const std::stri
return s_placeholder_texture; return s_placeholder_texture;
} }
HostDisplayTexture* ImGuiFullscreen::GetCachedTexture(const std::string_view& name) GPUTexture* ImGuiFullscreen::GetCachedTexture(const std::string_view& name)
{ {
std::shared_ptr<HostDisplayTexture>* tex_ptr = s_texture_cache.Lookup(name); std::shared_ptr<GPUTexture>* tex_ptr = s_texture_cache.Lookup(name);
if (!tex_ptr) if (!tex_ptr)
{ {
std::shared_ptr<HostDisplayTexture> tex(LoadTexture(name)); std::shared_ptr<GPUTexture> tex(LoadTexture(name));
tex_ptr = s_texture_cache.Insert(std::string(name), std::move(tex)); tex_ptr = s_texture_cache.Insert(std::string(name), std::move(tex));
} }
return tex_ptr->get(); return tex_ptr->get();
} }
HostDisplayTexture* ImGuiFullscreen::GetCachedTextureAsync(const std::string_view& name) GPUTexture* ImGuiFullscreen::GetCachedTextureAsync(const std::string_view& name)
{ {
std::shared_ptr<HostDisplayTexture>* tex_ptr = s_texture_cache.Lookup(name); std::shared_ptr<GPUTexture>* tex_ptr = s_texture_cache.Lookup(name);
if (!tex_ptr) if (!tex_ptr)
{ {
// insert the placeholder // insert the placeholder
@ -334,7 +334,7 @@ void ImGuiFullscreen::UploadAsyncTextures()
s_texture_upload_queue.pop_front(); s_texture_upload_queue.pop_front();
lock.unlock(); lock.unlock();
std::shared_ptr<HostDisplayTexture> tex = UploadTexture(it.first.c_str(), it.second); std::shared_ptr<GPUTexture> tex = UploadTexture(it.first.c_str(), it.second);
if (tex) if (tex)
s_texture_cache.Insert(std::move(it.first), std::move(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); const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
if (!notif.badge_path.empty()) if (!notif.badge_path.empty())
{ {
HostDisplayTexture* tex = GetCachedTexture(notif.badge_path.c_str()); GPUTexture* tex = GetCachedTexture(notif.badge_path.c_str());
if (tex) if (tex)
dl->AddImage(static_cast<ImTextureID>(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); const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);

View File

@ -9,7 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
class HostDisplayTexture; class GPUTexture;
namespace ImGuiFullscreen { namespace ImGuiFullscreen {
#define HEX_TO_IMVEC4(hex, alpha) \ #define HEX_TO_IMVEC4(hex, alpha) \
@ -121,10 +121,10 @@ bool UpdateLayoutScale();
void Shutdown(); void Shutdown();
/// Texture cache. /// Texture cache.
const std::shared_ptr<HostDisplayTexture>& GetPlaceholderTexture(); const std::shared_ptr<GPUTexture>& GetPlaceholderTexture();
std::shared_ptr<HostDisplayTexture> LoadTexture(const std::string_view& path); std::shared_ptr<GPUTexture> LoadTexture(const std::string_view& path);
HostDisplayTexture* GetCachedTexture(const std::string_view& name); GPUTexture* GetCachedTexture(const std::string_view& name);
HostDisplayTexture* GetCachedTextureAsync(const std::string_view& name); GPUTexture* GetCachedTextureAsync(const std::string_view& name);
bool InvalidateCachedTexture(const std::string& path); bool InvalidateCachedTexture(const std::string& path);
void UploadAsyncTextures(); void UploadAsyncTextures();

View File

@ -251,7 +251,7 @@ bool ImGui_ImplDX11_CreateFontsTexture()
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
const u32 stride = sizeof(u32) * width; 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; return false;
// Store our identifier // Store our identifier

View File

@ -266,7 +266,7 @@ bool ImGui_ImplDX12_CreateFontsTexture()
// Upload texture to graphics system // Upload texture to graphics system
if (bd->FontTexture.GetWidth() != static_cast<u32>(width) || bd->FontTexture.GetHeight() != static_cast<u32>(height)) if (bd->FontTexture.GetWidth() != static_cast<u32>(width) || bd->FontTexture.GetHeight() != static_cast<u32>(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, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
D3D12_RESOURCE_FLAG_NONE)) D3D12_RESOURCE_FLAG_NONE))
{ {

View File

@ -110,20 +110,20 @@
// OpenGL Data // OpenGL Data
struct ImGui_ImplOpenGL3_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) 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. char GlslVersionString[32] = {}; // Specified by user or detected based on compile time GL settings.
GL::Texture FontTexture; GL::Texture FontTexture;
GLuint ShaderHandle; GLuint ShaderHandle = 0;
GLint AttribLocationTex; // Uniforms location GLint AttribLocationTex = 0; // Uniforms location
GLint AttribLocationProjMtx; GLint AttribLocationProjMtx = 0;
GLuint AttribLocationVtxPos; // Vertex attributes location GLuint AttribLocationVtxPos = 0; // Vertex attributes location
GLuint AttribLocationVtxUV; GLuint AttribLocationVtxUV = 0;
GLuint AttribLocationVtxColor; GLuint AttribLocationVtxColor = 0;
unsigned int VboHandle, ElementsHandle, VaoHandle; unsigned int VboHandle = 0, ElementsHandle = 0, VaoHandle = 0;
GLsizeiptr VertexBufferSize; GLsizeiptr VertexBufferSize = 0;
GLsizeiptr IndexBufferSize; 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 // 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 // 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) // (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); bd->FontTexture.SetLinearFilter(true);
// Store our identifier // Store our identifier
@ -326,7 +326,6 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
void ImGui_ImplOpenGL3_DestroyFontsTexture() void ImGui_ImplOpenGL3_DestroyFontsTexture()
{ {
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->FontTexture.IsValid()) if (bd->FontTexture.IsValid())
bd->FontTexture.Destroy(); bd->FontTexture.Destroy();

View File

@ -409,7 +409,7 @@ struct ListEntry
std::string game_code; std::string game_code;
std::string title; std::string title;
std::string formatted_timestamp; std::string formatted_timestamp;
std::unique_ptr<HostDisplayTexture> preview_texture; std::unique_ptr<GPUTexture> preview_texture;
s32 slot; s32 slot;
bool global; bool global;
}; };
@ -564,13 +564,13 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn
if (ssi && !ssi->screenshot_data.empty()) if (ssi && !ssi->screenshot_data.empty())
{ {
li->preview_texture = g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, 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); sizeof(u32) * ssi->screenshot_width, false);
} }
else else
{ {
li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, 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); sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
} }
@ -591,7 +591,7 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, std::str
if (g_host_display) if (g_host_display)
{ {
li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, 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); sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
if (!li->preview_texture) if (!li->preview_texture)
Log_ErrorPrintf("Failed to upload save state image to GPU"); Log_ErrorPrintf("Failed to upload save state image to GPU");
@ -645,7 +645,7 @@ void SaveStateSelectorUI::Draw()
{ {
ImGui::SetCursorPosY(y_start + padding); ImGui::SetCursorPosY(y_start + padding);
ImGui::SetCursorPosX(padding); ImGui::SetCursorPosX(padding);
ImGui::Image(reinterpret_cast<ImTextureID>(entry.preview_texture->GetHandle()), image_size); ImGui::Image(entry.preview_texture.get(), image_size);
} }
ImGui::SetCursorPosY(y_start + padding); ImGui::SetCursorPosY(y_start + padding);

View File

@ -16,36 +16,6 @@ enum : u32
TEXTURE_STREAM_BUFFER_SIZE = 16 * 1024 * 1024, 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<GL::Texture*>(&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() = default;
OpenGLHostDisplay::~OpenGLHostDisplay() OpenGLHostDisplay::~OpenGLHostDisplay()
@ -74,54 +44,134 @@ void* OpenGLHostDisplay::GetRenderContext() const
return m_gl_context.get(); return m_gl_context.get();
} }
static const std::tuple<GLenum, GLenum, GLenum>& GetPixelFormatMapping(bool is_gles, HostDisplayPixelFormat format) std::unique_ptr<GPUTexture> 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<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(HostDisplayPixelFormat::Count)> std::unique_ptr<GL::Texture> tex(std::make_unique<GL::Texture>());
mapping = {{ if (!tex->Create(width, height, layers, levels, samples, format, data, data_stride))
{}, // Unknown tex.reset();
{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
}};
static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(HostDisplayPixelFormat::Count)> return tex;
mapping_gles2 = {{ }
{}, // Unknown
{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
{}, // BGRA8
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565
{} // RGBA5551
}};
if (is_gles && !GLAD_GL_ES_VERSION_3_0) bool OpenGLHostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer,
return mapping_gles2[static_cast<u32>(format)]; 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 else
return mapping[static_cast<u32>(format)]; {
std::vector<u8>& 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<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, void OpenGLHostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height)
u32 samples, HostDisplayPixelFormat format,
const void* data, u32 data_stride,
bool dynamic /* = false */)
{ {
if (layers != 1 || levels != 1) const u32 pixel_size = texture->GetPixelSize();
return {}; const u32 stride = Common::AlignUpPow2(width * pixel_size, 4);
const u32 size_required = stride * height;
GL::Texture* gl_texture = static_cast<GL::Texture*>(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 gl_texture->Bind();
Assert(!data || data_stride == (width * sizeof(u32))); if (buffer && size_required < buffer->GetSize())
{
buffer->Unmap(size_required);
buffer->Bind();
GL::Texture tex; if (whole_texture)
if (!tex.Create(width, height, layers, levels, samples, gl_internal_format, gl_format, gl_type, data, data_stride)) {
return {}; glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type,
reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture_stream_buffer_offset)));
}
else
{
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type,
reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture_stream_buffer_offset)));
}
return std::make_unique<OpenGLHostDisplayTexture>(std::move(tex), format); buffer->Unbind();
}
else
{
std::vector<u8>& 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, bool OpenGLHostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 width, u32 height, void* out_data, u32 out_data_stride) u32 pitch)
{
GL::Texture* gl_texture = static_cast<GL::Texture*>(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<u8>& 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; GLint alignment;
if (out_data_stride & 1) if (out_data_stride & 1)
@ -137,14 +187,13 @@ bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
if (!m_use_gles2_draw_path) if (!m_use_gles2_draw_path)
{ {
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length); 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<const GL::Texture*>(texture_handle); const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(texture->GetFormat());
const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), texture_format);
GL::Texture::GetTextureSubImage(texture->GetGLId(), 0, x, y, 0, width, height, 1, gl_format, gl_type, GL::Texture::GetTextureSubImage(static_cast<const GL::Texture*>(texture)->GetGLId(), 0, x, y, 0, width, height, 1,
height * out_data_stride, out_data); gl_format, gl_type, height * out_data_stride, out_data);
glPixelStorei(GL_PACK_ALIGNMENT, old_alignment); glPixelStorei(GL_PACK_ALIGNMENT, old_alignment);
if (!m_use_gles2_draw_path) if (!m_use_gles2_draw_path)
@ -152,9 +201,9 @@ bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
return true; 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<GLenum>(0)); return (gl_internal_format != static_cast<GLenum>(0));
} }
@ -594,11 +643,10 @@ bool OpenGLHostDisplay::Render(bool skip_present)
} }
bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) GPUTexture::Format* out_format)
{ {
GL::Texture texture; GL::Texture texture;
if (!texture.Create(width, height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr) || if (!texture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0) || !texture.CreateFramebuffer())
!texture.CreateFramebuffer())
{ {
return false; return false;
} }
@ -615,22 +663,21 @@ bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
if (!m_post_processing_chain.IsEmpty()) if (!m_post_processing_chain.IsEmpty())
{ {
ApplyPostProcessingChain(texture.GetGLFramebufferID(), left, height - top - draw_height, draw_width, draw_height, ApplyPostProcessingChain(texture.GetGLFramebufferID(), left, height - top - draw_height, draw_width, draw_height,
m_display_texture_handle, m_display_texture_width, m_display_texture_height, static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
m_display_texture_view_height, width, height); width, height);
} }
else else
{ {
RenderDisplay(left, height - top - draw_height, draw_width, draw_height, m_display_texture_handle, RenderDisplay(left, height - top - draw_height, draw_width, draw_height,
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
IsUsingLinearFiltering());
} }
} }
out_pixels->resize(width * height); out_pixels->resize(width * height);
*out_stride = sizeof(u32) * width; *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()); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, out_pixels->data());
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -653,16 +700,16 @@ void OpenGLHostDisplay::RenderDisplay()
if (!m_post_processing_chain.IsEmpty()) if (!m_post_processing_chain.IsEmpty())
{ {
ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height, m_display_texture_handle, ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height,
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
GetWindowWidth(), GetWindowHeight()); GetWindowWidth(), GetWindowHeight());
return; return;
} }
RenderDisplay(left, GetWindowHeight() - top - height, width, height, m_display_texture_handle, RenderDisplay(left, GetWindowHeight() - top - height, width, height, static_cast<GL::Texture*>(m_display_texture),
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); 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, 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); glDisableVertexAttribArray(0);
} }
void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, GL::Texture* texture,
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_width, s32 texture_view_height, bool linear_filter) s32 texture_view_height, bool linear_filter)
{ {
const GL::Texture* texture = static_cast<const GL::Texture*>(texture_handle);
glViewport(left, bottom, width, height); glViewport(left, bottom, width, height);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glDisable(GL_CULL_FACE); 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 size_adjust = linear ? 1.0f : 0.0f;
const float flip_adjust = (texture_view_height < 0) ? -1.0f : 1.0f; const float flip_adjust = (texture_view_height < 0) ? -1.0f : 1.0f;
m_display_program.Uniform4f( m_display_program.Uniform4f(
0, (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width), 0, (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_y) + (position_adjust * flip_adjust)) / static_cast<float>(texture_height), (static_cast<float>(texture_view_y) + (position_adjust * flip_adjust)) / static_cast<float>(texture->GetHeight()),
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width), (static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_height) - (size_adjust * flip_adjust)) / static_cast<float>(texture_height)); (static_cast<float>(texture_view_height) - (size_adjust * flip_adjust)) /
static_cast<float>(texture->GetHeight()));
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler); glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
glBindVertexArray(m_display_vao); glBindVertexArray(m_display_vao);
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
@ -725,7 +771,7 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
texture->SetLinearFilter(linear_filter); texture->SetLinearFilter(linear_filter);
DrawFullscreenQuadES2(m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, 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()); RenderSoftwareCursor(left, GetWindowHeight() - top - height, width, height, m_cursor_texture.get());
} }
void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle)
HostDisplayTexture* texture_handle)
{ {
glViewport(left, bottom, width, height); glViewport(left, bottom, width, height);
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -749,7 +794,7 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
m_cursor_program.Bind(); m_cursor_program.Bind();
glBindTexture(GL_TEXTURE_2D, static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetGLID()); static_cast<GL::Texture*>(texture_handle)->Bind();
if (!m_use_gles2_draw_path) if (!m_use_gles2_draw_path)
{ {
@ -761,8 +806,8 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3
} }
else else
{ {
const s32 tex_width = static_cast<s32>(static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetWidth()); const s32 tex_width = static_cast<s32>(texture_handle->GetWidth());
const s32 tex_height = static_cast<s32>(static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetHeight()); const s32 tex_height = static_cast<s32>(texture_handle->GetHeight());
DrawFullscreenQuadES2(0, 0, tex_width, tex_height, tex_width, tex_height); 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 || if (m_post_processing_input_texture.GetWidth() != target_width ||
m_post_processing_input_texture.GetHeight() != target_height) 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, if (!m_post_processing_input_texture.Create(target_width, target_height, 1, 1, 1, GPUTexture::Format::RGBA8) ||
GL_UNSIGNED_BYTE) ||
!m_post_processing_input_texture.CreateFramebuffer()) !m_post_processing_input_texture.CreateFramebuffer())
{ {
return false; return false;
@ -856,7 +900,7 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
PostProcessingStage& pps = m_post_processing_stages[i]; PostProcessingStage& pps = m_post_processing_stages[i];
if (pps.output_texture.GetWidth() != target_width || pps.output_texture.GetHeight() != target_height) 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()) !pps.output_texture.CreateFramebuffer())
{ {
return false; 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, 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 final_height, GL::Texture* texture, s32 texture_view_x,
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_width, u32 target_height)
u32 target_height)
{ {
if (!CheckPostProcessingRenderTargets(target_width, target_height)) if (!CheckPostProcessingRenderTargets(target_width, target_height))
{ {
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle, RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture,
texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
texture_view_height, IsUsingLinearFiltering());
return; return;
} }
// downsample/upsample - use same viewport for remainder // downsample/upsample - use same viewport for remainder
m_post_processing_input_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_post_processing_input_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle, RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture,
texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
IsUsingLinearFiltering());
texture_handle = &m_post_processing_input_texture; texture = &m_post_processing_input_texture;
texture_width = m_post_processing_input_texture.GetWidth();
texture_height = m_post_processing_input_texture.GetHeight();
texture_view_x = final_left; texture_view_x = final_left;
texture_view_y = final_top; texture_view_y = final_top;
texture_view_width = final_width; texture_view_width = final_width;
@ -914,12 +953,12 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_
pps.program.Bind(); pps.program.Bind();
static_cast<const GL::Texture*>(texture_handle)->Bind(); static_cast<const GL::Texture*>(texture)->Bind();
glBindSampler(0, m_display_nearest_sampler); glBindSampler(0, m_display_nearest_sampler);
const auto map_result = m_post_processing_ubo->Map(m_uniform_buffer_alignment, pps.uniforms_size); const auto map_result = m_post_processing_ubo->Map(m_uniform_buffer_alignment, pps.uniforms_size);
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( 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); texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
m_post_processing_ubo->Unmap(pps.uniforms_size); m_post_processing_ubo->Unmap(pps.uniforms_size);
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_post_processing_ubo->GetGLBufferId(), map_result.buffer_offset, 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); glDrawArrays(GL_TRIANGLES, 0, 3);
if (i != final_stage) if (i != final_stage)
texture_handle = &pps.output_texture; texture = &pps.output_texture;
} }
glBindSampler(0, 0); glBindSampler(0, 0);
@ -955,7 +994,7 @@ void OpenGLHostDisplay::DestroyTimestampQueries()
if (m_timestamp_query_started) if (m_timestamp_query_started)
{ {
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery; const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
EndQuery(m_timestamp_queries[m_write_timestamp_query]); EndQuery(GL_TIME_ELAPSED);
} }
DeleteQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data()); DeleteQueries(static_cast<u32>(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); m_texture_stream_buffer = GL::StreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, TEXTURE_STREAM_BUFFER_SIZE);
return m_texture_stream_buffer.get(); 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<OpenGLHostDisplay*>(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<u8>& 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<OpenGLHostDisplay*>(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<void*>(static_cast<uintptr_t>(m_map_offset)));
}
else
{
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type,
reinterpret_cast<void*>(static_cast<uintptr_t>(m_map_offset)));
}
buffer->Unbind();
}
else
{
std::vector<u8>& 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<OpenGLHostDisplay*>(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<u8>& 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;
}

View File

@ -40,18 +40,21 @@ public:
bool SetPostProcessingChain(const std::string_view& config) override; bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
HostDisplayPixelFormat format, const void* data, u32 data_stride, GPUTexture::Format format, const void* data, u32 data_stride,
bool dynamic = false) override; bool dynamic = false) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
u32 height, void* out_data, u32 out_data_stride) override; void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const 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; void SetVSync(bool enabled) override;
bool Render(bool skip_present) override; bool Render(bool skip_present) override;
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) override; GPUTexture::Format* out_format) override;
bool SetGPUTimingEnabled(bool enabled) override; bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override; float GetAndResetAccumulatedGPUTime() override;
@ -80,10 +83,9 @@ protected:
void RenderImGui(); void RenderImGui();
void RenderSoftwareCursor(); void RenderSoftwareCursor();
void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, u32 texture_width, void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, GL::Texture* texture, s32 texture_view_x,
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
s32 texture_view_height, bool linear_filter); void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle);
void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, HostDisplayTexture* texture_handle);
struct PostProcessingStage struct PostProcessingStage
{ {
@ -94,9 +96,8 @@ protected:
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); 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 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, GL::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, u32 target_width, s32 texture_view_height, u32 target_width, u32 target_height);
u32 target_height);
void CreateTimestampQueries(); void CreateTimestampQueries();
void DestroyTimestampQueries(); void DestroyTimestampQueries();
@ -114,6 +115,7 @@ protected:
std::unique_ptr<GL::StreamBuffer> m_texture_stream_buffer; std::unique_ptr<GL::StreamBuffer> m_texture_stream_buffer;
std::vector<u8> m_texture_repack_buffer; std::vector<u8> m_texture_repack_buffer;
u32 m_texture_stream_buffer_offset = 0;
FrontendCommon::PostProcessingChain m_post_processing_chain; FrontendCommon::PostProcessingChain m_post_processing_chain;
GL::Texture m_post_processing_input_texture; GL::Texture m_post_processing_input_texture;

View File

@ -18,43 +18,6 @@
#include <array> #include <array>
Log_SetChannel(VulkanHostDisplay); 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<Vulkan::Texture*>(&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() = default;
VulkanHostDisplay::~VulkanHostDisplay() VulkanHostDisplay::~VulkanHostDisplay()
@ -172,56 +135,65 @@ void VulkanHostDisplay::DestroyRenderSurface()
m_swap_chain.reset(); m_swap_chain.reset();
} }
static constexpr std::array<VkFormat, static_cast<u32>(HostDisplayPixelFormat::Count)> s_display_pixel_format_mapping = std::unique_ptr<GPUTexture> VulkanHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
{{VK_FORMAT_UNDEFINED, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16, GPUTexture::Format format, const void* data,
VK_FORMAT_A1R5G5B5_UNORM_PACK16}}; u32 data_stride, bool dynamic /* = false */)
std::unique_ptr<HostDisplayTexture> VulkanHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels,
u32 samples, HostDisplayPixelFormat format,
const void* data, u32 data_stride,
bool dynamic /* = false */)
{ {
const VkFormat vk_format = s_display_pixel_format_mapping[static_cast<u32>(format)]; const VkFormat vk_format = Vulkan::Texture::GetVkFormat(format);
if (vk_format == VK_FORMAT_UNDEFINED) if (vk_format == VK_FORMAT_UNDEFINED)
return {}; return {};
static constexpr VkImageUsageFlags usage = static constexpr VkImageUsageFlags usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; 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(), std::unique_ptr<Vulkan::Texture> texture(std::make_unique<Vulkan::Texture>());
"VulkanHostDisplay::CreateTexture"); if (!texture->Create(width, height, levels, layers, vk_format, static_cast<VkSampleCountFlagBits>(samples),
(layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
Vulkan::Texture texture; usage))
if (!texture.Create(width, height, levels, layers, vk_format, static_cast<VkSampleCountFlagBits>(samples),
(layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
usage))
{ {
return {}; 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) 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 else
{ {
// clear it instead so we don't read uninitialized data (and keep the validation layer happy!) // clear it instead so we don't read uninitialized data (and keep the validation layer happy!)
static constexpr VkClearColorValue ccv = {}; static constexpr VkClearColorValue ccv = {};
static constexpr VkImageSubresourceRange isr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; static constexpr VkImageSubresourceRange isr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
vkCmdClearColorImage(g_vulkan_context->GetCurrentCommandBuffer(), texture.GetImage(), texture.GetLayout(), &ccv, 1u, vkCmdClearColorImage(g_vulkan_context->GetCurrentCommandBuffer(), texture->GetImage(), texture->GetLayout(), &ccv,
&isr); 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<VulkanHostDisplayTexture>(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<u32>(format)]; return static_cast<Vulkan::Texture*>(texture)->BeginUpdate(width, height, out_buffer, out_pitch);
}
void VulkanHostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height)
{
static_cast<Vulkan::Texture*>(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<Vulkan::Texture*>(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) if (vk_format == VK_FORMAT_UNDEFINED)
return false; return false;
@ -310,12 +282,12 @@ void VulkanHostDisplay::DestroyStagingBuffer()
} }
} }
bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, bool VulkanHostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 width, u32 height, void* out_data, u32 out_data_stride) u32 out_data_stride)
{ {
Vulkan::Texture* texture = static_cast<Vulkan::Texture*>(const_cast<void*>(texture_handle)); Vulkan::Texture* tex = static_cast<Vulkan::Texture*>(texture);
const u32 pitch = texture->CalcUpdatePitch(width); const u32 pitch = tex->CalcUpdatePitch(width);
const u32 size = pitch * height; const u32 size = pitch * height;
const u32 level = 0; const u32 level = 0;
if (!CheckStagingBufferSize(size)) if (!CheckStagingBufferSize(size))
@ -328,16 +300,16 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
const VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer(); const VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
const Vulkan::Util::DebugScope debugScope(cmdbuf, "VulkanHostDisplay::DownloadTexture(%u,%u)", width, height); 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) 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 = {}; VkBufferImageCopy image_copy = {};
const VkImageAspectFlags aspect = Vulkan::Util::IsDepthFormat(static_cast<VkFormat>(texture->GetFormat())) ? const VkImageAspectFlags aspect = Vulkan::Util::IsDepthFormat(static_cast<VkFormat>(tex->GetFormat())) ?
VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_DEPTH_BIT :
VK_IMAGE_ASPECT_COLOR_BIT; VK_IMAGE_ASPECT_COLOR_BIT;
image_copy.bufferOffset = 0; image_copy.bufferOffset = 0;
image_copy.bufferRowLength = texture->CalcUpdateRowLength(pitch); image_copy.bufferRowLength = tex->CalcUpdateRowLength(pitch);
image_copy.bufferImageHeight = 0; image_copy.bufferImageHeight = 0;
image_copy.imageSubresource = {aspect, level, 0u, 1u}; image_copy.imageSubresource = {aspect, level, 0u, 1u};
image_copy.imageOffset = {static_cast<s32>(x), static_cast<s32>(y), 0}; image_copy.imageOffset = {static_cast<s32>(x), static_cast<s32>(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); VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
// do the copy // do the copy
vkCmdCopyImageToBuffer(cmdbuf, texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_readback_staging_buffer, vkCmdCopyImageToBuffer(cmdbuf, tex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_readback_staging_buffer, 1,
1, &image_copy); &image_copy);
// flush gpu cache // flush gpu cache
Vulkan::Util::BufferMemoryBarrier(cmdbuf, m_readback_staging_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, 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) 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<u32>* out_pixels, u32* out_stride, bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* 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... // in theory we could do this without a swap chain, but postprocessing assumes it for now...
if (!m_swap_chain) if (!m_swap_chain)
@ -685,26 +657,26 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
{ {
case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SRGB: case VK_FORMAT_R8G8B8A8_SRGB:
*out_format = HostDisplayPixelFormat::RGBA8; *out_format = GPUTexture::Format::RGBA8;
*out_stride = sizeof(u32) * width; *out_stride = sizeof(u32) * width;
out_pixels->resize(width * height); out_pixels->resize(width * height);
break; break;
case VK_FORMAT_B8G8R8A8_UNORM: case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_B8G8R8A8_SRGB: case VK_FORMAT_B8G8R8A8_SRGB:
*out_format = HostDisplayPixelFormat::BGRA8; *out_format = GPUTexture::Format::BGRA8;
*out_stride = sizeof(u32) * width; *out_stride = sizeof(u32) * width;
out_pixels->resize(width * height); out_pixels->resize(width * height);
break; break;
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
*out_format = HostDisplayPixelFormat::RGBA5551; *out_format = GPUTexture::Format::RGBA5551;
*out_stride = sizeof(u16) * width; *out_stride = sizeof(u16) * width;
out_pixels->resize(((width * height) + 1) / 2); out_pixels->resize(((width * height) + 1) / 2);
break; break;
case VK_FORMAT_R5G6B5_UNORM_PACK16: case VK_FORMAT_R5G6B5_UNORM_PACK16:
*out_format = HostDisplayPixelFormat::RGB565; *out_format = GPUTexture::Format::RGB565;
*out_stride = sizeof(u16) * width; *out_stride = sizeof(u16) * width;
out_pixels->resize(((width * height) + 1) / 2); out_pixels->resize(((width * height) + 1) / 2);
break; break;
@ -746,22 +718,22 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
if (!m_post_processing_chain.IsEmpty()) if (!m_post_processing_chain.IsEmpty())
{ {
ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, static_cast<Vulkan::Texture*>(m_display_texture),
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_width, m_display_texture_view_height, width, height); m_display_texture_view_height, width, height);
} }
else else
{ {
BeginSwapChainRenderPass(fb, width, height); BeginSwapChainRenderPass(fb, width, height);
RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width, RenderDisplay(left, top, draw_width, draw_height, static_cast<Vulkan::Texture*>(m_display_texture),
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); m_display_texture_view_height, IsUsingLinearFiltering());
} }
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer()); vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer()); Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
tex.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 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 // destroying these immediately should be safe since nothing's going to access them, and it's not part of the command
// stream // stream
@ -800,27 +772,27 @@ void VulkanHostDisplay::RenderDisplay()
if (!m_post_processing_chain.IsEmpty()) if (!m_post_processing_chain.IsEmpty())
{ {
ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height, m_display_texture_handle, ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height,
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
return; return;
} }
BeginSwapChainRenderPass(m_swap_chain->GetCurrentFramebuffer(), m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); 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, RenderDisplay(left, top, width, height, static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
m_display_texture_view_height, IsUsingLinearFiltering()); IsUsingLinearFiltering());
} }
void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, Vulkan::Texture* texture,
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_width, s32 texture_view_height, bool linear_filter) s32 texture_view_height, bool linear_filter)
{ {
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
const Vulkan::Util::DebugScope debugScope( const Vulkan::Util::DebugScope debugScope(
cmdbuffer, "VulkanHostDisplay::RenderDisplay: {%u,%u} %ux%u | %ux%u | {%u,%u} %ux%u", left, top, width, height, 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); VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_descriptor_set_layout);
if (ds == VK_NULL_HANDLE) 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<Vulkan::Texture*>(texture_handle);
Vulkan::DescriptorSetUpdateBuilder dsupdate; Vulkan::DescriptorSetUpdateBuilder dsupdate;
dsupdate.AddCombinedImageSamplerDescriptorWrite( 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()); dsupdate.Update(g_vulkan_context->GetDevice());
} }
const float position_adjust = IsUsingLinearFiltering() ? 0.5f : 0.0f; const float position_adjust = IsUsingLinearFiltering() ? 0.5f : 0.0f;
const float size_adjust = IsUsingLinearFiltering() ? 1.0f : 0.0f; const float size_adjust = IsUsingLinearFiltering() ? 1.0f : 0.0f;
const PushConstants pc{(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width), const PushConstants pc{
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height), (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width), (static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture_height)}; (static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_display_pipeline); vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_display_pipeline);
vkCmdPushConstants(cmdbuffer, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pc), &pc); 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()); 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(); VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
const Vulkan::Util::DebugScope debugScope(cmdbuffer, "VulkanHostDisplay::RenderSoftwareCursor: {%u,%u} %ux%u", left, 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; Vulkan::DescriptorSetUpdateBuilder dsupdate;
dsupdate.AddCombinedImageSamplerDescriptorWrite( dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 0, static_cast<Vulkan::Texture*>(texture)->GetView(),
ds, 0, static_cast<VulkanHostDisplayTexture*>(texture)->GetTexture().GetView(), m_linear_sampler); m_linear_sampler);
dsupdate.Update(g_vulkan_context->GetDevice()); 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, void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top,
s32 final_width, s32 final_height, void* texture_handle, s32 final_width, s32 final_height, Vulkan::Texture* texture,
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, s32 texture_view_height, u32 target_width, u32 target_height)
u32 target_width, u32 target_height)
{ {
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
const Vulkan::Util::DebugScope post_scope(cmdbuffer, "VulkanHostDisplay::ApplyPostProcessingChain"); 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)) if (!CheckPostProcessingRenderTargets(target_width, target_height))
{ {
BeginSwapChainRenderPass(target_fb, 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, RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); texture_view_width, texture_view_height, IsUsingLinearFiltering());
return; return;
} }
// downsample/upsample - use same viewport for remainder // downsample/upsample - use same viewport for remainder
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
BeginSwapChainRenderPass(m_post_processing_input_framebuffer, target_width, target_height); 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, RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering()); texture_view_width, texture_view_height, IsUsingLinearFiltering());
vkCmdEndRenderPass(cmdbuffer); vkCmdEndRenderPass(cmdbuffer);
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer()); Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
texture_handle = &m_post_processing_input_texture; texture = &m_post_processing_input_texture;
texture_width = m_post_processing_input_texture.GetWidth();
texture_height = m_post_processing_input_texture.GetHeight();
texture_view_x = final_left; texture_view_x = final_left;
texture_view_y = final_top; texture_view_y = final_top;
texture_view_width = final_width; texture_view_width = final_width;
@ -1177,17 +1146,16 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
return; return;
} }
const Vulkan::Texture* vktex = static_cast<Vulkan::Texture*>(texture_handle);
Vulkan::DescriptorSetUpdateBuilder dsupdate; 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) if (use_push_constants)
{ {
u8 buffer[FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD]; u8 buffer[FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD];
Assert(pps.uniforms_size <= sizeof(buffer)); Assert(pps.uniforms_size <= sizeof(buffer));
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
buffer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height, buffer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width,
GetWindowWidth(), GetWindowHeight(), 0.0f); texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
vkCmdPushConstants(cmdbuffer, m_post_process_pipeline_layout, vkCmdPushConstants(cmdbuffer, m_post_process_pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, pps.uniforms_size, buffer); 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(); const u32 offset = m_post_processing_ubo.GetCurrentOffset();
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
m_post_processing_ubo.GetCurrentHostPointer(), texture_width, texture_height, texture_view_x, texture_view_y, m_post_processing_ubo.GetCurrentHostPointer(), texture->GetWidth(), texture->GetHeight(), texture_view_x,
texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f); texture_view_y, texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
m_post_processing_ubo.CommitMemory(pps.uniforms_size); m_post_processing_ubo.CommitMemory(pps.uniforms_size);
dsupdate.AddBufferDescriptorWrite(ds, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, dsupdate.AddBufferDescriptorWrite(ds, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
@ -1226,7 +1194,7 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
vkCmdEndRenderPass(cmdbuffer); vkCmdEndRenderPass(cmdbuffer);
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer()); Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
pps.output_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); pps.output_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
texture_handle = &pps.output_texture; texture = &pps.output_texture;
} }
} }
} }

View File

@ -30,7 +30,7 @@ public:
bool threaded_presentation) override; bool threaded_presentation) override;
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device, bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
bool threaded_presentation) override; bool threaded_presentation) override;
bool MakeRenderContextCurrent() override; bool MakeRenderContextCurrent() override;
bool DoneRenderContextCurrent() override; bool DoneRenderContextCurrent() override;
@ -44,18 +44,21 @@ public:
bool SetPostProcessingChain(const std::string_view& config) override; bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
HostDisplayPixelFormat format, const void* data, u32 data_stride, GPUTexture::Format format, const void* data, u32 data_stride,
bool dynamic = false) override; bool dynamic = false) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
u32 height, void* out_data, u32 out_data_stride) override; void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const 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; void SetVSync(bool enabled) override;
bool Render(bool skip_present) override; bool Render(bool skip_present) override;
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride, bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
HostDisplayPixelFormat* out_format) override; GPUTexture::Format* out_format) override;
bool SetGPUTimingEnabled(bool enabled) override; bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override; float GetAndResetAccumulatedGPUTime() override;
@ -85,9 +88,8 @@ protected:
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
void ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top, s32 final_width, 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 final_height, Vulkan::Texture* texture, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height);
u32 target_width, u32 target_height);
VkRenderPass GetRenderPassForDisplay() const; VkRenderPass GetRenderPassForDisplay() const;
@ -106,10 +108,9 @@ protected:
void RenderImGui(); void RenderImGui();
void RenderSoftwareCursor(); void RenderSoftwareCursor();
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width, void RenderDisplay(s32 left, s32 top, s32 width, s32 height, Vulkan::Texture* texture, s32 texture_view_x,
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
s32 texture_view_height, bool linear_filter); void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle);
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
std::unique_ptr<Vulkan::SwapChain> m_swap_chain; std::unique_ptr<Vulkan::SwapChain> m_swap_chain;