HostDisplay: Common texture base class for all APIs

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1,145 @@
#include "gpu_texture.h"
#include "log.h"
#include "string_util.h"
Log_SetChannel(GPUTexture);
GPUTexture::GPUTexture() = default;
GPUTexture::GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, GPUTexture::Format format)
: m_width(width), m_height(height), m_layers(layers), m_levels(levels), m_samples(samples), m_format(format)
{
}
GPUTexture::~GPUTexture() = default;
void GPUTexture::ClearBaseProperties()
{
m_width = 0;
m_height = 0;
m_layers = 0;
m_levels = 0;
m_samples = 0;
m_format = GPUTexture::Format::Unknown;
}
u32 GPUTexture::GPUTexture::GetPixelSize(GPUTexture::Format format)
{
switch (format)
{
case Format::RGBA8:
case Format::BGRA8:
return 4;
case Format::RGBA5551:
case Format::RGB565:
case Format::D16:
return 2;
case Format::R8:
return 1;
default:
return 0;
}
}
bool GPUTexture::IsDepthFormat(Format format)
{
return (format == Format::D16);
}
bool GPUTexture::ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data,
u32& texture_data_stride, GPUTexture::Format format)
{
switch (format)
{
case GPUTexture::Format::BGRA8:
{
for (u32 y = 0; y < height; y++)
{
u32* pixels = reinterpret_cast<u32*>(reinterpret_cast<u8*>(texture_data.data()) + (y * texture_data_stride));
for (u32 x = 0; x < width; x++)
pixels[x] = (pixels[x] & 0xFF00FF00) | ((pixels[x] & 0xFF) << 16) | ((pixels[x] >> 16) & 0xFF);
}
return true;
}
case GPUTexture::Format::RGBA8:
return true;
case GPUTexture::Format::RGB565:
{
std::vector<u32> temp(width * height);
for (u32 y = 0; y < height; y++)
{
const u8* pixels_in = reinterpret_cast<u8*>(texture_data.data()) + (y * texture_data_stride);
u32* pixels_out = &temp[y * width];
for (u32 x = 0; x < width; x++)
{
// RGB565 -> RGBA8
u16 pixel_in;
std::memcpy(&pixel_in, pixels_in, sizeof(u16));
pixels_in += sizeof(u16);
const u8 r5 = Truncate8(pixel_in >> 11);
const u8 g6 = Truncate8((pixel_in >> 5) & 0x3F);
const u8 b5 = Truncate8(pixel_in & 0x1F);
*(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 2) | (g6 & 3)) << 8) |
(ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (0xFF000000u);
}
}
texture_data = std::move(temp);
texture_data_stride = sizeof(u32) * width;
return true;
}
case GPUTexture::Format::RGBA5551:
{
std::vector<u32> temp(width * height);
for (u32 y = 0; y < height; y++)
{
const u8* pixels_in = reinterpret_cast<u8*>(texture_data.data()) + (y * texture_data_stride);
u32* pixels_out = &temp[y * width];
for (u32 x = 0; x < width; x++)
{
// RGBA5551 -> RGBA8
u16 pixel_in;
std::memcpy(&pixel_in, pixels_in, sizeof(u16));
pixels_in += sizeof(u16);
const u8 a1 = Truncate8(pixel_in >> 15);
const u8 r5 = Truncate8((pixel_in >> 10) & 0x1F);
const u8 g6 = Truncate8((pixel_in >> 5) & 0x1F);
const u8 b5 = Truncate8(pixel_in & 0x1F);
*(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 3) | (g6 & 7)) << 8) |
(ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (a1 ? 0xFF000000u : 0u);
}
}
texture_data = std::move(temp);
texture_data_stride = sizeof(u32) * width;
return true;
}
default:
Log_ErrorPrintf("Unknown pixel format %u", static_cast<u32>(format));
return false;
}
}
void GPUTexture::FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride)
{
std::vector<u32> temp(width);
for (u32 flip_row = 0; flip_row < (height / 2); flip_row++)
{
u32* top_ptr = &texture_data[flip_row * width];
u32* bottom_ptr = &texture_data[((height - 1) - flip_row) * width];
std::memcpy(temp.data(), top_ptr, texture_data_stride);
std::memcpy(top_ptr, bottom_ptr, texture_data_stride);
std::memcpy(bottom_ptr, temp.data(), texture_data_stride);
}
}

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

@ -0,0 +1,68 @@
#pragma once
#include "types.h"
#include <algorithm>
#include <vector>
class GPUTexture
{
public:
enum : u32
{
MAX_WIDTH = 65535,
MAX_HEIGHT = 65535,
MAX_LAYERS = 255,
MAX_LEVELS = 255,
MAX_SAMPLES = 255,
};
enum class Format : u8
{
Unknown,
RGBA8,
BGRA8,
RGB565,
RGBA5551,
R8,
D16,
Count
};
public:
virtual ~GPUTexture();
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
ALWAYS_INLINE u32 GetLayers() const { return m_layers; }
ALWAYS_INLINE u32 GetLevels() const { return m_levels; }
ALWAYS_INLINE u32 GetSamples() const { return m_samples; }
ALWAYS_INLINE GPUTexture::Format GetFormat() const { return m_format; }
ALWAYS_INLINE bool IsTextureArray() const { return m_layers > 1; }
ALWAYS_INLINE bool IsMultisampled() const { return m_samples > 1; }
ALWAYS_INLINE u32 GetPixelSize() const { return GetPixelSize(m_format); }
ALWAYS_INLINE u32 GetMipWidth(u32 level) const { return std::max<u32>(m_width >> level, 1u); }
ALWAYS_INLINE u32 GetMipHeight(u32 level) const { return std::max<u32>(m_height >> level, 1u); }
virtual bool IsValid() const = 0;
static u32 GetPixelSize(GPUTexture::Format format);
static bool IsDepthFormat(GPUTexture::Format format);
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
GPUTexture::Format format);
static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride);
protected:
GPUTexture();
GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Format format);
void ClearBaseProperties();
u16 m_width = 0;
u16 m_height = 0;
u8 m_layers = 0;
u8 m_levels = 0;
u8 m_samples = 0;
Format m_format = Format::Unknown;
};

View File

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

View File

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