From 6c6fdeb15e63e8a120e96823bc0658caaf851eb1 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 23 Jan 2021 18:05:33 +1000 Subject: [PATCH] HostDisplay: Make textures have levels/layers/samples attributes --- src/common/d3d11/texture.cpp | 6 +- src/common/d3d11/texture.h | 2 +- src/core/host_display.cpp | 8 +- src/core/host_display.h | 12 +- src/duckstation-sdl/sdl_host_interface.cpp | 4 +- src/frontend-common/common_host_interface.cpp | 4 +- src/frontend-common/d3d11_host_display.cpp | 81 +++++------- src/frontend-common/d3d11_host_display.h | 5 +- src/frontend-common/opengl_host_display.cpp | 78 ++++++----- src/frontend-common/opengl_host_display.h | 5 +- .../save_state_selector_ui.cpp | 18 +-- src/frontend-common/vulkan_host_display.cpp | 123 +++++++++--------- src/frontend-common/vulkan_host_display.h | 5 +- 13 files changed, 175 insertions(+), 176 deletions(-) diff --git a/src/common/d3d11/texture.cpp b/src/common/d3d11/texture.cpp index 22f4c617e..d74030842 100644 --- a/src/common/d3d11/texture.cpp +++ b/src/common/d3d11/texture.cpp @@ -28,7 +28,7 @@ D3D11_TEXTURE2D_DESC Texture::GetDesc() const 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 */, bool dynamic) { @@ -84,8 +84,8 @@ bool Texture::Create(ID3D11Device* device, u32 width, u32 height, u16 levels, u1 m_rtv = std::move(rtv); m_width = width; m_height = height; - m_levels = levels; - m_samples = samples; + m_levels = static_cast(levels); + m_samples = static_cast(samples); return true; } diff --git a/src/common/d3d11/texture.h b/src/common/d3d11/texture.h index dbe9394c4..8919b4618 100644 --- a/src/common/d3d11/texture.h +++ b/src/common/d3d11/texture.h @@ -34,7 +34,7 @@ public: ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); } ALWAYS_INLINE operator bool() const { return static_cast(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); bool Adopt(ID3D11Device* device, ComPtr texture); diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index d97f88064..c534c82d4 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -99,7 +99,8 @@ void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/) { - std::unique_ptr tex = CreateTexture(width, height, pixels, stride, false); + std::unique_ptr tex = + CreateTexture(width, height, 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixels, stride, false); if (!tex) return false; @@ -124,8 +125,9 @@ bool HostDisplay::SetSoftwareCursor(const char* path, float scale /*= 1.0f*/) return false; } - std::unique_ptr tex = CreateTexture(static_cast(width), static_cast(height), pixel_data, - sizeof(u32) * static_cast(width), false); + std::unique_ptr tex = + CreateTexture(static_cast(width), static_cast(height), 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixel_data, + sizeof(u32) * static_cast(width), false); stbi_image_free(pixel_data); if (!tex) return false; diff --git a/src/core/host_display.h b/src/core/host_display.h index 1458a0666..9bbd0b406 100644 --- a/src/core/host_display.h +++ b/src/core/host_display.h @@ -26,8 +26,10 @@ public: virtual void* GetHandle() const = 0; virtual u32 GetWidth() const = 0; virtual u32 GetHeight() const = 0; - - ALWAYS_INLINE HostDisplayPixelFormat GetFormat() const { return HostDisplayPixelFormat::RGBA8; } + virtual u32 GetLayers() const = 0; + virtual u32 GetLevels() const = 0; + virtual u32 GetSamples() const = 0; + virtual HostDisplayPixelFormat GetFormat() const = 0; }; // Interface to the frontend's renderer. @@ -92,8 +94,9 @@ 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 CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, - bool dynamic = false) = 0; + virtual std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + 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, u32 data_stride) = 0; @@ -163,7 +166,6 @@ public: static u32 GetDisplayPixelFormatSize(HostDisplayPixelFormat format); - virtual bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const = 0; virtual bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer, diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index 95c5781ee..e70c1aea6 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -170,8 +170,8 @@ bool SDLHostInterface::CreateDisplay() return false; } - m_app_icon_texture = - display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, APP_ICON_DATA, APP_ICON_WIDTH * sizeof(u32)); + m_app_icon_texture = display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, + APP_ICON_DATA, APP_ICON_WIDTH * sizeof(u32)); if (!m_app_icon_texture) return false; diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index ace58049f..d2b6bcd3d 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -437,8 +437,8 @@ bool CommonHostInterface::SetFullscreen(bool enabled) bool CommonHostInterface::CreateHostDisplayResources() { - m_logo_texture = - m_display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, APP_ICON_DATA, sizeof(u32) * APP_ICON_WIDTH, false); + m_logo_texture = m_display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, + APP_ICON_DATA, sizeof(u32) * APP_ICON_WIDTH, false); if (!m_logo_texture) Log_WarningPrintf("Failed to create logo texture"); diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp index 4b9831724..78ab38439 100644 --- a/src/frontend-common/d3d11_host_display.cpp +++ b/src/frontend-common/d3d11_host_display.cpp @@ -23,52 +23,28 @@ namespace FrontendCommon { class D3D11HostDisplayTexture : public HostDisplayTexture { public: - template - using ComPtr = Microsoft::WRL::ComPtr; - - D3D11HostDisplayTexture(ComPtr texture, ComPtr 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(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 m_srv.Get(); } - u32 GetWidth() const override { return m_width; } - u32 GetHeight() const override { return m_height; } + void* GetHandle() const override { return m_texture.GetD3DSRV(); } + 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; } - ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } - ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } - ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); } - bool IsDynamic() const { return m_dynamic; } - - static std::unique_ptr 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 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, - 1); - ComPtr srv; - hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf()); - if (FAILED(hr)) - return {}; - - return std::make_unique(std::move(texture), std::move(srv), width, height, dynamic); - } + 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: - ComPtr m_texture; - ComPtr m_srv; - u32 m_width; - u32 m_height; + D3D11::Texture m_texture; + HostDisplayPixelFormat m_format; bool m_dynamic; }; @@ -105,10 +81,27 @@ bool D3D11HostDisplay::HasRenderSurface() const return static_cast(m_swap_chain); } -std::unique_ptr D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data, - u32 initial_data_stride, bool dynamic) +static constexpr std::array(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 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(format)], D3D11_BIND_SHADER_RESOURCE, data, + data_stride, dynamic)) + { + return {}; + } + + return std::make_unique(std::move(tex), format, dynamic); } 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(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 { const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast(format)]; diff --git a/src/frontend-common/d3d11_host_display.h b/src/frontend-common/d3d11_host_display.h index 91497ddbe..d84f3907c 100644 --- a/src/frontend-common/d3d11_host_display.h +++ b/src/frontend-common/d3d11_host_display.h @@ -50,8 +50,9 @@ public: virtual bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, const void* initial_data, - u32 initial_data_stride, bool dynamic) override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + 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, u32 texture_data_stride) override; bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, diff --git a/src/frontend-common/opengl_host_display.cpp b/src/frontend-common/opengl_host_display.cpp index d0826d4bb..9e07b82da 100644 --- a/src/frontend-common/opengl_host_display.cpp +++ b/src/frontend-common/opengl_host_display.cpp @@ -16,41 +16,25 @@ namespace FrontendCommon { class OpenGLHostDisplayTexture : public HostDisplayTexture { public: - OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {} - ~OpenGLHostDisplayTexture() override { glDeleteTextures(1, &m_id); } - - void* GetHandle() const override { return reinterpret_cast(static_cast(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 Create(u32 width, u32 height, const void* initial_data, - u32 initial_data_stride) + OpenGLHostDisplayTexture(GL::Texture texture, HostDisplayPixelFormat format) + : m_texture(std::move(texture)), m_format(format) { - GLuint id; - glGenTextures(1, &id); - - GLint old_texture_binding = 0; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding); - - // TODO: Set pack width - 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(id, width, height); } + ~OpenGLHostDisplayTexture() override = default; + + void* GetHandle() const override { return reinterpret_cast(static_cast(m_texture.GetGLId())); } + 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; } + + GLuint GetGLID() const { return m_texture.GetGLId(); } private: - GLuint m_id; - u32 m_width; - u32 m_height; + GL::Texture m_texture; + HostDisplayPixelFormat m_format; }; OpenGLHostDisplay::OpenGLHostDisplay() = default; @@ -75,21 +59,35 @@ void* OpenGLHostDisplay::GetRenderContext() const return m_gl_context.get(); } -std::unique_ptr 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, static_cast(HostDisplayPixelFormat::Count)> s_display_pixel_format_mapping = {{ {}, // Unknown - {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8 - {GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 - {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 + {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 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(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(std::move(tex), format); +} + void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride) { diff --git a/src/frontend-common/opengl_host_display.h b/src/frontend-common/opengl_host_display.h index 3fe0fb7d9..82ff57f97 100644 --- a/src/frontend-common/opengl_host_display.h +++ b/src/frontend-common/opengl_host_display.h @@ -48,8 +48,9 @@ public: virtual bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, const void* initial_data, - u32 initial_data_stride, bool dynamic) override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + 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, u32 texture_data_stride) override; bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width, diff --git a/src/frontend-common/save_state_selector_ui.cpp b/src/frontend-common/save_state_selector_ui.cpp index babcae759..da261831d 100644 --- a/src/frontend-common/save_state_selector_ui.cpp +++ b/src/frontend-common/save_state_selector_ui.cpp @@ -131,15 +131,15 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, CommonHostInterface li->preview_texture.reset(); if (ssi && !ssi->screenshot_data.empty()) { - li->preview_texture = m_host_interface->GetDisplay()->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, - ssi->screenshot_data.data(), - sizeof(u32) * ssi->screenshot_width, false); + li->preview_texture = m_host_interface->GetDisplay()->CreateTexture( + ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, HostDisplayPixelFormat::RGBA8, + ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false); } else { - li->preview_texture = - m_host_interface->GetDisplay()->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, - PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); + li->preview_texture = m_host_interface->GetDisplay()->CreateTexture( + PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA, + sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); } if (!li->preview_texture) @@ -165,9 +165,9 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, s32 slot li->slot = slot; li->global = global; - li->preview_texture = - m_host_interface->GetDisplay()->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, - PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); + li->preview_texture = m_host_interface->GetDisplay()->CreateTexture( + PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA, + sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false); if (!li->preview_texture) Log_ErrorPrintf("Failed to upload save state image to GPU"); diff --git a/src/frontend-common/vulkan_host_display.cpp b/src/frontend-common/vulkan_host_display.cpp index 61ef4084c..938254b5e 100644 --- a/src/frontend-common/vulkan_host_display.cpp +++ b/src/frontend-common/vulkan_host_display.cpp @@ -23,8 +23,9 @@ namespace FrontendCommon { class VulkanHostDisplayTexture : public HostDisplayTexture { public: - VulkanHostDisplayTexture(Vulkan::Texture texture, Vulkan::StagingTexture staging_texture) - : m_texture(std::move(texture)), m_staging_texture(std::move(staging_texture)) + VulkanHostDisplayTexture(Vulkan::Texture texture, Vulkan::StagingTexture staging_texture, + HostDisplayPixelFormat format) + : m_texture(std::move(texture)), m_staging_texture(std::move(staging_texture)), m_format(format) { } ~VulkanHostDisplayTexture() override = default; @@ -32,64 +33,19 @@ public: void* GetHandle() const override { return const_cast(&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; } const Vulkan::Texture& GetTexture() const { return m_texture; } Vulkan::Texture& GetTexture() { return m_texture; } Vulkan::StagingTexture& GetStagingTexture() { return m_staging_texture; } - static std::unique_ptr 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(std::move(texture), std::move(staging_texture)); - } - private: Vulkan::Texture m_texture; Vulkan::StagingTexture m_staging_texture; + HostDisplayPixelFormat m_format; }; VulkanHostDisplay::VulkanHostDisplay() = default; @@ -195,10 +151,63 @@ void VulkanHostDisplay::DestroyRenderSurface() m_swap_chain.reset(); } -std::unique_ptr VulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* data, - u32 data_stride, bool dynamic) +static constexpr std::array(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 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(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(std::move(texture), std::move(staging_texture), format); } 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; } -static constexpr std::array(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 { const VkFormat vk_format = s_display_pixel_format_mapping[static_cast(format)]; diff --git a/src/frontend-common/vulkan_host_display.h b/src/frontend-common/vulkan_host_display.h index 64904620b..24f1c7edf 100644 --- a/src/frontend-common/vulkan_host_display.h +++ b/src/frontend-common/vulkan_host_display.h @@ -47,8 +47,9 @@ public: virtual bool SetPostProcessingChain(const std::string_view& config) override; - std::unique_ptr CreateTexture(u32 width, u32 height, const void* initial_data, - u32 initial_data_stride, bool dynamic) override; + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + 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, u32 texture_data_stride) override; bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,