mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-19 00:35:46 -04:00
HostDisplay: Common texture base class for all APIs
This commit is contained in:
@ -412,9 +412,9 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/,
|
||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing |
|
||||
ImGuiWindowFlags_NoBackground))
|
||||
{
|
||||
HostDisplayTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png");
|
||||
GPUTexture* tex = ImGuiFullscreen::GetCachedTexture("images/duck.png");
|
||||
if (tex)
|
||||
ImGui::Image(tex->GetHandle(), ImVec2(logo_width, logo_height));
|
||||
ImGui::Image(tex, ImVec2(logo_width, logo_height));
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
|
@ -21,69 +21,6 @@ Log_SetChannel(D3D11HostDisplay);
|
||||
#pragma comment(lib, "d3d11.lib")
|
||||
#pragma comment(lib, "dxgi.lib")
|
||||
|
||||
class D3D11HostDisplayTexture final : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
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 const_cast<D3D11::Texture*>(&m_texture); }
|
||||
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; }
|
||||
|
||||
bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override
|
||||
{
|
||||
if (!m_dynamic || m_texture.GetWidth() != width || m_texture.GetHeight() != height)
|
||||
return false;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE sr;
|
||||
HRESULT hr = static_cast<ID3D11DeviceContext*>(g_host_display->GetRenderContext())
|
||||
->Map(m_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Log_ErrorPrintf("Map pixels texture failed: %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_buffer = sr.pData;
|
||||
*out_pitch = sr.RowPitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndUpdate(u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
static_cast<ID3D11DeviceContext*>(g_host_display->GetRenderContext())->Unmap(m_texture, 0);
|
||||
}
|
||||
|
||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override
|
||||
{
|
||||
if (m_dynamic)
|
||||
return HostDisplayTexture::Update(x, y, width, height, data, pitch);
|
||||
|
||||
const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1);
|
||||
static_cast<ID3D11DeviceContext*>(g_host_display->GetRenderContext())
|
||||
->UpdateSubresource(m_texture, 0, &dst_box, data, pitch, pitch * height);
|
||||
return true;
|
||||
}
|
||||
|
||||
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:
|
||||
D3D11::Texture m_texture;
|
||||
HostDisplayPixelFormat m_format;
|
||||
bool m_dynamic;
|
||||
};
|
||||
|
||||
D3D11HostDisplay::D3D11HostDisplay() = default;
|
||||
|
||||
D3D11HostDisplay::~D3D11HostDisplay()
|
||||
@ -120,34 +57,61 @@ bool D3D11HostDisplay::HasRenderSurface() const
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
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}};
|
||||
|
||||
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 */)
|
||||
std::unique_ptr<GPUTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data,
|
||||
u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
if (layers != 1)
|
||||
return {};
|
||||
|
||||
D3D11::Texture tex;
|
||||
if (!tex.Create(m_device.Get(), width, height, layers, levels, samples,
|
||||
s_display_pixel_format_mapping[static_cast<u32>(format)], D3D11_BIND_SHADER_RESOURCE, data,
|
||||
data_stride, dynamic))
|
||||
std::unique_ptr<D3D11::Texture> tex(std::make_unique<D3D11::Texture>());
|
||||
if (!tex->Create(m_device.Get(), width, height, layers, levels, samples, format, D3D11_BIND_SHADER_RESOURCE, data,
|
||||
data_stride, dynamic))
|
||||
{
|
||||
return {};
|
||||
tex.reset();
|
||||
}
|
||||
|
||||
return std::make_unique<D3D11HostDisplayTexture>(std::move(tex), format, dynamic);
|
||||
return tex;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||
u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||
bool D3D11HostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch)
|
||||
{
|
||||
const D3D11::Texture* tex = static_cast<const D3D11::Texture*>(texture_handle);
|
||||
if (!CheckStagingBufferSize(width, height, tex->GetFormat()))
|
||||
D3D11::Texture* tex = static_cast<D3D11::Texture*>(texture);
|
||||
if (!tex->IsDynamic() || tex->GetWidth() != width || tex->GetHeight() != height)
|
||||
return false;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE sr;
|
||||
HRESULT hr = m_context->Map(tex->GetD3DTexture(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Log_ErrorPrintf("Map pixels texture failed: %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_buffer = sr.pData;
|
||||
*out_pitch = sr.RowPitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
D3D11::Texture* tex = static_cast<D3D11::Texture*>(texture);
|
||||
m_context->Unmap(tex->GetD3DTexture(), 0);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
|
||||
{
|
||||
D3D11::Texture* tex = static_cast<D3D11::Texture*>(texture);
|
||||
if (tex->IsDynamic())
|
||||
return HostDisplay::UpdateTexture(texture, x, y, width, height, data, pitch);
|
||||
|
||||
const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1);
|
||||
m_context->UpdateSubresource(tex->GetD3DTexture(), 0, &dst_box, data, pitch, pitch * height);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
const D3D11::Texture* tex = static_cast<const D3D11::Texture*>(texture);
|
||||
if (!CheckStagingBufferSize(width, height, tex->GetDXGIFormat()))
|
||||
return false;
|
||||
|
||||
const CD3D11_BOX box(static_cast<LONG>(x), static_cast<LONG>(y), 0, static_cast<LONG>(x + width),
|
||||
@ -162,7 +126,7 @@ bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPi
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 copy_size = GetDisplayPixelFormatSize(texture_format) * width;
|
||||
const u32 copy_size = tex->GetPixelSize() * width;
|
||||
StringUtil::StrideMemCpy(out_data, out_data_stride, sr.pData, sr.RowPitch, copy_size, height);
|
||||
m_context->Unmap(m_readback_staging_texture.Get(), 0);
|
||||
return true;
|
||||
@ -195,9 +159,9 @@ void D3D11HostDisplay::DestroyStagingBuffer()
|
||||
m_readback_staging_texture_format = DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||
bool D3D11HostDisplay::SupportsTextureFormat(GPUTexture::Format format) const
|
||||
{
|
||||
const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast<u32>(format)];
|
||||
const DXGI_FORMAT dfmt = D3D11::Texture::GetDXGIFormat(format);
|
||||
if (dfmt == DXGI_FORMAT_UNKNOWN)
|
||||
return false;
|
||||
|
||||
@ -767,13 +731,12 @@ bool D3D11HostDisplay::Render(bool skip_present)
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format)
|
||||
GPUTexture::Format* out_format)
|
||||
{
|
||||
static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
static constexpr HostDisplayPixelFormat hdformat = HostDisplayPixelFormat::RGBA8;
|
||||
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8;
|
||||
|
||||
D3D11::Texture render_texture;
|
||||
if (!render_texture.Create(m_device.Get(), width, height, 1, 1, 1, format, D3D11_BIND_RENDER_TARGET))
|
||||
if (!render_texture.Create(m_device.Get(), width, height, 1, 1, 1, hdformat, D3D11_BIND_RENDER_TARGET))
|
||||
return false;
|
||||
|
||||
static constexpr std::array<float, 4> clear_color = {};
|
||||
@ -786,24 +749,24 @@ bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
||||
ApplyPostProcessingChain(render_texture.GetD3DRTV(), left, top, draw_width, draw_height,
|
||||
static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(left, top, draw_width, draw_height, static_cast<D3D11::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
m_context->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
|
||||
const u32 stride = GetDisplayPixelFormatSize(hdformat) * width;
|
||||
const u32 stride = GPUTexture::GetPixelSize(hdformat) * width;
|
||||
out_pixels->resize(width * height);
|
||||
if (!DownloadTexture(&render_texture, hdformat, 0, 0, width, height, out_pixels->data(), stride))
|
||||
if (!DownloadTexture(&render_texture, 0, 0, width, height, out_pixels->data(), stride))
|
||||
return false;
|
||||
|
||||
*out_stride = stride;
|
||||
@ -826,36 +789,36 @@ void D3D11HostDisplay::RenderDisplay()
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
||||
ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height,
|
||||
static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
GetWindowWidth(), GetWindowHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(left, top, width, height, static_cast<D3D11::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, D3D11::Texture* texture,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
|
||||
m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0);
|
||||
m_context->PSSetShaderResources(0, 1, static_cast<D3D11::Texture*>(texture_handle)->GetD3DSRVArray());
|
||||
m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray());
|
||||
m_context->PSSetSamplers(0, 1, linear_filter ? m_linear_sampler.GetAddressOf() : m_point_sampler.GetAddressOf());
|
||||
|
||||
const bool linear = IsUsingLinearFiltering();
|
||||
const float position_adjust = linear ? 0.5f : 0.0f;
|
||||
const float size_adjust = linear ? 1.0f : 0.0f;
|
||||
const float uniforms[4] = {
|
||||
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture_height)};
|
||||
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
|
||||
const auto map = m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), sizeof(uniforms));
|
||||
std::memcpy(map.pointer, uniforms, sizeof(uniforms));
|
||||
m_display_uniform_buffer.Unmap(m_context.Get(), sizeof(uniforms));
|
||||
@ -880,13 +843,12 @@ void D3D11HostDisplay::RenderSoftwareCursor()
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle)
|
||||
void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle)
|
||||
{
|
||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
|
||||
m_context->PSSetShader(m_display_alpha_pixel_shader.Get(), nullptr, 0);
|
||||
m_context->PSSetShaderResources(0, 1, static_cast<D3D11HostDisplayTexture*>(texture_handle)->GetD3DSRVArray());
|
||||
m_context->PSSetShaderResources(0, 1, static_cast<D3D11::Texture*>(texture_handle)->GetD3DSRVArray());
|
||||
m_context->PSSetSamplers(0, 1, m_linear_sampler.GetAddressOf());
|
||||
|
||||
const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
@ -1052,7 +1014,7 @@ bool D3D11HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 ta
|
||||
{
|
||||
DebugAssert(!m_post_processing_stages.empty());
|
||||
|
||||
const DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
const GPUTexture::Format format = GPUTexture::Format::RGBA8;
|
||||
const u32 bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
if (m_post_processing_input_texture.GetWidth() != target_width ||
|
||||
@ -1080,29 +1042,26 @@ bool D3D11HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 ta
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top,
|
||||
s32 final_width, s32 final_height, void* texture_handle,
|
||||
u32 texture_width, s32 texture_height, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height)
|
||||
s32 final_width, s32 final_height, D3D11::Texture* texture,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, u32 target_width, u32 target_height)
|
||||
{
|
||||
static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
if (!CheckPostProcessingRenderTargets(target_width, target_height))
|
||||
{
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
|
||||
texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
return;
|
||||
}
|
||||
|
||||
// downsample/upsample - use same viewport for remainder
|
||||
m_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), clear_color.data());
|
||||
m_context->OMSetRenderTargets(1, m_post_processing_input_texture.GetD3DRTVArray(), nullptr);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
|
||||
texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
|
||||
texture_handle = &m_post_processing_input_texture;
|
||||
texture_width = m_post_processing_input_texture.GetWidth();
|
||||
texture_height = m_post_processing_input_texture.GetHeight();
|
||||
texture = &m_post_processing_input_texture;
|
||||
texture_view_x = final_left;
|
||||
texture_view_y = final_top;
|
||||
texture_view_width = final_width;
|
||||
@ -1125,13 +1084,13 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0);
|
||||
m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0);
|
||||
m_context->PSSetShaderResources(0, 1, static_cast<D3D11::Texture*>(texture_handle)->GetD3DSRVArray());
|
||||
m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray());
|
||||
m_context->PSSetSamplers(0, 1, m_point_sampler.GetAddressOf());
|
||||
|
||||
const auto map =
|
||||
m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), pps.uniforms_size);
|
||||
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
|
||||
map.pointer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width,
|
||||
map.pointer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width,
|
||||
texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
|
||||
m_display_uniform_buffer.Unmap(m_context.Get(), pps.uniforms_size);
|
||||
m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray());
|
||||
@ -1140,7 +1099,7 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||
m_context->Draw(3, 0);
|
||||
|
||||
if (i != final_stage)
|
||||
texture_handle = &pps.output_texture;
|
||||
texture = &pps.output_texture;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* null_srv = nullptr;
|
||||
|
@ -47,12 +47,15 @@ public:
|
||||
|
||||
bool SetPostProcessingChain(const std::string_view& config) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||
u32 height, void* out_data, u32 out_data_stride) override;
|
||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
|
||||
void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
|
||||
bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override;
|
||||
bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
@ -63,7 +66,7 @@ public:
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
GPUTexture::Format* out_format) override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
@ -90,10 +93,9 @@ protected:
|
||||
void RenderSoftwareCursor();
|
||||
void RenderImGui();
|
||||
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, D3D11::Texture* texture, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle);
|
||||
|
||||
struct PostProcessingStage
|
||||
{
|
||||
@ -105,9 +107,8 @@ protected:
|
||||
|
||||
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
|
||||
void ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width,
|
||||
s32 final_height, void* texture_handle, u32 texture_width, s32 texture_height,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height);
|
||||
s32 final_height, D3D11::Texture* texture, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height);
|
||||
|
||||
bool CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
|
@ -15,51 +15,6 @@
|
||||
#include <dxgi1_5.h>
|
||||
Log_SetChannel(D3D12HostDisplay);
|
||||
|
||||
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}};
|
||||
|
||||
class D3D12HostDisplayTexture final : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
D3D12HostDisplayTexture(D3D12::Texture texture) : m_texture(std::move(texture)) {}
|
||||
~D3D12HostDisplayTexture() override = default;
|
||||
|
||||
void* GetHandle() const override { return const_cast<D3D12::Texture*>(&m_texture); }
|
||||
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
|
||||
{
|
||||
for (u32 i = 0; i < static_cast<u32>(s_display_pixel_format_mapping.size()); i++)
|
||||
{
|
||||
if (m_texture.GetFormat() == s_display_pixel_format_mapping[i])
|
||||
return static_cast<HostDisplayPixelFormat>(i);
|
||||
}
|
||||
|
||||
return HostDisplayPixelFormat::Count;
|
||||
}
|
||||
|
||||
bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override
|
||||
{
|
||||
return m_texture.BeginStreamUpdate(0, 0, width, height, out_buffer, out_pitch);
|
||||
}
|
||||
|
||||
void EndUpdate(u32 x, u32 y, u32 width, u32 height) override
|
||||
{
|
||||
m_texture.EndStreamUpdate(x, y, width, height);
|
||||
}
|
||||
|
||||
const D3D12::Texture& GetTexture() const { return m_texture; }
|
||||
D3D12::Texture& GetTexture() { return m_texture; }
|
||||
|
||||
private:
|
||||
D3D12::Texture m_texture;
|
||||
};
|
||||
|
||||
D3D12HostDisplay::D3D12HostDisplay() = default;
|
||||
|
||||
D3D12HostDisplay::~D3D12HostDisplay()
|
||||
@ -98,47 +53,62 @@ bool D3D12HostDisplay::HasRenderSurface() const
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> D3D12HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels,
|
||||
u32 samples, HostDisplayPixelFormat format,
|
||||
const void* data, u32 data_stride,
|
||||
bool dynamic /* = false */)
|
||||
std::unique_ptr<GPUTexture> D3D12HostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data,
|
||||
u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
if (layers != 1)
|
||||
const DXGI_FORMAT dformat = D3D12::Texture::GetDXGIFormat(format);
|
||||
if (dformat == DXGI_FORMAT_UNKNOWN)
|
||||
return {};
|
||||
|
||||
const DXGI_FORMAT dxgi_format = s_display_pixel_format_mapping[static_cast<u32>(format)];
|
||||
D3D12::Texture tex;
|
||||
if (!tex.Create(width, height, samples, dxgi_format, dxgi_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
|
||||
D3D12_RESOURCE_FLAG_NONE))
|
||||
std::unique_ptr<D3D12::Texture> tex(std::make_unique<D3D12::Texture>());
|
||||
if (!tex->Create(width, height, layers, levels, samples, dformat, dformat, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
|
||||
D3D12_RESOURCE_FLAG_NONE))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (data && !tex.LoadData(0, 0, width, height, data, data_stride))
|
||||
if (data && !tex->LoadData(0, 0, width, height, data, data_stride))
|
||||
return {};
|
||||
|
||||
return std::make_unique<D3D12HostDisplayTexture>(std::move(tex));
|
||||
return tex;
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||
u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||
bool D3D12HostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch)
|
||||
{
|
||||
const D3D12::Texture* texture = static_cast<const D3D12::Texture*>(texture_handle);
|
||||
return static_cast<D3D12::Texture*>(texture)->BeginStreamUpdate(0, 0, width, height, out_buffer, out_pitch);
|
||||
}
|
||||
|
||||
if (!m_readback_staging_texture.EnsureSize(width, height, texture->GetFormat(), false))
|
||||
void D3D12HostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
static_cast<D3D12::Texture*>(texture)->EndStreamUpdate(x, y, width, height);
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||
u32 pitch)
|
||||
{
|
||||
return HostDisplay::UpdateTexture(texture, x, y, width, height, data, pitch);
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
const D3D12::Texture* tex = static_cast<const D3D12::Texture*>(texture);
|
||||
|
||||
if (!m_readback_staging_texture.EnsureSize(width, height, tex->GetDXGIFormat(), false))
|
||||
return false;
|
||||
|
||||
const D3D12_RESOURCE_STATES old_state = texture->GetState();
|
||||
texture->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
m_readback_staging_texture.CopyFromTexture(texture->GetResource(), 0, x, y, 0, 0, width, height);
|
||||
texture->TransitionToState(old_state);
|
||||
const D3D12_RESOURCE_STATES old_state = tex->GetState();
|
||||
tex->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
m_readback_staging_texture.CopyFromTexture(tex->GetResource(), 0, x, y, 0, 0, width, height);
|
||||
tex->TransitionToState(old_state);
|
||||
|
||||
return m_readback_staging_texture.ReadPixels(0, 0, width, height, out_data, out_data_stride);
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||
bool D3D12HostDisplay::SupportsTextureFormat(GPUTexture::Format format) const
|
||||
{
|
||||
const DXGI_FORMAT dfmt = s_display_pixel_format_mapping[static_cast<u32>(format)];
|
||||
const DXGI_FORMAT dfmt = D3D12::Texture::GetDXGIFormat(format);
|
||||
if (dfmt == DXGI_FORMAT_UNKNOWN)
|
||||
return false;
|
||||
|
||||
@ -654,13 +624,13 @@ bool D3D12HostDisplay::Render(bool skip_present)
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format)
|
||||
GPUTexture::Format* out_format)
|
||||
{
|
||||
static constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
static constexpr HostDisplayPixelFormat hdformat = HostDisplayPixelFormat::RGBA8;
|
||||
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8;
|
||||
|
||||
D3D12::Texture render_texture;
|
||||
if (!render_texture.Create(width, height, 1, format, DXGI_FORMAT_UNKNOWN, format, DXGI_FORMAT_UNKNOWN,
|
||||
if (!render_texture.Create(width, height, 1, 1, 1, format, DXGI_FORMAT_UNKNOWN, format, DXGI_FORMAT_UNKNOWN,
|
||||
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ||
|
||||
!m_readback_staging_texture.EnsureSize(width, height, format, false))
|
||||
{
|
||||
@ -676,9 +646,9 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0);
|
||||
RenderDisplay(cmdlist, left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast<D3D12::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr);
|
||||
@ -728,23 +698,22 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist)
|
||||
// return;
|
||||
// }
|
||||
|
||||
RenderDisplay(cmdlist, left, top, width, height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(cmdlist, left, top, width, height, static_cast<D3D12::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
|
||||
void* texture_handle, u32 texture_width, s32 texture_height, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
bool linear_filter)
|
||||
D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
const float position_adjust = linear_filter ? 0.5f : 0.0f;
|
||||
const float size_adjust = linear_filter ? 1.0f : 0.0f;
|
||||
const float uniforms[4] = {
|
||||
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture_height)};
|
||||
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
|
||||
if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
|
||||
Panic("Failed to reserve UBO space");
|
||||
|
||||
@ -755,7 +724,7 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 lef
|
||||
cmdlist->SetGraphicsRootSignature(m_display_root_signature.Get());
|
||||
cmdlist->SetPipelineState(m_display_pipeline.Get());
|
||||
cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset);
|
||||
cmdlist->SetGraphicsRootDescriptorTable(1, reinterpret_cast<D3D12::Texture*>(texture_handle)->GetSRVDescriptor());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(2, linear_filter ? m_linear_sampler : m_point_sampler);
|
||||
|
||||
D3D12::SetViewportAndScissor(cmdlist, left, top, width, height);
|
||||
@ -774,7 +743,7 @@ void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist)
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width,
|
||||
s32 height, HostDisplayTexture* texture_handle)
|
||||
s32 height, GPUTexture* texture_handle)
|
||||
{
|
||||
const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
|
||||
@ -786,8 +755,7 @@ void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist,
|
||||
|
||||
cmdlist->SetPipelineState(m_display_pipeline.Get());
|
||||
cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset);
|
||||
cmdlist->SetGraphicsRootDescriptorTable(
|
||||
1, static_cast<D3D12HostDisplayTexture*>(texture_handle)->GetTexture().GetRTVOrDSVDescriptor());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12::Texture*>(texture_handle)->GetRTVOrDSVDescriptor());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler);
|
||||
|
||||
D3D12::SetViewportAndScissor(cmdlist, left, top, width, height);
|
||||
|
@ -49,12 +49,15 @@ public:
|
||||
|
||||
bool SetPostProcessingChain(const std::string_view& config) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||
u32 height, void* out_data, u32 out_data_stride) override;
|
||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
|
||||
void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
|
||||
bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override;
|
||||
bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
@ -62,7 +65,7 @@ public:
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
GPUTexture::Format* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
@ -93,11 +96,11 @@ protected:
|
||||
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist);
|
||||
void RenderImGui(ID3D12GraphicsCommandList* cmdlist);
|
||||
|
||||
void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, void* texture_handle,
|
||||
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter);
|
||||
void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
|
||||
D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle);
|
||||
GPUTexture* texture_handle);
|
||||
|
||||
ComPtr<IDXGIFactory> m_dxgi_factory;
|
||||
ComPtr<IDXGISwapChain> m_swap_chain;
|
||||
|
@ -218,14 +218,14 @@ static std::deque<AsyncOpEntry> s_async_ops;
|
||||
static bool LoadResources();
|
||||
static void DestroyResources();
|
||||
|
||||
static std::shared_ptr<HostDisplayTexture> s_app_icon_texture;
|
||||
static std::array<std::shared_ptr<HostDisplayTexture>, static_cast<u32>(GameDatabase::CompatibilityRating::Count)>
|
||||
static std::shared_ptr<GPUTexture> s_app_icon_texture;
|
||||
static std::array<std::shared_ptr<GPUTexture>, static_cast<u32>(GameDatabase::CompatibilityRating::Count)>
|
||||
s_game_compatibility_textures;
|
||||
static std::shared_ptr<HostDisplayTexture> s_fallback_disc_texture;
|
||||
static std::shared_ptr<HostDisplayTexture> s_fallback_exe_texture;
|
||||
static std::shared_ptr<HostDisplayTexture> s_fallback_psf_texture;
|
||||
static std::shared_ptr<HostDisplayTexture> s_fallback_playlist_texture;
|
||||
static std::vector<std::unique_ptr<HostDisplayTexture>> s_cleanup_textures;
|
||||
static std::shared_ptr<GPUTexture> s_fallback_disc_texture;
|
||||
static std::shared_ptr<GPUTexture> s_fallback_exe_texture;
|
||||
static std::shared_ptr<GPUTexture> s_fallback_psf_texture;
|
||||
static std::shared_ptr<GPUTexture> s_fallback_playlist_texture;
|
||||
static std::vector<std::unique_ptr<GPUTexture>> s_cleanup_textures;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Landing
|
||||
@ -375,7 +375,7 @@ struct SaveStateListEntry
|
||||
std::string title;
|
||||
std::string summary;
|
||||
std::string path;
|
||||
std::unique_ptr<HostDisplayTexture> preview_texture;
|
||||
std::unique_ptr<GPUTexture> preview_texture;
|
||||
time_t timestamp;
|
||||
s32 slot;
|
||||
bool global;
|
||||
@ -415,9 +415,9 @@ static void HandleGameListOptions(const GameList::Entry* entry);
|
||||
static void DrawGameListSettingsPage(const ImVec2& heading_size);
|
||||
static void SwitchToGameList();
|
||||
static void PopulateGameListEntryList();
|
||||
static HostDisplayTexture* GetTextureForGameListEntryType(GameList::EntryType type);
|
||||
static HostDisplayTexture* GetGameListCover(const GameList::Entry* entry);
|
||||
static HostDisplayTexture* GetCoverForCurrentGame();
|
||||
static GPUTexture* GetTextureForGameListEntryType(GameList::EntryType type);
|
||||
static GPUTexture* GetGameListCover(const GameList::Entry* entry);
|
||||
static GPUTexture* GetCoverForCurrentGame();
|
||||
|
||||
// Lazily populated cover images.
|
||||
static std::unordered_map<std::string, std::string> s_cover_image_map;
|
||||
@ -717,7 +717,7 @@ void FullscreenUI::Render()
|
||||
if (!s_initialized)
|
||||
return;
|
||||
|
||||
for (std::unique_ptr<HostDisplayTexture>& tex : s_cleanup_textures)
|
||||
for (std::unique_ptr<GPUTexture>& tex : s_cleanup_textures)
|
||||
tex.reset();
|
||||
s_cleanup_textures.clear();
|
||||
ImGuiFullscreen::UploadAsyncTextures();
|
||||
@ -1077,7 +1077,7 @@ void FullscreenUI::DrawLandingWindow()
|
||||
const float image_size = LayoutScale(380.f);
|
||||
ImGui::SetCursorPos(ImVec2((ImGui::GetWindowWidth() * 0.5f) - (image_size * 0.5f),
|
||||
(ImGui::GetWindowHeight() * 0.5f) - (image_size * 0.5f)));
|
||||
ImGui::Image(s_app_icon_texture->GetHandle(), ImVec2(image_size, image_size));
|
||||
ImGui::Image(s_app_icon_texture.get(), ImVec2(image_size, image_size));
|
||||
}
|
||||
EndFullscreenColumnWindow();
|
||||
|
||||
@ -3885,7 +3885,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
|
||||
const ImVec2 image_min(display_size.x - LayoutScale(20.0f + 50.0f) - rp_height,
|
||||
display_size.y - LayoutScale(20.0f + 50.0f) - rp_height);
|
||||
const ImVec2 image_max(image_min.x + LayoutScale(50.0f) + rp_height, image_min.y + LayoutScale(50.0f) + rp_height);
|
||||
dl->AddImage(GetCoverForCurrentGame()->GetHandle(), image_min, image_max);
|
||||
dl->AddImage(GetCoverForCurrentGame(), image_min, image_max);
|
||||
}
|
||||
|
||||
const ImVec2 window_size(LayoutScale(500.0f, LAYOUT_SCREEN_HEIGHT));
|
||||
@ -4087,15 +4087,15 @@ void FullscreenUI::PopulateSaveStateScreenshot(SaveStateListEntry* li, const Ext
|
||||
li->preview_texture.reset();
|
||||
if (ssi && !ssi->screenshot_data.empty())
|
||||
{
|
||||
li->preview_texture = g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1,
|
||||
HostDisplayPixelFormat::RGBA8, ssi->screenshot_data.data(),
|
||||
sizeof(u32) * ssi->screenshot_width, false);
|
||||
li->preview_texture =
|
||||
g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, GPUTexture::Format::RGBA8,
|
||||
ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1,
|
||||
HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA,
|
||||
sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
|
||||
li->preview_texture =
|
||||
g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, GPUTexture::Format::RGBA8,
|
||||
PLACEHOLDER_ICON_DATA, sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
|
||||
}
|
||||
|
||||
if (!li->preview_texture)
|
||||
@ -4254,8 +4254,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading, bool fullscreen)
|
||||
ImVec2 pos(bb.Min);
|
||||
|
||||
// use aspect ratio of screenshot to determine height
|
||||
const HostDisplayTexture* image =
|
||||
entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
|
||||
const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
|
||||
const float image_height =
|
||||
max_image_width / (static_cast<float>(image->GetWidth()) / static_cast<float>(image->GetHeight()));
|
||||
const float image_margin = (max_image_height - image_height) / 2.0f;
|
||||
@ -4289,10 +4288,9 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading, bool fullscreen)
|
||||
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::GetWindowDrawList()->AddImage(static_cast<ImTextureID>(entry.preview_texture ?
|
||||
entry.preview_texture->GetHandle() :
|
||||
GetPlaceholderTexture()->GetHandle()),
|
||||
image_bb.Min, image_bb.Max);
|
||||
ImGui::GetWindowDrawList()->AddImage(
|
||||
static_cast<ImTextureID>(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()),
|
||||
image_bb.Min, image_bb.Max);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
@ -4353,18 +4351,16 @@ void FullscreenUI::DrawResumeStateSelector()
|
||||
ImGui::TextWrapped("A resume save state created at %s was found.\n\nDo you want to load this save and continue?",
|
||||
TimeToPrintableString(entry.timestamp).c_str());
|
||||
|
||||
const HostDisplayTexture* image =
|
||||
entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
|
||||
const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
|
||||
const float image_height = LayoutScale(250.0f);
|
||||
const float image_width =
|
||||
image_height * (static_cast<float>(image->GetWidth()) / static_cast<float>(image->GetHeight()));
|
||||
const ImVec2 pos(ImGui::GetCursorScreenPos() +
|
||||
ImVec2((ImGui::GetCurrentWindow()->WorkRect.GetWidth() - image_width) * 0.5f, LayoutScale(20.0f)));
|
||||
const ImRect image_bb(pos, pos + ImVec2(image_width, image_height));
|
||||
ImGui::GetWindowDrawList()->AddImage(static_cast<ImTextureID>(entry.preview_texture ?
|
||||
entry.preview_texture->GetHandle() :
|
||||
GetPlaceholderTexture()->GetHandle()),
|
||||
image_bb.Min, image_bb.Max);
|
||||
ImGui::GetWindowDrawList()->AddImage(
|
||||
static_cast<ImTextureID>(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()),
|
||||
image_bb.Min, image_bb.Max);
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + image_height + LayoutScale(40.0f));
|
||||
|
||||
@ -4564,7 +4560,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
if (!visible)
|
||||
continue;
|
||||
|
||||
HostDisplayTexture* cover_texture = GetGameListCover(entry);
|
||||
GPUTexture* cover_texture = GetGameListCover(entry);
|
||||
|
||||
if (entry->serial.empty())
|
||||
{
|
||||
@ -4582,8 +4578,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(cover_texture->GetWidth()),
|
||||
static_cast<float>(cover_texture->GetHeight()))));
|
||||
|
||||
ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), image_rect.Min, image_rect.Max,
|
||||
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f),
|
||||
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
const float midpoint = bb.Min.y + g_large_font->FontSize + LayoutScale(4.0f);
|
||||
const float text_start_x = bb.Min.x + image_size.x + LayoutScale(15.0f);
|
||||
@ -4623,7 +4619,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
|
||||
if (BeginFullscreenColumnWindow(-530.0f, 0.0f, "game_list_info", UIPrimaryDarkColor))
|
||||
{
|
||||
const HostDisplayTexture* cover_texture =
|
||||
const GPUTexture* cover_texture =
|
||||
selected_entry ? GetGameListCover(selected_entry) : GetTextureForGameListEntryType(GameList::EntryType::Count);
|
||||
if (cover_texture)
|
||||
{
|
||||
@ -4632,8 +4628,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
static_cast<float>(cover_texture->GetHeight()))));
|
||||
|
||||
ImGui::SetCursorPos(LayoutScale(ImVec2(90.0f, 50.0f)) + image_rect.Min);
|
||||
ImGui::Image(selected_entry ? GetGameListCover(selected_entry)->GetHandle() :
|
||||
GetTextureForGameListEntryType(GameList::EntryType::Count)->GetHandle(),
|
||||
ImGui::Image(selected_entry ? GetGameListCover(selected_entry) :
|
||||
GetTextureForGameListEntryType(GameList::EntryType::Count),
|
||||
image_rect.GetSize());
|
||||
}
|
||||
|
||||
@ -4683,7 +4679,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
fmt::format("fullscreenui/{}.png", Settings::GetDiscRegionName(selected_entry->region)));
|
||||
ImGui::TextUnformatted("Region: ");
|
||||
ImGui::SameLine();
|
||||
ImGui::Image(GetCachedTextureAsync(flag_texture.c_str())->GetHandle(), LayoutScale(23.0f, 16.0f));
|
||||
ImGui::Image(GetCachedTextureAsync(flag_texture.c_str()), LayoutScale(23.0f, 16.0f));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(" (%s)", Settings::GetDiscRegionDisplayName(selected_entry->region));
|
||||
}
|
||||
@ -4701,7 +4697,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
ImGui::SameLine();
|
||||
if (selected_entry->compatibility != GameDatabase::CompatibilityRating::Unknown)
|
||||
{
|
||||
ImGui::Image(s_game_compatibility_textures[static_cast<u32>(selected_entry->compatibility)]->GetHandle(),
|
||||
ImGui::Image(s_game_compatibility_textures[static_cast<u32>(selected_entry->compatibility)].get(),
|
||||
LayoutScale(64.0f, 16.0f));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
@ -4801,13 +4797,13 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
|
||||
bb.Min += style.FramePadding;
|
||||
bb.Max -= style.FramePadding;
|
||||
|
||||
const HostDisplayTexture* const cover_texture = GetGameListCover(entry);
|
||||
GPUTexture* const cover_texture = GetGameListCover(entry);
|
||||
const ImRect image_rect(
|
||||
CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(cover_texture->GetWidth()),
|
||||
static_cast<float>(cover_texture->GetHeight()))));
|
||||
|
||||
ImGui::GetWindowDrawList()->AddImage(cover_texture->GetHandle(), image_rect.Min, image_rect.Max,
|
||||
ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f),
|
||||
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
|
||||
const std::string_view title(
|
||||
@ -5111,7 +5107,7 @@ void FullscreenUI::SwitchToGameList()
|
||||
QueueResetFocus();
|
||||
}
|
||||
|
||||
HostDisplayTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry)
|
||||
GPUTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry)
|
||||
{
|
||||
// lookup and grab cover image
|
||||
auto cover_it = s_cover_image_map.find(entry->path);
|
||||
@ -5121,11 +5117,11 @@ HostDisplayTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry)
|
||||
cover_it = s_cover_image_map.emplace(entry->path, std::move(cover_path)).first;
|
||||
}
|
||||
|
||||
HostDisplayTexture* tex = (!cover_it->second.empty()) ? GetCachedTextureAsync(cover_it->second.c_str()) : nullptr;
|
||||
GPUTexture* tex = (!cover_it->second.empty()) ? GetCachedTextureAsync(cover_it->second.c_str()) : nullptr;
|
||||
return tex ? tex : GetTextureForGameListEntryType(entry->type);
|
||||
}
|
||||
|
||||
HostDisplayTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type)
|
||||
GPUTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@ -5144,7 +5140,7 @@ HostDisplayTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::Entry
|
||||
}
|
||||
}
|
||||
|
||||
HostDisplayTexture* FullscreenUI::GetCoverForCurrentGame()
|
||||
GPUTexture* FullscreenUI::GetCoverForCurrentGame()
|
||||
{
|
||||
auto lock = GameList::GetLock();
|
||||
|
||||
@ -5360,11 +5356,11 @@ void FullscreenUI::DrawAchievement(const Achievements::Achievement& cheevo)
|
||||
const std::string& badge_path = Achievements::GetAchievementBadgePath(cheevo);
|
||||
if (!badge_path.empty())
|
||||
{
|
||||
HostDisplayTexture* badge = GetCachedTextureAsync(badge_path.c_str());
|
||||
GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str());
|
||||
if (badge)
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f),
|
||||
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
ImGui::GetWindowDrawList()->AddImage(badge, bb.Min, bb.Min + image_size, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
|
||||
IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5463,11 +5459,11 @@ void FullscreenUI::DrawAchievementsWindow()
|
||||
const std::string& icon_path = Achievements::GetGameIcon();
|
||||
if (!icon_path.empty())
|
||||
{
|
||||
HostDisplayTexture* badge = GetCachedTexture(icon_path.c_str());
|
||||
GPUTexture* badge = GetCachedTexture(icon_path.c_str());
|
||||
if (badge)
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), icon_min, icon_max, ImVec2(0.0f, 0.0f),
|
||||
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
|
||||
IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5602,12 +5598,12 @@ void FullscreenUI::DrawPrimedAchievements()
|
||||
if (badge_path.empty())
|
||||
return true;
|
||||
|
||||
HostDisplayTexture* badge = GetCachedTextureAsync(badge_path.c_str());
|
||||
GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str());
|
||||
if (!badge)
|
||||
return true;
|
||||
|
||||
ImDrawList* dl = ImGui::GetBackgroundDrawList();
|
||||
dl->AddImage(badge->GetHandle(), position, position + image_size);
|
||||
dl->AddImage(badge, position, position + image_size);
|
||||
position.x -= x_advance;
|
||||
return true;
|
||||
});
|
||||
@ -5786,11 +5782,11 @@ void FullscreenUI::DrawLeaderboardsWindow()
|
||||
const std::string& icon_path = Achievements::GetGameIcon();
|
||||
if (!icon_path.empty())
|
||||
{
|
||||
HostDisplayTexture* badge = GetCachedTexture(icon_path.c_str());
|
||||
GPUTexture* badge = GetCachedTexture(icon_path.c_str());
|
||||
if (badge)
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddImage(badge->GetHandle(), icon_min, icon_max, ImVec2(0.0f, 0.0f),
|
||||
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
|
||||
IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class HostDisplayTexture;
|
||||
class GPUTexture;
|
||||
|
||||
struct Settings;
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace ImGuiFullscreen {
|
||||
using MessageDialogCallbackVariant = std::variant<InfoMessageDialogCallback, ConfirmMessageDialogCallback>;
|
||||
|
||||
static std::optional<Common::RGBA8Image> LoadTextureImage(const char* path);
|
||||
static std::shared_ptr<HostDisplayTexture> UploadTexture(const char* path, const Common::RGBA8Image& image);
|
||||
static std::shared_ptr<GPUTexture> UploadTexture(const char* path, const Common::RGBA8Image& image);
|
||||
static void TextureLoaderThread();
|
||||
|
||||
static void DrawFileSelector();
|
||||
@ -78,8 +78,8 @@ static u32 s_menu_button_index = 0;
|
||||
static u32 s_close_button_state = 0;
|
||||
static bool s_focus_reset_queued = false;
|
||||
|
||||
static LRUCache<std::string, std::shared_ptr<HostDisplayTexture>> s_texture_cache(128, true);
|
||||
static std::shared_ptr<HostDisplayTexture> s_placeholder_texture;
|
||||
static LRUCache<std::string, std::shared_ptr<GPUTexture>> s_texture_cache(128, true);
|
||||
static std::shared_ptr<GPUTexture> s_placeholder_texture;
|
||||
static std::atomic_bool s_texture_load_thread_quit{false};
|
||||
static std::mutex s_texture_load_mutex;
|
||||
static std::condition_variable s_texture_load_cv;
|
||||
@ -231,7 +231,7 @@ void ImGuiFullscreen::Shutdown()
|
||||
s_file_selector_items.clear();
|
||||
}
|
||||
|
||||
const std::shared_ptr<HostDisplayTexture>& ImGuiFullscreen::GetPlaceholderTexture()
|
||||
const std::shared_ptr<GPUTexture>& ImGuiFullscreen::GetPlaceholderTexture()
|
||||
{
|
||||
return s_placeholder_texture;
|
||||
}
|
||||
@ -262,10 +262,10 @@ std::optional<Common::RGBA8Image> ImGuiFullscreen::LoadTextureImage(const char*
|
||||
return image;
|
||||
}
|
||||
|
||||
std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image)
|
||||
std::shared_ptr<GPUTexture> ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image)
|
||||
{
|
||||
std::unique_ptr<HostDisplayTexture> texture =
|
||||
g_host_display->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, HostDisplayPixelFormat::RGBA8,
|
||||
std::unique_ptr<GPUTexture> texture =
|
||||
g_host_display->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Format::RGBA8,
|
||||
image.GetPixels(), image.GetPitch());
|
||||
if (!texture)
|
||||
{
|
||||
@ -274,16 +274,16 @@ std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::UploadTexture(const char* p
|
||||
}
|
||||
|
||||
Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight());
|
||||
return std::shared_ptr<HostDisplayTexture>(std::move(texture));
|
||||
return std::shared_ptr<GPUTexture>(std::move(texture));
|
||||
}
|
||||
|
||||
std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::LoadTexture(const std::string_view& path)
|
||||
std::shared_ptr<GPUTexture> ImGuiFullscreen::LoadTexture(const std::string_view& path)
|
||||
{
|
||||
std::string path_str(path);
|
||||
std::optional<Common::RGBA8Image> image(LoadTextureImage(path_str.c_str()));
|
||||
if (image.has_value())
|
||||
{
|
||||
std::shared_ptr<HostDisplayTexture> ret(UploadTexture(path_str.c_str(), image.value()));
|
||||
std::shared_ptr<GPUTexture> ret(UploadTexture(path_str.c_str(), image.value()));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -291,21 +291,21 @@ std::shared_ptr<HostDisplayTexture> ImGuiFullscreen::LoadTexture(const std::stri
|
||||
return s_placeholder_texture;
|
||||
}
|
||||
|
||||
HostDisplayTexture* ImGuiFullscreen::GetCachedTexture(const std::string_view& name)
|
||||
GPUTexture* ImGuiFullscreen::GetCachedTexture(const std::string_view& name)
|
||||
{
|
||||
std::shared_ptr<HostDisplayTexture>* tex_ptr = s_texture_cache.Lookup(name);
|
||||
std::shared_ptr<GPUTexture>* tex_ptr = s_texture_cache.Lookup(name);
|
||||
if (!tex_ptr)
|
||||
{
|
||||
std::shared_ptr<HostDisplayTexture> tex(LoadTexture(name));
|
||||
std::shared_ptr<GPUTexture> tex(LoadTexture(name));
|
||||
tex_ptr = s_texture_cache.Insert(std::string(name), std::move(tex));
|
||||
}
|
||||
|
||||
return tex_ptr->get();
|
||||
}
|
||||
|
||||
HostDisplayTexture* ImGuiFullscreen::GetCachedTextureAsync(const std::string_view& name)
|
||||
GPUTexture* ImGuiFullscreen::GetCachedTextureAsync(const std::string_view& name)
|
||||
{
|
||||
std::shared_ptr<HostDisplayTexture>* tex_ptr = s_texture_cache.Lookup(name);
|
||||
std::shared_ptr<GPUTexture>* tex_ptr = s_texture_cache.Lookup(name);
|
||||
if (!tex_ptr)
|
||||
{
|
||||
// insert the placeholder
|
||||
@ -334,7 +334,7 @@ void ImGuiFullscreen::UploadAsyncTextures()
|
||||
s_texture_upload_queue.pop_front();
|
||||
lock.unlock();
|
||||
|
||||
std::shared_ptr<HostDisplayTexture> tex = UploadTexture(it.first.c_str(), it.second);
|
||||
std::shared_ptr<GPUTexture> tex = UploadTexture(it.first.c_str(), it.second);
|
||||
if (tex)
|
||||
s_texture_cache.Insert(std::move(it.first), std::move(tex));
|
||||
|
||||
@ -2389,9 +2389,9 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
|
||||
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
|
||||
if (!notif.badge_path.empty())
|
||||
{
|
||||
HostDisplayTexture* tex = GetCachedTexture(notif.badge_path.c_str());
|
||||
GPUTexture* tex = GetCachedTexture(notif.badge_path.c_str());
|
||||
if (tex)
|
||||
dl->AddImage(static_cast<ImTextureID>(tex->GetHandle()), badge_min, badge_max);
|
||||
dl->AddImage(tex, badge_min, badge_max);
|
||||
}
|
||||
|
||||
const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class HostDisplayTexture;
|
||||
class GPUTexture;
|
||||
|
||||
namespace ImGuiFullscreen {
|
||||
#define HEX_TO_IMVEC4(hex, alpha) \
|
||||
@ -121,10 +121,10 @@ bool UpdateLayoutScale();
|
||||
void Shutdown();
|
||||
|
||||
/// Texture cache.
|
||||
const std::shared_ptr<HostDisplayTexture>& GetPlaceholderTexture();
|
||||
std::shared_ptr<HostDisplayTexture> LoadTexture(const std::string_view& path);
|
||||
HostDisplayTexture* GetCachedTexture(const std::string_view& name);
|
||||
HostDisplayTexture* GetCachedTextureAsync(const std::string_view& name);
|
||||
const std::shared_ptr<GPUTexture>& GetPlaceholderTexture();
|
||||
std::shared_ptr<GPUTexture> LoadTexture(const std::string_view& path);
|
||||
GPUTexture* GetCachedTexture(const std::string_view& name);
|
||||
GPUTexture* GetCachedTextureAsync(const std::string_view& name);
|
||||
bool InvalidateCachedTexture(const std::string& path);
|
||||
void UploadAsyncTextures();
|
||||
|
||||
|
@ -251,7 +251,7 @@ bool ImGui_ImplDX11_CreateFontsTexture()
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
const u32 stride = sizeof(u32) * width;
|
||||
if (!bd->FontTexture.Create(bd->pd3dDevice, width, height, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_BIND_SHADER_RESOURCE, pixels, stride))
|
||||
if (!bd->FontTexture.Create(bd->pd3dDevice, width, height, 1, 1, 1, GPUTexture::Format::RGBA8, D3D11_BIND_SHADER_RESOURCE, pixels, stride))
|
||||
return false;
|
||||
|
||||
// Store our identifier
|
||||
|
@ -266,7 +266,7 @@ bool ImGui_ImplDX12_CreateFontsTexture()
|
||||
// Upload texture to graphics system
|
||||
if (bd->FontTexture.GetWidth() != static_cast<u32>(width) || bd->FontTexture.GetHeight() != static_cast<u32>(height))
|
||||
{
|
||||
if (!bd->FontTexture.Create(width, height, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
if (!bd->FontTexture.Create(width, height, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
|
||||
D3D12_RESOURCE_FLAG_NONE))
|
||||
{
|
||||
|
@ -110,20 +110,20 @@
|
||||
// OpenGL Data
|
||||
struct ImGui_ImplOpenGL3_Data
|
||||
{
|
||||
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||
GLuint GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
char GlslVersionString[32] = {}; // Specified by user or detected based on compile time GL settings.
|
||||
GL::Texture FontTexture;
|
||||
GLuint ShaderHandle;
|
||||
GLint AttribLocationTex; // Uniforms location
|
||||
GLint AttribLocationProjMtx;
|
||||
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||
GLuint AttribLocationVtxUV;
|
||||
GLuint AttribLocationVtxColor;
|
||||
unsigned int VboHandle, ElementsHandle, VaoHandle;
|
||||
GLsizeiptr VertexBufferSize;
|
||||
GLsizeiptr IndexBufferSize;
|
||||
GLuint ShaderHandle = 0;
|
||||
GLint AttribLocationTex = 0; // Uniforms location
|
||||
GLint AttribLocationProjMtx = 0;
|
||||
GLuint AttribLocationVtxPos = 0; // Vertex attributes location
|
||||
GLuint AttribLocationVtxUV = 0;
|
||||
GLuint AttribLocationVtxColor = 0;
|
||||
unsigned int VboHandle = 0, ElementsHandle = 0, VaoHandle = 0;
|
||||
GLsizeiptr VertexBufferSize = 0;
|
||||
GLsizeiptr IndexBufferSize = 0;
|
||||
|
||||
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
ImGui_ImplOpenGL3_Data() = default;
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
@ -316,7 +316,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
bd->FontTexture.Create(width, height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
bd->FontTexture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, pixels);
|
||||
bd->FontTexture.SetLinearFilter(true);
|
||||
|
||||
// Store our identifier
|
||||
@ -326,7 +326,6 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->FontTexture.IsValid())
|
||||
bd->FontTexture.Destroy();
|
||||
|
@ -409,7 +409,7 @@ struct ListEntry
|
||||
std::string game_code;
|
||||
std::string title;
|
||||
std::string formatted_timestamp;
|
||||
std::unique_ptr<HostDisplayTexture> preview_texture;
|
||||
std::unique_ptr<GPUTexture> preview_texture;
|
||||
s32 slot;
|
||||
bool global;
|
||||
};
|
||||
@ -564,13 +564,13 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn
|
||||
if (ssi && !ssi->screenshot_data.empty())
|
||||
{
|
||||
li->preview_texture = g_host_display->CreateTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1,
|
||||
HostDisplayPixelFormat::RGBA8, ssi->screenshot_data.data(),
|
||||
GPUTexture::Format::RGBA8, ssi->screenshot_data.data(),
|
||||
sizeof(u32) * ssi->screenshot_width, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1,
|
||||
HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA,
|
||||
GPUTexture::Format::RGBA8, PLACEHOLDER_ICON_DATA,
|
||||
sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
|
||||
}
|
||||
|
||||
@ -591,7 +591,7 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, std::str
|
||||
if (g_host_display)
|
||||
{
|
||||
li->preview_texture = g_host_display->CreateTexture(PLACEHOLDER_ICON_WIDTH, PLACEHOLDER_ICON_HEIGHT, 1, 1, 1,
|
||||
HostDisplayPixelFormat::RGBA8, PLACEHOLDER_ICON_DATA,
|
||||
GPUTexture::Format::RGBA8, PLACEHOLDER_ICON_DATA,
|
||||
sizeof(u32) * PLACEHOLDER_ICON_WIDTH, false);
|
||||
if (!li->preview_texture)
|
||||
Log_ErrorPrintf("Failed to upload save state image to GPU");
|
||||
@ -645,7 +645,7 @@ void SaveStateSelectorUI::Draw()
|
||||
{
|
||||
ImGui::SetCursorPosY(y_start + padding);
|
||||
ImGui::SetCursorPosX(padding);
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(entry.preview_texture->GetHandle()), image_size);
|
||||
ImGui::Image(entry.preview_texture.get(), image_size);
|
||||
}
|
||||
|
||||
ImGui::SetCursorPosY(y_start + padding);
|
||||
|
@ -16,36 +16,6 @@ enum : u32
|
||||
TEXTURE_STREAM_BUFFER_SIZE = 16 * 1024 * 1024,
|
||||
};
|
||||
|
||||
class OpenGLHostDisplayTexture final : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplayTexture(GL::Texture texture, HostDisplayPixelFormat format)
|
||||
: m_texture(std::move(texture)), m_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
~OpenGLHostDisplayTexture() = default;
|
||||
|
||||
void* GetHandle() const override { return const_cast<GL::Texture*>(&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; }
|
||||
GLuint GetGLID() const { return m_texture.GetGLId(); }
|
||||
|
||||
bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
|
||||
void EndUpdate(u32 x, u32 y, u32 width, u32 height) override;
|
||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override;
|
||||
|
||||
private:
|
||||
GL::Texture m_texture;
|
||||
HostDisplayPixelFormat m_format;
|
||||
u32 m_map_offset = 0;
|
||||
};
|
||||
|
||||
OpenGLHostDisplay::OpenGLHostDisplay() = default;
|
||||
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay()
|
||||
@ -74,54 +44,134 @@ void* OpenGLHostDisplay::GetRenderContext() const
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
static const std::tuple<GLenum, GLenum, GLenum>& GetPixelFormatMapping(bool is_gles, HostDisplayPixelFormat format)
|
||||
std::unique_ptr<GPUTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data,
|
||||
u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(HostDisplayPixelFormat::Count)>
|
||||
mapping = {{
|
||||
{}, // Unknown
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
|
||||
{GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8
|
||||
{GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565
|
||||
{GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV} // RGBA5551
|
||||
}};
|
||||
std::unique_ptr<GL::Texture> tex(std::make_unique<GL::Texture>());
|
||||
if (!tex->Create(width, height, layers, levels, samples, format, data, data_stride))
|
||||
tex.reset();
|
||||
|
||||
static constexpr std::array<std::tuple<GLenum, GLenum, GLenum>, static_cast<u32>(HostDisplayPixelFormat::Count)>
|
||||
mapping_gles2 = {{
|
||||
{}, // Unknown
|
||||
{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
|
||||
{}, // BGRA8
|
||||
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565
|
||||
{} // RGBA5551
|
||||
}};
|
||||
return tex;
|
||||
}
|
||||
|
||||
if (is_gles && !GLAD_GL_ES_VERSION_3_0)
|
||||
return mapping_gles2[static_cast<u32>(format)];
|
||||
bool OpenGLHostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer,
|
||||
u32* out_pitch)
|
||||
{
|
||||
const u32 pixel_size = texture->GetPixelSize();
|
||||
const u32 stride = Common::AlignUpPow2(width * pixel_size, 4);
|
||||
const u32 size_required = stride * height;
|
||||
GL::StreamBuffer* buffer = UsePBOForUploads() ? GetTextureStreamBuffer() : nullptr;
|
||||
|
||||
if (buffer && size_required < buffer->GetSize())
|
||||
{
|
||||
auto map = buffer->Map(4096, size_required);
|
||||
m_texture_stream_buffer_offset = map.buffer_offset;
|
||||
*out_buffer = map.pointer;
|
||||
*out_pitch = stride;
|
||||
}
|
||||
else
|
||||
return mapping[static_cast<u32>(format)];
|
||||
{
|
||||
std::vector<u8>& repack_buffer = GetTextureRepackBuffer();
|
||||
if (repack_buffer.size() < size_required)
|
||||
repack_buffer.resize(size_required);
|
||||
|
||||
*out_buffer = repack_buffer.data();
|
||||
*out_pitch = stride;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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 */)
|
||||
void OpenGLHostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
if (layers != 1 || levels != 1)
|
||||
return {};
|
||||
const u32 pixel_size = texture->GetPixelSize();
|
||||
const u32 stride = Common::AlignUpPow2(width * pixel_size, 4);
|
||||
const u32 size_required = stride * height;
|
||||
GL::Texture* gl_texture = static_cast<GL::Texture*>(texture);
|
||||
GL::StreamBuffer* buffer = UsePBOForUploads() ? GetTextureStreamBuffer() : nullptr;
|
||||
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), format);
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(gl_texture->GetFormat());
|
||||
const bool whole_texture = (!gl_texture->UseTextureStorage() && x == 0 && y == 0 && width == gl_texture->GetWidth() &&
|
||||
height == gl_texture->GetHeight());
|
||||
|
||||
// TODO: Set pack width
|
||||
Assert(!data || data_stride == (width * sizeof(u32)));
|
||||
gl_texture->Bind();
|
||||
if (buffer && size_required < buffer->GetSize())
|
||||
{
|
||||
buffer->Unmap(size_required);
|
||||
buffer->Bind();
|
||||
|
||||
GL::Texture tex;
|
||||
if (!tex.Create(width, height, layers, levels, samples, gl_internal_format, gl_format, gl_type, data, data_stride))
|
||||
return {};
|
||||
if (whole_texture)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture_stream_buffer_offset)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture_stream_buffer_offset)));
|
||||
}
|
||||
|
||||
return std::make_unique<OpenGLHostDisplayTexture>(std::move(tex), format);
|
||||
buffer->Unbind();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<u8>& repack_buffer = GetTextureRepackBuffer();
|
||||
if (whole_texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data());
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data());
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
bool OpenGLHostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||
u32 pitch)
|
||||
{
|
||||
GL::Texture* gl_texture = static_cast<GL::Texture*>(texture);
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(gl_texture->GetFormat());
|
||||
const u32 pixel_size = gl_texture->GetPixelSize();
|
||||
const bool is_packed_tightly = (pitch == (pixel_size * width));
|
||||
|
||||
const bool whole_texture = (!gl_texture->UseTextureStorage() && x == 0 && y == 0 && width == gl_texture->GetWidth() &&
|
||||
height == gl_texture->GetHeight());
|
||||
gl_texture->Bind();
|
||||
|
||||
// If we have GLES3, we can set row_length.
|
||||
if (UseGLES3DrawPath() || is_packed_tightly)
|
||||
{
|
||||
if (!is_packed_tightly)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / pixel_size);
|
||||
|
||||
if (whole_texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data);
|
||||
|
||||
if (!is_packed_tightly)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, we need to repack the image.
|
||||
std::vector<u8>& repack_buffer = GetTextureRepackBuffer();
|
||||
const u32 packed_pitch = width * pixel_size;
|
||||
const u32 repack_size = packed_pitch * height;
|
||||
if (repack_buffer.size() < repack_size)
|
||||
repack_buffer.resize(repack_size);
|
||||
|
||||
StringUtil::StrideMemCpy(repack_buffer.data(), packed_pitch, data, pitch, packed_pitch, height);
|
||||
|
||||
if (whole_texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data());
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
GLint alignment;
|
||||
if (out_data_stride & 1)
|
||||
@ -137,14 +187,13 @@ bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
|
||||
if (!m_use_gles2_draw_path)
|
||||
{
|
||||
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / GetDisplayPixelFormatSize(texture_format));
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / texture->GetPixelSize());
|
||||
}
|
||||
|
||||
const GL::Texture* texture = static_cast<const GL::Texture*>(texture_handle);
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), texture_format);
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(texture->GetFormat());
|
||||
|
||||
GL::Texture::GetTextureSubImage(texture->GetGLId(), 0, x, y, 0, width, height, 1, gl_format, gl_type,
|
||||
height * out_data_stride, out_data);
|
||||
GL::Texture::GetTextureSubImage(static_cast<const GL::Texture*>(texture)->GetGLId(), 0, x, y, 0, width, height, 1,
|
||||
gl_format, gl_type, height * out_data_stride, out_data);
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, old_alignment);
|
||||
if (!m_use_gles2_draw_path)
|
||||
@ -152,9 +201,9 @@ bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||
bool OpenGLHostDisplay::SupportsTextureFormat(GPUTexture::Format format) const
|
||||
{
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), format);
|
||||
const auto [gl_internal_format, gl_format, gl_type] = GL::Texture::GetPixelFormatMapping(format);
|
||||
return (gl_internal_format != static_cast<GLenum>(0));
|
||||
}
|
||||
|
||||
@ -594,11 +643,10 @@ bool OpenGLHostDisplay::Render(bool skip_present)
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format)
|
||||
GPUTexture::Format* out_format)
|
||||
{
|
||||
GL::Texture texture;
|
||||
if (!texture.Create(width, height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr) ||
|
||||
!texture.CreateFramebuffer())
|
||||
if (!texture.Create(width, height, 1, 1, 1, GPUTexture::Format::RGBA8, nullptr, 0) || !texture.CreateFramebuffer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -615,22 +663,21 @@ bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(texture.GetGLFramebufferID(), left, height - top - draw_height, draw_width, draw_height,
|
||||
m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, width, height);
|
||||
static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderDisplay(left, height - top - draw_height, draw_width, draw_height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
IsUsingLinearFiltering());
|
||||
RenderDisplay(left, height - top - draw_height, draw_width, draw_height,
|
||||
static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
out_pixels->resize(width * height);
|
||||
*out_stride = sizeof(u32) * width;
|
||||
*out_format = HostDisplayPixelFormat::RGBA8;
|
||||
*out_format = GPUTexture::Format::RGBA8;
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, out_pixels->data());
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
@ -653,16 +700,16 @@ void OpenGLHostDisplay::RenderDisplay()
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
||||
ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height,
|
||||
static_cast<GL::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
GetWindowWidth(), GetWindowHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
RenderDisplay(left, GetWindowHeight() - top - height, width, height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(left, GetWindowHeight() - top - height, width, height, static_cast<GL::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_width, s32 tex_view_height,
|
||||
@ -689,12 +736,10 @@ static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_w
|
||||
glDisableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle,
|
||||
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, GL::Texture* texture,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
const GL::Texture* texture = static_cast<const GL::Texture*>(texture_handle);
|
||||
|
||||
glViewport(left, bottom, width, height);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
@ -711,10 +756,11 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
|
||||
const float size_adjust = linear ? 1.0f : 0.0f;
|
||||
const float flip_adjust = (texture_view_height < 0) ? -1.0f : 1.0f;
|
||||
m_display_program.Uniform4f(
|
||||
0, (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_y) + (position_adjust * flip_adjust)) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_height) - (size_adjust * flip_adjust)) / static_cast<float>(texture_height));
|
||||
0, (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_y) + (position_adjust * flip_adjust)) / static_cast<float>(texture->GetHeight()),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_height) - (size_adjust * flip_adjust)) /
|
||||
static_cast<float>(texture->GetHeight()));
|
||||
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
|
||||
glBindVertexArray(m_display_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
@ -725,7 +771,7 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
|
||||
texture->SetLinearFilter(linear_filter);
|
||||
|
||||
DrawFullscreenQuadES2(m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, m_display_texture_width, m_display_texture_height);
|
||||
m_display_texture_view_height, texture->GetWidth(), texture->GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@ -738,8 +784,7 @@ void OpenGLHostDisplay::RenderSoftwareCursor()
|
||||
RenderSoftwareCursor(left, GetWindowHeight() - top - height, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle)
|
||||
void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle)
|
||||
{
|
||||
glViewport(left, bottom, width, height);
|
||||
glEnable(GL_BLEND);
|
||||
@ -749,7 +794,7 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
m_cursor_program.Bind();
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetGLID());
|
||||
static_cast<GL::Texture*>(texture_handle)->Bind();
|
||||
|
||||
if (!m_use_gles2_draw_path)
|
||||
{
|
||||
@ -761,8 +806,8 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3
|
||||
}
|
||||
else
|
||||
{
|
||||
const s32 tex_width = static_cast<s32>(static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetWidth());
|
||||
const s32 tex_height = static_cast<s32>(static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetHeight());
|
||||
const s32 tex_width = static_cast<s32>(texture_handle->GetWidth());
|
||||
const s32 tex_height = static_cast<s32>(texture_handle->GetHeight());
|
||||
DrawFullscreenQuadES2(0, 0, tex_width, tex_height, tex_width, tex_height);
|
||||
}
|
||||
}
|
||||
@ -842,8 +887,7 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
|
||||
if (m_post_processing_input_texture.GetWidth() != target_width ||
|
||||
m_post_processing_input_texture.GetHeight() != target_height)
|
||||
{
|
||||
if (!m_post_processing_input_texture.Create(target_width, target_height, 1, 1, 1, GL_RGBA8, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE) ||
|
||||
if (!m_post_processing_input_texture.Create(target_width, target_height, 1, 1, 1, GPUTexture::Format::RGBA8) ||
|
||||
!m_post_processing_input_texture.CreateFramebuffer())
|
||||
{
|
||||
return false;
|
||||
@ -856,7 +900,7 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
|
||||
PostProcessingStage& pps = m_post_processing_stages[i];
|
||||
if (pps.output_texture.GetWidth() != target_width || pps.output_texture.GetHeight() != target_height)
|
||||
{
|
||||
if (!pps.output_texture.Create(target_width, target_height, 1, 1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE) ||
|
||||
if (!pps.output_texture.Create(target_width, target_height, 1, 1, 1, GPUTexture::Format::RGBA8) ||
|
||||
!pps.output_texture.CreateFramebuffer())
|
||||
{
|
||||
return false;
|
||||
@ -868,29 +912,24 @@ bool OpenGLHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_left, s32 final_top, s32 final_width,
|
||||
s32 final_height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, u32 target_width,
|
||||
u32 target_height)
|
||||
s32 final_height, GL::Texture* texture, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height)
|
||||
{
|
||||
if (!CheckPostProcessingRenderTargets(target_width, target_height))
|
||||
{
|
||||
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle,
|
||||
texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width,
|
||||
texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
return;
|
||||
}
|
||||
|
||||
// downsample/upsample - use same viewport for remainder
|
||||
m_post_processing_input_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle,
|
||||
texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height,
|
||||
IsUsingLinearFiltering());
|
||||
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
|
||||
texture_handle = &m_post_processing_input_texture;
|
||||
texture_width = m_post_processing_input_texture.GetWidth();
|
||||
texture_height = m_post_processing_input_texture.GetHeight();
|
||||
texture = &m_post_processing_input_texture;
|
||||
texture_view_x = final_left;
|
||||
texture_view_y = final_top;
|
||||
texture_view_width = final_width;
|
||||
@ -914,12 +953,12 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_
|
||||
|
||||
pps.program.Bind();
|
||||
|
||||
static_cast<const GL::Texture*>(texture_handle)->Bind();
|
||||
static_cast<const GL::Texture*>(texture)->Bind();
|
||||
glBindSampler(0, m_display_nearest_sampler);
|
||||
|
||||
const auto map_result = m_post_processing_ubo->Map(m_uniform_buffer_alignment, pps.uniforms_size);
|
||||
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
|
||||
map_result.pointer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width,
|
||||
map_result.pointer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width,
|
||||
texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
|
||||
m_post_processing_ubo->Unmap(pps.uniforms_size);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_post_processing_ubo->GetGLBufferId(), map_result.buffer_offset,
|
||||
@ -928,7 +967,7 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
if (i != final_stage)
|
||||
texture_handle = &pps.output_texture;
|
||||
texture = &pps.output_texture;
|
||||
}
|
||||
|
||||
glBindSampler(0, 0);
|
||||
@ -955,7 +994,7 @@ void OpenGLHostDisplay::DestroyTimestampQueries()
|
||||
if (m_timestamp_query_started)
|
||||
{
|
||||
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
|
||||
EndQuery(m_timestamp_queries[m_write_timestamp_query]);
|
||||
EndQuery(GL_TIME_ELAPSED);
|
||||
}
|
||||
|
||||
DeleteQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
|
||||
@ -1062,121 +1101,3 @@ GL::StreamBuffer* OpenGLHostDisplay::GetTextureStreamBuffer()
|
||||
m_texture_stream_buffer = GL::StreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, TEXTURE_STREAM_BUFFER_SIZE);
|
||||
return m_texture_stream_buffer.get();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplayTexture::BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch)
|
||||
{
|
||||
const u32 pixel_size = HostDisplay::GetDisplayPixelFormatSize(m_format);
|
||||
const u32 stride = Common::AlignUpPow2(width * pixel_size, 4);
|
||||
const u32 size_required = stride * height;
|
||||
OpenGLHostDisplay* display = static_cast<OpenGLHostDisplay*>(g_host_display.get());
|
||||
GL::StreamBuffer* buffer = display->UsePBOForUploads() ? display->GetTextureStreamBuffer() : nullptr;
|
||||
|
||||
if (buffer && size_required < buffer->GetSize())
|
||||
{
|
||||
auto map = buffer->Map(4096, size_required);
|
||||
m_map_offset = map.buffer_offset;
|
||||
*out_buffer = map.pointer;
|
||||
*out_pitch = stride;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<u8>& repack_buffer = display->GetTextureRepackBuffer();
|
||||
if (repack_buffer.size() < size_required)
|
||||
repack_buffer.resize(size_required);
|
||||
|
||||
*out_buffer = repack_buffer.data();
|
||||
*out_pitch = stride;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplayTexture::EndUpdate(u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
const u32 pixel_size = HostDisplay::GetDisplayPixelFormatSize(m_format);
|
||||
const u32 stride = Common::AlignUpPow2(width * pixel_size, 4);
|
||||
const u32 size_required = stride * height;
|
||||
OpenGLHostDisplay* display = static_cast<OpenGLHostDisplay*>(g_host_display.get());
|
||||
GL::StreamBuffer* buffer = display->UsePBOForUploads() ? display->GetTextureStreamBuffer() : nullptr;
|
||||
|
||||
const auto [gl_internal_format, gl_format, gl_type] =
|
||||
GetPixelFormatMapping(display->GetGLContext()->IsGLES(), m_format);
|
||||
const bool whole_texture = (!m_texture.UseTextureStorage() && x == 0 && y == 0 && width == m_texture.GetWidth() &&
|
||||
height == m_texture.GetHeight());
|
||||
|
||||
m_texture.Create(width, height, 1, 1, 1, gl_internal_format, gl_format, gl_type, nullptr, false, false);
|
||||
m_texture.Bind();
|
||||
if (buffer && size_required < buffer->GetSize())
|
||||
{
|
||||
buffer->Unmap(size_required);
|
||||
buffer->Bind();
|
||||
|
||||
if (whole_texture)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(m_map_offset)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(m_map_offset)));
|
||||
}
|
||||
|
||||
buffer->Unbind();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<u8>& repack_buffer = display->GetTextureRepackBuffer();
|
||||
|
||||
if (whole_texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data());
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data());
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplayTexture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
|
||||
{
|
||||
OpenGLHostDisplay* display = static_cast<OpenGLHostDisplay*>(g_host_display.get());
|
||||
const auto [gl_internal_format, gl_format, gl_type] =
|
||||
GetPixelFormatMapping(display->GetGLContext()->IsGLES(), m_format);
|
||||
const u32 pixel_size = HostDisplay::GetDisplayPixelFormatSize(m_format);
|
||||
const bool is_packed_tightly = (pitch == (pixel_size * width));
|
||||
|
||||
const bool whole_texture = (!m_texture.UseTextureStorage() && x == 0 && y == 0 && width == m_texture.GetWidth() &&
|
||||
height == m_texture.GetHeight());
|
||||
m_texture.Bind();
|
||||
|
||||
// If we have GLES3, we can set row_length.
|
||||
if (!display->UseGLES3DrawPath() || is_packed_tightly)
|
||||
{
|
||||
if (!is_packed_tightly)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / pixel_size);
|
||||
|
||||
if (whole_texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data);
|
||||
|
||||
if (!is_packed_tightly)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, we need to repack the image.
|
||||
std::vector<u8>& repack_buffer = display->GetTextureRepackBuffer();
|
||||
const u32 packed_pitch = width * pixel_size;
|
||||
const u32 repack_size = packed_pitch * height;
|
||||
if (repack_buffer.size() < repack_size)
|
||||
repack_buffer.resize(repack_size);
|
||||
|
||||
StringUtil::StrideMemCpy(repack_buffer.data(), packed_pitch, data, pitch, packed_pitch, height);
|
||||
|
||||
if (whole_texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, repack_buffer.data());
|
||||
else
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, repack_buffer.data());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -40,18 +40,21 @@ public:
|
||||
|
||||
bool SetPostProcessingChain(const std::string_view& config) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||
u32 height, void* out_data, u32 out_data_stride) override;
|
||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
|
||||
void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
|
||||
bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override;
|
||||
bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
GPUTexture::Format* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
@ -80,10 +83,9 @@ protected:
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, GL::Texture* texture, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle);
|
||||
|
||||
struct PostProcessingStage
|
||||
{
|
||||
@ -94,9 +96,8 @@ protected:
|
||||
|
||||
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
|
||||
void ApplyPostProcessingChain(GLuint final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
|
||||
void* texture_handle, u32 texture_width, s32 texture_height, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, u32 target_width,
|
||||
u32 target_height);
|
||||
GL::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, u32 target_width, u32 target_height);
|
||||
|
||||
void CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
@ -114,6 +115,7 @@ protected:
|
||||
|
||||
std::unique_ptr<GL::StreamBuffer> m_texture_stream_buffer;
|
||||
std::vector<u8> m_texture_repack_buffer;
|
||||
u32 m_texture_stream_buffer_offset = 0;
|
||||
|
||||
FrontendCommon::PostProcessingChain m_post_processing_chain;
|
||||
GL::Texture m_post_processing_input_texture;
|
||||
|
@ -18,43 +18,6 @@
|
||||
#include <array>
|
||||
Log_SetChannel(VulkanHostDisplay);
|
||||
|
||||
class VulkanHostDisplayTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
VulkanHostDisplayTexture(Vulkan::Texture texture, HostDisplayPixelFormat format)
|
||||
: m_texture(std::move(texture)), m_format(format)
|
||||
{
|
||||
}
|
||||
~VulkanHostDisplayTexture() override = default;
|
||||
|
||||
void* GetHandle() const override { return const_cast<Vulkan::Texture*>(&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; }
|
||||
|
||||
bool BeginUpdate(u32 width, u32 height, void** out_buffer, u32* out_pitch) override
|
||||
{
|
||||
return m_texture.BeginUpdate(width, height, out_buffer, out_pitch);
|
||||
}
|
||||
|
||||
void EndUpdate(u32 x, u32 y, u32 width, u32 height) override { m_texture.EndUpdate(x, y, width, height, 0, 0); }
|
||||
|
||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override
|
||||
{
|
||||
return m_texture.Update(x, y, width, height, 0, 0, data, pitch);
|
||||
}
|
||||
|
||||
const Vulkan::Texture& GetTexture() const { return m_texture; }
|
||||
Vulkan::Texture& GetTexture() { return m_texture; }
|
||||
|
||||
private:
|
||||
Vulkan::Texture m_texture;
|
||||
HostDisplayPixelFormat m_format;
|
||||
};
|
||||
|
||||
VulkanHostDisplay::VulkanHostDisplay() = default;
|
||||
|
||||
VulkanHostDisplay::~VulkanHostDisplay()
|
||||
@ -172,56 +135,65 @@ void VulkanHostDisplay::DestroyRenderSurface()
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
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}};
|
||||
|
||||
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 */)
|
||||
std::unique_ptr<GPUTexture> VulkanHostDisplay::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data,
|
||||
u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
const VkFormat vk_format = s_display_pixel_format_mapping[static_cast<u32>(format)];
|
||||
const VkFormat vk_format = Vulkan::Texture::GetVkFormat(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;
|
||||
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"VulkanHostDisplay::CreateTexture");
|
||||
|
||||
Vulkan::Texture texture;
|
||||
if (!texture.Create(width, height, levels, layers, vk_format, static_cast<VkSampleCountFlagBits>(samples),
|
||||
(layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
|
||||
usage))
|
||||
std::unique_ptr<Vulkan::Texture> texture(std::make_unique<Vulkan::Texture>());
|
||||
if (!texture->Create(width, height, levels, layers, vk_format, static_cast<VkSampleCountFlagBits>(samples),
|
||||
(layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
|
||||
usage))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
texture->TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
if (data)
|
||||
{
|
||||
texture.Update(0, 0, width, height, 0, 0, data, data_stride);
|
||||
texture->Update(0, 0, width, height, 0, 0, data, data_stride);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
texture->TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
return std::make_unique<VulkanHostDisplayTexture>(std::move(texture), format);
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||
bool VulkanHostDisplay::BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer,
|
||||
u32* out_pitch)
|
||||
{
|
||||
const VkFormat vk_format = s_display_pixel_format_mapping[static_cast<u32>(format)];
|
||||
return static_cast<Vulkan::Texture*>(texture)->BeginUpdate(width, height, out_buffer, out_pitch);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
static_cast<Vulkan::Texture*>(texture)->EndUpdate(x, y, width, height, 0, 0);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||
u32 pitch)
|
||||
{
|
||||
return static_cast<Vulkan::Texture*>(texture)->Update(x, y, width, height, 0, 0, data, pitch);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::SupportsTextureFormat(GPUTexture::Format format) const
|
||||
{
|
||||
const VkFormat vk_format = Vulkan::Texture::GetVkFormat(format);
|
||||
if (vk_format == VK_FORMAT_UNDEFINED)
|
||||
return false;
|
||||
|
||||
@ -310,12 +282,12 @@ void VulkanHostDisplay::DestroyStagingBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y,
|
||||
u32 width, u32 height, void* out_data, u32 out_data_stride)
|
||||
bool VulkanHostDisplay::DownloadTexture(GPUTexture* texture, u32 x, u32 y, 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* tex = static_cast<Vulkan::Texture*>(texture);
|
||||
|
||||
const u32 pitch = texture->CalcUpdatePitch(width);
|
||||
const u32 pitch = tex->CalcUpdatePitch(width);
|
||||
const u32 size = pitch * height;
|
||||
const u32 level = 0;
|
||||
if (!CheckStagingBufferSize(size))
|
||||
@ -328,16 +300,16 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
|
||||
const VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "VulkanHostDisplay::DownloadTexture(%u,%u)", width, height);
|
||||
|
||||
VkImageLayout old_layout = texture->GetLayout();
|
||||
VkImageLayout old_layout = tex->GetLayout();
|
||||
if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
texture->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
tex->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
VkBufferImageCopy image_copy = {};
|
||||
const VkImageAspectFlags aspect = Vulkan::Util::IsDepthFormat(static_cast<VkFormat>(texture->GetFormat())) ?
|
||||
const VkImageAspectFlags aspect = Vulkan::Util::IsDepthFormat(static_cast<VkFormat>(tex->GetFormat())) ?
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT :
|
||||
VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_copy.bufferOffset = 0;
|
||||
image_copy.bufferRowLength = texture->CalcUpdateRowLength(pitch);
|
||||
image_copy.bufferRowLength = tex->CalcUpdateRowLength(pitch);
|
||||
image_copy.bufferImageHeight = 0;
|
||||
image_copy.imageSubresource = {aspect, level, 0u, 1u};
|
||||
image_copy.imageOffset = {static_cast<s32>(x), static_cast<s32>(y), 0};
|
||||
@ -349,8 +321,8 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
// do the copy
|
||||
vkCmdCopyImageToBuffer(cmdbuf, texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_readback_staging_buffer,
|
||||
1, &image_copy);
|
||||
vkCmdCopyImageToBuffer(cmdbuf, tex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_readback_staging_buffer, 1,
|
||||
&image_copy);
|
||||
|
||||
// flush gpu cache
|
||||
Vulkan::Util::BufferMemoryBarrier(cmdbuf, m_readback_staging_buffer, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
@ -359,7 +331,7 @@ bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayP
|
||||
|
||||
if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
{
|
||||
texture->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, old_layout);
|
||||
tex->TransitionSubresourcesToLayout(cmdbuf, level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, old_layout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -674,7 +646,7 @@ bool VulkanHostDisplay::Render(bool skip_present)
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format)
|
||||
GPUTexture::Format* out_format)
|
||||
{
|
||||
// in theory we could do this without a swap chain, but postprocessing assumes it for now...
|
||||
if (!m_swap_chain)
|
||||
@ -685,26 +657,26 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
||||
{
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
*out_format = HostDisplayPixelFormat::RGBA8;
|
||||
*out_format = GPUTexture::Format::RGBA8;
|
||||
*out_stride = sizeof(u32) * width;
|
||||
out_pixels->resize(width * height);
|
||||
break;
|
||||
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
*out_format = HostDisplayPixelFormat::BGRA8;
|
||||
*out_format = GPUTexture::Format::BGRA8;
|
||||
*out_stride = sizeof(u32) * width;
|
||||
out_pixels->resize(width * height);
|
||||
break;
|
||||
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
||||
*out_format = HostDisplayPixelFormat::RGBA5551;
|
||||
*out_format = GPUTexture::Format::RGBA5551;
|
||||
*out_stride = sizeof(u16) * width;
|
||||
out_pixels->resize(((width * height) + 1) / 2);
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||
*out_format = HostDisplayPixelFormat::RGB565;
|
||||
*out_format = GPUTexture::Format::RGB565;
|
||||
*out_stride = sizeof(u16) * width;
|
||||
out_pixels->resize(((width * height) + 1) / 2);
|
||||
break;
|
||||
@ -746,22 +718,22 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, width, height);
|
||||
ApplyPostProcessingChain(fb, left, top, draw_width, draw_height, static_cast<Vulkan::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginSwapChainRenderPass(fb, width, height);
|
||||
RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(left, top, draw_width, draw_height, static_cast<Vulkan::Texture*>(m_display_texture),
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
tex.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
DownloadTexture(&tex, *out_format, 0, 0, width, height, out_pixels->data(), *out_stride);
|
||||
DownloadTexture(&tex, 0, 0, width, height, out_pixels->data(), *out_stride);
|
||||
|
||||
// destroying these immediately should be safe since nothing's going to access them, and it's not part of the command
|
||||
// stream
|
||||
@ -800,27 +772,27 @@ void VulkanHostDisplay::RenderDisplay()
|
||||
|
||||
if (!m_post_processing_chain.IsEmpty())
|
||||
{
|
||||
ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
||||
ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height,
|
||||
static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
BeginSwapChainRenderPass(m_swap_chain->GetCurrentFramebuffer(), m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
|
||||
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(left, top, width, height, static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, Vulkan::Texture* texture,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(
|
||||
cmdbuffer, "VulkanHostDisplay::RenderDisplay: {%u,%u} %ux%u | %ux%u | {%u,%u} %ux%u", left, top, width, height,
|
||||
texture_height, texture_width, texture_view_x, texture_view_y, texture_view_width, texture_view_height);
|
||||
texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width, texture_view_height);
|
||||
|
||||
VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_descriptor_set_layout);
|
||||
if (ds == VK_NULL_HANDLE)
|
||||
@ -830,19 +802,19 @@ void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height,
|
||||
}
|
||||
|
||||
{
|
||||
const Vulkan::Texture* vktex = static_cast<Vulkan::Texture*>(texture_handle);
|
||||
Vulkan::DescriptorSetUpdateBuilder dsupdate;
|
||||
dsupdate.AddCombinedImageSamplerDescriptorWrite(
|
||||
ds, 0, vktex->GetView(), linear_filter ? m_linear_sampler : m_point_sampler, vktex->GetLayout());
|
||||
ds, 0, texture->GetView(), linear_filter ? m_linear_sampler : m_point_sampler, texture->GetLayout());
|
||||
dsupdate.Update(g_vulkan_context->GetDevice());
|
||||
}
|
||||
|
||||
const float position_adjust = IsUsingLinearFiltering() ? 0.5f : 0.0f;
|
||||
const float size_adjust = IsUsingLinearFiltering() ? 1.0f : 0.0f;
|
||||
const PushConstants pc{(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture_height)};
|
||||
const PushConstants pc{
|
||||
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
|
||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
|
||||
|
||||
vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_display_pipeline);
|
||||
vkCmdPushConstants(cmdbuffer, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pc), &pc);
|
||||
@ -867,7 +839,7 @@ void VulkanHostDisplay::RenderSoftwareCursor()
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture)
|
||||
void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuffer, "VulkanHostDisplay::RenderSoftwareCursor: {%u,%u} %ux%u", left,
|
||||
@ -882,8 +854,8 @@ void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 h
|
||||
|
||||
{
|
||||
Vulkan::DescriptorSetUpdateBuilder dsupdate;
|
||||
dsupdate.AddCombinedImageSamplerDescriptorWrite(
|
||||
ds, 0, static_cast<VulkanHostDisplayTexture*>(texture)->GetTexture().GetView(), m_linear_sampler);
|
||||
dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 0, static_cast<Vulkan::Texture*>(texture)->GetView(),
|
||||
m_linear_sampler);
|
||||
dsupdate.Update(g_vulkan_context->GetDevice());
|
||||
}
|
||||
|
||||
@ -1118,10 +1090,9 @@ bool VulkanHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top,
|
||||
s32 final_width, s32 final_height, void* texture_handle,
|
||||
u32 texture_width, s32 texture_height, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height)
|
||||
s32 final_width, s32 final_height, Vulkan::Texture* texture,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, u32 target_width, u32 target_height)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope post_scope(cmdbuffer, "VulkanHostDisplay::ApplyPostProcessingChain");
|
||||
@ -1129,23 +1100,21 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
||||
if (!CheckPostProcessingRenderTargets(target_width, target_height))
|
||||
{
|
||||
BeginSwapChainRenderPass(target_fb, target_width, target_height);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
|
||||
texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
return;
|
||||
}
|
||||
|
||||
// downsample/upsample - use same viewport for remainder
|
||||
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
BeginSwapChainRenderPass(m_post_processing_input_framebuffer, target_width, target_height);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
|
||||
texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
texture_handle = &m_post_processing_input_texture;
|
||||
texture_width = m_post_processing_input_texture.GetWidth();
|
||||
texture_height = m_post_processing_input_texture.GetHeight();
|
||||
texture = &m_post_processing_input_texture;
|
||||
texture_view_x = final_left;
|
||||
texture_view_y = final_top;
|
||||
texture_view_width = final_width;
|
||||
@ -1177,17 +1146,16 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
||||
return;
|
||||
}
|
||||
|
||||
const Vulkan::Texture* vktex = static_cast<Vulkan::Texture*>(texture_handle);
|
||||
Vulkan::DescriptorSetUpdateBuilder dsupdate;
|
||||
dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 1, vktex->GetView(), m_point_sampler, vktex->GetLayout());
|
||||
dsupdate.AddCombinedImageSamplerDescriptorWrite(ds, 1, texture->GetView(), m_point_sampler, texture->GetLayout());
|
||||
|
||||
if (use_push_constants)
|
||||
{
|
||||
u8 buffer[FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD];
|
||||
Assert(pps.uniforms_size <= sizeof(buffer));
|
||||
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
|
||||
buffer, texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height,
|
||||
GetWindowWidth(), GetWindowHeight(), 0.0f);
|
||||
buffer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width,
|
||||
texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
|
||||
|
||||
vkCmdPushConstants(cmdbuffer, m_post_process_pipeline_layout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, pps.uniforms_size, buffer);
|
||||
@ -1206,8 +1174,8 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
||||
|
||||
const u32 offset = m_post_processing_ubo.GetCurrentOffset();
|
||||
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
|
||||
m_post_processing_ubo.GetCurrentHostPointer(), texture_width, texture_height, texture_view_x, texture_view_y,
|
||||
texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
|
||||
m_post_processing_ubo.GetCurrentHostPointer(), texture->GetWidth(), texture->GetHeight(), texture_view_x,
|
||||
texture_view_y, texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(), 0.0f);
|
||||
m_post_processing_ubo.CommitMemory(pps.uniforms_size);
|
||||
|
||||
dsupdate.AddBufferDescriptorWrite(ds, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||
@ -1226,7 +1194,7 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
pps.output_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
texture_handle = &pps.output_texture;
|
||||
texture = &pps.output_texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
bool threaded_presentation) override;
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
|
||||
bool threaded_presentation) override;
|
||||
|
||||
|
||||
bool MakeRenderContextCurrent() override;
|
||||
bool DoneRenderContextCurrent() override;
|
||||
|
||||
@ -44,18 +44,21 @@ public:
|
||||
|
||||
bool SetPostProcessingChain(const std::string_view& config) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
|
||||
u32 height, void* out_data, u32 out_data_stride) override;
|
||||
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Format format, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
bool BeginTextureUpdate(GPUTexture* texture, u32 width, u32 height, void** out_buffer, u32* out_pitch) override;
|
||||
void EndTextureUpdate(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height) override;
|
||||
bool UpdateTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) override;
|
||||
bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
GPUTexture::Format* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
@ -85,9 +88,8 @@ protected:
|
||||
|
||||
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
|
||||
void ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top, s32 final_width,
|
||||
s32 final_height, void* texture_handle, u32 texture_width, s32 texture_height,
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height);
|
||||
s32 final_height, Vulkan::Texture* texture, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height);
|
||||
|
||||
VkRenderPass GetRenderPassForDisplay() const;
|
||||
|
||||
@ -106,10 +108,9 @@ protected:
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, Vulkan::Texture* texture, s32 texture_view_x,
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture_handle);
|
||||
|
||||
std::unique_ptr<Vulkan::SwapChain> m_swap_chain;
|
||||
|
||||
|
Reference in New Issue
Block a user