mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-25 22:25:58 +01:00
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.
This commit is contained in:
parent
8c3c6987db
commit
98cf38601f
7 changed files with 101 additions and 87 deletions
|
@ -54,10 +54,8 @@ void wlr_renderer_init(struct wlr_renderer *renderer,
|
||||||
const struct wlr_renderer_impl *impl);
|
const struct wlr_renderer_impl *impl);
|
||||||
|
|
||||||
struct wlr_texture_impl {
|
struct wlr_texture_impl {
|
||||||
bool (*write_pixels)(struct wlr_texture *texture,
|
bool (*update_from_buffer)(struct wlr_texture *texture,
|
||||||
uint32_t stride, uint32_t width, uint32_t height,
|
struct wlr_buffer *buffer, pixman_region32_t *damage);
|
||||||
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
|
|
||||||
const void *data);
|
|
||||||
void (*destroy)(struct wlr_texture *texture);
|
void (*destroy)(struct wlr_texture *texture);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef WLR_RENDER_WLR_TEXTURE_H
|
#ifndef WLR_RENDER_WLR_TEXTURE_H
|
||||||
#define WLR_RENDER_WLR_TEXTURE_H
|
#define WLR_RENDER_WLR_TEXTURE_H
|
||||||
|
|
||||||
|
#include <pixman.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/render/dmabuf.h>
|
#include <wlr/render/dmabuf.h>
|
||||||
|
@ -37,13 +38,17 @@ struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
|
||||||
struct wlr_dmabuf_attributes *attribs);
|
struct wlr_dmabuf_attributes *attribs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a texture with raw pixels. The texture must be mutable, and the input
|
* Update a texture with a struct wlr_buffer's contents.
|
||||||
* data must have the same pixel format that the texture was created with.
|
*
|
||||||
|
* The update might be rejected (in case the texture is immutable, the buffer
|
||||||
|
* has an unsupported type/format, etc), so callers must be prepared to fall
|
||||||
|
* back to re-creating the texture from scratch via wlr_texture_from_buffer().
|
||||||
|
*
|
||||||
|
* The damage can be used by the renderer as an optimization: only the supplied
|
||||||
|
* region needs to be updated.
|
||||||
*/
|
*/
|
||||||
bool wlr_texture_write_pixels(struct wlr_texture *texture,
|
bool wlr_texture_update_from_buffer(struct wlr_texture *texture,
|
||||||
uint32_t stride, uint32_t width, uint32_t height,
|
struct wlr_buffer *buffer, pixman_region32_t *damage);
|
||||||
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
|
|
||||||
const void *data);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the texture.
|
* Destroys the texture.
|
||||||
|
|
|
@ -151,9 +151,6 @@ struct wlr_client_buffer {
|
||||||
// private state
|
// private state
|
||||||
|
|
||||||
struct wl_listener source_destroy;
|
struct wl_listener source_destroy;
|
||||||
|
|
||||||
// If the client buffer has been created from a wl_shm buffer
|
|
||||||
uint32_t shm_source_format;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -44,14 +44,24 @@ static bool check_stride(const struct wlr_pixel_format_info *fmt,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
|
static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture,
|
||||||
uint32_t stride, uint32_t width, uint32_t height,
|
struct wlr_buffer *buffer, pixman_region32_t *damage) {
|
||||||
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
|
|
||||||
const void *data) {
|
|
||||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||||
|
|
||||||
if (texture->target != GL_TEXTURE_2D || texture->image != EGL_NO_IMAGE_KHR) {
|
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;
|
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);
|
drm_get_pixel_format_info(texture->drm_format);
|
||||||
assert(drm_fmt);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +86,21 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->tex);
|
glBindTexture(GL_TEXTURE_2D, texture->tex);
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8));
|
int rects_len = 0;
|
||||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x);
|
pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len);
|
||||||
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y);
|
|
||||||
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
|
for (int i = 0; i < rects_len; i++) {
|
||||||
fmt->gl_format, fmt->gl_type, data);
|
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_ROW_LENGTH_EXT, 0);
|
||||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS_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_egl_restore_context(&prev_ctx);
|
||||||
|
|
||||||
|
wlr_buffer_end_data_ptr_access(buffer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +178,7 @@ static void gles2_texture_unref(struct wlr_texture *wlr_texture) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wlr_texture_impl texture_impl = {
|
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,
|
.destroy = gles2_texture_unref,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -136,12 +136,45 @@ static bool write_pixels(struct wlr_texture *wlr_texture,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool vulkan_texture_write_pixels(struct wlr_texture *wlr_texture,
|
static bool vulkan_texture_update_from_buffer(struct wlr_texture *wlr_texture,
|
||||||
uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x,
|
struct wlr_buffer *buffer, pixman_region32_t *damage) {
|
||||||
uint32_t src_y, uint32_t dst_x, uint32_t dst_y, const void *vdata) {
|
struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture);
|
||||||
return write_pixels(wlr_texture, stride, width, height, src_x, src_y,
|
|
||||||
dst_x, dst_y, vdata, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
void *data;
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
|
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) {
|
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 = {
|
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,
|
.destroy = vulkan_texture_unref,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,13 +71,19 @@ struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer,
|
||||||
return renderer->impl->texture_from_buffer(renderer, buffer);
|
return renderer->impl->texture_from_buffer(renderer, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_texture_write_pixels(struct wlr_texture *texture,
|
bool wlr_texture_update_from_buffer(struct wlr_texture *texture,
|
||||||
uint32_t stride, uint32_t width, uint32_t height,
|
struct wlr_buffer *buffer, pixman_region32_t *damage) {
|
||||||
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
|
if (!texture->impl->update_from_buffer) {
|
||||||
const void *data) {
|
|
||||||
if (!texture->impl->write_pixels) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return texture->impl->write_pixels(texture, stride, width, height,
|
if (texture->width != (uint32_t)buffer->width ||
|
||||||
src_x, src_y, dst_x, dst_y, data);
|
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->update_from_buffer(texture, buffer, damage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,14 +285,6 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
|
||||||
wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy);
|
wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy);
|
||||||
client_buffer->source_destroy.notify = client_buffer_handle_source_destroy;
|
client_buffer->source_destroy.notify = client_buffer_handle_source_destroy;
|
||||||
|
|
||||||
if (buffer_is_shm_client_buffer(buffer)) {
|
|
||||||
struct wlr_shm_client_buffer *shm_client_buffer =
|
|
||||||
shm_client_buffer_from_buffer(buffer);
|
|
||||||
client_buffer->shm_source_format = shm_client_buffer->format;
|
|
||||||
} else {
|
|
||||||
client_buffer->shm_source_format = DRM_FORMAT_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the buffer will be released before being destroyed
|
// Ensure the buffer will be released before being destroyed
|
||||||
wlr_buffer_lock(&client_buffer->base);
|
wlr_buffer_lock(&client_buffer->base);
|
||||||
wlr_buffer_drop(&client_buffer->base);
|
wlr_buffer_drop(&client_buffer->base);
|
||||||
|
@ -307,46 +299,7 @@ bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint32_t)next->width != client_buffer->texture->width ||
|
return wlr_texture_update_from_buffer(client_buffer->texture, next, damage);
|
||||||
(uint32_t)next->height != client_buffer->texture->height) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client_buffer->shm_source_format == DRM_FORMAT_INVALID) {
|
|
||||||
// Uploading only damaged regions only works for wl_shm buffers and
|
|
||||||
// mutable textures (created from wl_shm buffer)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
uint32_t format;
|
|
||||||
size_t stride;
|
|
||||||
if (!wlr_buffer_begin_data_ptr_access(next, WLR_BUFFER_DATA_PTR_ACCESS_READ,
|
|
||||||
&data, &format, &stride)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format != client_buffer->shm_source_format) {
|
|
||||||
// Uploading to textures can't change the format
|
|
||||||
wlr_buffer_end_data_ptr_access(next);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n;
|
|
||||||
pixman_box32_t *rects = pixman_region32_rectangles(damage, &n);
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
pixman_box32_t *r = &rects[i];
|
|
||||||
if (!wlr_texture_write_pixels(client_buffer->texture, stride,
|
|
||||||
r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
|
|
||||||
r->x1, r->y1, data)) {
|
|
||||||
wlr_buffer_end_data_ptr_access(next);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_buffer_end_data_ptr_access(next);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wlr_buffer_impl shm_client_buffer_impl;
|
static const struct wlr_buffer_impl shm_client_buffer_impl;
|
||||||
|
|
Loading…
Reference in a new issue