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(" gc {}", request.gc);
dprintln(" mask {8h}", request.mask); dprintln(" mask {8h}", request.mask);
// TODO: support invisible background
uint32_t foreground = 0x000000; uint32_t foreground = 0x000000;
uint32_t background = 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++) for (size_t i = 0; i < 32; i++)
{ {
if (!((request.mask >> i) & 1)) if (!((request.mask >> i) & 1))
@ -2487,6 +2492,18 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" background: {8h}", value); dprintln(" background: {8h}", value);
background = value; background = value;
break; 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: default:
dprintln(" {8h}: {8h}", 1 << i, value); dprintln(" {8h}: {8h}", 1 << i, value);
break; break;
@ -2499,6 +2516,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.object = Object::GraphicsContext { .object = Object::GraphicsContext {
.foreground = foreground, .foreground = foreground,
.background = background, .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(); auto request = decode<xChangeGCReq>(packet).value();
dprintln("ChangeGC"); dprintln("ChangeGC");
dprintln(" gc {}", request.gc); dprintln(" gc: {}", request.gc);
dprintln(" mask {8h}", request.mask); dprintln(" mask: {8h}", request.mask);
auto& object = *g_objects[request.gc]; auto& object = *g_objects[request.gc];
ASSERT(object.type == Object::Type::GraphicsContext); ASSERT(object.type == Object::Type::GraphicsContext);
auto& gc = object.object.get<Object::GraphicsContext>(); auto& gc = object.object.get<Object::GraphicsContext>();
// TODO: support invisible background
for (size_t i = 0; i < 32; i++) for (size_t i = 0; i < 32; i++)
{ {
if (!((request.mask >> i) & 1)) if (!((request.mask >> i) & 1))
@ -2533,6 +2555,19 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" background: {8h}", value); dprintln(" background: {8h}", value);
gc.background = value; gc.background = value;
break; 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: default:
dprintln(" {8h}: {8h}", 1 << i, value); dprintln(" {8h}: {8h}", 1 << i, value);
break; break;
@ -2541,6 +2576,34 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
break; 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: case X_FreeGC:
{ {
const CARD32 gc = packet.as_span<const uint32_t>()[1]; 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("CopyArea");
dprintln(" srcDrawable: {}", request.srcDrawable); dprintln(" srcDrawable: {}", request.srcDrawable);
dprintln(" dstDrawable: {}", request.dstDrawable); dprintln(" dstDrawable: {}", request.dstDrawable);
dprintln(" gc: {}", request.gc);
dprintln(" srcX: {}", request.srcX); dprintln(" srcX: {}", request.srcX);
dprintln(" srcY: {}", request.srcY); dprintln(" srcY: {}", request.srcY);
dprintln(" dstX: {}", request.dstX); 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_drawable = TRY_REF(get_drawable(request.dstDrawable));
auto [dst_data, dst_w, dst_h, dst_depth] = get_drawable_info(dst_drawable); 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 = const auto get_pixel =
[&](int32_t x, int32_t y) -> uint32_t [&](int32_t x, int32_t y) -> uint32_t
{ {
@ -2673,7 +2741,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
continue; continue;
if (dst_x < 0 || dst_x >= dst_w) if (dst_x < 0 || dst_x >= dst_w)
continue; continue;
set_pixel(dst_x, dst_y, get_pixel(src_x, src_y)); 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]; auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext); 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; const auto foreground = gc_object.object.get<Object::GraphicsContext>().foreground;
@ -2715,7 +2785,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto* data_u32 = data.as_span<uint32_t>().data(); auto* data_u32 = data.as_span<uint32_t>().data();
for (int32_t y = min_y; y < max_y; y++) for (int32_t y = min_y; y < max_y; y++)
for (int32_t x = min_x; x < max_x; x++) for (int32_t x = min_x; x < max_x; x++)
data_u32[y * w + x] = foreground; if (!gc.is_clipped(x, y))
data_u32[y * w + x] = foreground;
if (drawable.type == Object::Type::Window) if (drawable.type == Object::Type::Window)
invalidate_window(request.drawable, min_x, min_y, max_x - min_x, max_y - min_y); invalidate_window(request.drawable, min_x, min_y, max_x - min_x, max_y - min_y);
@ -2733,6 +2804,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
auto& gc_object = *g_objects[request.gc]; auto& gc_object = *g_objects[request.gc];
ASSERT(gc_object.type == Object::Type::GraphicsContext); 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; const auto foreground = gc_object.object.get<Object::GraphicsContext>().foreground;
@ -2805,7 +2877,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
} }
} }
texture.set_pixel(x, y, foreground); 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 #if 0
dprintln("PutImage"); dprintln("PutImage");
dprintln(" drawable: {}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc);
dprintln(" format: {}", request.format); dprintln(" format: {}", request.format);
dprintln(" depth: {}", request.depth); dprintln(" depth: {}", request.depth);
dprintln(" dstX: {}", request.dstX); 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& object = TRY_REF(get_drawable(request.drawable));
auto [out_data, out_w, out_h, out_depth] = get_drawable_info(object); 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()) if (packet.empty())
{ {
dwarnln("no data in PutImage"); dwarnln("no data in PutImage");
@ -2855,6 +2933,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.h = request.height, .h = request.height,
.left_pad = request.leftPad, .left_pad = request.leftPad,
.format = request.format, .format = request.format,
.gc = gc,
}); });
if (object.type == Object::Type::Window) if (object.type == Object::Type::Window)

View File

@ -107,6 +107,30 @@ struct Object
{ {
uint32_t foreground; uint32_t foreground;
uint32_t background; 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; 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& object = TRY_REF(get_drawable(request.drawable));
auto [out_data, out_w, out_h, out_depth] = get_drawable_info(object); 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({ put_image({
.out_data = out_data.data(), .out_data = out_data.data(),
.out_x = request.dstX, .out_x = request.dstX,
@ -239,6 +243,7 @@ static BAN::ErrorOr<void> extension_shm(Client& client_info, BAN::ConstByteSpan
.h = request.srcHeight, .h = request.srcHeight,
.left_pad = 0, .left_pad = 0,
.format = request.format, .format = request.format,
.gc = gc,
}); });
if (object.type == Object::Type::Window) if (object.type == Object::Type::Window)

View File

@ -52,7 +52,8 @@ void put_image(const PutImageInfo& info)
for (size_t i = 0; i < info.in_depth; i++) for (size_t i = 0; i < info.in_depth; i++)
if (in_data_u32[dword + i * dwords_per_plane] & bit_mask) if (in_data_u32[dword + i * dwords_per_plane] & bit_mask)
pixel |= 1u << i; pixel |= 1u << i;
out_data_u32[dst_off + x] = pixel; if (!info.gc.is_clipped(x, y))
out_data_u32[dst_off + x] = pixel;
} }
} }
break; break;
@ -60,7 +61,7 @@ void put_image(const PutImageInfo& info)
case ZPixmap: case ZPixmap:
{ {
ASSERT(info.left_pad == 0); 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; const auto bytes_per_row = (max_x - min_x) * 4;
for (int32_t y = min_y; y < max_y; y++) for (int32_t y = min_y; y < max_y; y++)
@ -82,7 +83,8 @@ 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 bit_offset = (info.in_y + y) * bits_per_scanline + (info.in_x + x) * in_bpp;
const auto dword = bit_offset / 32; const auto dword = bit_offset / 32;
const auto shift = bit_offset % 32; const auto shift = bit_offset % 32;
out_data_u32[dst_off + x] = (in_data_u32[dword] >> shift) & pixel_mask; 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 #pragma once
#include <stdint.h> #include "Definitions.h"
#include <stddef.h>
struct PutImageInfo struct PutImageInfo
{ {
@ -24,6 +23,8 @@ struct PutImageInfo
uint32_t left_pad; uint32_t left_pad;
uint8_t format; uint8_t format;
const Object::GraphicsContext& gc;
}; };
struct GetImageInfo struct GetImageInfo