mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-15 08:22:07 -04:00
wlr_raster: Implement multi-renderer blits
We also need to introduce allocator variants to wlr_raster_upload_texture and wlr_raster_attach so that the given allocator can be used to allocate a stanging buffer to aid in blitting
This commit is contained in:
parent
6caa8cd4f0
commit
5ac236085d
2 changed files with 185 additions and 12 deletions
|
|
@ -18,12 +18,15 @@ struct wlr_texture;
|
|||
struct wlr_renderer;
|
||||
struct wlr_drm_syncobj_timeline;
|
||||
struct wlr_surface;
|
||||
struct wlr_allocator;
|
||||
|
||||
struct wlr_raster_source {
|
||||
struct wlr_texture *texture;
|
||||
struct wlr_allocator *allocator; // may be NULL
|
||||
struct wl_list link;
|
||||
|
||||
struct wl_listener renderer_destroy;
|
||||
struct wl_listener allocator_destroy;
|
||||
};
|
||||
|
||||
struct wlr_raster {
|
||||
|
|
@ -47,8 +50,6 @@ struct wlr_raster {
|
|||
size_t n_locks;
|
||||
|
||||
struct wl_listener buffer_release;
|
||||
|
||||
struct wl_listener renderer_destroy;
|
||||
};
|
||||
|
||||
struct wlr_raster_create_options {
|
||||
|
|
@ -92,6 +93,20 @@ void wlr_raster_unlock(struct wlr_raster *raster);
|
|||
struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer);
|
||||
|
||||
/**
|
||||
* Returns the texture allocated for this renderer. If there is none,
|
||||
* a new texture will be created and attached to this wlr_raster. Users do not
|
||||
* own the texture returned by this function and can only be used for read-only
|
||||
* purposes.
|
||||
*
|
||||
* An optional allocator can be provided which will be used to allocate staging
|
||||
* buffers to blit between graphics devices if needed.
|
||||
*
|
||||
* Will return NULL if the creation was unsuccessful.
|
||||
*/
|
||||
struct wlr_texture *wlr_raster_obtain_texture_with_allocator(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer, struct wlr_allocator *allocator);
|
||||
|
||||
/**
|
||||
* Creates a wlr_raster from a surface. This will automatically deduplicate
|
||||
* rasters if multiple are consumed from the same surface so that redundant
|
||||
|
|
|
|||
|
|
@ -1,13 +1,21 @@
|
|||
#include <assert.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <pixman.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_raster.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "render/drm_format_set.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
|
||||
static void raster_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -49,6 +57,7 @@ struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer,
|
|||
static void raster_source_destroy(struct wlr_raster_source *source) {
|
||||
wl_list_remove(&source->link);
|
||||
wl_list_remove(&source->renderer_destroy.link);
|
||||
wl_list_remove(&source->allocator_destroy.link);
|
||||
free(source);
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +116,15 @@ static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
|
|||
raster_source_destroy(source);
|
||||
}
|
||||
|
||||
static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) {
|
||||
static void handle_allocator_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_raster_source *source = wl_container_of(listener, source, allocator_destroy);
|
||||
source->allocator = NULL;
|
||||
wl_list_remove(&source->allocator_destroy.link);
|
||||
wl_list_init(&source->allocator_destroy.link);
|
||||
}
|
||||
|
||||
static void raster_attach_with_allocator(struct wlr_raster *raster,
|
||||
struct wlr_texture *texture, struct wlr_allocator *allocator) {
|
||||
assert(texture->width == raster->width && texture->height == raster->height);
|
||||
|
||||
struct wlr_raster_source *source;
|
||||
|
|
@ -123,8 +140,20 @@ static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture
|
|||
source->renderer_destroy.notify = handle_renderer_destroy;
|
||||
wl_signal_add(&texture->renderer->events.destroy, &source->renderer_destroy);
|
||||
|
||||
if (allocator) {
|
||||
source->allocator_destroy.notify = handle_allocator_destroy;
|
||||
wl_signal_add(&allocator->events.destroy, &source->allocator_destroy);
|
||||
} else {
|
||||
wl_list_init(&source->allocator_destroy.link);
|
||||
}
|
||||
|
||||
wl_list_insert(&raster->sources, &source->link);
|
||||
source->texture = texture;
|
||||
source->allocator = allocator;
|
||||
}
|
||||
|
||||
static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) {
|
||||
raster_attach_with_allocator(raster, texture, NULL);
|
||||
}
|
||||
|
||||
static struct wlr_texture *wlr_raster_get_texture(struct wlr_raster *raster,
|
||||
|
|
@ -139,27 +168,156 @@ static struct wlr_texture *wlr_raster_get_texture(struct wlr_raster *raster,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
|
||||
static bool compute_import_buffer_format(struct wlr_raster *raster, struct wlr_drm_format *drm_fmt,
|
||||
struct wlr_renderer *dst) {
|
||||
const struct wlr_drm_format_set *texture_formats =
|
||||
wlr_renderer_get_texture_formats(dst, WLR_BUFFER_CAP_DMABUF);
|
||||
if (!texture_formats) {
|
||||
wlr_log(WLR_ERROR, "Failed to get texture_formats");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// For now, let's only use XRGB
|
||||
uint32_t fmt = raster->opaque ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_ARGB8888;
|
||||
const struct wlr_drm_format *drm_fmt_inv =
|
||||
wlr_drm_format_set_get(texture_formats, fmt);
|
||||
|
||||
if (!wlr_drm_format_copy(drm_fmt, drm_fmt_inv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < drm_fmt->len; i++) {
|
||||
uint64_t mod = drm_fmt->modifiers[i];
|
||||
if (mod != DRM_FORMAT_MOD_INVALID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t j = i + 1; j < drm_fmt->len; j++) {
|
||||
drm_fmt->modifiers[j] = drm_fmt->modifiers[j + 1];
|
||||
}
|
||||
|
||||
drm_fmt->len--;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct wlr_buffer *raster_try_blit(struct wlr_raster *raster,
|
||||
struct wlr_raster_source *source, struct wlr_renderer *dst) {
|
||||
if (!source->allocator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Attempting a multigpu blit through a GPU");
|
||||
|
||||
struct wlr_renderer *src = source->texture->renderer;
|
||||
|
||||
// The src needs to be able to render into this format
|
||||
const struct wlr_drm_format_set *render_formats =
|
||||
wlr_renderer_get_render_formats(src);
|
||||
if (!render_formats) {
|
||||
wlr_log(WLR_ERROR, "Failed to get render_formats");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_drm_format fmt = {0};
|
||||
if (!compute_import_buffer_format(raster, &fmt, dst)) {
|
||||
wlr_log(WLR_ERROR, "Could not find a common format modifiers for all GPUs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wlr_drm_format_intersect(&fmt, &fmt,
|
||||
wlr_drm_format_set_get(render_formats, fmt.format))) {
|
||||
wlr_drm_format_finish(&fmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_buffer *buffer = wlr_allocator_create_buffer(
|
||||
source->allocator, raster->width, raster->height, &fmt);
|
||||
wlr_drm_format_finish(&fmt);
|
||||
if (!buffer) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate multirenderer blit buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(src, buffer, NULL);
|
||||
if (!pass) {
|
||||
wlr_log(WLR_ERROR, "Failed to create a render pass");
|
||||
wlr_buffer_drop(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options) {
|
||||
.texture = source->texture,
|
||||
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
|
||||
});
|
||||
|
||||
if (!wlr_render_pass_submit(pass)) {
|
||||
wlr_log(WLR_ERROR, "Failed to renedr to a multigpu blit buffer");
|
||||
wlr_buffer_drop(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static struct wlr_texture *raster_try_texture_from_blit(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer) {
|
||||
struct wlr_buffer *imported = NULL;
|
||||
|
||||
struct wlr_raster_source *source;
|
||||
wl_list_for_each(source, &raster->sources, link) {
|
||||
imported = raster_try_blit(raster, source, renderer);
|
||||
if (imported) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!imported) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_buffer_drop(imported);
|
||||
|
||||
return wlr_texture_from_buffer(renderer, imported);
|
||||
}
|
||||
|
||||
struct wlr_texture *wlr_raster_obtain_texture_with_allocator(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer, struct wlr_allocator *allocator) {
|
||||
struct wlr_texture *texture = wlr_raster_get_texture(raster, renderer);
|
||||
if (texture) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
assert(raster->buffer);
|
||||
if (raster->buffer) {
|
||||
struct wlr_client_buffer *client_buffer =
|
||||
wlr_client_buffer_get(raster->buffer);
|
||||
if (client_buffer != NULL) {
|
||||
return client_buffer->texture;
|
||||
}
|
||||
|
||||
struct wlr_client_buffer *client_buffer =
|
||||
wlr_client_buffer_get(raster->buffer);
|
||||
if (client_buffer != NULL) {
|
||||
return client_buffer->texture;
|
||||
// if we have a buffer, try and import that
|
||||
texture = wlr_texture_from_buffer(renderer, raster->buffer);
|
||||
if (texture) {
|
||||
raster_attach_with_allocator(raster, texture, allocator);
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
|
||||
texture = wlr_texture_from_buffer(renderer, raster->buffer);
|
||||
// try to blit using the textures already available to us
|
||||
texture = raster_try_texture_from_blit(raster, renderer);
|
||||
if (texture) {
|
||||
raster_attach(raster, texture);
|
||||
raster_attach_with_allocator(raster, texture, allocator);
|
||||
return texture;
|
||||
}
|
||||
|
||||
return texture;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer) {
|
||||
return wlr_raster_create_texture_with_allocator(raster, renderer, NULL);
|
||||
}
|
||||
|
||||
struct raster_update_state {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue