HostDisplay: Common texture base class for all APIs
This commit is contained in:
parent
12d400b76a
commit
a9038133c8
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class HostDisplayTexture;
|
||||
class GPUTexture;
|
||||
|
||||
struct Settings;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue