HostDisplay: Make textures have levels/layers/samples attributes

This commit is contained in:
Connor McLaughlin 2021-01-23 18:05:33 +10:00
parent e54ba23c4f
commit 6c6fdeb15e
13 changed files with 174 additions and 175 deletions

View file

@ -28,7 +28,7 @@ D3D11_TEXTURE2D_DESC Texture::GetDesc() const
return desc; return desc;
} }
bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u16 levels, u16 samples, DXGI_FORMAT format, bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 levels, u32 samples, DXGI_FORMAT format,
u32 bind_flags, const void* initial_data /* = nullptr */, u32 initial_data_stride /* = 0 */, u32 bind_flags, const void* initial_data /* = nullptr */, u32 initial_data_stride /* = 0 */,
bool dynamic) bool dynamic)
{ {
@ -84,8 +84,8 @@ bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u16 levels, u1
m_rtv = std::move(rtv); m_rtv = std::move(rtv);
m_width = width; m_width = width;
m_height = height; m_height = height;
m_levels = levels; m_levels = static_cast<u16>(levels);
m_samples = samples; m_samples = static_cast<u16>(samples);
return true; return true;
} }

View file

@ -34,7 +34,7 @@ public:
ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); } ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); }
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); } ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
bool Create(ID3D11Device* device, u32 width, u32 height, u16 levels, u16 samples, DXGI_FORMAT format, u32 bind_flags, bool Create(ID3D11Device* device, u32 width, u32 height, u32 levels, u32 samples, DXGI_FORMAT format, u32 bind_flags,
const void* initial_data = nullptr, u32 initial_data_stride = 0, bool dynamic = false); const void* initial_data = nullptr, u32 initial_data_stride = 0, bool dynamic = false);
bool Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture); bool Adopt(ID3D11Device* device, ComPtr<ID3D11Texture2D> texture);

View file

@ -99,7 +99,8 @@ void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture,
bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/) bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/)
{ {
std::unique_ptr<HostDisplayTexture> tex = CreateTexture(width, height, pixels, stride, false); std::unique_ptr<HostDisplayTexture> tex =
CreateTexture(width, height, 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixels, stride, false);
if (!tex) if (!tex)
return false; return false;
@ -124,8 +125,9 @@ bool HostDisplay::SetSoftwareCursor(const char* path, float scale /*= 1.0f*/)
return false; return false;
} }
std::unique_ptr<HostDisplayTexture> tex = CreateTexture(static_cast<u32>(width), static_cast<u32>(height), pixel_data, std::unique_ptr<HostDisplayTexture> tex =
sizeof(u32) * static_cast<u32>(width), false); CreateTexture(static_cast<u32>(width), static_cast<u32>(height), 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixel_data,
sizeof(u32) * static_cast<u32>(width), false);
stbi_image_free(pixel_data); stbi_image_free(pixel_data);
if (!tex) if (!tex)
return false; return false;

View file

@ -26,8 +26,10 @@ public:
virtual void* GetHandle() const = 0; virtual void* GetHandle() const = 0;
virtual u32 GetWidth() const = 0; virtual u32 GetWidth() const = 0;
virtual u32 GetHeight() const = 0; virtual u32 GetHeight() const = 0;
virtual u32 GetLayers() const = 0;
ALWAYS_INLINE HostDisplayPixelFormat GetFormat() const { return HostDisplayPixelFormat::RGBA8; } virtual u32 GetLevels() const = 0;
virtual u32 GetSamples() const = 0;
virtual HostDisplayPixelFormat GetFormat() const = 0;
}; };
// Interface to the frontend's renderer. // Interface to the frontend's renderer.
@ -92,8 +94,9 @@ public:
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) = 0; virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) = 0;
/// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below. /// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below.
virtual std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, virtual std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
bool dynamic = false) = 0; HostDisplayPixelFormat format, const void* data,
u32 data_stride, bool dynamic = false) = 0;
virtual void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, virtual void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) = 0; u32 data_stride) = 0;
@ -163,7 +166,6 @@ public:
static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format); static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format);
virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0; virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0;
virtual bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer, virtual bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,

View file

@ -170,8 +170,8 @@ bool SDLHostInterface::CreateDisplay()
return false; return false;
} }
m_app_icon_texture = m_app_icon_texture = display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8,
display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, APP_ICON_DATA, APP_ICON_WIDTH * sizeof(u32)); APP_ICON_DATA, APP_ICON_WIDTH * sizeof(u32));
if (!m_app_icon_texture) if (!m_app_icon_texture)
return false; return false;

View file

@ -437,8 +437,8 @@ bool CommonHostInterface::SetFullscreen(bool enabled)
bool CommonHostInterface::CreateHostDisplayResources() bool CommonHostInterface::CreateHostDisplayResources()
{ {
m_logo_texture = m_logo_texture = m_display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8,
m_display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, APP_ICON_DATA, sizeof(u32) * APP_ICON_WIDTH, false); APP_ICON_DATA, sizeof(u32) * APP_ICON_WIDTH, false);
if (!m_logo_texture) if (!m_logo_texture)
Log_WarningPrintf("Failed to create logo texture"); Log_WarningPrintf("Failed to create logo texture");

View file

@ -23,52 +23,28 @@ namespace FrontendCommon {
class D3D11HostDisplayTexture : public HostDisplayTexture class D3D11HostDisplayTexture : public HostDisplayTexture
{ {
public: public:
template<typename T> D3D11HostDisplayTexture(D3D11::Texture texture, HostDisplayPixelFormat format, bool dynamic)
using ComPtr = Microsoft::WRL::ComPtr<T>; : m_texture(std::move(texture)), m_format(format), m_dynamic(dynamic)
D3D11HostDisplayTexture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, u32 width, u32 height,
bool dynamic)
: m_texture(std::move(texture)), m_srv(std::move(srv)), m_width(width), m_height(height), m_dynamic(dynamic)
{ {
} }
~D3D11HostDisplayTexture() override = default; ~D3D11HostDisplayTexture() override = default;
void* GetHandle() const override { return m_srv.Get(); } void* GetHandle() const override { return m_texture.GetD3DSRV(); }
u32 GetWidth() const override { return m_width; } u32 GetWidth() const override { return m_texture.GetWidth(); }
u32 GetHeight() const override { return m_height; } u32 GetHeight() const override { return m_texture.GetHeight(); }
u32 GetLayers() const override { return 1; }
ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } u32 GetLevels() const override { return m_texture.GetLevels(); }
ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } u32 GetSamples() const override { return m_texture.GetSamples(); }
ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); } HostDisplayPixelFormat GetFormat() const override { return m_format; }
bool IsDynamic() const { return m_dynamic; }
static std::unique_ptr<D3D11HostDisplayTexture> Create(ID3D11Device* device, u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1, 1, D3D11_BIND_SHADER_RESOURCE,
dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT,
dynamic ? D3D11_CPU_ACCESS_WRITE : 0, 1, 0, 0);
const D3D11_SUBRESOURCE_DATA srd{data, data_stride, data_stride * height};
ComPtr<ID3D11Texture2D> texture;
HRESULT hr = device->CreateTexture2D(&desc, data ? &srd : nullptr, texture.GetAddressOf());
if (FAILED(hr))
return {};
const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 1, 0, ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.GetD3DTexture(); }
1); ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_texture.GetD3DSRV(); }
ComPtr<ID3D11ShaderResourceView> srv; ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_texture.GetD3DSRVArray(); }
hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf()); ALWAYS_INLINE bool IsDynamic() const { return m_dynamic; }
if (FAILED(hr))
return {};
return std::make_unique<D3D11HostDisplayTexture>(std::move(texture), std::move(srv), width, height, dynamic);
}
private: private:
ComPtr<ID3D11Texture2D> m_texture; D3D11::Texture m_texture;
ComPtr<ID3D11ShaderResourceView> m_srv; HostDisplayPixelFormat m_format;
u32 m_width;
u32 m_height;
bool m_dynamic; bool m_dynamic;
}; };
@ -105,10 +81,27 @@ bool D3D11HostDisplay::HasRenderSurface() const
return static_cast<bool>(m_swap_chain); return static_cast<bool>(m_swap_chain);
} }
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data, static constexpr std::array<DXGI_FORMAT, static_cast<u32>(HostDisplayPixelFormat::Count)>
u32 initial_data_stride, bool dynamic) 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 */)
{ {
return D3D11HostDisplayTexture::Create(m_device.Get(), width, height, initial_data, initial_data_stride, dynamic); if (layers != 1)
return {};
D3D11::Texture tex;
if (!tex.Create(m_device.Get(), width, height, levels, samples,
s_display_pixel_format_mapping[static_cast<u32>(format)], D3D11_BIND_SHADER_RESOURCE, data,
data_stride, dynamic))
{
return {};
}
return std::make_unique<D3D11HostDisplayTexture>(std::move(tex), format, dynamic);
} }
void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
@ -175,10 +168,6 @@ bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPi
} }
} }
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}};
bool D3D11HostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const bool D3D11HostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
{ {
const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast<u32>(format)]; const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast<u32>(format)];

View file

@ -50,8 +50,9 @@ public:
virtual bool SetPostProcessingChain(const std::string_view& config) override; virtual bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data, std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
u32 initial_data_stride, bool dynamic) override; HostDisplayPixelFormat 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* texture_data, void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
u32 texture_data_stride) override; u32 texture_data_stride) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,

View file

@ -16,41 +16,25 @@ namespace FrontendCommon {
class OpenGLHostDisplayTexture : public HostDisplayTexture class OpenGLHostDisplayTexture : public HostDisplayTexture
{ {
public: public:
OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {} OpenGLHostDisplayTexture(GL::Texture texture, HostDisplayPixelFormat format)
~OpenGLHostDisplayTexture() override { glDeleteTextures(1, &m_id); } : m_texture(std::move(texture)), m_format(format)
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_id)); }
u32 GetWidth() const override { return m_width; }
u32 GetHeight() const override { return m_height; }
GLuint GetGLID() const { return m_id; }
static std::unique_ptr<OpenGLHostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride)
{ {
GLuint id; }
glGenTextures(1, &id); ~OpenGLHostDisplayTexture() override = default;
GLint old_texture_binding = 0; void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture.GetGLId())); }
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding); 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 { return m_format; }
// TODO: Set pack width GLuint GetGLID() const { return m_texture.GetGLId(); }
Assert(!initial_data || initial_data_stride == (width * sizeof(u32)));
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, initial_data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, id);
return std::make_unique<OpenGLHostDisplayTexture>(id, width, height);
}
private: private:
GLuint m_id; GL::Texture m_texture;
u32 m_width; HostDisplayPixelFormat m_format;
u32 m_height;
}; };
OpenGLHostDisplay::OpenGLHostDisplay() = default; OpenGLHostDisplay::OpenGLHostDisplay() = default;
@ -75,21 +59,35 @@ void* OpenGLHostDisplay::GetRenderContext() const
return m_gl_context.get(); return m_gl_context.get();
} }
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride, bool dynamic)
{
return OpenGLHostDisplayTexture::Create(width, height, initial_data, initial_data_stride);
}
static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(HostDisplayPixelFormat::Count)> static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(HostDisplayPixelFormat::Count)>
s_display_pixel_format_mapping = {{ s_display_pixel_format_mapping = {{
{}, // Unknown {}, // Unknown
{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
{GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 {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_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV} // RGBA5551
}}; }};
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 */)
{
if (layers != 1 || levels != 1)
return {};
const auto [gl_internal_format, gl_format, gl_type] = s_display_pixel_format_mapping[static_cast<u32>(format)];
// TODO: Set pack width
Assert(!data || data_stride == (width * sizeof(u32)));
GL::Texture tex;
if (!tex.Create(width, height, samples, gl_internal_format, gl_format, gl_type, data, data_stride))
return {};
return std::make_unique<OpenGLHostDisplayTexture>(std::move(tex), format);
}
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
const void* texture_data, u32 texture_data_stride) const void* texture_data, u32 texture_data_stride)
{ {

View file

@ -48,8 +48,9 @@ public:
virtual bool SetPostProcessingChain(const std::string_view& config) override; virtual bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data, std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
u32 initial_data_stride, bool dynamic) override; HostDisplayPixelFormat 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* texture_data, void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
u32 texture_data_stride) override; u32 texture_data_stride) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,

View file

@ -131,15 +131,15 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, CommonHostInterface
li->preview_texture.reset(); li->preview_texture.reset();
if (ssi && !ssi->screenshot_data.empty()) if (ssi && !ssi->screenshot_data.empty())
{ {
li->preview_texture = m_host_interface->GetDisplay()->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, li->preview_texture = m_host_interface->GetDisplay()->CreateTexture(
ssi->screenshot_data.data(), ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, HostDisplayPixelFormat::RGBA8,
sizeof(u32) * ssi->screenshot_width, false); ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false);
} }
else else
{ {
li->preview_texture = li->preview_texture = m_host_interface->GetDisplay()->CreateTexture(
m_host_interface->GetDisplay()->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA,
PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
} }
if (!li->preview_texture) if (!li->preview_texture)
@ -165,9 +165,9 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, s32 slot
li->slot = slot; li->slot = slot;
li->global = global; li->global = global;
li->preview_texture = li->preview_texture = m_host_interface->GetDisplay()->CreateTexture(
m_host_interface->GetDisplay()->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA,
PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
if (!li->preview_texture) if (!li->preview_texture)
Log_ErrorPrintf("Failed to upload save state image to GPU"); Log_ErrorPrintf("Failed to upload save state image to GPU");

View file

@ -23,8 +23,9 @@ namespace FrontendCommon {
class VulkanHostDisplayTexture : public HostDisplayTexture class VulkanHostDisplayTexture : public HostDisplayTexture
{ {
public: public:
VulkanHostDisplayTexture(Vulkan::Texture texture, Vulkan::StagingTexture staging_texture) VulkanHostDisplayTexture(Vulkan::Texture texture, Vulkan::StagingTexture staging_texture,
: m_texture(std::move(texture)), m_staging_texture(std::move(staging_texture)) HostDisplayPixelFormat format)
: m_texture(std::move(texture)), m_staging_texture(std::move(staging_texture)), m_format(format)
{ {
} }
~VulkanHostDisplayTexture() override = default; ~VulkanHostDisplayTexture() override = default;
@ -32,64 +33,19 @@ public:
void* GetHandle() const override { return const_cast<Vulkan::Texture*>(&m_texture); } void* GetHandle() const override { return const_cast<Vulkan::Texture*>(&m_texture); }
u32 GetWidth() const override { return m_texture.GetWidth(); } u32 GetWidth() const override { return m_texture.GetWidth(); }
u32 GetHeight() const override { return m_texture.GetHeight(); } 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; }
const Vulkan::Texture& GetTexture() const { return m_texture; } const Vulkan::Texture& GetTexture() const { return m_texture; }
Vulkan::Texture& GetTexture() { return m_texture; } Vulkan::Texture& GetTexture() { return m_texture; }
Vulkan::StagingTexture& GetStagingTexture() { return m_staging_texture; } Vulkan::StagingTexture& GetStagingTexture() { return m_staging_texture; }
static std::unique_ptr<VulkanHostDisplayTexture> Create(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic)
{
static constexpr VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
static constexpr VkImageUsageFlags usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
Vulkan::Texture texture;
if (!texture.Create(width, height, 1, 1, format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL, usage))
{
return {};
}
Vulkan::StagingTexture staging_texture;
if (data || dynamic)
{
if (!staging_texture.Create(dynamic ? Vulkan::StagingBuffer::Type::Mutable : Vulkan::StagingBuffer::Type::Upload,
format, width, height))
{
return {};
}
}
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
if (data)
{
staging_texture.WriteTexels(0, 0, width, height, data, data_stride);
staging_texture.CopyToTexture(g_vulkan_context->GetCurrentCommandBuffer(), 0, 0, texture, 0, 0, 0, 0, width,
height);
}
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);
}
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// don't need to keep the staging texture around if we're not dynamic
if (!dynamic)
staging_texture.Destroy(true);
return std::make_unique<VulkanHostDisplayTexture>(std::move(texture), std::move(staging_texture));
}
private: private:
Vulkan::Texture m_texture; Vulkan::Texture m_texture;
Vulkan::StagingTexture m_staging_texture; Vulkan::StagingTexture m_staging_texture;
HostDisplayPixelFormat m_format;
}; };
VulkanHostDisplay::VulkanHostDisplay() = default; VulkanHostDisplay::VulkanHostDisplay() = default;
@ -195,10 +151,63 @@ void VulkanHostDisplay::DestroyRenderSurface()
m_swap_chain.reset(); m_swap_chain.reset();
} }
std::unique_ptr<HostDisplayTexture> VulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* data, static constexpr std::array<VkFormat, static_cast<u32>(HostDisplayPixelFormat::Count)> s_display_pixel_format_mapping =
u32 data_stride, bool dynamic) {{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 */)
{ {
return VulkanHostDisplayTexture::Create(width, height, data, data_stride, dynamic); const VkFormat vk_format = s_display_pixel_format_mapping[static_cast<u32>(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;
Vulkan::Texture texture;
if (!texture.Create(width, height, levels, layers, vk_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL, usage))
{
return {};
}
Vulkan::StagingTexture staging_texture;
if (data || dynamic)
{
if (!staging_texture.Create(dynamic ? Vulkan::StagingBuffer::Type::Mutable : Vulkan::StagingBuffer::Type::Upload,
vk_format, width, height))
{
return {};
}
}
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
if (data)
{
staging_texture.WriteTexels(0, 0, width, height, data, data_stride);
staging_texture.CopyToTexture(g_vulkan_context->GetCurrentCommandBuffer(), 0, 0, texture, 0, 0, 0, 0, width,
height);
}
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);
}
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// don't need to keep the staging texture around if we're not dynamic
if (!dynamic)
staging_texture.Destroy(true);
return std::make_unique<VulkanHostDisplayTexture>(std::move(texture), std::move(staging_texture), format);
} }
void VulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, void VulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
@ -246,10 +255,6 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
return true; return true;
} }
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}};
bool VulkanHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const bool VulkanHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
{ {
const VkFormat vk_format = s_display_pixel_format_mapping[static_cast<u32>(format)]; const VkFormat vk_format = s_display_pixel_format_mapping[static_cast<u32>(format)];

View file

@ -47,8 +47,9 @@ public:
virtual bool SetPostProcessingChain(const std::string_view& config) override; virtual bool SetPostProcessingChain(const std::string_view& config) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data, std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
u32 initial_data_stride, bool dynamic) override; HostDisplayPixelFormat 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* texture_data, void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
u32 texture_data_stride) override; u32 texture_data_stride) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,