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
file_system.cpp
file_system.h
gpu_texture.cpp
gpu_texture.h
image.cpp
image.h
hash_combine.h

View File

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

View File

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

View File

@ -1,38 +1,63 @@
#include "texture.h"
#include "../log.h"
#include <array>
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,
ComPtr<ID3D11RenderTargetView> rtv)
D3D11::Texture::Texture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
ComPtr<ID3D11RenderTargetView> rtv)
: m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv(std::move(rtv))
{
const D3D11_TEXTURE2D_DESC desc = GetDesc();
m_width = static_cast<u16>(desc.Width);
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_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();
}
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;
m_texture->GetDesc(&desc);
return desc;
}
bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples,
DXGI_FORMAT format, u32 bind_flags, const void* initial_data /* = nullptr */,
u32 initial_data_stride /* = 0 */, bool dynamic /* = false */)
bool D3D11::Texture::IsValid() const
{
return static_cast<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 ||
layers > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION || (layers > 1 && samples > 1))
@ -42,7 +67,7 @@ bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u3
return false;
}
CD3D11_TEXTURE2D_DESC desc(format, width, height, layers, levels, bind_flags,
CD3D11_TEXTURE2D_DESC desc(GetDXGIFormat(format), width, height, layers, levels, bind_flags,
dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0,
samples, 0, 0);
@ -96,13 +121,15 @@ bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u3
m_rtv = std::move(rtv);
m_width = static_cast<u16>(width);
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_samples = static_cast<u8>(samples);
m_format = format;
m_dynamic = dynamic;
return true;
}
bool Texture::Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture)
bool D3D11::Texture::Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture)
{
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
@ -140,22 +167,18 @@ bool Texture::Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture)
m_rtv = std::move(rtv);
m_width = static_cast<u16>(desc.Width);
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_samples = static_cast<u8>(desc.SampleDesc.Count);
m_dynamic = (desc.Usage == D3D11_USAGE_DYNAMIC);
return true;
}
void Texture::Destroy()
void D3D11::Texture::Destroy()
{
m_rtv.Reset();
m_srv.Reset();
m_texture.Reset();
m_width = 0;
m_height = 0;
m_layers = 0;
m_levels = 0;
m_samples = 0;
m_dynamic = false;
ClearBaseProperties();
}
} // namespace D3D11

View File

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

View File

@ -8,79 +8,111 @@
#include "util.h"
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();
m_width = static_cast<u32>(desc.Width);
m_height = desc.Height;
m_samples = desc.SampleDesc.Count;
m_format = desc.Format;
m_width = static_cast<u16>(desc.Width);
m_height = static_cast<u16>(desc.Height);
m_layers = static_cast<u8>(desc.DepthOrArraySize);
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_rtv_or_dsv_descriptor(texture.m_rtv_or_dsv_descriptor), m_width(texture.m_width), m_height(texture.m_height),
m_samples(texture.m_samples), m_format(texture.m_format), m_state(texture.m_state),
m_is_depth_view(texture.m_is_depth_view)
m_rtv_or_dsv_descriptor(texture.m_rtv_or_dsv_descriptor), m_is_depth_view(texture.m_is_depth_view)
{
m_width = texture.m_width;
m_height = texture.m_height;
m_layers = texture.m_layers;
m_levels = texture.m_levels;
m_samples = texture.m_samples;
texture.m_srv_descriptor = {};
texture.m_rtv_or_dsv_descriptor = {};
texture.m_width = 0;
texture.m_height = 0;
texture.m_samples = 0;
texture.m_format = DXGI_FORMAT_UNKNOWN;
texture.m_state = D3D12_RESOURCE_STATE_COMMON;
texture.m_is_depth_view = false;
texture.ClearBaseProperties();
}
Texture::~Texture()
DXGI_FORMAT D3D12::Texture::GetDXGIFormat(Format format)
{
return s_dxgi_mapping[static_cast<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();
}
Texture& Texture::operator=(Texture&& texture)
D3D12::Texture& D3D12::Texture::operator=(Texture&& texture)
{
Destroy();
m_width = texture.m_width;
m_height = texture.m_height;
m_layers = texture.m_layers;
m_levels = texture.m_levels;
m_samples = texture.m_samples;
m_resource = std::move(texture.m_resource);
m_srv_descriptor = texture.m_srv_descriptor;
m_rtv_or_dsv_descriptor = texture.m_rtv_or_dsv_descriptor;
m_width = texture.m_width;
m_height = texture.m_height;
m_samples = texture.m_samples;
m_format = texture.m_format;
m_state = texture.m_state;
m_is_depth_view = texture.m_is_depth_view;
texture.ClearBaseProperties();
texture.m_srv_descriptor = {};
texture.m_rtv_or_dsv_descriptor = {};
texture.m_width = 0;
texture.m_height = 0;
texture.m_samples = 0;
texture.m_format = DXGI_FORMAT_UNKNOWN;
texture.m_state = D3D12_RESOURCE_STATE_COMMON;
texture.m_is_depth_view = false;
return *this;
}
D3D12_RESOURCE_DESC Texture::GetDesc() const
D3D12_RESOURCE_DESC D3D12::Texture::GetDesc() const
{
return m_resource->GetDesc();
}
bool Texture::Create(u32 width, u32 height, u32 samples, DXGI_FORMAT format, DXGI_FORMAT srv_format,
DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags)
bool D3D12::Texture::IsValid() const
{
return static_cast<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};
if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES)
{
Log_ErrorPrintf("Invalid dimensions: %ux%ux%u %u %u", width, height, layers, levels, samples);
return false;
}
D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Width = width;
desc.Height = height;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Height = static_cast<u16>(height);
desc.DepthOrArraySize = static_cast<u16>(layers);
desc.MipLevels = static_cast<u16>(levels);
desc.Format = format;
desc.SampleDesc.Count = samples;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
@ -147,17 +179,19 @@ bool Texture::Create(u32 width, u32 height, u32 samples, DXGI_FORMAT format, DXG
m_resource = std::move(resource);
m_srv_descriptor = std::move(srv_descriptor);
m_rtv_or_dsv_descriptor = std::move(rtv_descriptor);
m_width = width;
m_height = height;
m_samples = samples;
m_format = format;
m_width = static_cast<u16>(width);
m_height = static_cast<u16>(height);
m_layers = static_cast<u8>(layers);
m_levels = static_cast<u8>(levels);
m_samples = static_cast<u8>(samples);
m_format = LookupBaseFormat(format);
m_state = state;
m_is_depth_view = is_depth_view;
return true;
}
bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state)
bool D3D12::Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state)
{
const D3D12_RESOURCE_DESC desc(texture->GetDesc());
@ -168,6 +202,8 @@ bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI
return false;
}
m_is_depth_view = false;
if (rtv_format != DXGI_FORMAT_UNKNOWN)
{
Assert(dsv_format == DXGI_FORMAT_UNKNOWN);
@ -184,20 +220,24 @@ bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false;
}
m_is_depth_view = true;
}
m_resource = std::move(texture);
m_srv_descriptor = std::move(srv_descriptor);
m_rtv_or_dsv_descriptor = std::move(rtv_descriptor);
m_width = static_cast<u32>(desc.Width);
m_height = desc.Height;
m_samples = desc.SampleDesc.Count;
m_format = desc.Format;
m_width = static_cast<u16>(desc.Width);
m_height = static_cast<u16>(desc.Height);
m_layers = static_cast<u8>(desc.DepthOrArraySize);
m_levels = static_cast<u8>(desc.MipLevels);
m_samples = static_cast<u8>(desc.SampleDesc.Count);
m_format = LookupBaseFormat(desc.Format);
m_state = state;
return true;
}
void Texture::Destroy(bool defer /* = true */)
void D3D12::Texture::Destroy(bool defer /* = true */)
{
if (defer)
{
@ -220,14 +260,11 @@ void Texture::Destroy(bool defer /* = true */)
m_resource.Reset();
}
m_width = 0;
m_height = 0;
m_samples = 0;
m_format = DXGI_FORMAT_UNKNOWN;
ClearBaseProperties();
m_is_depth_view = false;
}
void Texture::TransitionToState(D3D12_RESOURCE_STATES state) const
void D3D12::Texture::TransitionToState(D3D12_RESOURCE_STATES state) const
{
if (m_state == state)
return;
@ -236,9 +273,9 @@ void Texture::TransitionToState(D3D12_RESOURCE_STATES state) const
m_state = state;
}
bool Texture::BeginStreamUpdate(u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch)
bool D3D12::Texture::BeginStreamUpdate(u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch)
{
const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 copy_pitch = Common::AlignUpPow2(width * GetPixelSize(), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = copy_pitch * height;
if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
@ -258,9 +295,9 @@ bool Texture::BeginStreamUpdate(u32 x, u32 y, u32 width, u32 height, void** out_
return true;
}
void Texture::EndStreamUpdate(u32 x, u32 y, u32 width, u32 height)
void D3D12::Texture::EndStreamUpdate(u32 x, u32 y, u32 width, u32 height)
{
const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 copy_pitch = Common::AlignUpPow2(width * GetPixelSize(), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = copy_pitch * height;
StreamBuffer& sb = g_d3d12_context->GetTextureStreamBuffer();
@ -270,7 +307,8 @@ void Texture::EndStreamUpdate(u32 x, u32 y, u32 width, u32 height)
CopyFromBuffer(x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset);
}
void Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset)
void D3D12::Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer,
u32 buffer_offset)
{
D3D12_TEXTURE_COPY_LOCATION src;
src.pResource = buffer;
@ -281,7 +319,7 @@ void Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3
src.PlacedFootprint.Footprint.Height = height;
src.PlacedFootprint.Footprint.Depth = 1;
src.PlacedFootprint.Footprint.RowPitch = pitch;
src.PlacedFootprint.Footprint.Format = m_format;
src.PlacedFootprint.Footprint.Format = GetDXGIFormat();
D3D12_TEXTURE_COPY_LOCATION dst;
dst.pResource = m_resource.Get();
@ -295,15 +333,15 @@ void Texture::CopyFromBuffer(u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3
TransitionToState(old_state);
}
bool Texture::LoadData(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
bool D3D12::Texture::LoadData(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
{
const u32 texel_size = GetTexelSize(m_format);
const u32 texel_size = GetPixelSize();
const u32 upload_pitch = Common::AlignUpPow2(width * texel_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = upload_pitch * height;
if (upload_size >= g_d3d12_context->GetTextureStreamBuffer().GetSize())
{
StagingTexture st;
if (!st.Create(width, height, m_format, true) || !st.WritePixels(0, 0, width, height, data, pitch))
if (!st.Create(width, height, GetDXGIFormat(), true) || !st.WritePixels(0, 0, width, height, data, pitch))
return false;
D3D12_RESOURCE_STATES old_state = m_state;
@ -324,7 +362,7 @@ bool Texture::LoadData(u32 x, u32 y, u32 width, u32 height, const void* data, u3
return true;
}
void Texture::CopyToUploadBuffer(const void* src_data, u32 src_pitch, u32 height, void* dst_data, u32 dst_pitch)
void D3D12::Texture::CopyToUploadBuffer(const void* src_data, u32 src_pitch, u32 height, void* dst_data, u32 dst_pitch)
{
const u8* src_ptr = static_cast<const u8*>(src_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))
{
@ -362,7 +401,8 @@ bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format,
return true;
}
bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, DescriptorHandle* dh)
bool D3D12::Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled,
DescriptorHandle* dh)
{
if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh))
{
@ -377,7 +417,8 @@ bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format,
return true;
}
bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled, DescriptorHandle* dh)
bool D3D12::Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, bool multisampled,
DescriptorHandle* dh)
{
if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh))
{
@ -391,5 +432,3 @@ bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format,
g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
return true;
}
} // namespace D3D12

View File

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

View File

@ -1,51 +1,78 @@
#include "texture.h"
#include "../assert.h"
#include "../log.h"
#include <array>
#include <limits>
#include <tuple>
Log_SetChannel(GL);
namespace GL {
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)
const std::tuple<GLenum, GLenum, GLenum>& GL::Texture::GetPixelFormatMapping(GPUTexture::Format format)
{
moved.m_id = 0;
moved.m_width = 0;
moved.m_height = 0;
moved.m_samples = 0;
moved.m_fbo_id = 0;
static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(GPUTexture::Format::Count)> mapping =
{{
{}, // Unknown
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
{GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8
{GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565
{GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // RGBA5551
{GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_SHORT}, // D16
}};
static constexpr std::array<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();
}
bool Texture::UseTextureStorage(bool multisampled)
bool GL::Texture::UseTextureStorage(bool multisampled)
{
return GLAD_GL_ARB_texture_storage || (multisampled ? GLAD_GL_ES_VERSION_3_1 : GLAD_GL_ES_VERSION_3_0);
}
bool Texture::UseTextureStorage() const
bool GL::Texture::UseTextureStorage() const
{
return UseTextureStorage(IsMultisampled());
}
bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GLenum internal_format, GLenum format,
GLenum type, const void* data /* = nullptr */, bool linear_filter /* = false */,
bool wrap /* = false */)
bool GL::Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Format format,
const void* data /* = nullptr */, u32 data_pitch /* = 0 */, bool linear /* = true */,
bool wrap /* = true */)
{
glGetError();
if (width > MAX_DIMENSIONS || height > MAX_DIMENSIONS || layers > MAX_DIMENSIONS || levels > MAX_DIMENSIONS ||
samples > MAX_SAMPLES)
if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES)
{
Log_ErrorPrintf("Invalid dimensions: %ux%ux%u %u %u", width, height, layers, levels, samples);
return false;
@ -65,6 +92,7 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
const GLenum target = ((samples > 1) ? ((layers > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D_MULTISAMPLE_ARRAY) :
((layers > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D));
const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(format);
GLuint id;
glGenTextures(1, &id);
@ -76,16 +104,16 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
if (UseTextureStorage(true))
{
if (layers > 1)
glTexStorage3DMultisample(target, samples, internal_format, width, height, layers, GL_FALSE);
glTexStorage3DMultisample(target, samples, gl_internal_format, width, height, layers, GL_FALSE);
else
glTexStorage2DMultisample(target, samples, internal_format, width, height, GL_FALSE);
glTexStorage2DMultisample(target, samples, gl_internal_format, width, height, GL_FALSE);
}
else
{
if (layers > 1)
glTexImage3DMultisample(target, samples, internal_format, width, height, layers, GL_FALSE);
glTexImage3DMultisample(target, samples, gl_internal_format, width, height, layers, GL_FALSE);
else
glTexImage2DMultisample(target, samples, internal_format, width, height, GL_FALSE);
glTexImage2DMultisample(target, samples, gl_internal_format, width, height, GL_FALSE);
}
}
else
@ -93,17 +121,17 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
if (UseTextureStorage(false))
{
if (layers > 1)
glTexStorage3D(target, levels, internal_format, width, height, layers);
glTexStorage3D(target, levels, gl_internal_format, width, height, layers);
else
glTexStorage2D(target, levels, internal_format, width, height);
glTexStorage2D(target, levels, gl_internal_format, width, height);
if (data)
{
// TODO: Fix data for mipmaps here.
if (layers > 1)
glTexSubImage3D(target, 0, 0, 0, 0, width, height, layers, format, type, data);
glTexSubImage3D(target, 0, 0, 0, 0, width, height, layers, gl_format, gl_type, data);
else
glTexSubImage2D(target, 0, 0, 0, width, height, format, type, data);
glTexSubImage2D(target, 0, 0, 0, width, height, gl_format, gl_type, data);
}
}
else
@ -112,17 +140,17 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
{
// TODO: Fix data pointer here.
if (layers > 1)
glTexImage3D(target, i, internal_format, width, height, layers, 0, format, type, data);
glTexImage3D(target, i, gl_internal_format, width, height, layers, 0, gl_format, gl_type, data);
else
glTexImage2D(target, i, internal_format, width, height, 0, format, type, data);
glTexImage2D(target, i, gl_internal_format, width, height, 0, gl_format, gl_type, data);
}
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels);
}
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap ? GL_REPEAT : GL_CLAMP_TO_EDGE);
@ -148,16 +176,16 @@ bool Texture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
m_id = id;
m_width = static_cast<u16>(width);
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_samples = static_cast<u8>(samples);
m_format = format;
return true;
}
void Texture::Replace(u32 width, u32 height, GLenum internal_format, GLenum format, GLenum type, const void* data)
void GL::Texture::Replace(u32 width, u32 height, GLenum internal_format, GLenum format, GLenum type, const void* data)
{
Assert(IsValid() && width < MAX_DIMENSIONS && height < MAX_DIMENSIONS && m_layers == 1 && m_samples == 1 &&
m_levels == 1);
Assert(IsValid() && width < MAX_WIDTH && height < MAX_HEIGHT && m_layers == 1 && m_samples == 1 && m_levels == 1);
const bool size_changed = (width != m_width || height != m_height);
@ -186,7 +214,7 @@ void Texture::Replace(u32 width, u32 height, GLenum internal_format, GLenum form
}
}
void Texture::ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, const void* data)
void GL::Texture::ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, const void* data)
{
Assert(IsValid() && !IsMultisampled());
@ -197,8 +225,8 @@ void Texture::ReplaceImage(u32 layer, u32 level, GLenum format, GLenum type, con
glTexSubImage2D(target, level, 0, 0, m_width, m_height, format, type, data);
}
void Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type,
const void* data)
void GL::Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32 height, GLenum format, GLenum type,
const void* data)
{
Assert(IsValid() && !IsMultisampled());
@ -209,7 +237,7 @@ void Texture::ReplaceSubImage(u32 layer, u32 level, u32 x, u32 y, u32 width, u32
glTexSubImage2D(target, level, x, y, width, height, format, type, data);
}
void Texture::SetLinearFilter(bool enabled) const
void GL::Texture::SetLinearFilter(bool enabled) const
{
Assert(!IsMultisampled());
@ -220,7 +248,17 @@ void Texture::SetLinearFilter(bool enabled) const
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, enabled ? GL_LINEAR : GL_NEAREST);
}
bool Texture::CreateFramebuffer()
void GL::Texture::SetWrap(bool enabled) const
{
const GLenum target = GetGLTarget();
glTexParameteri(target, GL_TEXTURE_WRAP_S, enabled ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, enabled ? GL_REPEAT : GL_CLAMP_TO_EDGE);
if (m_layers > 1)
glTexParameteri(target, GL_TEXTURE_WRAP_R, enabled ? GL_REPEAT : GL_CLAMP_TO_EDGE);
}
bool GL::Texture::CreateFramebuffer()
{
if (!IsValid())
return false;
@ -244,7 +282,7 @@ bool Texture::CreateFramebuffer()
return true;
}
void Texture::Destroy()
void GL::Texture::Destroy()
{
if (m_fbo_id != 0)
{
@ -257,54 +295,46 @@ void Texture::Destroy()
m_id = 0;
}
m_width = 0;
m_height = 0;
m_layers = 0;
m_levels = 0;
m_samples = 0;
ClearBaseProperties();
}
void Texture::Bind() const
void GL::Texture::Bind() const
{
glBindTexture(GetGLTarget(), m_id);
}
void Texture::BindFramebuffer(GLenum target /*= GL_DRAW_FRAMEBUFFER*/) const
void GL::Texture::BindFramebuffer(GLenum target /*= GL_DRAW_FRAMEBUFFER*/) const
{
DebugAssert(m_fbo_id != 0);
glBindFramebuffer(target, m_fbo_id);
}
void Texture::Unbind() const
void GL::Texture::Unbind() const
{
glBindTexture(GetGLTarget(), 0);
}
Texture& Texture::operator=(Texture&& moved)
GL::Texture& GL::Texture::operator=(Texture&& moved)
{
Destroy();
m_id = moved.m_id;
m_fbo_id = moved.m_fbo_id;
m_width = moved.m_width;
m_height = moved.m_height;
m_layers = moved.m_layers;
m_levels = moved.m_levels;
m_samples = moved.m_samples;
m_fbo_id = moved.m_fbo_id;
moved.m_id = 0;
moved.m_width = 0;
moved.m_height = 0;
moved.m_layers = 0;
moved.m_levels = 0;
moved.m_samples = 0;
moved.m_fbo_id = 0;
moved.ClearBaseProperties();
return *this;
}
void Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
GLsizei bufSize, void* pixels)
void GL::Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
GLsizei bufSize, void* pixels)
{
if (GLAD_GL_VERSION_4_5 || GLAD_GL_ARB_get_texture_sub_image)
{
@ -341,5 +371,3 @@ void Texture::GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLi
glBindFramebuffer(target, old_read_fbo);
glDeleteFramebuffers(1, &temp_fbo);
}
} // namespace GL

View File

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

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>
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,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
Vulkan::Texture::Texture() = default;
Vulkan::Texture::Texture(Texture&& move)
: m_width(move.m_width), m_height(move.m_height), m_levels(move.m_levels), m_layers(move.m_layers),
m_format(move.m_format), m_samples(move.m_samples), m_view_type(move.m_view_type), m_layout(move.m_layout),
m_image(move.m_image), m_allocation(move.m_allocation), m_view(move.m_view)
: m_view_type(move.m_view_type), m_layout(move.m_layout), m_image(move.m_image), m_allocation(move.m_allocation),
m_view(move.m_view)
{
move.m_width = 0;
move.m_height = 0;
move.m_levels = 0;
move.m_layers = 0;
move.m_format = VK_FORMAT_UNDEFINED;
move.m_samples = VK_SAMPLE_COUNT_1_BIT;
m_width = move.m_width;
m_height = move.m_height;
m_layers = move.m_layers;
m_levels = move.m_levels;
m_samples = move.m_samples;
move.ClearBaseProperties();
move.m_view_type = VK_IMAGE_VIEW_TYPE_2D;
move.m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
move.m_image = VK_NULL_HANDLE;
@ -37,6 +41,26 @@ Vulkan::Texture::~Texture()
Destroy(true);
}
VkFormat Vulkan::Texture::GetVkFormat(Format format)
{
return s_vk_mapping[static_cast<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)
{
if (IsValid())
@ -129,12 +153,12 @@ bool Vulkan::Texture::Create(u32 width, u32 height, u32 levels, u32 layers, VkFo
if (IsValid())
Destroy(true);
m_width = width;
m_height = height;
m_levels = levels;
m_layers = layers;
m_format = format;
m_samples = samples;
m_width = static_cast<u16>(width);
m_height = static_cast<u16>(height);
m_levels = static_cast<u8>(levels);
m_layers = static_cast<u8>(layers);
m_samples = static_cast<u8>(samples);
m_format = LookupBaseFormat(format);
m_view_type = view_type;
m_image = image;
m_allocation = allocation;
@ -171,12 +195,12 @@ bool Vulkan::Texture::Adopt(VkImage existing_image, VkImageViewType view_type, u
if (IsValid())
Destroy(true);
m_width = width;
m_height = height;
m_levels = levels;
m_layers = layers;
m_format = format;
m_samples = samples;
m_width = static_cast<u16>(width);
m_height = static_cast<u16>(height);
m_levels = static_cast<u8>(levels);
m_layers = static_cast<u8>(layers);
m_format = LookupBaseFormat(format);
m_samples = static_cast<u8>(samples);
m_view_type = view_type;
m_image = existing_image;
m_view = view;
@ -206,11 +230,7 @@ void Vulkan::Texture::Destroy(bool defer /* = true */)
m_allocation = VK_NULL_HANDLE;
}
m_width = 0;
m_height = 0;
m_levels = 0;
m_layers = 0;
m_format = VK_FORMAT_UNDEFINED;
ClearBaseProperties();
m_samples = VK_SAMPLE_COUNT_1_BIT;
m_view_type = VK_IMAGE_VIEW_TYPE_2D;
m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -252,8 +272,7 @@ void Vulkan::Texture::TransitionSubresourcesToLayout(VkCommandBuffer command_buf
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image
{static_cast<VkImageAspectFlags>(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT :
VK_IMAGE_ASPECT_COLOR_BIT),
{static_cast<VkImageAspectFlags>(IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
start_level, num_levels, start_layer, num_layers} // VkImageSubresourceRange subresourceRange
};
@ -392,13 +411,12 @@ void Vulkan::Texture::UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 la
u32 Vulkan::Texture::CalcUpdatePitch(u32 width) const
{
return Common::AlignUp(width * Vulkan::Util::GetTexelSize(m_format),
g_vulkan_context->GetBufferCopyRowPitchAlignment());
return Common::AlignUp(width * GetPixelSize(), g_vulkan_context->GetBufferCopyRowPitchAlignment());
}
u32 Vulkan::Texture::CalcUpdateRowLength(u32 pitch) const
{
return pitch / Vulkan::Util::GetTexelSize(m_format);
return pitch / GetPixelSize();
}
bool Vulkan::Texture::BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch)

View File

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

View File

@ -163,7 +163,7 @@ void GPU::SoftReset()
UpdateGPUIdle();
}
bool GPU::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display)
bool GPU::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display)
{
if (sw.IsReading())
{

View File

@ -15,7 +15,7 @@
class StateWrapper;
class HostDisplay;
class HostDisplayTexture;
class GPUTexture;
class TimingEvent;
class Timers;
@ -83,7 +83,7 @@ public:
virtual bool Initialize();
virtual void Reset(bool clear_vram);
virtual bool DoState(StateWrapper& sw, HostDisplayTexture** save_to_texture, bool update_display);
virtual bool DoState(StateWrapper& sw, GPUTexture** save_to_texture, bool update_display);
// Graphics API state reset/restore - call when drawing the UI etc.
virtual void ResetGraphicsAPIState();

View File

@ -123,7 +123,7 @@ void GPU_HW::Reset(bool clear_vram)
SetFullVRAMDirtyRectangle();
}
bool GPU_HW::DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display)
bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display)
{
if (!GPU::DoState(sw, host_texture, update_display))
return false;

View File

@ -37,7 +37,7 @@ public:
virtual bool Initialize() override;
virtual void Reset(bool clear_vram) override;
virtual bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
virtual bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override;
void UpdateResolutionScale() override final;
std::tuple<u32, u32> GetEffectiveDisplayResolution(bool scaled = true) override final;

View File

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

View File

@ -23,7 +23,7 @@ public:
bool Initialize() override;
void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override;
void ResetGraphicsAPIState() override;
void RestoreGraphicsAPIState() override;

View File

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

View File

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

View File

@ -20,7 +20,7 @@ public:
bool Initialize() override;
void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override;
void ResetGraphicsAPIState() override;
void RestoreGraphicsAPIState() override;
@ -55,8 +55,6 @@ private:
ALWAYS_INLINE bool IsGLES() const { return (m_render_api == RenderAPI::OpenGLES); }
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities();
bool CreateFramebuffer();
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 bool PER_SAMPLE_SHADING = " << (m_per_sample_shading ? "true" : "false") << ";\n";
ss << R"(
float fixYCoord(float y)
{
#if API_OPENGL || API_OPENGL_ES
return 1.0 - RCP_VRAM_SIZE.y - y;
#else
return y;
#endif
}
uint fixYCoord(uint y)
{
#if API_OPENGL || API_OPENGL_ES
return VRAM_SIZE.y - y - 1u;
#else
return y;
#endif
}
uint RGBA8ToRGBA5551(float4 v)
{
uint r = uint(roundEven(v.r * 31.0));
@ -85,23 +66,6 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured)
WriteCommonFunctions(ss);
WriteBatchUniformBuffer(ss);
ss << R"(
// OpenGL seems to be off by one pixel in the Y direction due to lower-left origin, but only on
// Intel and NVIDIA drivers. AMD is fine. V3D requires coordinates to be slightly offset even further.
#if API_OPENGL || API_OPENGL_ES
#ifdef DRIVER_V3D
CONSTANT float POS_EPSILON = 0.0001;
#else
#ifdef DRIVER_POWERVR
CONSTANT float POS_EPSILON = 0.001;
#else
CONSTANT float POS_EPSILON = 0.00001;
#endif
#endif
#endif
)";
if (textured)
{
if (m_uv_limits)
@ -145,14 +109,12 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured)
#endif
#if API_OPENGL || API_OPENGL_ES
pos_y += POS_EPSILON;
// 0..1 to -1..1 depth range.
pos_z = (pos_z * 2.0) - 1.0;
#endif
// NDC space Y flip in Vulkan.
#if API_VULKAN
#if API_OPENGL || API_OPENGL_ES || API_VULKAN
pos_y = -pos_y;
#endif
@ -767,7 +729,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
#endif
// fixup coords
uint2 vicoord = uint2(texpage.x + index_coord.x * RESOLUTION_SCALE, fixYCoord(texpage.y + index_coord.y * RESOLUTION_SCALE));
uint2 vicoord = texpage.xy + (index_coord * uint2(RESOLUTION_SCALE, RESOLUTION_SCALE));
// load colour/palette
float4 texel = SAMPLE_TEXTURE(samp0, float2(vicoord) * RCP_VRAM_SIZE);
@ -783,12 +745,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
#endif
// sample palette
uint2 palette_icoord = uint2(texpage.z + (palette_index * RESOLUTION_SCALE), fixYCoord(texpage.w));
uint2 palette_icoord = uint2(texpage.z + (palette_index * RESOLUTION_SCALE), texpage.w);
return SAMPLE_TEXTURE(samp0, float2(palette_icoord) * RCP_VRAM_SIZE);
#else
// Direct texturing. Render-to-texture effects. Use upscaled coordinates.
uint2 icoord = ApplyUpscaledTextureWindow(FloatToIntegerCoords(coords));
uint2 direct_icoord = uint2(texpage.x + icoord.x, fixYCoord(texpage.y + icoord.y));
uint2 direct_icoord = texpage.xy + icoord;
return SAMPLE_TEXTURE(samp0, float2(direct_icoord) * RCP_VRAM_SIZE);
#endif
}
@ -831,7 +793,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords)
float oalpha;
#if INTERLACING
if ((fixYCoord(uint(v_pos.y)) & 1u) == u_interlaced_displayed_field)
if ((uint(v_pos.y) & 1u) == u_interlaced_displayed_field)
discard;
#endif
@ -1097,7 +1059,7 @@ float3 SampleVRAM24Smoothed(uint2 icoords)
uint2 icoords = uint2(v_pos.xy) + uint2(u_crop_left, 0u);
#if INTERLACED
if ((fixYCoord(icoords.y) & 1u) != u_field_offset)
if ((icoords.y & 1u) != u_field_offset)
discard;
#if !INTERLEAVED
@ -1167,13 +1129,6 @@ uint SampleVRAM(uint2 coords)
ss << R"(
{
uint2 sample_coords = uint2(uint(v_pos.x) * 2u, uint(v_pos.y));
#if API_OPENGL || API_OPENGL_ES
// Lower-left origin flip for OpenGL.
// We want to write the image out upside-down so we can read it top-to-bottom.
sample_coords.y = u_size.y - sample_coords.y - 1u;
#endif
sample_coords += u_base_coords;
// We're encoding as 32-bit, so the output width is halved and we pack two 16-bit pixels in one 32-bit pixel.
@ -1222,7 +1177,7 @@ std::string GPU_HW_ShaderGen::GenerateVRAMWriteFragmentShader(bool use_ssbo)
DeclareFragmentEntryPoint(ss, 0, 1, {}, true, 1, true);
ss << R"(
{
uint2 coords = uint2(uint(v_pos.x) / RESOLUTION_SCALE, fixYCoord(uint(v_pos.y)) / RESOLUTION_SCALE);
uint2 coords = uint2(v_pos.xy) / uint2(RESOLUTION_SCALE, RESOLUTION_SCALE);
// make sure it's not oversized and out of range
if ((coords.x < u_base_coords.x && coords.x >= u_end_coords.x) ||
@ -1320,7 +1275,7 @@ std::string GPU_HW_ShaderGen::GenerateVRAMFillFragmentShader(bool wrapped, bool
ss << R"(
{
#if INTERLACED || WRAPPED
uint2 dst_coords = uint2(uint(v_pos.x), fixYCoord(uint(v_pos.y)));
uint2 dst_coords = uint2(v_pos.xy);
#endif
#if INTERLACED

View File

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

View File

@ -18,7 +18,7 @@ public:
bool Initialize() override;
void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override;
void ResetGraphicsAPIState() override;
void RestoreGraphicsAPIState() override;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -251,7 +251,7 @@ bool ImGui_ImplDX11_CreateFontsTexture()
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
const u32 stride = sizeof(u32) * width;
if (!bd->FontTexture.Create(bd->pd3dDevice, width, height, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_BIND_SHADER_RESOURCE, pixels, stride))
if (!bd->FontTexture.Create(bd->pd3dDevice, width, height, 1, 1, 1, GPUTexture::Format::RGBA8, D3D11_BIND_SHADER_RESOURCE, pixels, stride))
return false;
// Store our identifier

View File

@ -266,7 +266,7 @@ bool ImGui_ImplDX12_CreateFontsTexture()
// Upload texture to graphics system
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,
D3D12_RESOURCE_FLAG_NONE))
{

View File

@ -110,20 +110,20 @@
// OpenGL Data
struct ImGui_ImplOpenGL3_Data
{
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
GLuint GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
char GlslVersionString[32] = {}; // Specified by user or detected based on compile time GL settings.
GL::Texture FontTexture;
GLuint ShaderHandle;
GLint AttribLocationTex; // Uniforms location
GLint AttribLocationProjMtx;
GLuint AttribLocationVtxPos; // Vertex attributes location
GLuint AttribLocationVtxUV;
GLuint AttribLocationVtxColor;
unsigned int VboHandle, ElementsHandle, VaoHandle;
GLsizeiptr VertexBufferSize;
GLsizeiptr IndexBufferSize;
GLuint ShaderHandle = 0;
GLint AttribLocationTex = 0; // Uniforms location
GLint AttribLocationProjMtx = 0;
GLuint AttribLocationVtxPos = 0; // Vertex attributes location
GLuint AttribLocationVtxUV = 0;
GLuint AttribLocationVtxColor = 0;
unsigned int VboHandle = 0, ElementsHandle = 0, VaoHandle = 0;
GLsizeiptr VertexBufferSize = 0;
GLsizeiptr IndexBufferSize = 0;
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
ImGui_ImplOpenGL3_Data() = default;
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
@ -316,7 +316,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
// Upload texture to graphics system
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
bd->FontTexture.Create(width, height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
bd->FontTexture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, pixels);
bd->FontTexture.SetLinearFilter(true);
// Store our identifier
@ -326,7 +326,6 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->FontTexture.IsValid())
bd->FontTexture.Destroy();

View File

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

View File

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

View File

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

View File

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