diff --git a/include/zen/renderer/gl-texture.h b/include/zen/renderer/gl-texture.h index d493c663..2f79b04b 100644 --- a/include/zen/renderer/gl-texture.h +++ b/include/zen/renderer/gl-texture.h @@ -15,6 +15,10 @@ void znr_gl_texture_image_2d(struct znr_gl_texture *self, uint32_t target, int32_t border, uint32_t format, uint32_t type, struct zwnr_mem_storage *storage); +void znr_gl_texture_sub_image_2d(struct znr_gl_texture *self, uint32_t target, + int32_t level, int32_t xoffset, int32_t yoffset, uint32_t width, uint32_t height, + uint32_t format, uint32_t type, struct zwnr_mem_storage *storage); + void znr_gl_texture_generate_mipmap( struct znr_gl_texture *self, uint32_t target); diff --git a/include/zen/view-child.h b/include/zen/view-child.h index 4e900b6e..424ac7ce 100644 --- a/include/zen/view-child.h +++ b/include/zen/view-child.h @@ -14,6 +14,7 @@ struct zn_view_child_interface { struct zn_view_child { void *user_data; struct wlr_surface *surface; // nonnull + bool surface_on_partial_updates; const struct zn_view_child_interface *impl; diff --git a/include/zen/view.h b/include/zen/view.h index b3375d2b..9a205fe2 100644 --- a/include/zen/view.h +++ b/include/zen/view.h @@ -28,6 +28,7 @@ struct zn_view_interface { struct zn_view { void *user_data; struct wlr_surface *surface; // nonnull + bool surface_on_partial_updates; const struct zn_view_interface *impl; @@ -87,6 +88,8 @@ void zn_view_move( void zn_view_set_maximized(struct zn_view *self, bool maximized); +void zn_view_reset_partial_updates(struct zn_view *self); + /** lifetime of given wlr_surface must be longer than zn_view */ struct zn_view *zn_view_create(struct wlr_surface *surface, const struct zn_view_interface *impl, void *user_data); diff --git a/zen/server.c b/zen/server.c index 64feda96..c603e6e6 100644 --- a/zen/server.c +++ b/zen/server.c @@ -13,6 +13,7 @@ #include "zen/screen/output.h" #include "zen/virtual-object.h" #include "zen/wlr/render/glew.h" +#include "zen/view.h" static struct zn_server *server_singleton = NULL; @@ -79,6 +80,7 @@ zn_server_change_display_system( struct zn_server *self, enum zn_display_system_state display_system) { struct zn_screen *screen; + struct zn_view *view; if (self->display_system == display_system) return; @@ -88,6 +90,10 @@ zn_server_change_display_system( zn_screen_damage_whole(screen); } + wl_list_for_each (view, &self->scene->view_list, link) { + zn_view_reset_partial_updates(view); + } + self->display_system = display_system; wl_signal_emit(&self->events.display_system_changed, &self->display_system); diff --git a/zen/view-child.c b/zen/view-child.c index 9535699f..efd99583 100644 --- a/zen/view-child.c +++ b/zen/view-child.c @@ -134,6 +134,7 @@ zn_view_child_create(struct wlr_surface *surface, struct zn_view *view, self->user_data = user_data; self->surface = surface; + self->surface_on_partial_updates = false; self->impl = impl; self->view = view; diff --git a/zen/view.c b/zen/view.c index 11428e30..96c3c05c 100644 --- a/zen/view.c +++ b/zen/view.c @@ -268,6 +268,10 @@ zn_view_set_maximized(struct zn_view *self, bool maximized) self->maximize_status.maximized = maximized; } +void zn_view_reset_partial_updates(struct zn_view *self){ + self->surface_on_partial_updates = false; +} + struct zn_view * zn_view_create(struct wlr_surface *surface, const struct zn_view_interface *impl, void *user_data) @@ -282,6 +286,7 @@ zn_view_create(struct wlr_surface *surface, } self->surface = surface; + self->surface_on_partial_updates = false; self->impl = impl; self->user_data = user_data; diff --git a/zna/base-unit.c b/zna/base-unit.c index 32e23bfc..060efb85 100644 --- a/zna/base-unit.c +++ b/zna/base-unit.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -79,7 +80,8 @@ zna_base_unit_read_cairo_surface( void zna_base_unit_read_wlr_texture( - struct zna_base_unit *self, struct wlr_texture *texture) + struct zna_base_unit *self, struct wlr_texture *texture, + pixman_region32_t* damage, bool *on_partial_updates) { struct zn_server *server = zn_server_get_singleton(); struct zwnr_mem_storage *storage; @@ -90,9 +92,6 @@ zna_base_unit_read_wlr_texture( return; } - storage = - zwnr_mem_storage_create(NULL, 32 * texture->width * texture->height); - struct wlr_glew_texture_attribs texture_attrib; wlr_glew_texture_get_attribs(texture, &texture_attrib); @@ -122,25 +121,72 @@ zna_base_unit_read_wlr_texture( glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0); - glReadPixels(0, 0, texture->width, texture->height, GL_RGBA, GL_UNSIGNED_BYTE, - storage->data); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteTextures(1, &depth_texture); - glDeleteFramebuffers(1, &framebuffer); - - zn_wlr_egl_unset_current(egl); - if (self->has_texture_data == false) { self->has_texture_data = true; znr_gl_base_technique_bind_texture( self->technique, 0, "", self->texture0, GL_TEXTURE_2D, self->sampler0); } - znr_gl_texture_image_2d(self->texture0, GL_TEXTURE_2D, 0, GL_RGBA, - texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, storage); + bool need_to_full_load_texture = true; - zwnr_mem_storage_unref(storage); + if (damage != NULL) { + if (on_partial_updates != NULL) { + if (*on_partial_updates == true) + { + need_to_full_load_texture = false; + } + } + } + + if (need_to_full_load_texture) { + storage = + zwnr_mem_storage_create(NULL, 32 * texture->width * texture->height); + + glReadPixels(0, 0, texture->width, texture->height, GL_RGBA, GL_UNSIGNED_BYTE, + storage->data); + + znr_gl_texture_image_2d(self->texture0, GL_TEXTURE_2D, 0, GL_RGBA, + texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, storage); + + + if (on_partial_updates != NULL) { + *on_partial_updates = true; + } + + zwnr_mem_storage_unref(storage); + } else { + struct wlr_fbox damage_box; + pixman_box32_t *rects; + int rect_count; + rects = pixman_region32_rectangles(damage, &rect_count); + + for (int i = 0; i < rect_count; ++i) { + damage_box.x = rects[i].x1; + damage_box.y = rects[i].y1; + damage_box.width = rects[i].x2 - rects[i].x1; + damage_box.height = rects[i].y2 - rects[i].y1; + + storage = + zwnr_mem_storage_create(NULL, 32 * damage_box.width * damage_box.height); + + glReadPixels(damage_box.x, damage_box.y, damage_box.width, damage_box.height, + GL_RGBA, GL_UNSIGNED_BYTE, + storage->data); + + znr_gl_texture_sub_image_2d(self->texture0, GL_TEXTURE_2D, 0, damage_box.x, + damage_box.y, damage_box.width, damage_box.height, GL_RGBA, + GL_UNSIGNED_BYTE, storage); + + zwnr_mem_storage_unref(storage); + } + + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteTextures(1, &depth_texture); + glDeleteFramebuffers(1, &framebuffer); + + zn_wlr_egl_unset_current(egl); } void diff --git a/zna/base-unit.h b/zna/base-unit.h index bf9dd889..931e6f02 100644 --- a/zna/base-unit.h +++ b/zna/base-unit.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -55,7 +56,8 @@ void zna_base_unit_read_cairo_surface( struct zna_base_unit *self, cairo_surface_t *surface); void zna_base_unit_read_wlr_texture( - struct zna_base_unit *self, struct wlr_texture *texture); + struct zna_base_unit *self, struct wlr_texture *texture, + pixman_region32_t *damage, bool *on_partial_updates); void zna_base_unit_setup_renderer_objects(struct zna_base_unit *self, struct znr_dispatcher *dispatcher, diff --git a/zna/cursor.c b/zna/cursor.c index 606cee41..1277045b 100644 --- a/zna/cursor.c +++ b/zna/cursor.c @@ -29,7 +29,7 @@ zna_cursor_commit(struct zna_cursor *self, uint32_t damage) if (damage & ZNA_CURSOR_DAMAGE_TEXTURE) { zna_base_unit_read_wlr_texture( - self->base_unit, zn_cursor_get_texture(self->zn_cursor)); + self->base_unit, zn_cursor_get_texture(self->zn_cursor), NULL, NULL); znr_gl_sampler_parameter_i( self->base_unit->sampler0, GL_TEXTURE_MAG_FILTER, GL_LINEAR); znr_gl_sampler_parameter_i( diff --git a/zna/view-child.c b/zna/view-child.c index 93c81d38..4c018c5b 100644 --- a/zna/view-child.c +++ b/zna/view-child.c @@ -27,7 +27,9 @@ zna_view_child_commit(struct zna_view_child *self, uint32_t damage) struct wlr_texture *texture = wlr_surface_get_texture(self->zn_view_child->surface); if (texture) { - zna_base_unit_read_wlr_texture(self->base_unit, texture); + zna_base_unit_read_wlr_texture(self->base_unit, texture, + &self->zn_view_child->surface->buffer_damage, + &self->zn_view_child->surface_on_partial_updates); znr_gl_texture_generate_mipmap(self->base_unit->texture0, GL_TEXTURE_2D); znr_gl_sampler_parameter_i( self->base_unit->sampler0, GL_TEXTURE_MAG_FILTER, GL_LINEAR); diff --git a/zna/view.c b/zna/view.c index ed06af12..fa0e6070 100644 --- a/zna/view.c +++ b/zna/view.c @@ -27,7 +27,9 @@ zna_view_commit(struct zna_view *self, uint32_t damage) struct wlr_texture *texture = wlr_surface_get_texture(self->zn_view->surface); if (texture) { - zna_base_unit_read_wlr_texture(self->base_unit, texture); + zna_base_unit_read_wlr_texture(self->base_unit, texture, + &self->zn_view->surface->buffer_damage, + &self->zn_view->surface_on_partial_updates); znr_gl_texture_generate_mipmap(self->base_unit->texture0, GL_TEXTURE_2D); znr_gl_sampler_parameter_i( self->base_unit->sampler0, GL_TEXTURE_MAG_FILTER, GL_LINEAR); diff --git a/znr-remote/src/gl-texture.cc b/znr-remote/src/gl-texture.cc index bfeb78e2..0b237396 100644 --- a/znr-remote/src/gl-texture.cc +++ b/znr-remote/src/gl-texture.cc @@ -23,6 +23,24 @@ znr_gl_texture_image_2d(struct znr_gl_texture *self, uint32_t target, border, format, type, std::move(buffer)); } +void +znr_gl_texture_sub_image_2d(struct znr_gl_texture *self, uint32_t target, + int32_t level, int32_t xoffset, int32_t yoffset, uint32_t width, uint32_t height, + uint32_t format, uint32_t type, + struct zwnr_mem_storage *storage) +{ + auto loop = std::make_unique(wl_display_get_event_loop(self->display)); + + zwnr_mem_storage_ref(storage); + + auto buffer = zen::remote::server::CreateBuffer( + storage->data, [storage] { zwnr_mem_storage_unref(storage); }, + std::move(loop)); + + self->proxy->GlTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, std::move(buffer)); +} + void znr_gl_texture_generate_mipmap(struct znr_gl_texture *self, uint32_t target) {