mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 14:25:37 +00:00
HostDisplay: Support screenshotting 16-bit display formats
This commit is contained in:
parent
189656cbc4
commit
ca84925ff8
|
@ -1,4 +1,5 @@
|
||||||
#include "host_display.h"
|
#include "host_display.h"
|
||||||
|
#include "common/align.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/file_system.h"
|
#include "common/file_system.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
@ -277,9 +278,93 @@ std::tuple<float, float> HostDisplay::ConvertWindowCoordinatesToDisplayCoordinat
|
||||||
return std::make_tuple(display_x, display_y);
|
return std::make_tuple(display_x, display_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
|
||||||
|
HostDisplayPixelFormat format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case HostDisplayPixelFormat::BGRA8:
|
||||||
|
{
|
||||||
|
for (u32 y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
u32* pixels = reinterpret_cast<u32*>(reinterpret_cast<u8*>(texture_data.data()) + (y * texture_data_stride));
|
||||||
|
for (u32 x = 0; x < width; x++)
|
||||||
|
pixels[x] = (pixels[x] & 0xFF00FF00) | ((pixels[x] & 0xFF) << 16) | ((pixels[x] >> 16) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case HostDisplayPixelFormat::RGBA8:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HostDisplayPixelFormat::RGB565:
|
||||||
|
{
|
||||||
|
std::vector<u32> temp(width * height);
|
||||||
|
|
||||||
|
for (u32 y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
const u8* pixels_in = reinterpret_cast<u8*>(texture_data.data()) + (y * texture_data_stride);
|
||||||
|
u32* pixels_out = &temp[y * width];
|
||||||
|
|
||||||
|
for (u32 x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
// RGB565 -> RGBA8
|
||||||
|
u16 pixel_in;
|
||||||
|
std::memcpy(&pixel_in, pixels_in, sizeof(u16));
|
||||||
|
pixels_in += sizeof(u16);
|
||||||
|
const u8 r5 = Truncate8(pixel_in >> 11);
|
||||||
|
const u8 g6 = Truncate8((pixel_in >> 5) & 0x3F);
|
||||||
|
const u8 b5 = Truncate8(pixel_in & 0x1F);
|
||||||
|
*(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 2) | (g6 & 3)) << 8) |
|
||||||
|
(ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (0xFF000000u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_data = std::move(temp);
|
||||||
|
texture_data_stride = sizeof(u32) * width;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case HostDisplayPixelFormat::RGBA5551:
|
||||||
|
{
|
||||||
|
std::vector<u32> temp(width * height);
|
||||||
|
|
||||||
|
for (u32 y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
const u8* pixels_in = reinterpret_cast<u8*>(texture_data.data()) + (y * texture_data_stride);
|
||||||
|
u32* pixels_out = &temp[y * width];
|
||||||
|
|
||||||
|
for (u32 x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
// RGBA5551 -> RGBA8
|
||||||
|
u16 pixel_in;
|
||||||
|
std::memcpy(&pixel_in, pixels_in, sizeof(u16));
|
||||||
|
pixels_in += sizeof(u16);
|
||||||
|
const u8 a1 = Truncate8(pixel_in >> 15);
|
||||||
|
const u8 r5 = Truncate8((pixel_in >> 10) & 0x1F);
|
||||||
|
const u8 g6 = Truncate8((pixel_in >> 5) & 0x1F);
|
||||||
|
const u8 b5 = Truncate8(pixel_in & 0x1F);
|
||||||
|
*(pixels_out++) = ZeroExtend32((r5 << 3) | (r5 & 7)) | (ZeroExtend32((g6 << 3) | (g6 & 7)) << 8) |
|
||||||
|
(ZeroExtend32((b5 << 3) | (b5 & 7)) << 16) | (a1 ? 0xFF000000u : 0u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_data = std::move(temp);
|
||||||
|
texture_data_stride = sizeof(u32) * width;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log_ErrorPrintf("Unknown pixel format %u", static_cast<u32>(format));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string filename, FileSystem::ManagedCFilePtr fp,
|
static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string filename, FileSystem::ManagedCFilePtr fp,
|
||||||
bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height,
|
bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height,
|
||||||
std::vector<u32> texture_data, u32 texture_data_stride)
|
std::vector<u32> texture_data, u32 texture_data_stride,
|
||||||
|
HostDisplayPixelFormat texture_format)
|
||||||
{
|
{
|
||||||
|
|
||||||
const char* extension = std::strrchr(filename.c_str(), '.');
|
const char* extension = std::strrchr(filename.c_str(), '.');
|
||||||
|
@ -289,6 +374,9 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ConvertTextureDataToRGBA8(width, height, texture_data, texture_data_stride, texture_format))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (clear_alpha)
|
if (clear_alpha)
|
||||||
{
|
{
|
||||||
for (u32& pixel : texture_data)
|
for (u32& pixel : texture_data)
|
||||||
|
@ -359,13 +447,13 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
||||||
std::string filename, bool clear_alpha /* = true */, bool flip_y /* = false */,
|
HostDisplayPixelFormat format, std::string filename, bool clear_alpha /* = true */,
|
||||||
u32 resize_width /* = 0 */, u32 resize_height /* = 0 */,
|
bool flip_y /* = false */, u32 resize_width /* = 0 */, u32 resize_height /* = 0 */,
|
||||||
bool compress_on_thread /* = false */)
|
bool compress_on_thread /* = false */)
|
||||||
{
|
{
|
||||||
std::vector<u32> texture_data(width * height);
|
std::vector<u32> texture_data(width * height);
|
||||||
u32 texture_data_stride = sizeof(u32) * width;
|
u32 texture_data_stride = Common::AlignUpPow2(GetDisplayPixelFormatSize(format) * width, 4);
|
||||||
if (!DownloadTexture(texture_handle, x, y, width, height, texture_data.data(), texture_data_stride))
|
if (!DownloadTexture(texture_handle, format, x, y, width, height, texture_data.data(), texture_data_stride))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Texture download failed");
|
Log_ErrorPrintf("Texture download failed");
|
||||||
return false;
|
return false;
|
||||||
|
@ -381,12 +469,13 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u
|
||||||
if (!compress_on_thread)
|
if (!compress_on_thread)
|
||||||
{
|
{
|
||||||
return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), clear_alpha, flip_y,
|
return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), clear_alpha, flip_y,
|
||||||
resize_width, resize_height, std::move(texture_data), texture_data_stride);
|
resize_width, resize_height, std::move(texture_data), texture_data_stride,
|
||||||
|
format);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp),
|
std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp),
|
||||||
clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data),
|
clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data),
|
||||||
texture_data_stride);
|
texture_data_stride, format);
|
||||||
compress_thread.detach();
|
compress_thread.detach();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -394,7 +483,7 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u
|
||||||
bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_resolution /* = true */,
|
bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_resolution /* = true */,
|
||||||
bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = false */)
|
bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = false */)
|
||||||
{
|
{
|
||||||
if (!m_display_texture_handle || m_display_texture_format != HostDisplayPixelFormat::RGBA8)
|
if (!m_display_texture_handle)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
apply_aspect_ratio = (m_display_aspect_ratio > 0) ? apply_aspect_ratio : false;
|
apply_aspect_ratio = (m_display_aspect_ratio > 0) ? apply_aspect_ratio : false;
|
||||||
|
@ -454,14 +543,14 @@ bool HostDisplay::WriteDisplayTextureToFile(std::string filename, bool full_reso
|
||||||
}
|
}
|
||||||
|
|
||||||
return WriteTextureToFile(m_display_texture_handle, m_display_texture_view_x, read_y, m_display_texture_view_width,
|
return WriteTextureToFile(m_display_texture_handle, m_display_texture_view_x, read_y, m_display_texture_view_width,
|
||||||
read_height, std::move(filename), true, flip_y, static_cast<u32>(resize_width),
|
read_height, m_display_texture_format, std::move(filename), true, flip_y,
|
||||||
static_cast<u32>(resize_height), compress_on_thread);
|
static_cast<u32>(resize_width), static_cast<u32>(resize_height), compress_on_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resize_width /* = 0 */,
|
bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resize_width /* = 0 */,
|
||||||
u32 resize_height /* = 0 */, bool clear_alpha /* = true */)
|
u32 resize_height /* = 0 */, bool clear_alpha /* = true */)
|
||||||
{
|
{
|
||||||
if (!m_display_texture_handle || m_display_texture_format != HostDisplayPixelFormat::RGBA8)
|
if (!m_display_texture_handle)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const bool flip_y = (m_display_texture_view_height < 0);
|
const bool flip_y = (m_display_texture_view_height < 0);
|
||||||
|
@ -478,14 +567,17 @@ bool HostDisplay::WriteDisplayTextureToBuffer(std::vector<u32>* buffer, u32 resi
|
||||||
u32 width = static_cast<u32>(read_width);
|
u32 width = static_cast<u32>(read_width);
|
||||||
u32 height = static_cast<u32>(read_height);
|
u32 height = static_cast<u32>(read_height);
|
||||||
std::vector<u32> texture_data(width * height);
|
std::vector<u32> texture_data(width * height);
|
||||||
u32 texture_data_stride = sizeof(u32) * width;
|
u32 texture_data_stride = Common::AlignUpPow2(GetDisplayPixelFormatSize(m_display_texture_format) * width, 4);
|
||||||
if (!DownloadTexture(m_display_texture_handle, read_x, read_y, width, height, texture_data.data(),
|
if (!DownloadTexture(m_display_texture_handle, m_display_texture_format, read_x, read_y, width, height,
|
||||||
texture_data_stride))
|
texture_data.data(), texture_data_stride))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to download texture from GPU.");
|
Log_ErrorPrintf("Failed to download texture from GPU.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ConvertTextureDataToRGBA8(width, height, texture_data, texture_data_stride, m_display_texture_format))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (clear_alpha)
|
if (clear_alpha)
|
||||||
{
|
{
|
||||||
for (u32& pixel : texture_data)
|
for (u32& pixel : texture_data)
|
||||||
|
|
|
@ -95,8 +95,8 @@ public:
|
||||||
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;
|
||||||
|
|
||||||
virtual bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
virtual bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||||
u32 out_data_stride) = 0;
|
u32 width, u32 height, void* out_data, u32 out_data_stride) = 0;
|
||||||
|
|
||||||
/// Returns false if the window was completely occluded.
|
/// Returns false if the window was completely occluded.
|
||||||
virtual bool Render() = 0;
|
virtual bool Render() = 0;
|
||||||
|
@ -194,8 +194,9 @@ public:
|
||||||
s32 window_height, s32 top_margin) const;
|
s32 window_height, s32 top_margin) const;
|
||||||
|
|
||||||
/// Helper function to save texture data to a PNG. If flip_y is set, the image will be flipped aka OpenGL.
|
/// Helper function to save texture data to a PNG. If flip_y is set, the image will be flipped aka OpenGL.
|
||||||
bool WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, std::string filename,
|
bool WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
||||||
bool clear_alpha = true, bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0,
|
HostDisplayPixelFormat format, std::string filename, bool clear_alpha = true,
|
||||||
|
bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0,
|
||||||
bool compress_on_thread = false);
|
bool compress_on_thread = false);
|
||||||
|
|
||||||
/// Helper function to save current display texture to PNG.
|
/// Helper function to save current display texture to PNG.
|
||||||
|
|
|
@ -156,8 +156,8 @@ void LibretroHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LibretroHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
bool LibretroHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x,
|
||||||
void* out_data, u32 out_data_stride)
|
u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@ public:
|
||||||
bool dynamic) override;
|
bool dynamic) override;
|
||||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||||
u32 data_stride) override;
|
u32 data_stride) override;
|
||||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||||
u32 out_data_stride) override;
|
u32 height, void* out_data, u32 out_data_stride) override;
|
||||||
|
|
||||||
void SetVSync(bool enabled) override;
|
void SetVSync(bool enabled) override;
|
||||||
|
|
||||||
|
|
|
@ -155,8 +155,8 @@ void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||||
u32 out_data_stride)
|
u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||||
{
|
{
|
||||||
ID3D11ShaderResourceView* srv =
|
ID3D11ShaderResourceView* srv =
|
||||||
const_cast<ID3D11ShaderResourceView*>(static_cast<const ID3D11ShaderResourceView*>(texture_handle));
|
const_cast<ID3D11ShaderResourceView*>(static_cast<const ID3D11ShaderResourceView*>(texture_handle));
|
||||||
|
@ -169,8 +169,17 @@ bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_readback_staging_texture.CopyFromTexture(m_context.Get(), srv_resource.Get(), 0, x, y, 0, 0, width, height);
|
m_readback_staging_texture.CopyFromTexture(m_context.Get(), srv_resource.Get(), 0, x, y, 0, 0, width, height);
|
||||||
return m_readback_staging_texture.ReadPixels<u32>(m_context.Get(), 0, 0, width, height, out_data_stride / sizeof(u32),
|
|
||||||
static_cast<u32*>(out_data));
|
if (srv_desc.Format == DXGI_FORMAT_B5G6R5_UNORM || srv_desc.Format == DXGI_FORMAT_B5G5R5A1_UNORM)
|
||||||
|
{
|
||||||
|
return m_readback_staging_texture.ReadPixels<u16>(m_context.Get(), 0, 0, width, height,
|
||||||
|
out_data_stride / sizeof(u16), static_cast<u16*>(out_data));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_readback_staging_texture.ReadPixels<u32>(m_context.Get(), 0, 0, width, height,
|
||||||
|
out_data_stride / sizeof(u32), static_cast<u32*>(out_data));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<DXGI_FORMAT, static_cast<u32>(HostDisplayPixelFormat::Count)>
|
static constexpr std::array<DXGI_FORMAT, static_cast<u32>(HostDisplayPixelFormat::Count)>
|
||||||
|
|
|
@ -55,8 +55,8 @@ public:
|
||||||
u32 initial_data_stride, bool dynamic) override;
|
u32 initial_data_stride, bool dynamic) 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, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||||
u32 out_data_stride) override;
|
u32 height, void* out_data, u32 out_data_stride) override;
|
||||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||||
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
|
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
|
||||||
u32* out_pitch) override;
|
u32* out_pitch) override;
|
||||||
|
|
|
@ -83,46 +83,6 @@ std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width,
|
||||||
return OpenGLHostDisplayTexture::Create(width, height, initial_data, initial_data_stride);
|
return OpenGLHostDisplayTexture::Create(width, height, initial_data, initial_data_stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
|
||||||
const void* texture_data, u32 texture_data_stride)
|
|
||||||
{
|
|
||||||
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
|
|
||||||
Assert((texture_data_stride % sizeof(u32)) == 0);
|
|
||||||
|
|
||||||
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
|
|
||||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
|
|
||||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
|
|
||||||
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_row_length);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture_data_stride / sizeof(u32));
|
|
||||||
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
|
||||||
u32 out_data_stride)
|
|
||||||
{
|
|
||||||
GLint old_alignment = 0, old_row_length = 0;
|
|
||||||
glGetIntegerv(GL_PACK_ALIGNMENT, &old_alignment);
|
|
||||||
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length);
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, sizeof(u32));
|
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / sizeof(u32));
|
|
||||||
|
|
||||||
const GLuint texture = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle));
|
|
||||||
GL::Texture::GetTextureSubImage(texture, 0, x, y, 0, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
||||||
height * out_data_stride, out_data);
|
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, old_alignment);
|
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, old_row_length);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -132,6 +92,65 @@ static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>
|
||||||
{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
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||||
|
const void* texture_data, u32 texture_data_stride)
|
||||||
|
{
|
||||||
|
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
|
||||||
|
const auto [gl_internal_format, gl_format, gl_type] =
|
||||||
|
s_display_pixel_format_mapping[static_cast<u32>(texture->GetFormat())];
|
||||||
|
GLint alignment;
|
||||||
|
if (texture_data_stride & 1)
|
||||||
|
alignment = 1;
|
||||||
|
else if (texture_data_stride & 2)
|
||||||
|
alignment = 2;
|
||||||
|
else
|
||||||
|
alignment = 4;
|
||||||
|
|
||||||
|
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
|
||||||
|
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
|
||||||
|
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_row_length);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture_data_stride / GetDisplayPixelFormatSize(texture->GetFormat()));
|
||||||
|
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, texture_data);
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||||
|
u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||||
|
{
|
||||||
|
GLint alignment;
|
||||||
|
if (out_data_stride & 1)
|
||||||
|
alignment = 1;
|
||||||
|
else if (out_data_stride & 2)
|
||||||
|
alignment = 2;
|
||||||
|
else
|
||||||
|
alignment = 4;
|
||||||
|
|
||||||
|
GLint old_alignment = 0, old_row_length = 0;
|
||||||
|
glGetIntegerv(GL_PACK_ALIGNMENT, &old_alignment);
|
||||||
|
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length);
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, alignment);
|
||||||
|
glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / GetDisplayPixelFormatSize(texture_format));
|
||||||
|
|
||||||
|
const GLuint texture = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle));
|
||||||
|
const auto [gl_internal_format, gl_format, gl_type] =
|
||||||
|
s_display_pixel_format_mapping[static_cast<u32>(texture_format)];
|
||||||
|
|
||||||
|
GL::Texture::GetTextureSubImage(texture, 0, x, y, 0, width, height, 1, gl_format, gl_type, height * out_data_stride,
|
||||||
|
out_data);
|
||||||
|
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, old_alignment);
|
||||||
|
glPixelStorei(GL_PACK_ROW_LENGTH, old_row_length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||||
{
|
{
|
||||||
return (std::get<0>(s_display_pixel_format_mapping[static_cast<u32>(format)]) != static_cast<GLenum>(0));
|
return (std::get<0>(s_display_pixel_format_mapping[static_cast<u32>(format)]) != static_cast<GLenum>(0));
|
||||||
|
|
|
@ -55,8 +55,8 @@ public:
|
||||||
u32 initial_data_stride, bool dynamic) override;
|
u32 initial_data_stride, bool dynamic) 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, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||||
u32 out_data_stride) override;
|
u32 height, void* out_data, u32 out_data_stride) override;
|
||||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||||
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
|
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
|
||||||
u32* out_pitch) override;
|
u32* out_pitch) override;
|
||||||
|
|
|
@ -230,14 +230,13 @@ void VulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y,
|
||||||
staging_texture->CopyToTexture(0, 0, vk_texture->GetTexture(), x, y, 0, 0, width, height);
|
staging_texture->CopyToTexture(0, 0, vk_texture->GetTexture(), x, y, 0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||||
u32 out_data_stride)
|
u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||||
{
|
{
|
||||||
Vulkan::Texture* texture = static_cast<Vulkan::Texture*>(const_cast<void*>(texture_handle));
|
Vulkan::Texture* texture = static_cast<Vulkan::Texture*>(const_cast<void*>(texture_handle));
|
||||||
|
|
||||||
if ((m_readback_staging_texture.GetWidth() < width || m_readback_staging_texture.GetHeight() < height) &&
|
if ((m_readback_staging_texture.GetWidth() < width || m_readback_staging_texture.GetHeight() < height) &&
|
||||||
!m_readback_staging_texture.Create(Vulkan::StagingBuffer::Type::Readback, VK_FORMAT_R8G8B8A8_UNORM, width,
|
!m_readback_staging_texture.Create(Vulkan::StagingBuffer::Type::Readback, texture->GetFormat(), width, height))
|
||||||
height))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ public:
|
||||||
u32 initial_data_stride, bool dynamic) override;
|
u32 initial_data_stride, bool dynamic) 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, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||||
u32 out_data_stride) override;
|
u32 height, void* out_data, u32 out_data_stride) override;
|
||||||
|
|
||||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||||
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
|
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
|
||||||
|
|
Loading…
Reference in a new issue