aboutsummaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2022-05-29 11:50:47 +0200
committerSimon Ser <contact@emersion.fr>2022-08-12 08:41:32 +0000
commit98cf38601fdf32fdd1d40ed4a92b1f31fb75d667 (patch)
treefdb35534a2dc7439349948ffb9048d67e33115e0 /render
parent8c3c6987dbdffa74eb1fee901b4ab1d73641e29f (diff)
render: replace wlr_texture_write_pixels with update_from_buffer
This lets the renderer handle the wlr_buffer directly, just like it does in texture_from_buffer. This also allows the renderer to batch the rectangle updates, and update more than the damage region if desirable (e.g. too many rects), so can be more efficient.
Diffstat (limited to 'render')
-rw-r--r--render/gles2/texture.c46
-rw-r--r--render/vulkan/texture.c47
-rw-r--r--render/wlr_texture.c20
3 files changed, 87 insertions, 26 deletions
diff --git a/render/gles2/texture.c b/render/gles2/texture.c
index d794e436..8b4ce673 100644
--- a/render/gles2/texture.c
+++ b/render/gles2/texture.c
@@ -44,14 +44,24 @@ static bool check_stride(const struct wlr_pixel_format_info *fmt,
return true;
}
-static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
- uint32_t stride, uint32_t width, uint32_t height,
- uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
- const void *data) {
+static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture,
+ struct wlr_buffer *buffer, pixman_region32_t *damage) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
if (texture->target != GL_TEXTURE_2D || texture->image != EGL_NO_IMAGE_KHR) {
- wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture");
+ return false;
+ }
+
+ void *data;
+ uint32_t format;
+ size_t stride;
+ if (!wlr_buffer_begin_data_ptr_access(buffer,
+ WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
+ return false;
+ }
+
+ if (format != texture->drm_format) {
+ wlr_buffer_end_data_ptr_access(buffer);
return false;
}
@@ -63,7 +73,8 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
drm_get_pixel_format_info(texture->drm_format);
assert(drm_fmt);
- if (!check_stride(drm_fmt, stride, width)) {
+ if (!check_stride(drm_fmt, stride, buffer->width)) {
+ wlr_buffer_end_data_ptr_access(buffer);
return false;
}
@@ -75,12 +86,21 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
glBindTexture(GL_TEXTURE_2D, texture->tex);
- glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8));
- glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x);
- glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y);
+ int rects_len = 0;
+ pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len);
- glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
- fmt->gl_format, fmt->gl_type, data);
+ for (int i = 0; i < rects_len; i++) {
+ pixman_box32_t rect = rects[i];
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8));
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1);
+
+ int width = rect.x2 - rect.x1;
+ int height = rect.y2 - rect.y1;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height,
+ fmt->gl_format, fmt->gl_type, data);
+ }
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
@@ -92,6 +112,8 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
wlr_egl_restore_context(&prev_ctx);
+ wlr_buffer_end_data_ptr_access(buffer);
+
return true;
}
@@ -156,7 +178,7 @@ static void gles2_texture_unref(struct wlr_texture *wlr_texture) {
}
static const struct wlr_texture_impl texture_impl = {
- .write_pixels = gles2_texture_write_pixels,
+ .update_from_buffer = gles2_texture_update_from_buffer,
.destroy = gles2_texture_unref,
};
diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c
index 35b9562e..88298d93 100644
--- a/render/vulkan/texture.c
+++ b/render/vulkan/texture.c
@@ -136,12 +136,45 @@ static bool write_pixels(struct wlr_texture *wlr_texture,
return true;
}
-static bool vulkan_texture_write_pixels(struct wlr_texture *wlr_texture,
- uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x,
- uint32_t src_y, uint32_t dst_x, uint32_t dst_y, const void *vdata) {
- return write_pixels(wlr_texture, stride, width, height, src_x, src_y,
- dst_x, dst_y, vdata, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
+static bool vulkan_texture_update_from_buffer(struct wlr_texture *wlr_texture,
+ struct wlr_buffer *buffer, pixman_region32_t *damage) {
+ struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture);
+
+ void *data;
+ uint32_t format;
+ size_t stride;
+ if (!wlr_buffer_begin_data_ptr_access(buffer,
+ WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
+ return false;
+ }
+
+ bool ok = true;
+
+ if (format != texture->format->drm_format) {
+ ok = false;
+ goto out;
+ }
+
+ int rects_len = 0;
+ pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len);
+
+ for (int i = 0; i < rects_len; i++) {
+ pixman_box32_t rect = rects[i];
+ uint32_t width = rect.x2 - rect.x1;
+ uint32_t height = rect.y2 - rect.y1;
+
+ // TODO: only map memory once
+ ok = write_pixels(wlr_texture, stride, width, height, rect.x1, rect.y1,
+ rect.x1, rect.y1, data, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
+ if (!ok) {
+ goto out;
+ }
+ }
+
+out:
+ wlr_buffer_end_data_ptr_access(buffer);
+ return ok;
}
void vulkan_texture_destroy(struct wlr_vk_texture *texture) {
@@ -191,7 +224,7 @@ static void vulkan_texture_unref(struct wlr_texture *wlr_texture) {
}
static const struct wlr_texture_impl texture_impl = {
- .write_pixels = vulkan_texture_write_pixels,
+ .update_from_buffer = vulkan_texture_update_from_buffer,
.destroy = vulkan_texture_unref,
};
diff --git a/render/wlr_texture.c b/render/wlr_texture.c
index fa864d02..7a59af30 100644
--- a/render/wlr_texture.c
+++ b/render/wlr_texture.c
@@ -71,13 +71,19 @@ struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer,
return renderer->impl->texture_from_buffer(renderer, buffer);
}
-bool wlr_texture_write_pixels(struct wlr_texture *texture,
- uint32_t stride, uint32_t width, uint32_t height,
- uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
- const void *data) {
- if (!texture->impl->write_pixels) {
+bool wlr_texture_update_from_buffer(struct wlr_texture *texture,
+ struct wlr_buffer *buffer, pixman_region32_t *damage) {
+ if (!texture->impl->update_from_buffer) {
+ return false;
+ }
+ if (texture->width != (uint32_t)buffer->width ||
+ texture->height != (uint32_t)buffer->height) {
+ return false;
+ }
+ const pixman_box32_t *extents = pixman_region32_extents(damage);
+ if (extents->x1 < 0 || extents->y1 < 0 || extents->x2 > buffer->width ||
+ extents->y2 > buffer->height) {
return false;
}
- return texture->impl->write_pixels(texture, stride, width, height,
- src_x, src_y, dst_x, dst_y, data);
+ return texture->impl->update_from_buffer(texture, buffer, damage);
}