HW cleanup
This commit is contained in:
parent
4c35f3dcd4
commit
df789e8df9
|
@ -814,9 +814,10 @@ std::string GPUDevice::GetShaderDumpPath(const std::string_view& name)
|
||||||
|
|
||||||
std::array<float, 4> GPUDevice::RGBA8ToFloat(u32 rgba)
|
std::array<float, 4> GPUDevice::RGBA8ToFloat(u32 rgba)
|
||||||
{
|
{
|
||||||
return std::array<float, 4>{static_cast<float>(rgba & 0xFF) / 255.0f, static_cast<float>((rgba >> 8) & 0xFF) / 255.0f,
|
return std::array<float, 4>{static_cast<float>(rgba & UINT32_C(0xFF)) * (1.0f / 255.0f),
|
||||||
static_cast<float>((rgba >> 16) & 0xFF) / 255.0f,
|
static_cast<float>((rgba >> 8) & UINT32_C(0xFF)) * (1.0f / 255.0f),
|
||||||
static_cast<float>((rgba >> 24) & 0xFF) / 255.0f};
|
static_cast<float>((rgba >> 16) & UINT32_C(0xFF)) * (1.0f / 255.0f),
|
||||||
|
static_cast<float>(rgba >> 24) * (1.0f / 255.0f)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPUDevice::UpdateImGuiFontTexture()
|
bool GPUDevice::UpdateImGuiFontTexture()
|
||||||
|
|
|
@ -46,6 +46,29 @@ ALWAYS_INLINE static bool ShouldDisableColorPerspective()
|
||||||
return g_settings.gpu_pgxp_enable && g_settings.gpu_pgxp_texture_correction && !g_settings.gpu_pgxp_color_correction;
|
return g_settings.gpu_pgxp_enable && g_settings.gpu_pgxp_texture_correction && !g_settings.gpu_pgxp_color_correction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the specified texture filtering mode requires dual-source blending.
|
||||||
|
static bool TextureFilterRequiresDualSourceBlend(GPUTextureFilter filter)
|
||||||
|
{
|
||||||
|
return (filter == GPUTextureFilter::Bilinear || filter == GPUTextureFilter::JINC2 || filter == GPUTextureFilter::xBR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the area affected by a VRAM transfer, including wrap-around of X.
|
||||||
|
static Common::Rectangle<u32> GetVRAMTransferBounds(u32 x, u32 y, u32 width, u32 height)
|
||||||
|
{
|
||||||
|
Common::Rectangle<u32> out_rc = Common::Rectangle<u32>::FromExtents(x % VRAM_WIDTH, y % VRAM_HEIGHT, width, height);
|
||||||
|
if (out_rc.right > VRAM_WIDTH)
|
||||||
|
{
|
||||||
|
out_rc.left = 0;
|
||||||
|
out_rc.right = VRAM_WIDTH;
|
||||||
|
}
|
||||||
|
if (out_rc.bottom > VRAM_HEIGHT)
|
||||||
|
{
|
||||||
|
out_rc.top = 0;
|
||||||
|
out_rc.bottom = VRAM_HEIGHT;
|
||||||
|
}
|
||||||
|
return out_rc;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class ShaderCompileProgressTracker
|
class ShaderCompileProgressTracker
|
||||||
{
|
{
|
||||||
|
@ -405,6 +428,27 @@ GPUDownsampleMode GPU_HW::GetDownsampleMode(u32 resolution_scale) const
|
||||||
return (resolution_scale == 1) ? GPUDownsampleMode::Disabled : g_settings.gpu_downsample_mode;
|
return (resolution_scale == 1) ? GPUDownsampleMode::Disabled : g_settings.gpu_downsample_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPU_HW::IsUsingMultisampling() const
|
||||||
|
{
|
||||||
|
return m_multisamples > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GPU_HW::IsUsingDownsampling() const
|
||||||
|
{
|
||||||
|
return (m_downsample_mode != GPUDownsampleMode::Disabled && !m_GPUSTAT.display_area_color_depth_24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU_HW::SetFullVRAMDirtyRectangle()
|
||||||
|
{
|
||||||
|
m_vram_dirty_rect.Set(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||||
|
m_draw_mode.SetTexturePageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU_HW::ClearVRAMDirtyRectangle()
|
||||||
|
{
|
||||||
|
m_vram_dirty_rect.SetInvalid();
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<u32, u32> GPU_HW::GetEffectiveDisplayResolution(bool scaled /* = true */)
|
std::tuple<u32, u32> GPU_HW::GetEffectiveDisplayResolution(bool scaled /* = true */)
|
||||||
{
|
{
|
||||||
const u32 scale = scaled ? m_resolution_scale : 1u;
|
const u32 scale = scaled ? m_resolution_scale : 1u;
|
||||||
|
@ -1739,76 +1783,6 @@ void GPU_HW::LoadVertices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_HW::VRAMFillUBOData GPU_HW::GetVRAMFillUBOData(u32 x, u32 y, u32 width, u32 height, u32 color) const
|
|
||||||
{
|
|
||||||
// drop precision unless true colour is enabled
|
|
||||||
if (!m_true_color)
|
|
||||||
color = VRAMRGBA5551ToRGBA8888(VRAMRGBA8888ToRGBA5551(color));
|
|
||||||
|
|
||||||
VRAMFillUBOData uniforms;
|
|
||||||
uniforms.u_dst_x = (x % VRAM_WIDTH) * m_resolution_scale;
|
|
||||||
uniforms.u_dst_y = (y % VRAM_HEIGHT) * m_resolution_scale;
|
|
||||||
uniforms.u_end_x = ((x + width) % VRAM_WIDTH) * m_resolution_scale;
|
|
||||||
uniforms.u_end_y = ((y + height) % VRAM_HEIGHT) * m_resolution_scale;
|
|
||||||
std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) =
|
|
||||||
RGBA8ToFloat(color);
|
|
||||||
|
|
||||||
uniforms.u_interlaced_displayed_field = GetActiveLineLSB();
|
|
||||||
return uniforms;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::Rectangle<u32> GPU_HW::GetVRAMTransferBounds(u32 x, u32 y, u32 width, u32 height) const
|
|
||||||
{
|
|
||||||
Common::Rectangle<u32> out_rc = Common::Rectangle<u32>::FromExtents(x % VRAM_WIDTH, y % VRAM_HEIGHT, width, height);
|
|
||||||
if (out_rc.right > VRAM_WIDTH)
|
|
||||||
{
|
|
||||||
out_rc.left = 0;
|
|
||||||
out_rc.right = VRAM_WIDTH;
|
|
||||||
}
|
|
||||||
if (out_rc.bottom > VRAM_HEIGHT)
|
|
||||||
{
|
|
||||||
out_rc.top = 0;
|
|
||||||
out_rc.bottom = VRAM_HEIGHT;
|
|
||||||
}
|
|
||||||
return out_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPU_HW::VRAMWriteUBOData GPU_HW::GetVRAMWriteUBOData(u32 x, u32 y, u32 width, u32 height, u32 buffer_offset,
|
|
||||||
bool set_mask, bool check_mask) const
|
|
||||||
{
|
|
||||||
const VRAMWriteUBOData uniforms = {
|
|
||||||
(x % VRAM_WIDTH), (y % VRAM_HEIGHT), ((x + width) % VRAM_WIDTH), ((y + height) % VRAM_HEIGHT), width,
|
|
||||||
height, buffer_offset, (set_mask) ? 0x8000u : 0x00, GetCurrentNormalizedVertexDepth()};
|
|
||||||
return uniforms;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GPU_HW::UseVRAMCopyShader(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) const
|
|
||||||
{
|
|
||||||
// masking enabled, oversized, or overlapping
|
|
||||||
return (m_GPUSTAT.IsMaskingEnabled() || ((src_x % VRAM_WIDTH) + width) > VRAM_WIDTH ||
|
|
||||||
((src_y % VRAM_HEIGHT) + height) > VRAM_HEIGHT || ((dst_x % VRAM_WIDTH) + width) > VRAM_WIDTH ||
|
|
||||||
((dst_y % VRAM_HEIGHT) + height) > VRAM_HEIGHT ||
|
|
||||||
Common::Rectangle<u32>::FromExtents(src_x, src_y, width, height)
|
|
||||||
.Intersects(Common::Rectangle<u32>::FromExtents(dst_x, dst_y, width, height)));
|
|
||||||
}
|
|
||||||
|
|
||||||
GPU_HW::VRAMCopyUBOData GPU_HW::GetVRAMCopyUBOData(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width,
|
|
||||||
u32 height) const
|
|
||||||
{
|
|
||||||
const VRAMCopyUBOData uniforms = {(src_x % VRAM_WIDTH) * m_resolution_scale,
|
|
||||||
(src_y % VRAM_HEIGHT) * m_resolution_scale,
|
|
||||||
(dst_x % VRAM_WIDTH) * m_resolution_scale,
|
|
||||||
(dst_y % VRAM_HEIGHT) * m_resolution_scale,
|
|
||||||
((dst_x + width) % VRAM_WIDTH) * m_resolution_scale,
|
|
||||||
((dst_y + height) % VRAM_HEIGHT) * m_resolution_scale,
|
|
||||||
width * m_resolution_scale,
|
|
||||||
height * m_resolution_scale,
|
|
||||||
m_GPUSTAT.set_mask_while_drawing ? 1u : 0u,
|
|
||||||
GetCurrentNormalizedVertexDepth()};
|
|
||||||
|
|
||||||
return uniforms;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GPU_HW::BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u32 dst_x, u32 dst_y, u32 width,
|
bool GPU_HW::BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u32 dst_x, u32 dst_y, u32 width,
|
||||||
u32 height)
|
u32 height)
|
||||||
{
|
{
|
||||||
|
@ -1857,6 +1831,19 @@ void GPU_HW::IncludeVRAMDirtyRectangle(const Common::Rectangle<u32>& rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPU_HW::InterlacedRenderMode GPU_HW::GetInterlacedRenderMode() const
|
||||||
|
{
|
||||||
|
if (IsInterlacedDisplayEnabled())
|
||||||
|
{
|
||||||
|
return m_GPUSTAT.vertical_resolution ? InterlacedRenderMode::InterleavedFields :
|
||||||
|
InterlacedRenderMode::SeparateFields;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return InterlacedRenderMode::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GPU_HW::EnsureVertexBufferSpace(u32 required_vertices)
|
void GPU_HW::EnsureVertexBufferSpace(u32 required_vertices)
|
||||||
{
|
{
|
||||||
if (m_batch_current_vertex_ptr)
|
if (m_batch_current_vertex_ptr)
|
||||||
|
@ -1972,70 +1959,49 @@ void GPU_HW::FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) co
|
||||||
cmd->window = m_draw_mode.texture_window;
|
cmd->window = m_draw_mode.texture_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW::ReadSoftwareRendererVRAM(u32 x, u32 y, u32 width, u32 height)
|
|
||||||
{
|
|
||||||
DebugAssert(m_sw_renderer);
|
|
||||||
m_sw_renderer->Sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_HW::UpdateSoftwareRendererVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask,
|
|
||||||
bool check_mask)
|
|
||||||
{
|
|
||||||
const u32 num_words = width * height;
|
|
||||||
GPUBackendUpdateVRAMCommand* cmd = m_sw_renderer->NewUpdateVRAMCommand(num_words);
|
|
||||||
FillBackendCommandParameters(cmd);
|
|
||||||
cmd->params.set_mask_while_drawing = set_mask;
|
|
||||||
cmd->params.check_mask_before_draw = check_mask;
|
|
||||||
cmd->x = static_cast<u16>(x);
|
|
||||||
cmd->y = static_cast<u16>(y);
|
|
||||||
cmd->width = static_cast<u16>(width);
|
|
||||||
cmd->height = static_cast<u16>(height);
|
|
||||||
std::memcpy(cmd->data, data, sizeof(u16) * num_words);
|
|
||||||
m_sw_renderer->PushCommand(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_HW::FillSoftwareRendererVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
|
||||||
{
|
|
||||||
GPUBackendFillVRAMCommand* cmd = m_sw_renderer->NewFillVRAMCommand();
|
|
||||||
FillBackendCommandParameters(cmd);
|
|
||||||
cmd->x = static_cast<u16>(x);
|
|
||||||
cmd->y = static_cast<u16>(y);
|
|
||||||
cmd->width = static_cast<u16>(width);
|
|
||||||
cmd->height = static_cast<u16>(height);
|
|
||||||
cmd->color = color;
|
|
||||||
m_sw_renderer->PushCommand(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_HW::CopySoftwareRendererVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height)
|
|
||||||
{
|
|
||||||
GPUBackendCopyVRAMCommand* cmd = m_sw_renderer->NewCopyVRAMCommand();
|
|
||||||
FillBackendCommandParameters(cmd);
|
|
||||||
cmd->src_x = static_cast<u16>(src_x);
|
|
||||||
cmd->src_y = static_cast<u16>(src_y);
|
|
||||||
cmd->dst_x = static_cast<u16>(dst_x);
|
|
||||||
cmd->dst_y = static_cast<u16>(dst_y);
|
|
||||||
cmd->width = static_cast<u16>(width);
|
|
||||||
cmd->height = static_cast<u16>(height);
|
|
||||||
m_sw_renderer->PushCommand(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
{
|
{
|
||||||
if (IsUsingSoftwareRendererForReadbacks())
|
if (m_sw_renderer)
|
||||||
FillSoftwareRendererVRAM(x, y, width, height, color);
|
{
|
||||||
|
GPUBackendFillVRAMCommand* cmd = m_sw_renderer->NewFillVRAMCommand();
|
||||||
|
FillBackendCommandParameters(cmd);
|
||||||
|
cmd->x = static_cast<u16>(x);
|
||||||
|
cmd->y = static_cast<u16>(y);
|
||||||
|
cmd->width = static_cast<u16>(width);
|
||||||
|
cmd->height = static_cast<u16>(height);
|
||||||
|
cmd->color = color;
|
||||||
|
m_sw_renderer->PushCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
IncludeVRAMDirtyRectangle(
|
IncludeVRAMDirtyRectangle(
|
||||||
Common::Rectangle<u32>::FromExtents(x, y, width, height).Clamped(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
|
Common::Rectangle<u32>::FromExtents(x, y, width, height).Clamped(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
|
||||||
|
|
||||||
g_gpu_device->SetPipeline(m_vram_fill_pipelines[BoolToUInt8(IsVRAMFillOversized(x, y, width, height))]
|
const bool is_oversized = (((x + width) > VRAM_WIDTH || (y + height) > VRAM_HEIGHT));
|
||||||
[BoolToUInt8(IsInterlacedRenderingEnabled())]
|
g_gpu_device->SetPipeline(
|
||||||
.get());
|
m_vram_fill_pipelines[BoolToUInt8(is_oversized)][BoolToUInt8(IsInterlacedRenderingEnabled())].get());
|
||||||
|
|
||||||
const Common::Rectangle<u32> bounds(GetVRAMTransferBounds(x, y, width, height));
|
const Common::Rectangle<u32> bounds(GetVRAMTransferBounds(x, y, width, height));
|
||||||
g_gpu_device->SetViewportAndScissor(bounds.left * m_resolution_scale, bounds.top * m_resolution_scale,
|
g_gpu_device->SetViewportAndScissor(bounds.left * m_resolution_scale, bounds.top * m_resolution_scale,
|
||||||
bounds.GetWidth() * m_resolution_scale, bounds.GetHeight() * m_resolution_scale);
|
bounds.GetWidth() * m_resolution_scale, bounds.GetHeight() * m_resolution_scale);
|
||||||
|
|
||||||
const VRAMFillUBOData uniforms = GetVRAMFillUBOData(x, y, width, height, color);
|
struct VRAMFillUBOData
|
||||||
|
{
|
||||||
|
u32 u_dst_x;
|
||||||
|
u32 u_dst_y;
|
||||||
|
u32 u_end_x;
|
||||||
|
u32 u_end_y;
|
||||||
|
std::array<float, 4> u_fill_color;
|
||||||
|
u32 u_interlaced_displayed_field;
|
||||||
|
};
|
||||||
|
VRAMFillUBOData uniforms;
|
||||||
|
uniforms.u_dst_x = (x % VRAM_WIDTH) * m_resolution_scale;
|
||||||
|
uniforms.u_dst_y = (y % VRAM_HEIGHT) * m_resolution_scale;
|
||||||
|
uniforms.u_end_x = ((x + width) % VRAM_WIDTH) * m_resolution_scale;
|
||||||
|
uniforms.u_end_y = ((y + height) % VRAM_HEIGHT) * m_resolution_scale;
|
||||||
|
// drop precision unless true colour is enabled
|
||||||
|
uniforms.u_fill_color =
|
||||||
|
GPUDevice::RGBA8ToFloat(m_true_color ? color : VRAMRGBA5551ToRGBA8888(VRAMRGBA8888ToRGBA5551(color)));
|
||||||
|
uniforms.u_interlaced_displayed_field = GetActiveLineLSB();
|
||||||
g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms));
|
g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms));
|
||||||
g_gpu_device->Draw(3, 0);
|
g_gpu_device->Draw(3, 0);
|
||||||
|
|
||||||
|
@ -2044,9 +2010,9 @@ void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
|
|
||||||
void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
|
void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
|
||||||
{
|
{
|
||||||
if (IsUsingSoftwareRendererForReadbacks())
|
if (m_sw_renderer)
|
||||||
{
|
{
|
||||||
ReadSoftwareRendererVRAM(x, y, width, height);
|
m_sw_renderer->Sync(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2075,8 +2041,20 @@ void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
|
||||||
|
|
||||||
void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask)
|
void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask)
|
||||||
{
|
{
|
||||||
if (IsUsingSoftwareRendererForReadbacks())
|
if (m_sw_renderer)
|
||||||
UpdateSoftwareRendererVRAM(x, y, width, height, data, set_mask, check_mask);
|
{
|
||||||
|
const u32 num_words = width * height;
|
||||||
|
GPUBackendUpdateVRAMCommand* cmd = m_sw_renderer->NewUpdateVRAMCommand(num_words);
|
||||||
|
FillBackendCommandParameters(cmd);
|
||||||
|
cmd->params.set_mask_while_drawing = set_mask;
|
||||||
|
cmd->params.check_mask_before_draw = check_mask;
|
||||||
|
cmd->x = static_cast<u16>(x);
|
||||||
|
cmd->y = static_cast<u16>(y);
|
||||||
|
cmd->width = static_cast<u16>(width);
|
||||||
|
cmd->height = static_cast<u16>(height);
|
||||||
|
std::memcpy(cmd->data, data, sizeof(u16) * num_words);
|
||||||
|
m_sw_renderer->PushCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
const Common::Rectangle<u32> bounds = GetVRAMTransferBounds(x, y, width, height);
|
const Common::Rectangle<u32> bounds = GetVRAMTransferBounds(x, y, width, height);
|
||||||
|
|
||||||
|
@ -2104,7 +2082,21 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
|
||||||
std::memcpy(map, data, num_pixels * sizeof(u16));
|
std::memcpy(map, data, num_pixels * sizeof(u16));
|
||||||
m_vram_upload_buffer->Unmap(num_pixels);
|
m_vram_upload_buffer->Unmap(num_pixels);
|
||||||
|
|
||||||
const VRAMWriteUBOData uniforms = GetVRAMWriteUBOData(x, y, width, height, map_index, set_mask, check_mask);
|
struct VRAMWriteUBOData
|
||||||
|
{
|
||||||
|
u32 u_dst_x;
|
||||||
|
u32 u_dst_y;
|
||||||
|
u32 u_end_x;
|
||||||
|
u32 u_end_y;
|
||||||
|
u32 u_width;
|
||||||
|
u32 u_height;
|
||||||
|
u32 u_buffer_base_offset;
|
||||||
|
u32 u_mask_or_bits;
|
||||||
|
float u_depth_value;
|
||||||
|
};
|
||||||
|
const VRAMWriteUBOData uniforms = {
|
||||||
|
(x % VRAM_WIDTH), (y % VRAM_HEIGHT), ((x + width) % VRAM_WIDTH), ((y + height) % VRAM_HEIGHT), width,
|
||||||
|
height, map_index, (set_mask) ? 0x8000u : 0x00, GetCurrentNormalizedVertexDepth()};
|
||||||
|
|
||||||
// the viewport should already be set to the full vram, so just adjust the scissor
|
// the viewport should already be set to the full vram, so just adjust the scissor
|
||||||
const Common::Rectangle<u32> scaled_bounds = bounds * m_resolution_scale;
|
const Common::Rectangle<u32> scaled_bounds = bounds * m_resolution_scale;
|
||||||
|
@ -2119,10 +2111,28 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
|
||||||
|
|
||||||
void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height)
|
void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height)
|
||||||
{
|
{
|
||||||
if (IsUsingSoftwareRendererForReadbacks())
|
if (m_sw_renderer)
|
||||||
CopySoftwareRendererVRAM(src_x, src_y, dst_x, dst_y, width, height);
|
{
|
||||||
|
GPUBackendCopyVRAMCommand* cmd = m_sw_renderer->NewCopyVRAMCommand();
|
||||||
|
FillBackendCommandParameters(cmd);
|
||||||
|
cmd->src_x = static_cast<u16>(src_x);
|
||||||
|
cmd->src_y = static_cast<u16>(src_y);
|
||||||
|
cmd->dst_x = static_cast<u16>(dst_x);
|
||||||
|
cmd->dst_y = static_cast<u16>(dst_y);
|
||||||
|
cmd->width = static_cast<u16>(width);
|
||||||
|
cmd->height = static_cast<u16>(height);
|
||||||
|
m_sw_renderer->PushCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
if (UseVRAMCopyShader(src_x, src_y, dst_x, dst_y, width, height) || IsUsingMultisampling())
|
// masking enabled, oversized, or overlapping
|
||||||
|
const bool use_shader =
|
||||||
|
(m_GPUSTAT.IsMaskingEnabled() || ((src_x % VRAM_WIDTH) + width) > VRAM_WIDTH ||
|
||||||
|
((src_y % VRAM_HEIGHT) + height) > VRAM_HEIGHT || ((dst_x % VRAM_WIDTH) + width) > VRAM_WIDTH ||
|
||||||
|
((dst_y % VRAM_HEIGHT) + height) > VRAM_HEIGHT ||
|
||||||
|
Common::Rectangle<u32>::FromExtents(src_x, src_y, width, height)
|
||||||
|
.Intersects(Common::Rectangle<u32>::FromExtents(dst_x, dst_y, width, height)));
|
||||||
|
|
||||||
|
if (use_shader || IsUsingMultisampling())
|
||||||
{
|
{
|
||||||
const Common::Rectangle<u32> src_bounds = GetVRAMTransferBounds(src_x, src_y, width, height);
|
const Common::Rectangle<u32> src_bounds = GetVRAMTransferBounds(src_x, src_y, width, height);
|
||||||
const Common::Rectangle<u32> dst_bounds = GetVRAMTransferBounds(dst_x, dst_y, width, height);
|
const Common::Rectangle<u32> dst_bounds = GetVRAMTransferBounds(dst_x, dst_y, width, height);
|
||||||
|
@ -2130,7 +2140,29 @@ void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
|
||||||
UpdateVRAMReadTexture();
|
UpdateVRAMReadTexture();
|
||||||
IncludeVRAMDirtyRectangle(dst_bounds);
|
IncludeVRAMDirtyRectangle(dst_bounds);
|
||||||
|
|
||||||
const VRAMCopyUBOData uniforms = GetVRAMCopyUBOData(src_x, src_y, dst_x, dst_y, width, height);
|
struct VRAMCopyUBOData
|
||||||
|
{
|
||||||
|
u32 u_src_x;
|
||||||
|
u32 u_src_y;
|
||||||
|
u32 u_dst_x;
|
||||||
|
u32 u_dst_y;
|
||||||
|
u32 u_end_x;
|
||||||
|
u32 u_end_y;
|
||||||
|
u32 u_width;
|
||||||
|
u32 u_height;
|
||||||
|
u32 u_set_mask_bit;
|
||||||
|
float u_depth_value;
|
||||||
|
};
|
||||||
|
const VRAMCopyUBOData uniforms = {(src_x % VRAM_WIDTH) * m_resolution_scale,
|
||||||
|
(src_y % VRAM_HEIGHT) * m_resolution_scale,
|
||||||
|
(dst_x % VRAM_WIDTH) * m_resolution_scale,
|
||||||
|
(dst_y % VRAM_HEIGHT) * m_resolution_scale,
|
||||||
|
((dst_x + width) % VRAM_WIDTH) * m_resolution_scale,
|
||||||
|
((dst_y + height) % VRAM_HEIGHT) * m_resolution_scale,
|
||||||
|
width * m_resolution_scale,
|
||||||
|
height * m_resolution_scale,
|
||||||
|
m_GPUSTAT.set_mask_while_drawing ? 1u : 0u,
|
||||||
|
GetCurrentNormalizedVertexDepth()};
|
||||||
|
|
||||||
// VRAM read texture should already be bound.
|
// VRAM read texture should already be bound.
|
||||||
const Common::Rectangle<u32> dst_bounds_scaled(dst_bounds * m_resolution_scale);
|
const Common::Rectangle<u32> dst_bounds_scaled(dst_bounds * m_resolution_scale);
|
||||||
|
|
|
@ -55,13 +55,10 @@ public:
|
||||||
std::tuple<u32, u32> GetEffectiveDisplayResolution(bool scaled = true) override final;
|
std::tuple<u32, u32> GetEffectiveDisplayResolution(bool scaled = true) override final;
|
||||||
std::tuple<u32, u32> GetFullDisplayResolution(bool scaled = true) override final;
|
std::tuple<u32, u32> GetFullDisplayResolution(bool scaled = true) override final;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
// TODO: Remove these
|
|
||||||
VRAM_UPDATE_TEXTURE_BUFFER_SIZE = 4 * 1024 * 1024,
|
VRAM_UPDATE_TEXTURE_BUFFER_SIZE = 4 * 1024 * 1024,
|
||||||
VERTEX_BUFFER_SIZE = 4 * 1024 * 1024,
|
|
||||||
UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024,
|
|
||||||
MAX_BATCH_VERTEX_COUNTER_IDS = 65536 - 2,
|
MAX_BATCH_VERTEX_COUNTER_IDS = 65536 - 2,
|
||||||
MAX_VERTICES_FOR_RECTANGLE = 6 * (((MAX_PRIMITIVE_WIDTH + (TEXTURE_PAGE_WIDTH - 1)) / TEXTURE_PAGE_WIDTH) + 1u) *
|
MAX_VERTICES_FOR_RECTANGLE = 6 * (((MAX_PRIMITIVE_WIDTH + (TEXTURE_PAGE_WIDTH - 1)) / TEXTURE_PAGE_WIDTH) + 1u) *
|
||||||
(((MAX_PRIMITIVE_HEIGHT + (TEXTURE_PAGE_HEIGHT - 1)) / TEXTURE_PAGE_HEIGHT) + 1u)
|
(((MAX_PRIMITIVE_HEIGHT + (TEXTURE_PAGE_HEIGHT - 1)) / TEXTURE_PAGE_HEIGHT) + 1u)
|
||||||
|
@ -139,44 +136,6 @@ protected:
|
||||||
u32 u_set_mask_while_drawing;
|
u32 u_set_mask_while_drawing;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: move all these to source
|
|
||||||
struct VRAMFillUBOData
|
|
||||||
{
|
|
||||||
u32 u_dst_x;
|
|
||||||
u32 u_dst_y;
|
|
||||||
u32 u_end_x;
|
|
||||||
u32 u_end_y;
|
|
||||||
float u_fill_color[4];
|
|
||||||
u32 u_interlaced_displayed_field;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VRAMWriteUBOData
|
|
||||||
{
|
|
||||||
u32 u_dst_x;
|
|
||||||
u32 u_dst_y;
|
|
||||||
u32 u_end_x;
|
|
||||||
u32 u_end_y;
|
|
||||||
u32 u_width;
|
|
||||||
u32 u_height;
|
|
||||||
u32 u_buffer_base_offset;
|
|
||||||
u32 u_mask_or_bits;
|
|
||||||
float u_depth_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VRAMCopyUBOData
|
|
||||||
{
|
|
||||||
u32 u_src_x;
|
|
||||||
u32 u_src_y;
|
|
||||||
u32 u_dst_x;
|
|
||||||
u32 u_dst_y;
|
|
||||||
u32 u_end_x;
|
|
||||||
u32 u_end_y;
|
|
||||||
u32 u_width;
|
|
||||||
u32 u_height;
|
|
||||||
u32 u_set_mask_bit;
|
|
||||||
float u_depth_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RendererStats
|
struct RendererStats
|
||||||
{
|
{
|
||||||
u32 num_batches;
|
u32 num_batches;
|
||||||
|
@ -184,14 +143,6 @@ protected:
|
||||||
u32 num_uniform_buffer_updates;
|
u32 num_uniform_buffer_updates;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::tuple<float, float, float, float> RGBA8ToFloat(u32 rgba)
|
|
||||||
{
|
|
||||||
return std::make_tuple(static_cast<float>(rgba & UINT32_C(0xFF)) * (1.0f / 255.0f),
|
|
||||||
static_cast<float>((rgba >> 8) & UINT32_C(0xFF)) * (1.0f / 255.0f),
|
|
||||||
static_cast<float>((rgba >> 16) & UINT32_C(0xFF)) * (1.0f / 255.0f),
|
|
||||||
static_cast<float>(rgba >> 24) * (1.0f / 255.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreateBuffers();
|
bool CreateBuffers();
|
||||||
void ClearFramebuffer();
|
void ClearFramebuffer();
|
||||||
void DestroyBuffers();
|
void DestroyBuffers();
|
||||||
|
@ -212,24 +163,22 @@ protected:
|
||||||
u32 CalculateResolutionScale() const;
|
u32 CalculateResolutionScale() const;
|
||||||
GPUDownsampleMode GetDownsampleMode(u32 resolution_scale) const;
|
GPUDownsampleMode GetDownsampleMode(u32 resolution_scale) const;
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsUsingMultisampling() const { return m_multisamples > 1; }
|
bool IsUsingMultisampling() const;
|
||||||
ALWAYS_INLINE bool IsUsingDownsampling() const
|
bool IsUsingDownsampling() const;
|
||||||
{
|
|
||||||
return (m_downsample_mode != GPUDownsampleMode::Disabled && !m_GPUSTAT.display_area_color_depth_24);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFullVRAMDirtyRectangle()
|
void SetFullVRAMDirtyRectangle();
|
||||||
{
|
void ClearVRAMDirtyRectangle();
|
||||||
m_vram_dirty_rect.Set(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
|
||||||
m_draw_mode.SetTexturePageChanged();
|
|
||||||
}
|
|
||||||
void ClearVRAMDirtyRectangle() { m_vram_dirty_rect.SetInvalid(); }
|
|
||||||
void IncludeVRAMDirtyRectangle(const Common::Rectangle<u32>& rect);
|
void IncludeVRAMDirtyRectangle(const Common::Rectangle<u32>& rect);
|
||||||
|
|
||||||
bool IsFlushed() const { return m_batch_current_vertex_ptr == m_batch_start_vertex_ptr; }
|
ALWAYS_INLINE bool IsFlushed() const { return m_batch_current_vertex_ptr == m_batch_start_vertex_ptr; }
|
||||||
|
ALWAYS_INLINE u32 GetBatchVertexSpace() const
|
||||||
u32 GetBatchVertexSpace() const { return static_cast<u32>(m_batch_end_vertex_ptr - m_batch_current_vertex_ptr); }
|
{
|
||||||
u32 GetBatchVertexCount() const { return static_cast<u32>(m_batch_current_vertex_ptr - m_batch_start_vertex_ptr); }
|
return static_cast<u32>(m_batch_end_vertex_ptr - m_batch_current_vertex_ptr);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE u32 GetBatchVertexCount() const
|
||||||
|
{
|
||||||
|
return static_cast<u32>(m_batch_current_vertex_ptr - m_batch_start_vertex_ptr);
|
||||||
|
}
|
||||||
void EnsureVertexBufferSpace(u32 required_vertices);
|
void EnsureVertexBufferSpace(u32 required_vertices);
|
||||||
void EnsureVertexBufferSpaceForCurrentCommand();
|
void EnsureVertexBufferSpaceForCurrentCommand();
|
||||||
void ResetBatchVertexDepth();
|
void ResetBatchVertexDepth();
|
||||||
|
@ -241,40 +190,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the interlaced mode to use when scanning out/displaying.
|
/// Returns the interlaced mode to use when scanning out/displaying.
|
||||||
ALWAYS_INLINE InterlacedRenderMode GetInterlacedRenderMode() const
|
InterlacedRenderMode GetInterlacedRenderMode() const;
|
||||||
{
|
|
||||||
if (IsInterlacedDisplayEnabled())
|
|
||||||
{
|
|
||||||
return m_GPUSTAT.vertical_resolution ? InterlacedRenderMode::InterleavedFields :
|
|
||||||
InterlacedRenderMode::SeparateFields;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return InterlacedRenderMode::None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the specified texture filtering mode requires dual-source blending.
|
|
||||||
ALWAYS_INLINE bool TextureFilterRequiresDualSourceBlend(GPUTextureFilter filter)
|
|
||||||
{
|
|
||||||
return (filter == GPUTextureFilter::Bilinear || filter == GPUTextureFilter::JINC2 ||
|
|
||||||
filter == GPUTextureFilter::xBR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if alpha blending should be enabled for drawing the current batch.
|
|
||||||
ALWAYS_INLINE bool UseAlphaBlending(GPUTransparencyMode transparency_mode, BatchRenderMode render_mode) const
|
|
||||||
{
|
|
||||||
if (m_texture_filtering == GPUTextureFilter::Bilinear || m_texture_filtering == GPUTextureFilter::JINC2 ||
|
|
||||||
m_texture_filtering == GPUTextureFilter::xBR)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transparency_mode == GPUTransparencyMode::Disabled || render_mode == BatchRenderMode::OnlyOpaque)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// We need two-pass rendering when using BG-FG blending and texturing, as the transparency can be enabled
|
/// We need two-pass rendering when using BG-FG blending and texturing, as the transparency can be enabled
|
||||||
/// on a per-pixel basis, and the opaque pixels shouldn't be blended at all.
|
/// on a per-pixel basis, and the opaque pixels shouldn't be blended at all.
|
||||||
|
@ -285,22 +201,9 @@ protected:
|
||||||
(!m_supports_dual_source_blend && m_batch.transparency_mode != GPUTransparencyMode::Disabled)));
|
(!m_supports_dual_source_blend && m_batch.transparency_mode != GPUTransparencyMode::Disabled)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the specified VRAM fill is oversized.
|
|
||||||
ALWAYS_INLINE static bool IsVRAMFillOversized(u32 x, u32 y, u32 width, u32 height)
|
|
||||||
{
|
|
||||||
return ((x + width) > VRAM_WIDTH || (y + height) > VRAM_HEIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsUsingSoftwareRendererForReadbacks() { return static_cast<bool>(m_sw_renderer); }
|
|
||||||
|
|
||||||
void FillBackendCommandParameters(GPUBackendCommand* cmd) const;
|
void FillBackendCommandParameters(GPUBackendCommand* cmd) const;
|
||||||
void FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) const;
|
void FillDrawCommand(GPUBackendDrawCommand* cmd, GPURenderCommand rc) const;
|
||||||
void UpdateSoftwareRenderer(bool copy_vram_from_hw);
|
void UpdateSoftwareRenderer(bool copy_vram_from_hw);
|
||||||
void ReadSoftwareRendererVRAM(u32 x, u32 y, u32 width, u32 height);
|
|
||||||
void UpdateSoftwareRendererVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask,
|
|
||||||
bool check_mask);
|
|
||||||
void FillSoftwareRendererVRAM(u32 x, u32 y, u32 width, u32 height, u32 color);
|
|
||||||
void CopySoftwareRendererVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height);
|
|
||||||
|
|
||||||
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override;
|
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override;
|
||||||
void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override;
|
void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override;
|
||||||
|
@ -310,22 +213,6 @@ protected:
|
||||||
void FlushRender() override;
|
void FlushRender() override;
|
||||||
void DrawRendererStats(bool is_idle_frame) override;
|
void DrawRendererStats(bool is_idle_frame) override;
|
||||||
|
|
||||||
std::tuple<s32, s32> ScaleVRAMCoordinates(s32 x, s32 y) const
|
|
||||||
{
|
|
||||||
return std::make_tuple(x * s32(m_resolution_scale), y * s32(m_resolution_scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the area affected by a VRAM transfer, including wrap-around of X.
|
|
||||||
Common::Rectangle<u32> GetVRAMTransferBounds(u32 x, u32 y, u32 width, u32 height) const;
|
|
||||||
|
|
||||||
/// Returns true if the VRAM copy shader should be used (oversized copies, masking).
|
|
||||||
bool UseVRAMCopyShader(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) const;
|
|
||||||
|
|
||||||
VRAMFillUBOData GetVRAMFillUBOData(u32 x, u32 y, u32 width, u32 height, u32 color) const;
|
|
||||||
VRAMWriteUBOData GetVRAMWriteUBOData(u32 x, u32 y, u32 width, u32 height, u32 buffer_offset, bool set_mask,
|
|
||||||
bool check_mask) const;
|
|
||||||
VRAMCopyUBOData GetVRAMCopyUBOData(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) const;
|
|
||||||
|
|
||||||
bool BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u32 dst_x, u32 dst_y, u32 width, u32 height);
|
bool BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u32 dst_x, u32 dst_y, u32 width, u32 height);
|
||||||
|
|
||||||
/// Expands a line into two triangles.
|
/// Expands a line into two triangles.
|
||||||
|
@ -444,12 +331,6 @@ protected:
|
||||||
RendererStats m_last_renderer_stats = {};
|
RendererStats m_last_renderer_stats = {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum : u32
|
|
||||||
{
|
|
||||||
MIN_BATCH_VERTEX_COUNT = 6,
|
|
||||||
MAX_BATCH_VERTEX_COUNT = VERTEX_BUFFER_SIZE / sizeof(BatchVertex)
|
|
||||||
};
|
|
||||||
|
|
||||||
void LoadVertices();
|
void LoadVertices();
|
||||||
|
|
||||||
ALWAYS_INLINE void AddVertex(const BatchVertex& v)
|
ALWAYS_INLINE void AddVertex(const BatchVertex& v)
|
||||||
|
|
Loading…
Reference in New Issue