commit d33c804
hovercats
·
2026-04-16 04:44:32 +0000 UTC
parent 505dc1c
wld: add wip patches for better font rendering
4 files changed,
+464,
-1
+1,
-0
1@@ -167,6 +167,7 @@
2 [submodule "pkg/wld/src"]
3 path = pkg/wld/src
4 url = https://github.com/michaelforney/wld
5+ ignore = all
6 [submodule "pkg/wayland-protocols/src"]
7 path = pkg/wayland-protocols/src
8 url = https://gitlab.freedesktop.org/wayland/wayland-protocols.git
1@@ -0,0 +1,296 @@
2+From f3798978fc437ef7c6f62cc5be226332bc73a3e2 Mon Sep 17 00:00:00 2001
3+From: shrub <maybeshrub@gmail.com>
4+Date: Sun, 1 Feb 2026 18:24:41 +0000
5+Subject: [PATCH] text: support grayscale freetype glyphs
6+
7+---
8+ font.c | 5 ++--
9+ intel.c | 26 +++++++++++++++++--
10+ nouveau.c | 72 +++++++++++++++++++++++++++++++++++++++++++---------
11+ pixman.c | 76 ++++++++++++++++++++++++++++++++++++++++---------------
12+ 4 files changed, 142 insertions(+), 37 deletions(-)
13+
14+diff --git a/font.c b/font.c
15+index 41fd9ca..cbb187c 100644
16+--- a/font.c
17++++ b/font.c
18+@@ -172,7 +172,8 @@ font_ensure_glyph(struct font *font, FT_UInt glyph_index)
19+ if (!glyph)
20+ return false;
21+
22+- FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO);
23++ FT_Load_Glyph(font->face, glyph_index,
24++ FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
25+
26+ FT_Bitmap_New(&glyph->bitmap);
27+
28+@@ -217,7 +218,7 @@ wld_font_text_extents_n(struct wld_font *font_base,
29+
30+ extents->advance = 0;
31+
32+- while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length) > 0) && c != '\0') {
33++ while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length)) > 0 && c != '\0') {
34+ length -= ret;
35+ text += ret;
36+ glyph_index = FT_Get_Char_Index(font->face, c);
37+diff --git a/intel.c b/intel.c
38+index 95624e9..8cf0a21 100644
39+--- a/intel.c
40++++ b/intel.c
41+@@ -29,6 +29,7 @@
42+
43+ #include <i915_drm.h>
44+ #include <intel_bufmgr.h>
45++#include <string.h>
46+ #include <unistd.h>
47+
48+ struct intel_context {
49+@@ -57,6 +58,20 @@ IMPL(intel_context, wld_context)
50+ IMPL(intel_renderer, wld_renderer)
51+ IMPL(intel_buffer, wld_buffer)
52+
53++static void
54++pack_gray_row_to_mono(uint8_t *dst, const uint8_t *src, uint32_t width)
55++{
56++ uint32_t x, bytes_per_row;
57++
58++ bytes_per_row = (width + 7) / 8;
59++ memset(dst, 0, bytes_per_row);
60++
61++ for (x = 0; x < width; ++x) {
62++ if (src[x] >= 128)
63++ dst[x / 8] |= 0x80 >> (x & 7);
64++ }
65++}
66++
67+ /**** DRM driver ****/
68+ bool
69+ driver_device_supported(uint32_t vendor_id, uint32_t device_id)
70+@@ -315,8 +330,15 @@ renderer_draw_text(struct wld_renderer *base,
71+
72+ /* XY_TEXT_IMMEDIATE requires a pitch with no extra bytes */
73+ for (row = 0; row < glyph->bitmap.rows; ++row) {
74+- memcpy(byte, glyph->bitmap.buffer + (row * glyph->bitmap.pitch),
75+- (glyph->bitmap.width + 7) / 8);
76++ const uint8_t *src = glyph->bitmap.buffer +
77++ (row * glyph->bitmap.pitch);
78++ uint32_t bytes_per_row = (glyph->bitmap.width + 7) / 8;
79++
80++ if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
81++ memcpy(byte, src, bytes_per_row);
82++ } else {
83++ pack_gray_row_to_mono(byte, src, glyph->bitmap.width);
84++ }
85+ byte += (glyph->bitmap.width + 7) / 8;
86+ }
87+
88+diff --git a/nouveau.c b/nouveau.c
89+index 6742f25..6bd7ab1 100644
90+--- a/nouveau.c
91++++ b/nouveau.c
92+@@ -34,6 +34,7 @@
93+ #include "pixman.h"
94+
95+ #include <nouveau.h>
96++#include <string.h>
97+ #include <sys/mman.h>
98+
99+ enum nv_architecture {
100+@@ -75,6 +76,20 @@ IMPL(nouveau_context, wld_context)
101+ IMPL(nouveau_renderer, wld_renderer)
102+ IMPL(nouveau_buffer, wld_buffer)
103+
104++static void
105++pack_gray_row_to_mono(uint8_t *dst, const uint8_t *src, uint32_t width)
106++{
107++ uint32_t x, bytes_per_row;
108++
109++ bytes_per_row = (width + 7) / 8;
110++ memset(dst, 0, bytes_per_row);
111++
112++ for (x = 0; x < width; ++x) {
113++ if (src[x] >= 128)
114++ dst[x / 8] |= 0x80 >> (x & 7);
115++ }
116++}
117++
118+ /**** DRM driver ****/
119+ bool
120+ driver_device_supported(uint32_t vendor_id, uint32_t device_id)
121+@@ -594,22 +609,55 @@ renderer_draw_text(struct wld_renderer *base,
122+ if (glyph->bitmap.width == 0 || glyph->bitmap.rows == 0)
123+ goto advance;
124+
125+- count = (glyph->bitmap.pitch * glyph->bitmap.rows + 3) / 4;
126++ if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
127++ count = (glyph->bitmap.pitch * glyph->bitmap.rows + 3) / 4;
128++ } else {
129++ uint32_t bytes_per_row = (glyph->bitmap.width + 7) / 8;
130++ count = (bytes_per_row * glyph->bitmap.rows + 3) / 4;
131++ }
132+
133+ if (!ensure_space(renderer->pushbuf, 12 + count))
134+ return;
135+
136+- nvc0_2d(renderer->pushbuf, G80_2D_SIFC_WIDTH, 10,
137+- /* Use the pitch instead of width to ensure the correct
138+- * alignment is used. */
139+- glyph->bitmap.pitch * 8, glyph->bitmap.rows,
140+- 0, 1, 0, 1,
141+- 0, origin_x + glyph->x, 0, y + glyph->y);
142+- nv_add_dword(renderer->pushbuf,
143+- nvc0_command(GF100_COMMAND_TYPE_NON_INCREASING,
144+- GF100_SUBCHANNEL_2D,
145+- G80_2D_SIFC_DATA, count));
146+- nv_add_data(renderer->pushbuf, glyph->bitmap.buffer, count);
147++ if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
148++ nvc0_2d(renderer->pushbuf, G80_2D_SIFC_WIDTH, 10,
149++ /* Use the pitch instead of width to ensure the correct
150++ * alignment is used. */
151++ glyph->bitmap.pitch * 8, glyph->bitmap.rows,
152++ 0, 1, 0, 1,
153++ 0, origin_x + glyph->x, 0, y + glyph->y);
154++ nv_add_dword(renderer->pushbuf,
155++ nvc0_command(GF100_COMMAND_TYPE_NON_INCREASING,
156++ GF100_SUBCHANNEL_2D,
157++ G80_2D_SIFC_DATA, count));
158++ nv_add_data(renderer->pushbuf, glyph->bitmap.buffer, count);
159++ } else {
160++ uint32_t bytes_per_row = (glyph->bitmap.width + 7) / 8;
161++ uint32_t row;
162++ uint8_t *mono = malloc(bytes_per_row * glyph->bitmap.rows);
163++ uint8_t *dst = mono;
164++
165++ if (!mono)
166++ return;
167++
168++ for (row = 0; row < glyph->bitmap.rows; ++row) {
169++ const uint8_t *src = glyph->bitmap.buffer +
170++ (row * glyph->bitmap.pitch);
171++ pack_gray_row_to_mono(dst, src, glyph->bitmap.width);
172++ dst += bytes_per_row;
173++ }
174++
175++ nvc0_2d(renderer->pushbuf, G80_2D_SIFC_WIDTH, 10,
176++ bytes_per_row * 8, glyph->bitmap.rows,
177++ 0, 1, 0, 1,
178++ 0, origin_x + glyph->x, 0, y + glyph->y);
179++ nv_add_dword(renderer->pushbuf,
180++ nvc0_command(GF100_COMMAND_TYPE_NON_INCREASING,
181++ GF100_SUBCHANNEL_2D,
182++ G80_2D_SIFC_DATA, count));
183++ nv_add_data(renderer->pushbuf, mono, count);
184++ free(mono);
185++ }
186+
187+ advance:
188+ origin_x += glyph->advance;
189+diff --git a/pixman.c b/pixman.c
190+index bd95f8b..3012ecd 100644
191+--- a/pixman.c
192++++ b/pixman.c
193+@@ -24,6 +24,8 @@
194+ #include "pixman.h"
195+ #include "wld-private.h"
196+
197++#include <string.h>
198++
199+ #define PIXMAN_COLOR(c) \
200+ { \
201+ .alpha = ((c >> 24) & 0xff) * 0x101, \
202+@@ -344,6 +346,58 @@ reverse(uint8_t byte)
203+ return byte;
204+ }
205+
206++static pixman_image_t *
207++glyph_bitmap_to_pixman_image(struct glyph *glyph)
208++{
209++ FT_Bitmap *bitmap = &glyph->bitmap;
210++ pixman_image_t *image;
211++ uint8_t *src, *dst;
212++ uint32_t row, byte_index, bytes_per_row, pitch;
213++
214++ switch (bitmap->pixel_mode) {
215++ case FT_PIXEL_MODE_MONO:
216++ image = pixman_image_create_bits(PIXMAN_a1, bitmap->width,
217++ bitmap->rows, NULL, bitmap->pitch);
218++ if (!image)
219++ return NULL;
220++
221++ pitch = pixman_image_get_stride(image);
222++ bytes_per_row = (bitmap->width + 7) / 8;
223++ src = bitmap->buffer;
224++ dst = (uint8_t *)pixman_image_get_data(image);
225++
226++ for (row = 0; row < bitmap->rows; ++row) {
227++ /* Pixman's A1 format expects the bits in the opposite order
228++ * that Freetype gives us. */
229++ for (byte_index = 0; byte_index < bytes_per_row; ++byte_index)
230++ dst[byte_index] = reverse(src[byte_index]);
231++
232++ dst += pitch;
233++ src += bitmap->pitch;
234++ }
235++ return image;
236++ case FT_PIXEL_MODE_GRAY:
237++ image = pixman_image_create_bits(PIXMAN_a8, bitmap->width,
238++ bitmap->rows, NULL, 0);
239++ if (!image)
240++ return NULL;
241++
242++ pitch = pixman_image_get_stride(image);
243++ src = bitmap->buffer;
244++ dst = (uint8_t *)pixman_image_get_data(image);
245++
246++ for (row = 0; row < bitmap->rows; ++row) {
247++ memset(dst, 0, pitch);
248++ memcpy(dst, src, bitmap->width);
249++ dst += pitch;
250++ src += bitmap->pitch;
251++ }
252++ return image;
253++ default:
254++ return NULL;
255++ }
256++}
257++
258+ void
259+ renderer_draw_text(struct wld_renderer *base,
260+ struct font *font, uint32_t color,
261+@@ -385,32 +439,12 @@ renderer_draw_text(struct wld_renderer *base,
262+ /* If we don't have the glyph in our cache, do some conversions to make
263+ * pixman happy, and then insert it. */
264+ if (!glyphs[index].glyph) {
265+- uint8_t *src, *dst;
266+- uint32_t row, byte_index, bytes_per_row, pitch;
267+ pixman_image_t *image;
268+- FT_Bitmap *bitmap;
269+-
270+- bitmap = &glyph->bitmap;
271+- image = pixman_image_create_bits(PIXMAN_a1, bitmap->width, bitmap->rows, NULL, bitmap->pitch);
272++ image = glyph_bitmap_to_pixman_image(glyph);
273+
274+ if (!image)
275+ goto advance;
276+
277+- pitch = pixman_image_get_stride(image);
278+- bytes_per_row = (bitmap->width + 7) / 8;
279+- src = bitmap->buffer;
280+- dst = (uint8_t *)pixman_image_get_data(image);
281+-
282+- for (row = 0; row < bitmap->rows; ++row) {
283+- /* Pixman's A1 format expects the bits in the opposite order
284+- * that Freetype gives us. Sigh... */
285+- for (byte_index = 0; byte_index < bytes_per_row; ++byte_index)
286+- dst[byte_index] = reverse(src[byte_index]);
287+-
288+- dst += pitch;
289+- src += bitmap->pitch;
290+- }
291+-
292+ /* Insert the glyph into the cache. */
293+ pixman_glyph_cache_freeze(renderer->glyph_cache);
294+ glyphs[index].glyph = pixman_glyph_cache_insert(renderer->glyph_cache, font, glyph,
295+--
296+2.49.0
297+
1@@ -0,0 +1,166 @@
2+From c4801596c8ecc0f6476d0bf14582d2086f531853 Mon Sep 17 00:00:00 2001
3+From: dalem <lain@dalem.foo>
4+Date: Sat, 14 Mar 2026 19:30:03 +0100
5+Subject: [PATCH] renderer: add circle and line primitives
6+
7+---
8+ interface/renderer.h | 2 +
9+ renderer.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
10+ wld-private.h | 4 ++
11+ wld.h | 6 +++
12+ 4 files changed, 107 insertions(+)
13+
14+diff --git a/interface/renderer.h b/interface/renderer.h
15+index 021aea1..0dabbfd 100644
16+--- a/interface/renderer.h
17++++ b/interface/renderer.h
18+@@ -61,6 +61,8 @@ static const struct wld_renderer_impl wld_renderer_impl = {
19+ .fill_region = &default_fill_region,
20+ .copy_region = &default_copy_region,
21+ #endif
22++ .draw_circle = &wld_draw_circle,
23++ .draw_line = &wld_draw_line,
24+ .draw_text = &renderer_draw_text,
25+ .flush = &renderer_flush,
26+ .destroy = &renderer_destroy
27+diff --git a/renderer.c b/renderer.c
28+index 569d6ba..e8a59c9 100644
29+--- a/renderer.c
30++++ b/renderer.c
31+@@ -139,6 +139,101 @@ wld_copy_region(struct wld_renderer *renderer,
32+ dst_x, dst_y, region);
33+ }
34+
35++static void
36++circle_points(struct wld_renderer *renderer, uint32_t color,
37++ int32_t x1, int32_t y1,
38++ int32_t x2, int32_t y2, bool fill)
39++{
40++ if (fill) {
41++ renderer->impl->fill_rectangle(renderer, color, x1-x2, y1+y2,
42++ 2*x2+1, 1);
43++ renderer->impl->fill_rectangle(renderer, color, x1-x2, y1-y2,
44++ 2*x2+1, 1);
45++ renderer->impl->fill_rectangle(renderer, color, x1-y2, y1+x2,
46++ 2*y2+1, 1);
47++ renderer->impl->fill_rectangle(renderer, color, x1-y2, y1-x2,
48++ 2*y2+1, 1);
49++ } else {
50++ renderer->impl->fill_rectangle(renderer, color, x1+x2, y1+y2, 1, 1);
51++ renderer->impl->fill_rectangle(renderer, color, x1-x2, y1+y2, 1, 1);
52++ renderer->impl->fill_rectangle(renderer, color, x1+x2, y1-y2, 1, 1);
53++ renderer->impl->fill_rectangle(renderer, color, x1-x2, y1-y2, 1, 1);
54++ renderer->impl->fill_rectangle(renderer, color, x1+y2, y1+x2, 1, 1);
55++ renderer->impl->fill_rectangle(renderer, color, x1-y2, y1+x2, 1, 1);
56++ renderer->impl->fill_rectangle(renderer, color, x1+y2, y1-x2, 1, 1);
57++ renderer->impl->fill_rectangle(renderer, color, x1-y2, y1-x2, 1, 1);
58++ }
59++}
60++
61++EXPORT
62++void
63++wld_draw_circle(struct wld_renderer *renderer, uint32_t color,
64++ int32_t x1, int32_t y1,
65++ uint32_t r, bool fill)
66++{
67++ int32_t x2 = 0, y2 = r;
68++ int32_t d = 3 - (2*r);
69++
70++ circle_points(renderer, color, x1, y1, x2, y2, fill);
71++
72++ while (y2 >= x2) {
73++ if (d > 0) {
74++ y2--;
75++ d = d + 4*(x2-y2) + 10;
76++ }
77++ else
78++ d = d + 4*x2 + 6;
79++
80++ x2++;
81++
82++ circle_points(renderer, color, x1, y1, x2, y2, fill);
83++ }
84++}
85++
86++
87++EXPORT
88++void
89++wld_draw_line(struct wld_renderer *renderer, uint32_t color,
90++ int32_t x1, int32_t y1,
91++ int32_t x2, int32_t y2)
92++{
93++ int32_t dx = abs(x2-x1), sx = x1 < x2 ? 1 : -1;
94++ int32_t dy = -abs(y2-y1), sy = y1 < y2 ? 1 : -1;
95++ int32_t err = dx + dy, e2;
96++
97++ /* just use fill_rectangle for purely vertical and horizontal line */
98++ if (y1 == y2) {
99++ int32_t lx = sx > 0 ? x1 : x2;
100++ renderer->impl->fill_rectangle(renderer, color, lx, y1, dx + 1, 1);
101++ return;
102++ }
103++
104++ if (x1 == x2) {
105++ int32_t ly = sy > 0 ? y1 : y2;
106++ renderer->impl->fill_rectangle(renderer, color, x1, ly, 1, -dy + 1);
107++ return;
108++ }
109++
110++ while (true) {
111++ renderer->impl->fill_rectangle(renderer, color, x1, y1, 1, 1);
112++
113++ if (x1 == x2 && y1 == y2)
114++ break;
115++
116++ e2 = 2 * err;
117++
118++ if (e2 >= dy) {
119++ err += dy;
120++ x1 += sx;
121++ }
122++
123++ if (e2 <= dx) {
124++ err += dx;
125++ y1 += sy;
126++ }
127++ }
128++}
129++
130+ EXPORT
131+ void
132+ wld_draw_text(struct wld_renderer *renderer,
133+diff --git a/wld-private.h b/wld-private.h
134+index 5bdaed3..0953edb 100644
135+--- a/wld-private.h
136++++ b/wld-private.h
137+@@ -108,6 +108,10 @@ struct wld_renderer_impl {
138+ void (*copy_region)(struct wld_renderer *renderer, struct buffer *src,
139+ int32_t dst_x, int32_t dst_y,
140+ pixman_region32_t *region);
141++ void (*draw_circle)(struct wld_renderer *renderer, uint32_t color,
142++ int32_t x1, int32_t y1, uint32_t r, bool fill);
143++ void (*draw_line)(struct wld_renderer *renderer, uint32_t color,
144++ int32_t x1, int32_t y1, int32_t x2, int32_t y2);
145+ void (*draw_text)(struct wld_renderer *renderer,
146+ struct font *font, uint32_t color,
147+ int32_t x, int32_t y, const char *text, uint32_t length,
148+diff --git a/wld.h b/wld.h
149+index 9eabdd6..b1c53c6 100644
150+--- a/wld.h
151++++ b/wld.h
152+@@ -249,6 +249,12 @@ void wld_copy_rectangle(struct wld_renderer *renderer,
153+ int32_t src_x, int32_t src_y,
154+ uint32_t width, uint32_t height);
155+
156++void wld_draw_circle(struct wld_renderer *renderer, uint32_t color,
157++ int32_t x1, int32_t y1, uint32_t r, bool fill);
158++
159++void wld_draw_line(struct wld_renderer *renderer, uint32_t color,
160++ int32_t x1, int32_t y1, int32_t x2, int32_t y2);
161++
162+ void wld_copy_region(struct wld_renderer *renderer,
163+ struct wld_buffer *buffer,
164+ int32_t dst_x, int32_t dst_y, pixman_region32_t *region);
165+--
166+2.49.0
167+
+1,
-1
1@@ -1 +1 @@
2-3fe15e769c r0
3+3fe15e769c r1