mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:48:10 +00:00
LibGfx: Trim scanline to right clip in path rasterizer
There's no need to accumulate past the right clip, so we also don't need to store it.
This commit is contained in:
parent
ec93973158
commit
9c3bb94d14
1 changed files with 21 additions and 17 deletions
|
@ -96,8 +96,6 @@ template<unsigned SamplesPerPixel>
|
||||||
EdgeFlagPathRasterizer<SamplesPerPixel>::EdgeFlagPathRasterizer(IntSize size)
|
EdgeFlagPathRasterizer<SamplesPerPixel>::EdgeFlagPathRasterizer(IntSize size)
|
||||||
: m_size(size.width() + 1, size.height() + 1)
|
: m_size(size.width() + 1, size.height() + 1)
|
||||||
{
|
{
|
||||||
// FIXME: Clip the scanline width to the visible section (tricky).
|
|
||||||
m_scanline.resize(m_size.width());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned SamplesPerPixel>
|
template<unsigned SamplesPerPixel>
|
||||||
|
@ -135,6 +133,14 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Pa
|
||||||
m_blit_origin = dest_rect.top_left();
|
m_blit_origin = dest_rect.top_left();
|
||||||
m_clip = dest_rect.intersected(painter.clip_rect());
|
m_clip = dest_rect.intersected(painter.clip_rect());
|
||||||
|
|
||||||
|
// Only allocate enough to plot the parts of the scanline that could be visible.
|
||||||
|
// Note: This can't clip the LHS.
|
||||||
|
auto scanline_length = min(m_size.width(), m_clip.right() - m_blit_origin.x());
|
||||||
|
if (scanline_length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_scanline.resize(scanline_length);
|
||||||
|
|
||||||
if (m_clip.is_empty())
|
if (m_clip.is_empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -167,15 +173,15 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Pa
|
||||||
auto for_each_sample = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent, auto callback) {
|
auto for_each_sample = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent, auto callback) {
|
||||||
for (int y = start_subpixel_y; y < end_subpixel_y; y++) {
|
for (int y = start_subpixel_y; y < end_subpixel_y; y++) {
|
||||||
auto xi = static_cast<int>(edge.x + SubpixelSample::nrooks_subpixel_offsets[y]);
|
auto xi = static_cast<int>(edge.x + SubpixelSample::nrooks_subpixel_offsets[y]);
|
||||||
if (xi < 0 || size_t(xi) >= m_scanline.size()) [[unlikely]] {
|
if (xi >= 0 && size_t(xi) < m_scanline.size()) [[likely]] {
|
||||||
// FIXME: For very low dxdy values, floating point error can push the sample outside the scanline.
|
SampleType sample = 1 << y;
|
||||||
// This does not seem to make a visible difference most of the time (and is more likely from generated
|
callback(xi, y, sample);
|
||||||
// paths, such as this 3D canvas demo: https://www.kevs3d.co.uk/dev/html5logo/).
|
} else if (xi < 0) {
|
||||||
dbgln_if(FILL_PATH_DEBUG, "fill_path: Sample out of bounds: {} not in [0, {})", xi, m_scanline.size());
|
if (edge.dxdy <= 0)
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
xi = m_scanline.size() - 1;
|
||||||
}
|
}
|
||||||
SampleType sample = 1 << y;
|
|
||||||
callback(xi, y, sample);
|
|
||||||
edge.x += edge.dxdy;
|
edge.x += edge.dxdy;
|
||||||
edge_extent.min_x = min(edge_extent.min_x, xi);
|
edge_extent.min_x = min(edge_extent.min_x, xi);
|
||||||
edge_extent.max_x = max(edge_extent.max_x, xi);
|
edge_extent.max_x = max(edge_extent.max_x, xi);
|
||||||
|
@ -200,7 +206,7 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Pa
|
||||||
// Only allocate the winding buffer if needed.
|
// Only allocate the winding buffer if needed.
|
||||||
// NOTE: non-zero fills are a fair bit less efficient. So if you can do an even-odd fill do that :^)
|
// NOTE: non-zero fills are a fair bit less efficient. So if you can do an even-odd fill do that :^)
|
||||||
if (m_windings.is_empty())
|
if (m_windings.is_empty())
|
||||||
m_windings.resize(m_size.width());
|
m_windings.resize(m_scanline.size());
|
||||||
|
|
||||||
auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent) {
|
auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent) {
|
||||||
for_each_sample(edge, start_subpixel_y, end_subpixel_y, edge_extent, [&](int xi, int y, SampleType sample) {
|
for_each_sample(edge, start_subpixel_y, end_subpixel_y, edge_extent, [&](int xi, int y, SampleType sample) {
|
||||||
|
@ -372,14 +378,12 @@ FLATTEN __attribute__((hot)) void EdgeFlagPathRasterizer<SamplesPerPixel>::write
|
||||||
{
|
{
|
||||||
// Handle scanline clipping.
|
// Handle scanline clipping.
|
||||||
auto left_clip = m_clip.left() - m_blit_origin.x();
|
auto left_clip = m_clip.left() - m_blit_origin.x();
|
||||||
auto right_clip = m_clip.right() - m_blit_origin.x() - 1;
|
EdgeExtent clipped_extent { max(left_clip, edge_extent.min_x), edge_extent.max_x };
|
||||||
EdgeExtent clipped_extent { max(left_clip, edge_extent.min_x), min(right_clip, edge_extent.max_x) };
|
|
||||||
if (clipped_extent.min_x > clipped_extent.max_x) {
|
if (clipped_extent.min_x > clipped_extent.max_x) {
|
||||||
// Fully clipped. Unfortunately we still need to zero the scanline data (before the right clip).
|
// Fully clipped. Unfortunately we still need to zero the scanline data.
|
||||||
EdgeExtent zero_extent { edge_extent.min_x, clipped_extent.max_x };
|
edge_extent.memset_extent(m_scanline.data(), 0);
|
||||||
zero_extent.memset_extent(m_scanline.data(), 0);
|
|
||||||
if constexpr (WindingRule == Painter::WindingRule::Nonzero)
|
if constexpr (WindingRule == Painter::WindingRule::Nonzero)
|
||||||
zero_extent.memset_extent(m_windings.data(), 0);
|
edge_extent.memset_extent(m_windings.data(), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue