diff --git a/include/render/gles2.h b/include/render/gles2.h index 714bacf56..5ae43500b 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -125,6 +125,8 @@ struct wlr_gles2_renderer *gles2_get_renderer( struct wlr_renderer *wlr_renderer); struct wlr_gles2_texture *gles2_get_texture( struct wlr_texture *wlr_texture); +struct wlr_gles2_texture *gles2_raster_upload(struct wlr_gles2_renderer *renderer, + struct wlr_raster *wlr_raster); struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *data); diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 1cba5a192..492b44823 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -256,6 +256,8 @@ struct wlr_vk_texture { }; struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture); +struct wlr_vk_texture *vulkan_raster_upload(struct wlr_vk_renderer *renderer, + struct wlr_raster *wlr_raster); VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer, const struct wlr_dmabuf_attributes *attribs, VkDeviceMemory mems[static WLR_DMABUF_MAX_PLANES], uint32_t *n_mems, diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 20d755f9d..bf5cd58a3 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -27,6 +27,8 @@ struct wlr_renderer_impl { void (*end)(struct wlr_renderer *renderer); void (*clear)(struct wlr_renderer *renderer, const float color[static 4]); void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box); + bool (*raster_upload)(struct wlr_renderer *renderer, + struct wlr_raster *raster); bool (*render_subtexture_with_matrix)(struct wlr_renderer *renderer, struct wlr_texture *texture, const struct wlr_fbox *box, const float matrix[static 9], float alpha); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 50ba6b215..b14c2b4fb 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -48,6 +48,14 @@ void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); * box. */ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); + +/** + * The renderer will attempt to upload the raster using an available compatible + * source found in the raster to the device that the renderer is running on. + * If the raster is already uploaded to said device, then this is a no-op. + */ +bool wlr_renderer_raster_upload(struct wlr_renderer *r, + struct wlr_raster *raster); /** * Renders the requested texture. */ diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 5a2f31b55..48d293d13 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -534,6 +534,13 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { free(renderer); } +static bool _gles2_raster_upload(struct wlr_renderer *wlr_renderer, + struct wlr_raster *raster) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_texture *texture = gles2_raster_upload(renderer, raster); + return texture; +} + static const struct wlr_renderer_impl renderer_impl = { .destroy = gles2_destroy, .bind_buffer = gles2_bind_buffer, @@ -541,6 +548,7 @@ static const struct wlr_renderer_impl renderer_impl = { .end = gles2_end, .clear = gles2_clear, .scissor = gles2_scissor, + .raster_upload = _gles2_raster_upload, .render_subtexture_with_matrix = gles2_render_subtexture_with_matrix, .render_quad_with_matrix = gles2_render_quad_with_matrix, .get_shm_texture_formats = gles2_get_shm_texture_formats, diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 8b4ce6739..94ded6b17 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -376,6 +376,35 @@ struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer, } } +struct wlr_gles2_texture *gles2_raster_upload(struct wlr_gles2_renderer *renderer, + struct wlr_raster *wlr_raster) { + struct wlr_texture *texture; + wl_list_for_each(texture, &wlr_raster->sources, link) { + if (wlr_texture_is_gles2(texture)) { + struct wlr_gles2_texture *gles2_tex = + (struct wlr_gles2_texture *)texture; + if (gles2_tex->renderer != renderer) { + continue; + } + return gles2_tex; + } + } + + if (!wlr_raster->buffer) { + // we could possibly do a blit with another texture from another renderer, + // but this is unsupported currently. + return NULL; + } + + texture = gles2_texture_from_buffer(&renderer->wlr_renderer, wlr_raster->buffer); + if (!texture) { + return NULL; + } + + wlr_raster_attach(wlr_raster, texture); + return (struct wlr_gles2_texture *)texture; +} + void wlr_gles2_texture_get_attribs(struct wlr_texture *wlr_texture, struct wlr_gles2_texture_attribs *attribs) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); diff --git a/render/pixman/renderer.c b/render/pixman/renderer.c index 5874cc8c9..fbda32c01 100644 --- a/render/pixman/renderer.c +++ b/render/pixman/renderer.c @@ -46,8 +46,103 @@ static struct wlr_pixman_texture *get_texture( return (struct wlr_pixman_texture *)wlr_texture; } +static struct wlr_pixman_texture *pixman_texture_create( + struct wlr_pixman_renderer *renderer, uint32_t drm_format, + uint32_t width, uint32_t height) { + struct wlr_pixman_texture *texture = + calloc(1, sizeof(struct wlr_pixman_texture)); + if (texture == NULL) { + wlr_log_errno(WLR_ERROR, "Failed to allocate pixman texture"); + return NULL; + } + + wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); + texture->renderer = renderer; + + texture->format_info = drm_get_pixel_format_info(drm_format); + if (!texture->format_info) { + wlr_log(WLR_ERROR, "Unsupported drm format 0x%"PRIX32, drm_format); + free(texture); + return NULL; + } + + texture->format = get_pixman_format_from_drm(drm_format); + if (texture->format == 0) { + wlr_log(WLR_ERROR, "Unsupported pixman drm format 0x%"PRIX32, + drm_format); + free(texture); + return NULL; + } + + wl_list_insert(&renderer->textures, &texture->link); + + return texture; +} + +static struct wlr_texture *pixman_texture_from_buffer( + struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer) { + struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); + + void *data = NULL; + uint32_t drm_format; + size_t stride; + if (!wlr_buffer_begin_data_ptr_access(buffer, WLR_BUFFER_DATA_PTR_ACCESS_READ, + &data, &drm_format, &stride)) { + return NULL; + } + wlr_buffer_end_data_ptr_access(buffer); + + struct wlr_pixman_texture *texture = pixman_texture_create(renderer, + drm_format, buffer->width, buffer->height); + if (texture == NULL) { + return NULL; + } + + texture->image = pixman_image_create_bits_no_clear(texture->format, + buffer->width, buffer->height, data, stride); + if (!texture->image) { + wlr_log(WLR_ERROR, "Failed to create pixman image"); + wl_list_remove(&texture->link); + free(texture); + return NULL; + } + + texture->buffer = wlr_buffer_lock(buffer); + + return &texture->wlr_texture; +} + +static struct wlr_pixman_texture *raster_upload( + struct wlr_pixman_renderer *renderer, struct wlr_raster *wlr_raster) { + struct wlr_texture *texture; + wl_list_for_each(texture, &wlr_raster->sources, link) { + if (wlr_texture_is_pixman(texture)) { + struct wlr_pixman_texture *pixman_tex = + (struct wlr_pixman_texture *)texture; + if (pixman_tex->renderer != renderer) { + continue; + } + return pixman_tex; + } + } + + if (!wlr_raster->buffer) { + // we could possibly do a blit with another texture from another renderer, + // but this is unsupported currently. + return NULL; + } + + texture = pixman_texture_from_buffer(&renderer->wlr_renderer, wlr_raster->buffer); + if (!texture) { + return NULL; + } + + wlr_raster_attach(wlr_raster, texture); + return (struct wlr_pixman_texture *)texture; +} + static void texture_destroy(struct wlr_texture *wlr_texture) { - struct wlr_pixman_texture *texture = get_texture(wlr_texture); + struct wlr_pixman_texture *texture = (struct wlr_pixman_texture *)wlr_texture; wl_list_remove(&texture->link); pixman_image_unref(texture->image); wlr_buffer_unlock(texture->buffer); @@ -334,72 +429,6 @@ static const struct wlr_drm_format_set *pixman_get_render_formats( return &renderer->drm_formats; } -static struct wlr_pixman_texture *pixman_texture_create( - struct wlr_pixman_renderer *renderer, uint32_t drm_format, - uint32_t width, uint32_t height) { - struct wlr_pixman_texture *texture = - calloc(1, sizeof(struct wlr_pixman_texture)); - if (texture == NULL) { - wlr_log_errno(WLR_ERROR, "Failed to allocate pixman texture"); - return NULL; - } - - wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); - texture->renderer = renderer; - - texture->format_info = drm_get_pixel_format_info(drm_format); - if (!texture->format_info) { - wlr_log(WLR_ERROR, "Unsupported drm format 0x%"PRIX32, drm_format); - free(texture); - return NULL; - } - - texture->format = get_pixman_format_from_drm(drm_format); - if (texture->format == 0) { - wlr_log(WLR_ERROR, "Unsupported pixman drm format 0x%"PRIX32, - drm_format); - free(texture); - return NULL; - } - - wl_list_insert(&renderer->textures, &texture->link); - - return texture; -} - -static struct wlr_texture *pixman_texture_from_buffer( - struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer) { - struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); - - void *data = NULL; - uint32_t drm_format; - size_t stride; - if (!wlr_buffer_begin_data_ptr_access(buffer, WLR_BUFFER_DATA_PTR_ACCESS_READ, - &data, &drm_format, &stride)) { - return NULL; - } - wlr_buffer_end_data_ptr_access(buffer); - - struct wlr_pixman_texture *texture = pixman_texture_create(renderer, - drm_format, buffer->width, buffer->height); - if (texture == NULL) { - return NULL; - } - - texture->image = pixman_image_create_bits_no_clear(texture->format, - buffer->width, buffer->height, data, stride); - if (!texture->image) { - wlr_log(WLR_ERROR, "Failed to create pixman image"); - wl_list_remove(&texture->link); - free(texture); - return NULL; - } - - texture->buffer = wlr_buffer_lock(buffer); - - return &texture->wlr_texture; -} - static bool pixman_bind_buffer(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer) { struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); @@ -488,11 +517,19 @@ static uint32_t pixman_get_render_buffer_caps(struct wlr_renderer *renderer) { return WLR_BUFFER_CAP_DATA_PTR; } +static bool pixman_raster_upload(struct wlr_renderer *wlr_renderer, + struct wlr_raster *raster) { + struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); + struct wlr_pixman_texture *texture = raster_upload(renderer, raster); + return texture; +} + static const struct wlr_renderer_impl renderer_impl = { .begin = pixman_begin, .end = pixman_end, .clear = pixman_clear, .scissor = pixman_scissor, + .raster_upload = pixman_raster_upload, .render_subtexture_with_matrix = pixman_render_subtexture_with_matrix, .render_quad_with_matrix = pixman_render_quad_with_matrix, .get_shm_texture_formats = pixman_get_shm_texture_formats, diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index c373269df..a4be726b1 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -976,12 +976,20 @@ static uint32_t vulkan_get_render_buffer_caps(struct wlr_renderer *wlr_renderer) return WLR_BUFFER_CAP_DMABUF; } +static bool _vulkan_raster_upload(struct wlr_renderer *wlr_renderer, + struct wlr_raster *raster) { + struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); + struct wlr_vk_texture *texture = vulkan_raster_upload(renderer, raster); + return texture; +} + static const struct wlr_renderer_impl renderer_impl = { .bind_buffer = vulkan_bind_buffer, .begin = vulkan_begin, .end = vulkan_end, .clear = vulkan_clear, .scissor = vulkan_scissor, + .raster_upload = _vulkan_raster_upload, .render_subtexture_with_matrix = vulkan_render_subtexture_with_matrix, .render_quad_with_matrix = vulkan_render_quad_with_matrix, .get_shm_texture_formats = vulkan_get_shm_texture_formats, diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index 88298d93a..a4c2b4366 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -742,3 +742,32 @@ struct wlr_texture *vulkan_texture_from_buffer( return NULL; } } + +struct wlr_vk_texture *vulkan_raster_upload(struct wlr_vk_renderer *renderer, + struct wlr_raster *wlr_raster) { + struct wlr_texture *texture; + wl_list_for_each(texture, &wlr_raster->sources, link) { + if (wlr_texture_is_vk(texture)) { + struct wlr_vk_texture *vk_tex = + (struct wlr_vk_texture *)texture; + if (vk_tex->renderer != renderer) { + continue; + } + return vk_tex; + } + } + + if (!wlr_raster->buffer) { + // we could possibly do a blit with another texture from another renderer, + // but this is unsupported currently. + return NULL; + } + + texture = vulkan_texture_from_buffer(&renderer->wlr_renderer, wlr_raster->buffer); + if (!texture) { + return NULL; + } + + wlr_raster_attach(wlr_raster, texture); + return (struct wlr_vk_texture *)texture; +} diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 478db7453..a4965b538 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -35,6 +35,7 @@ void wlr_renderer_init(struct wlr_renderer *renderer, assert(impl->begin); assert(impl->clear); assert(impl->scissor); + assert(impl->raster_upload); assert(impl->render_subtexture_with_matrix); assert(impl->render_quad_with_matrix); assert(impl->get_shm_texture_formats); @@ -113,6 +114,11 @@ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box) { r->impl->scissor(r, box); } +bool wlr_renderer_raster_upload(struct wlr_renderer *r, + struct wlr_raster *raster) { + return r->impl->raster_upload(r, raster); +} + bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, const float projection[static 9], int x, int y, float alpha) { struct wlr_box box = {