mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 08:05:41 +00:00
HostDisplay: Make textures have levels/layers/samples attributes
This commit is contained in:
parent
e54ba23c4f
commit
6c6fdeb15e
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,7 +125,8 @@ 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 =
|
||||||
|
CreateTexture(static_cast<u32>(width), static_cast<u32>(height), 1, 1, 1, HostDisplayPixelFormat::RGBA8, pixel_data,
|
||||||
sizeof(u32) * static_cast<u32>(width), false);
|
sizeof(u32) * static_cast<u32>(width), false);
|
||||||
stbi_image_free(pixel_data);
|
stbi_image_free(pixel_data);
|
||||||
if (!tex)
|
if (!tex)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
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(); }
|
ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.GetD3DTexture(); }
|
||||||
ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); }
|
ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_texture.GetD3DSRV(); }
|
||||||
ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); }
|
ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_texture.GetD3DSRVArray(); }
|
||||||
bool IsDynamic() const { return m_dynamic; }
|
ALWAYS_INLINE 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,
|
|
||||||
1);
|
|
||||||
ComPtr<ID3D11ShaderResourceView> srv;
|
|
||||||
hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf());
|
|
||||||
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)];
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
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<OpenGLHostDisplayTexture>(id, width, height);
|
|
||||||
}
|
}
|
||||||
|
~OpenGLHostDisplayTexture() override = default;
|
||||||
|
|
||||||
|
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(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:
|
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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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)];
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue