mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 07:35:41 +00:00
GPU: Rework pre-draw clipping
This commit is contained in:
parent
7e22fb08d2
commit
d1483d8077
|
@ -299,22 +299,6 @@ protected:
|
||||||
return (m_drawing_area.left <= m_drawing_area.right && m_drawing_area.top <= m_drawing_area.bottom);
|
return (m_drawing_area.left <= m_drawing_area.right && m_drawing_area.top <= m_drawing_area.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clamps the specified coordinates to the drawing area.
|
|
||||||
ALWAYS_INLINE void ClampCoordinatesToDrawingArea(s32* x, s32* y)
|
|
||||||
{
|
|
||||||
const s32 x_value = *x;
|
|
||||||
if (x_value < static_cast<s32>(m_drawing_area.left))
|
|
||||||
*x = m_drawing_area.left;
|
|
||||||
else if (x_value >= static_cast<s32>(m_drawing_area.right))
|
|
||||||
*x = m_drawing_area.right - 1;
|
|
||||||
|
|
||||||
const s32 y_value = *y;
|
|
||||||
if (y_value < static_cast<s32>(m_drawing_area.top))
|
|
||||||
*y = m_drawing_area.top;
|
|
||||||
else if (y_value >= static_cast<s32>(m_drawing_area.bottom))
|
|
||||||
*y = m_drawing_area.bottom - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddCommandTicks(TickCount ticks);
|
void AddCommandTicks(TickCount ticks);
|
||||||
|
|
||||||
void WriteGP1(u32 value);
|
void WriteGP1(u32 value);
|
||||||
|
@ -332,15 +316,21 @@ protected:
|
||||||
virtual void UpdateDisplay();
|
virtual void UpdateDisplay();
|
||||||
virtual void DrawRendererStats();
|
virtual void DrawRendererStats();
|
||||||
|
|
||||||
ALWAYS_INLINE void AddDrawTriangleTicks(s32 x1, s32 y1, s32 x2, s32 y2, s32 x3, s32 y3, bool shaded, bool textured,
|
ALWAYS_INLINE_RELEASE void AddDrawTriangleTicks(s32 x1, s32 y1, s32 x2, s32 y2, s32 x3, s32 y3, bool shaded,
|
||||||
bool semitransparent)
|
bool textured, bool semitransparent)
|
||||||
{
|
{
|
||||||
// This will not produce the correct results for triangles which are partially outside the clip area.
|
// This will not produce the correct results for triangles which are partially outside the clip area.
|
||||||
// However, usually it'll undershoot not overshoot. If we wanted to make this more accurate, we'd need to intersect
|
// However, usually it'll undershoot not overshoot. If we wanted to make this more accurate, we'd need to intersect
|
||||||
// the edges with the clip rectangle.
|
// the edges with the clip rectangle.
|
||||||
ClampCoordinatesToDrawingArea(&x1, &y1);
|
// TODO: Coordinates are exclusive, so off by one here...
|
||||||
ClampCoordinatesToDrawingArea(&x2, &y2);
|
const s32 clip_right = static_cast<s32>(m_drawing_area.right) + 1;
|
||||||
ClampCoordinatesToDrawingArea(&x3, &y3);
|
const s32 clip_bottom = static_cast<s32>(m_drawing_area.bottom) + 1;
|
||||||
|
x1 = std::clamp(x1, static_cast<s32>(m_drawing_area.left), clip_right);
|
||||||
|
x2 = std::clamp(x2, static_cast<s32>(m_drawing_area.left), clip_right);
|
||||||
|
x3 = std::clamp(x3, static_cast<s32>(m_drawing_area.left), clip_right);
|
||||||
|
y1 = std::clamp(y1, static_cast<s32>(m_drawing_area.top), clip_bottom);
|
||||||
|
y2 = std::clamp(y2, static_cast<s32>(m_drawing_area.top), clip_bottom);
|
||||||
|
y3 = std::clamp(y3, static_cast<s32>(m_drawing_area.top), clip_bottom);
|
||||||
|
|
||||||
TickCount pixels = std::abs((x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2) / 2);
|
TickCount pixels = std::abs((x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2) / 2);
|
||||||
if (textured)
|
if (textured)
|
||||||
|
@ -352,24 +342,44 @@ protected:
|
||||||
|
|
||||||
AddCommandTicks(pixels);
|
AddCommandTicks(pixels);
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE void AddDrawRectangleTicks(u32 width, u32 height, bool textured, bool semitransparent)
|
ALWAYS_INLINE_RELEASE void AddDrawRectangleTicks(s32 x, s32 y, u32 width, u32 height, bool textured,
|
||||||
|
bool semitransparent)
|
||||||
{
|
{
|
||||||
u32 ticks_per_row = width;
|
// We do -1 on the inside of the clamp, in case the rectangle is entirely clipped.
|
||||||
|
u32 drawn_width = static_cast<u32>(
|
||||||
|
std::clamp<s32>(x + static_cast<s32>(width), static_cast<s32>(m_drawing_area.left),
|
||||||
|
static_cast<s32>(m_drawing_area.right) + 1) -
|
||||||
|
std::clamp<s32>(x, static_cast<s32>(m_drawing_area.left), static_cast<s32>(m_drawing_area.right) + 1));
|
||||||
|
u32 drawn_height = static_cast<u32>(
|
||||||
|
std::clamp<s32>(y + static_cast<s32>(height), static_cast<s32>(m_drawing_area.top),
|
||||||
|
static_cast<s32>(m_drawing_area.bottom) + 1) -
|
||||||
|
std::clamp<s32>(y, static_cast<s32>(m_drawing_area.top), static_cast<s32>(m_drawing_area.bottom) + 1));
|
||||||
|
|
||||||
|
u32 ticks_per_row = drawn_width;
|
||||||
if (textured)
|
if (textured)
|
||||||
ticks_per_row += width;
|
ticks_per_row += drawn_width;
|
||||||
if (semitransparent || m_GPUSTAT.check_mask_before_draw)
|
if (semitransparent || m_GPUSTAT.check_mask_before_draw)
|
||||||
ticks_per_row += (width + 1u) / 2u;
|
ticks_per_row += (drawn_width + 1u) / 2u;
|
||||||
if (m_GPUSTAT.SkipDrawingToActiveField())
|
if (m_GPUSTAT.SkipDrawingToActiveField())
|
||||||
height = std::max<u32>(height / 2, 1u);
|
drawn_height = std::max<u32>(drawn_height / 2, 1u);
|
||||||
|
|
||||||
AddCommandTicks(ticks_per_row * height);
|
AddCommandTicks(ticks_per_row * drawn_height);
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE void AddDrawLineTicks(u32 width, u32 height, bool shaded)
|
ALWAYS_INLINE_RELEASE void AddDrawLineTicks(s32 min_x, s32 min_y, s32 max_x, s32 max_y, bool shaded)
|
||||||
{
|
{
|
||||||
if (m_GPUSTAT.SkipDrawingToActiveField())
|
// We do -1 on the inside of the clamp, in case the rectangle is entirely clipped.
|
||||||
height = std::max<u32>(height / 2, 1u);
|
// Lines are inclusive?
|
||||||
|
u32 drawn_width = static_cast<u32>(
|
||||||
|
std::clamp<s32>(max_x + 1, static_cast<s32>(m_drawing_area.left), static_cast<s32>(m_drawing_area.right) + 1) -
|
||||||
|
std::clamp<s32>(min_x, static_cast<s32>(m_drawing_area.left), static_cast<s32>(m_drawing_area.right) + 1));
|
||||||
|
u32 drawn_height = static_cast<u32>(
|
||||||
|
std::clamp<s32>(max_y + 1, static_cast<s32>(m_drawing_area.top), static_cast<s32>(m_drawing_area.bottom) + 1) -
|
||||||
|
std::clamp<s32>(min_y, static_cast<s32>(m_drawing_area.top), static_cast<s32>(m_drawing_area.bottom) + 1));
|
||||||
|
|
||||||
AddCommandTicks(std::max(width, height));
|
if (m_GPUSTAT.SkipDrawingToActiveField())
|
||||||
|
drawn_height = std::max<u32>(drawn_height / 2, 1u);
|
||||||
|
|
||||||
|
AddCommandTicks(std::max(drawn_width, drawn_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<TimingEvent> m_crtc_tick_event;
|
std::unique_ptr<TimingEvent> m_crtc_tick_event;
|
||||||
|
|
|
@ -2213,14 +2213,7 @@ void GPU_HW::LoadVertices()
|
||||||
}
|
}
|
||||||
|
|
||||||
IncludeDrawnDirtyRectangle(pos_x, pos_y, pos_x + rectangle_width, pos_y + rectangle_height);
|
IncludeDrawnDirtyRectangle(pos_x, pos_y, pos_x + rectangle_width, pos_y + rectangle_height);
|
||||||
|
AddDrawRectangleTicks(pos_x, pos_y, rectangle_width, rectangle_height, rc.texture_enable, rc.transparency_enable);
|
||||||
const u32 clip_left = static_cast<u32>(std::clamp<s32>(pos_x, m_drawing_area.left, m_drawing_area.right));
|
|
||||||
const u32 clip_right =
|
|
||||||
static_cast<u32>(std::clamp<s32>(pos_x + rectangle_width, m_drawing_area.left, m_drawing_area.right)) + 1u;
|
|
||||||
const u32 clip_top = static_cast<u32>(std::clamp<s32>(pos_y, m_drawing_area.top, m_drawing_area.bottom));
|
|
||||||
const u32 clip_bottom =
|
|
||||||
static_cast<u32>(std::clamp<s32>(pos_y + rectangle_height, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
|
||||||
AddDrawRectangleTicks(clip_right - clip_left, clip_bottom - clip_top, rc.texture_enable, rc.transparency_enable);
|
|
||||||
|
|
||||||
if (m_sw_renderer)
|
if (m_sw_renderer)
|
||||||
{
|
{
|
||||||
|
@ -2276,15 +2269,8 @@ void GPU_HW::LoadVertices()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IncludeDrawnDirtyRectangle(min_x, min_y, max_x, max_y);
|
IncludeDrawnDirtyRectangle(min_x, min_y, max_x + 1, max_y + 1);
|
||||||
|
AddDrawLineTicks(min_x, min_y, max_x, max_y, rc.shading_enable);
|
||||||
const u32 clip_left = static_cast<u32>(std::clamp<s32>(min_x, m_drawing_area.left, m_drawing_area.right));
|
|
||||||
const u32 clip_right = static_cast<u32>(std::clamp<s32>(max_x, m_drawing_area.left, m_drawing_area.right)) + 1u;
|
|
||||||
const u32 clip_top = static_cast<u32>(std::clamp<s32>(min_y, m_drawing_area.top, m_drawing_area.bottom));
|
|
||||||
const u32 clip_bottom =
|
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
|
||||||
|
|
||||||
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
|
||||||
|
|
||||||
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
||||||
DrawLine(static_cast<float>(start_x), static_cast<float>(start_y), start_color, static_cast<float>(end_x),
|
DrawLine(static_cast<float>(start_x), static_cast<float>(start_y), start_color, static_cast<float>(end_x),
|
||||||
|
@ -2343,16 +2329,8 @@ void GPU_HW::LoadVertices()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IncludeDrawnDirtyRectangle(min_x, min_y, max_x, max_y);
|
IncludeDrawnDirtyRectangle(min_x, min_y, max_x + 1, max_y + 1);
|
||||||
|
AddDrawLineTicks(min_x, min_y, max_x, max_y, rc.shading_enable);
|
||||||
const u32 clip_left = static_cast<u32>(std::clamp<s32>(min_x, m_drawing_area.left, m_drawing_area.right));
|
|
||||||
const u32 clip_right =
|
|
||||||
static_cast<u32>(std::clamp<s32>(max_x, m_drawing_area.left, m_drawing_area.right)) + 1u;
|
|
||||||
const u32 clip_top = static_cast<u32>(std::clamp<s32>(min_y, m_drawing_area.top, m_drawing_area.bottom));
|
|
||||||
const u32 clip_bottom =
|
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
|
||||||
|
|
||||||
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
|
||||||
|
|
||||||
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
||||||
DrawLine(static_cast<float>(start_x), static_cast<float>(start_y), start_color, static_cast<float>(end_x),
|
DrawLine(static_cast<float>(start_x), static_cast<float>(start_y), start_color, static_cast<float>(end_x),
|
||||||
|
|
|
@ -677,15 +677,7 @@ void GPU_SW::DispatchRenderCommand()
|
||||||
if (!IsDrawingAreaIsValid())
|
if (!IsDrawingAreaIsValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const u32 clip_left = static_cast<u32>(std::clamp<s32>(cmd->x, m_drawing_area.left, m_drawing_area.right));
|
AddDrawRectangleTicks(cmd->x, cmd->y, cmd->width, cmd->height, rc.texture_enable, rc.transparency_enable);
|
||||||
const u32 clip_right =
|
|
||||||
static_cast<u32>(std::clamp<s32>(cmd->x + cmd->width, m_drawing_area.left, m_drawing_area.right)) + 1u;
|
|
||||||
const u32 clip_top = static_cast<u32>(std::clamp<s32>(cmd->y, m_drawing_area.top, m_drawing_area.bottom));
|
|
||||||
const u32 clip_bottom =
|
|
||||||
static_cast<u32>(std::clamp<s32>(cmd->y + cmd->height, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
|
||||||
|
|
||||||
// cmd->bounds.Set(Truncate16(clip_left), Truncate16(clip_top), Truncate16(clip_right), Truncate16(clip_bottom));
|
|
||||||
AddDrawRectangleTicks(clip_right - clip_left, clip_bottom - clip_top, rc.texture_enable, rc.transparency_enable);
|
|
||||||
|
|
||||||
m_backend.PushCommand(cmd);
|
m_backend.PushCommand(cmd);
|
||||||
}
|
}
|
||||||
|
@ -737,14 +729,7 @@ void GPU_SW::DispatchRenderCommand()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 clip_left = static_cast<u32>(std::clamp<s32>(min_x, m_drawing_area.left, m_drawing_area.right));
|
AddDrawLineTicks(min_x, min_y, max_x, max_y, rc.shading_enable);
|
||||||
const u32 clip_right = static_cast<u32>(std::clamp<s32>(max_x, m_drawing_area.left, m_drawing_area.right)) + 1u;
|
|
||||||
const u32 clip_top = static_cast<u32>(std::clamp<s32>(min_y, m_drawing_area.top, m_drawing_area.bottom));
|
|
||||||
const u32 clip_bottom =
|
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
|
||||||
// cmd->bounds.Set(Truncate16(clip_left), Truncate16(clip_top), Truncate16(clip_right),
|
|
||||||
// Truncate16(clip_bottom));
|
|
||||||
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
|
||||||
|
|
||||||
m_backend.PushCommand(cmd);
|
m_backend.PushCommand(cmd);
|
||||||
}
|
}
|
||||||
|
@ -760,7 +745,6 @@ void GPU_SW::DispatchRenderCommand()
|
||||||
cmd->vertices[0].x = start_vp.x + m_drawing_offset.x;
|
cmd->vertices[0].x = start_vp.x + m_drawing_offset.x;
|
||||||
cmd->vertices[0].y = start_vp.y + m_drawing_offset.y;
|
cmd->vertices[0].y = start_vp.y + m_drawing_offset.y;
|
||||||
cmd->vertices[0].color = m_render_command.color_for_first_vertex;
|
cmd->vertices[0].color = m_render_command.color_for_first_vertex;
|
||||||
// cmd->bounds.SetInvalid();
|
|
||||||
|
|
||||||
const bool shaded = m_render_command.shading_enable;
|
const bool shaded = m_render_command.shading_enable;
|
||||||
for (u32 i = 1; i < num_vertices; i++)
|
for (u32 i = 1; i < num_vertices; i++)
|
||||||
|
@ -780,16 +764,7 @@ void GPU_SW::DispatchRenderCommand()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const u32 clip_left = static_cast<u32>(std::clamp<s32>(min_x, m_drawing_area.left, m_drawing_area.right));
|
AddDrawLineTicks(min_x, min_y, max_x, max_y, rc.shading_enable);
|
||||||
const u32 clip_right =
|
|
||||||
static_cast<u32>(std::clamp<s32>(max_x, m_drawing_area.left, m_drawing_area.right)) + 1u;
|
|
||||||
const u32 clip_top = static_cast<u32>(std::clamp<s32>(min_y, m_drawing_area.top, m_drawing_area.bottom));
|
|
||||||
const u32 clip_bottom =
|
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
|
||||||
|
|
||||||
// cmd->bounds.Include(Truncate16(clip_left), Truncate16(clip_right), Truncate16(clip_top),
|
|
||||||
// Truncate16(clip_bottom));
|
|
||||||
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, m_render_command.shading_enable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue