commit 554f827

shrub  ·  2026-08-13 13:33:03 +0000 UTC
parent 83d1a75
implement blend
5 files changed,  +127, -6
M dumb.c
M wld.h
M dumb.c
+54, -5
  1@@ -31,6 +31,7 @@
  2 #include <xf86drm.h>
  3 
  4 #include <errno.h>
  5+#include <string.h>
  6 
  7 struct dumb_context {
  8 	struct wld_context base;
  9@@ -42,8 +43,11 @@ struct dumb_buffer {
 10 	struct wld_exporter exporter;
 11 	struct dumb_context *context;
 12 	uint32_t handle;
 13+	void *scanout;
 14+	bool shadowed;
 15 };
 16 
 17+#define BUFFER_IMPLEMENTS_FLUSH
 18 #include "interface/buffer.h"
 19 #include "interface/context.h"
 20 #define DRM_DRIVER_NAME dumb
 21@@ -105,7 +109,7 @@ static struct buffer *
 22 new_buffer(struct dumb_context *context,
 23            uint32_t width, uint32_t height,
 24            uint32_t format, uint32_t handle,
 25-           unsigned long pitch)
 26+           unsigned long pitch, bool shadowed)
 27 {
 28 	struct dumb_buffer *buffer;
 29 
 30@@ -116,6 +120,8 @@ new_buffer(struct dumb_context *context,
 31 	                  width, height, format, pitch);
 32 	buffer->context = context;
 33 	buffer->handle = handle;
 34+	buffer->scanout = NULL;
 35+	buffer->shadowed = shadowed;
 36 	buffer->exporter.export = &export;
 37 	wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
 38 
 39@@ -139,7 +145,8 @@ context_create_buffer(struct wld_context *base,
 40 		goto error0;
 41 
 42 	buffer = new_buffer(context, width, height, format,
 43-	                    create_dumb.handle, create_dumb.pitch);
 44+	                    create_dumb.handle, create_dumb.pitch,
 45+	                    flags & WLD_DRM_FLAG_SCANOUT);
 46 
 47 	if (!buffer)
 48 		goto error1;
 49@@ -175,7 +182,7 @@ context_import_buffer(struct wld_context *base,
 50 		return NULL;
 51 	}
 52 
 53-	return new_buffer(context, width, height, format, handle, pitch);
 54+	return new_buffer(context, width, height, format, handle, pitch, false);
 55 }
 56 
 57 void
 58@@ -209,20 +216,62 @@ buffer_map(struct buffer *base)
 59 	if (data == MAP_FAILED)
 60 		return false;
 61 
 62-	buffer->base.base.map = data;
 63+	buffer->scanout = data;
 64+	if (buffer->shadowed) {
 65+		buffer->base.base.map = calloc(buffer->base.base.height,
 66+		                               buffer->base.base.pitch);
 67+		if (!buffer->base.base.map) {
 68+			munmap(data, buffer->base.base.pitch * buffer->base.base.height);
 69+			buffer->scanout = NULL;
 70+			return false;
 71+		}
 72+	} else {
 73+		buffer->base.base.map = data;
 74+	}
 75 
 76 	return true;
 77 }
 78 
 79+void
 80+buffer_flush(struct buffer *base)
 81+{
 82+	struct dumb_buffer *buffer = dumb_buffer(&base->base);
 83+	pixman_box32_t *boxes;
 84+	int count;
 85+
 86+	if (!buffer->shadowed || !buffer->scanout)
 87+		return;
 88+
 89+	boxes = pixman_region32_rectangles(&base->base.damage, &count);
 90+	while (count--) {
 91+		int32_t y;
 92+		size_t offset = (size_t)boxes->y1 * base->base.pitch +
 93+		                (size_t)boxes->x1 * 4;
 94+		size_t size = (size_t)(boxes->x2 - boxes->x1) * 4;
 95+
 96+		for (y = boxes->y1; y < boxes->y2; ++y) {
 97+			memcpy((uint8_t *)buffer->scanout + offset,
 98+			       (uint8_t *)base->base.map + offset, size);
 99+			offset += base->base.pitch;
100+		}
101+		++boxes;
102+	}
103+}
104+
105 bool
106 buffer_unmap(struct buffer *buffer)
107 {
108-	if (munmap(buffer->base.map,
109+	struct dumb_buffer *dumb = dumb_buffer(&buffer->base);
110+
111+	if (munmap(dumb->scanout,
112 	           buffer->base.pitch * buffer->base.height)
113 	    == -1) {
114 		return false;
115 	}
116 
117+	if (dumb->shadowed)
118+		free(buffer->base.map);
119+	dumb->scanout = NULL;
120 	buffer->base.map = NULL;
121 
122 	return true;
+6, -0
 1@@ -23,10 +23,16 @@
 2 
 3 static bool buffer_map(struct buffer *drawable);
 4 static bool buffer_unmap(struct buffer *drawable);
 5+#ifdef BUFFER_IMPLEMENTS_FLUSH
 6+static void buffer_flush(struct buffer *drawable);
 7+#endif
 8 static void buffer_destroy(struct buffer *drawable);
 9 
10 static const struct wld_buffer_impl wld_buffer_impl = {
11 	.map = &buffer_map,
12 	.unmap = &buffer_unmap,
13+#ifdef BUFFER_IMPLEMENTS_FLUSH
14+	.flush = &buffer_flush,
15+#endif
16 	.destroy = &buffer_destroy
17 };
+61, -1
 1@@ -99,7 +99,11 @@ wld_set_target_surface(struct wld_renderer *renderer, struct wld_surface *surfac
 2 	if (!(back_buffer = surface->impl->back(surface)))
 3 		return false;
 4 
 5-	return renderer->impl->set_target(renderer, back_buffer);
 6+	if (!renderer->impl->set_target(renderer, back_buffer))
 7+		return false;
 8+
 9+	renderer->target = &back_buffer->base;
10+	return true;
11 }
12 
13 EXPORT
14@@ -139,6 +143,58 @@ wld_copy_region(struct wld_renderer *renderer,
15 	                            dst_x, dst_y, region);
16 }
17 
18+EXPORT
19+void
20+wld_blend_region(struct wld_renderer *renderer, struct wld_buffer *buffer,
21+                 int32_t dst_x, int32_t dst_y, pixman_region32_t *region)
22+{
23+	pixman_image_t *src = NULL, *dst = NULL;
24+	pixman_region32_t clip;
25+	pixman_box32_t *extents;
26+
27+	if (!renderer->target || !pixman_region32_not_empty(region))
28+		return;
29+
30+	/* Complete accelerator writes before accessing the buffers on the CPU. */
31+	renderer->impl->flush(renderer);
32+	if (!wld_map(buffer))
33+		return;
34+	if (!wld_map(renderer->target))
35+		goto unmap_src;
36+
37+	src = pixman_image_create_bits(format_wld_to_pixman(buffer->format),
38+	                               buffer->width, buffer->height,
39+	                               buffer->map, buffer->pitch);
40+	dst = pixman_image_create_bits(format_wld_to_pixman(renderer->target->format),
41+	                               renderer->target->width,
42+	                               renderer->target->height,
43+	                               renderer->target->map,
44+	                               renderer->target->pitch);
45+	if (!src || !dst)
46+		goto destroy;
47+
48+	pixman_region32_init(&clip);
49+	pixman_region32_copy(&clip, region);
50+	pixman_region32_translate(&clip, dst_x, dst_y);
51+	extents = pixman_region32_extents(region);
52+	pixman_image_set_clip_region32(dst, &clip);
53+	pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
54+	                         extents->x1, extents->y1, 0, 0,
55+	                         extents->x1 + dst_x, extents->y1 + dst_y,
56+	                         extents->x2 - extents->x1,
57+	                         extents->y2 - extents->y1);
58+	pixman_region32_fini(&clip);
59+
60+destroy:
61+	if (src)
62+		pixman_image_unref(src);
63+	if (dst)
64+		pixman_image_unref(dst);
65+	wld_unmap(renderer->target);
66+unmap_src:
67+	wld_unmap(buffer);
68+}
69+
70 
71 /* https://en.wikipedia.org/wiki/Midpoint_circle_algorithm */
72 static void
73@@ -235,5 +291,9 @@ void
74 wld_flush(struct wld_renderer *renderer)
75 {
76 	renderer->impl->flush(renderer);
77+	if (renderer->target && ((struct buffer *)renderer->target)->base.impl->flush)
78+		((struct buffer *)renderer->target)->base.impl->flush(
79+		    (struct buffer *)renderer->target);
80 	renderer->impl->set_target(renderer, NULL);
81+	renderer->target = NULL;
82 }
+1, -0
1@@ -131,6 +131,7 @@ struct buffer {
2 struct wld_buffer_impl {
3 	bool (*map)(struct buffer *buffer);
4 	bool (*unmap)(struct buffer *buffer);
5+	void (*flush)(struct buffer *buffer);
6 	void (*destroy)(struct buffer *buffer);
7 };
8 
M wld.h
+5, -0
 1@@ -253,6 +253,11 @@ void wld_copy_region(struct wld_renderer *renderer,
 2                      struct wld_buffer *buffer,
 3                      int32_t dst_x, int32_t dst_y, pixman_region32_t *region);
 4 
 5+void wld_blend_region(struct wld_renderer *renderer,
 6+                      struct wld_buffer *buffer,
 7+                      int32_t dst_x, int32_t dst_y,
 8+                      pixman_region32_t *region);
 9+
10 void wld_draw_circle(struct wld_renderer *renderer, uint32_t color,
11 				int32_t x, int32_t y, uint32_t r, bool fill);
12