Implement SetClipRectangles

This fixes firefox flickering with SHM
This commit is contained in:
Oskari Alaranta 2026-02-21 03:45:45 +02:00
parent 406ea61be0
commit 2016621f78
5 changed files with 121 additions and 10 deletions

View File

@ -2469,8 +2469,13 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" gc {}", request.gc);
dprintln(" mask {8h}", request.mask);
// TODO: support invisible background
uint32_t foreground = 0x000000;
uint32_t background = 0x000000;
uint32_t clip_mask = 0;
int32_t clip_origin_x = 0;
int32_t clip_origin_y = 0;
for (size_t i = 0; i < 32; i++)
{
if (!((request.mask >> i) & 1))
@ -2487,6 +2492,18 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" background: {8h}", value);
background = value;
break;
case 17:
dprintln(" clip-origin-x: {}", value);
clip_origin_x = value;
break;
case 18:
dprintln(" clip-origin-y: {}", value);
clip_origin_y = value;
break;
case 19:
dprintln(" clip-mask: {}", value);
clip_mask = value;
break;
default:
dprintln(" {8h}: {8h}", 1 << i, value);
break;
@ -2499,6 +2516,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.object = Object::GraphicsContext {
.foreground = foreground,
.background = background,
.clip_mask = clip_mask,
.clip_origin_x = clip_origin_x,
.clip_origin_y = clip_origin_y,
}
}))));
@ -2509,14 +2529,16 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto request = decode<xChangeGCReq>(packet).value();
dprintln("ChangeGC");
dprintln(" gc {}", request.gc);
dprintln(" mask {8h}", request.mask);
dprintln(" gc: {}", request.gc);
dprintln(" mask: {8h}", request.mask);
auto& object = *g_objects[request.gc];
ASSERT(object.type == Object::Type::GraphicsContext);
auto& gc = object.object.get<Object::GraphicsContext>();
// TODO: support invisible background
for (size_t i = 0; i < 32; i++)
{
if (!((request.mask >> i) & 1))
@ -2533,6 +2555,19 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" background: {8h}", value);
gc.background = value;
break;
case 17:
dprintln(" clip-origin-x: {}", value);
gc.clip_origin_x = value;
break;
case 18:
dprintln(" clip-origin-y: {}", value);
gc.clip_origin_y = value;
break;
case 19:
dprintln(" clip-mask: {}", value);
gc.clip_mask = value;
gc.clip_rects.clear();
break;
default:
dprintln(" {8h}: {8h}", 1 << i, value);
break;
@ -2541,6 +2576,34 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
break;
}
case X_SetClipRectangles:
{
auto request = decode<xSetClipRectanglesReq>(packet).value();
dprintln("SetClipRectangles");
dprintln(" gc: {}", request.gc);
dprintln(" ordering: {}", request.ordering);
dprintln(" xOrigin: {}", request.xOrigin);
dprintln(" yOrigin: {}", request.yOrigin);
auto& object = *g_objects[request.gc];
ASSERT(object.type == Object::Type::GraphicsContext);
auto& gc = object.object.get<Object::GraphicsContext>();
auto rects = packet.as_span<const xRectangle>();
TRY(gc.clip_rects.resize(rects.size()));
gc.clip_mask = UINT32_MAX;
gc.clip_origin_x = request.xOrigin;
gc.clip_origin_y = request.yOrigin;
memcpy(gc.clip_rects.data(), rects.data(), rects.size() * sizeof(xRectangle));
dprintln(" rects:");
for (auto rect : rects)
dprintln(" {},{} {},{}", rect.x, rect.y, rect.width, rect.height);
break;
}
case X_FreeGC:
{
const CARD32 gc = packet.as_span<const uint32_t>()[1];
@ -2587,6 +2650,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln("CopyArea");
dprintln(" srcDrawable: {}", request.srcDrawable);
dprintln(" dstDrawable: {}", request.dstDrawable);
dprintln(" gc: {}", request.gc);
dprintln(" srcX: {}", request.srcX);
dprintln(" srcY: {}", request.srcY);
dprintln(" dstX: {}", request.dstX);
@ -2600,6 +2664,10 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto& dst_drawable = TRY_REF(get_drawable(request.dstDrawable));
auto [dst_data, dst_w, dst_h, dst_depth] = get_drawable_info(dst_drawable);
auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext);
auto& gc = gc_object.object.get<Object::GraphicsContext>();
const auto get_pixel =
[&](int32_t x, int32_t y) -> uint32_t
{
@ -2673,6 +2741,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
continue;
if (dst_x < 0 || dst_x >= dst_w)
continue;
if (!gc.is_clipped(dst_x, dst_y))
set_pixel(dst_x, dst_y, get_pixel(src_x, src_y));
}
}
@ -2692,6 +2761,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext);
auto& gc = gc_object.object.get<Object::GraphicsContext>();
const auto foreground = gc_object.object.get<Object::GraphicsContext>().foreground;
@ -2715,6 +2785,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto* data_u32 = data.as_span<uint32_t>().data();
for (int32_t y = min_y; y < max_y; y++)
for (int32_t x = min_x; x < max_x; x++)
if (!gc.is_clipped(x, y))
data_u32[y * w + x] = foreground;
if (drawable.type == Object::Type::Window)
@ -2733,6 +2804,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext);
auto& gc = gc_object.object.get<Object::GraphicsContext>();
const auto foreground = gc_object.object.get<Object::GraphicsContext>().foreground;
@ -2805,6 +2877,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
}
}
if (gc.is_clipped(x, y))
texture.set_pixel(x, y, foreground);
}
}
@ -2821,6 +2894,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
#if 0
dprintln("PutImage");
dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc);
dprintln(" format: {}", request.format);
dprintln(" depth: {}", request.depth);
dprintln(" dstX: {}", request.dstX);
@ -2832,6 +2906,10 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto& object = TRY_REF(get_drawable(request.drawable));
auto [out_data, out_w, out_h, out_depth] = get_drawable_info(object);
auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext);
auto& gc = gc_object.object.get<Object::GraphicsContext>();
if (packet.empty())
{
dwarnln("no data in PutImage");
@ -2855,6 +2933,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.h = request.height,
.left_pad = request.leftPad,
.format = request.format,
.gc = gc,
});
if (object.type == Object::Type::Window)

View File

@ -107,6 +107,30 @@ struct Object
{
uint32_t foreground;
uint32_t background;
uint32_t clip_mask;
int32_t clip_origin_x;
int32_t clip_origin_y;
BAN::Vector<xRectangle> clip_rects;
inline bool is_clipped(int32_t x, int32_t y) const
{
if (clip_mask == 0)
return false;
if (clip_mask == UINT32_MAX)
{
x -= clip_origin_x;
y -= clip_origin_y;
for (const auto& rect : clip_rects)
if (x >= rect.x && y >= rect.y && x < rect.x + rect.width && y < rect.y + rect.height)
return false;
return true;
}
// TODO pixmap clipping
return false;
}
};
BAN::Variant<Cursor, Window, Pixmap, GraphicsContext> object;

View File

@ -222,6 +222,10 @@ static BAN::ErrorOr<void> extension_shm(Client& client_info, BAN::ConstByteSpan
auto& object = TRY_REF(get_drawable(request.drawable));
auto [out_data, out_w, out_h, out_depth] = get_drawable_info(object);
auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext);
auto& gc = gc_object.object.get<Object::GraphicsContext>();
put_image({
.out_data = out_data.data(),
.out_x = request.dstX,
@ -239,6 +243,7 @@ static BAN::ErrorOr<void> extension_shm(Client& client_info, BAN::ConstByteSpan
.h = request.srcHeight,
.left_pad = 0,
.format = request.format,
.gc = gc,
});
if (object.type == Object::Type::Window)

View File

@ -52,6 +52,7 @@ void put_image(const PutImageInfo& info)
for (size_t i = 0; i < info.in_depth; i++)
if (in_data_u32[dword + i * dwords_per_plane] & bit_mask)
pixel |= 1u << i;
if (!info.gc.is_clipped(x, y))
out_data_u32[dst_off + x] = pixel;
}
}
@ -60,7 +61,7 @@ void put_image(const PutImageInfo& info)
case ZPixmap:
{
ASSERT(info.left_pad == 0);
if (in_bpp == 32)
if (in_bpp == 32 && info.gc.clip_mask == None)
{
const auto bytes_per_row = (max_x - min_x) * 4;
for (int32_t y = min_y; y < max_y; y++)
@ -82,6 +83,7 @@ void put_image(const PutImageInfo& info)
const auto bit_offset = (info.in_y + y) * bits_per_scanline + (info.in_x + x) * in_bpp;
const auto dword = bit_offset / 32;
const auto shift = bit_offset % 32;
if (!info.gc.is_clipped(x, y))
out_data_u32[dst_off + x] = (in_data_u32[dword] >> shift) & pixel_mask;
}
}

View File

@ -1,7 +1,6 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "Definitions.h"
struct PutImageInfo
{
@ -24,6 +23,8 @@ struct PutImageInfo
uint32_t left_pad;
uint8_t format;
const Object::GraphicsContext& gc;
};
struct GetImageInfo