diff --git a/shell/gpu/gpu_surface_vulkan.cc b/shell/gpu/gpu_surface_vulkan.cc index 51b7b87357f8e..fcfe0f97119fe 100644 --- a/shell/gpu/gpu_surface_vulkan.cc +++ b/shell/gpu/gpu_surface_vulkan.cc @@ -26,6 +26,16 @@ bool GPUSurfaceVulkan::IsValid() { return skia_context_ != nullptr; } +// Auxiliary function used to translate rectangles of type FlutterRect to +// SkIRect. +static const SkIRect FlutterRectToSkIRect(FlutterRect flutter_rect) { + SkIRect rect = {static_cast(flutter_rect.left), + static_cast(flutter_rect.top), + static_cast(flutter_rect.right), + static_cast(flutter_rect.bottom)}; + return rect; +} + std::unique_ptr GPUSurfaceVulkan::AcquireFrame( const SkISize& frame_size) { if (!IsValid()) { @@ -61,7 +71,7 @@ std::unique_ptr GPUSurfaceVulkan::AcquireFrame( } SurfaceFrame::SubmitCallback callback = [image = image, delegate = delegate_]( - const SurfaceFrame&, + const SurfaceFrame& frame, SkCanvas* canvas) -> bool { TRACE_EVENT0("flutter", "GPUSurfaceVulkan::PresentImage"); if (canvas == nullptr) { @@ -72,10 +82,20 @@ std::unique_ptr GPUSurfaceVulkan::AcquireFrame( canvas->flush(); return delegate->PresentImage(reinterpret_cast(image.image), - static_cast(image.format)); + static_cast(image.format), + *frame.submit_info().buffer_damage, + *frame.submit_info().frame_damage); }; - SurfaceFrame::FramebufferInfo framebuffer_info{.supports_readback = true}; + SurfaceFrame::FramebufferInfo framebuffer_info{ + .supports_readback = true, + }; + + if (image.partial_repaint_enabled) { + framebuffer_info.supports_partial_repaint = true; + framebuffer_info.existing_damage = + FlutterRectToSkIRect(image.image_damage.damage[0]); + } return std::make_unique( std::move(surface), std::move(framebuffer_info), std::move(callback)); diff --git a/shell/gpu/gpu_surface_vulkan_delegate.h b/shell/gpu/gpu_surface_vulkan_delegate.h index 023fe9261900b..9aa98eeb673a2 100644 --- a/shell/gpu/gpu_surface_vulkan_delegate.h +++ b/shell/gpu/gpu_surface_vulkan_delegate.h @@ -10,6 +10,7 @@ #include "flutter/vulkan/vulkan_device.h" #include "flutter/vulkan/vulkan_image.h" #include "flutter/vulkan/vulkan_proc_table.h" +#include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkSize.h" namespace flutter { @@ -42,7 +43,10 @@ class GPUSurfaceVulkanDelegate { /// @brief Called by the engine once a frame has been rendered to the image /// and it's ready to be bound for further reading/writing. /// - virtual bool PresentImage(VkImage image, VkFormat format) = 0; + virtual bool PresentImage(VkImage image, + VkFormat format, + SkIRect image_damage_skrect, + SkIRect frame_damage_skrect) = 0; }; } // namespace flutter diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 97fced2ab3001..326aa2324cf60 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -228,7 +228,7 @@ static void* DefaultGLProcResolver(const char* name) { } #endif // FML_OS_LINUX || FML_OS_WIN -#ifdef SHELL_ENABLE_GL +#if defined(SHELL_ENABLE_GL) || defined(SHELL_ENABLE_VULKAN) // Auxiliary function used to translate rectangles of type SkIRect to // FlutterRect. static FlutterRect SkIRectToFlutterRect(const SkIRect sk_rect) { @@ -238,7 +238,9 @@ static FlutterRect SkIRectToFlutterRect(const SkIRect sk_rect) { static_cast(sk_rect.fBottom)}; return flutter_rect; } +#endif +#ifdef SHELL_ENABLE_GL // Auxiliary function used to translate rectangles of type FlutterRect to // SkIRect. static const SkIRect FlutterRectToSkIRect(FlutterRect flutter_rect) { @@ -548,16 +550,54 @@ InferVulkanPlatformViewCreationCallback( static_cast(frame_size.height())}, }; - return ptr(user_data, &frame_info); + FlutterVulkanImage next_image = ptr(user_data, &frame_info); + + // Verify that at least one damage rectangle was provided. + if (next_image.image_damage.damage == nullptr || + next_image.image_damage.num_rects <= 0) { + FML_LOG(INFO) << "No damage was provided. Forcing full repaint."; + next_image.partial_repaint_enabled = false; + } else if (next_image.image_damage.num_rects > 1) { + // Log message notifying users that multi-damage is not yet available in + // case they try to make use of it. + FML_LOG(INFO) << "Damage with multiple rectangles not yet supported. " + "Repainting the whole frame."; + next_image.partial_repaint_enabled = false; + } else { + next_image.partial_repaint_enabled = true; + } + return next_image; }; auto vulkan_present_image_callback = [ptr = config->vulkan.present_image_callback, user_data]( - VkImage image, VkFormat format) -> bool { + VkImage image, VkFormat format, SkIRect image_damage_skrect, + SkIRect frame_damage_skrect) -> bool { + const size_t num_rects = 1; + + std::array image_damage_rect = { + SkIRectToFlutterRect(image_damage_skrect)}; + std::array frame_damage_rect = { + SkIRectToFlutterRect(frame_damage_skrect)}; + + FlutterDamage image_damage{ + .struct_size = sizeof(FlutterDamage), + .num_rects = image_damage_rect.size(), + .damage = image_damage_rect.data(), + }; + + FlutterDamage frame_damage{ + .struct_size = sizeof(FlutterDamage), + .num_rects = frame_damage_rect.size(), + .damage = frame_damage_rect.data(), + }; + FlutterVulkanImage image_desc = { .struct_size = sizeof(FlutterVulkanImage), .image = reinterpret_cast(image), .format = static_cast(format), + .image_damage = image_damage, + .frame_damage = frame_damage, }; return ptr(user_data, &image_desc); }; diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 93e92b7d4c6fa..458da4ae6626e 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -688,6 +688,18 @@ typedef struct { FlutterVulkanImageHandle image; /// The VkFormat of the image (for example: VK_FORMAT_R8G8B8A8_UNORM). uint32_t format; + /// Upon request, it represents the existing damage to the present image. At + /// present time, it represents the regions that need to be rendered. + FlutterDamage image_damage; + /// This field is used at present time to represent the regions that have + /// changed between this frame and the previous one. This is important so that + /// the user can keep track of images' existing damage. + FlutterDamage frame_damage; + /// This boolean is used to flag to the rendering backend whether partial + /// is enabled or not. Partial repaint should be enabled by default. It might + /// be disabled when the embedder does not receive the required information + /// to execute dirty region management. + bool partial_repaint_enabled; } FlutterVulkanImage; /// Callback to fetch a Vulkan function pointer for a given instance. Normally, @@ -751,13 +763,19 @@ typedef struct { /// The callback invoked when resolving Vulkan function pointers. FlutterVulkanInstanceProcAddressCallback get_instance_proc_address_callback; /// The callback invoked when the engine requests a VkImage from the embedder - /// for rendering the next frame. + /// for rendering the next frame. If using partial repaint, the user must + /// define this callback to fill in the value of image_damage of the image + /// being returned with the image's existing damage. If no image_damage is + /// given, the Embedder will do a full repaint. /// Not used if a FlutterCompositor is supplied in FlutterProjectArgs. FlutterVulkanImageCallback get_next_image_callback; /// The callback invoked when a VkImage has been written to and is ready for /// use by the embedder. Prior to calling this callback, the engine performs /// a host sync, and so the VkImage can be used in a pipeline by the embedder - /// without any additional synchronization. + /// without any additional synchronization. If using partial reapint, the user + /// must use the image and frame damages passed through the given + /// FlutterVulkanImage to render only the damage areas of the screen and to + /// keep track of a damage history. /// Not used if a FlutterCompositor is supplied in FlutterProjectArgs. FlutterVulkanPresentCallback present_image_callback; diff --git a/shell/platform/embedder/embedder_surface_gl.cc b/shell/platform/embedder/embedder_surface_gl.cc index f08793429c4d5..8ea01e0693ea1 100644 --- a/shell/platform/embedder/embedder_surface_gl.cc +++ b/shell/platform/embedder/embedder_surface_gl.cc @@ -53,7 +53,6 @@ bool EmbedderSurfaceGL::GLContextPresent(const GLPresentInfo& present_info) { // |GPUSurfaceGLDelegate| GLFBOInfo EmbedderSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { - // Get the FBO ID using the gl_fbo_callback and then get exiting damage by // passing that ID to the gl_populate_existing_damage. return gl_dispatch_table_.gl_populate_existing_damage( gl_dispatch_table_.gl_fbo_callback(frame_info)); diff --git a/shell/platform/embedder/embedder_surface_vulkan.cc b/shell/platform/embedder/embedder_surface_vulkan.cc index b3918a2420070..e116b38330da4 100644 --- a/shell/platform/embedder/embedder_surface_vulkan.cc +++ b/shell/platform/embedder/embedder_surface_vulkan.cc @@ -84,8 +84,12 @@ FlutterVulkanImage EmbedderSurfaceVulkan::AcquireImage(const SkISize& size) { } // |GPUSurfaceVulkanDelegate| -bool EmbedderSurfaceVulkan::PresentImage(VkImage image, VkFormat format) { - return vulkan_dispatch_table_.present_image(image, format); +bool EmbedderSurfaceVulkan::PresentImage(VkImage image, + VkFormat format, + SkIRect image_damage_skrect, + SkIRect frame_damage_skrect) { + return vulkan_dispatch_table_.present_image( + image, format, image_damage_skrect, frame_damage_skrect); } // |EmbedderSurface| diff --git a/shell/platform/embedder/embedder_surface_vulkan.h b/shell/platform/embedder/embedder_surface_vulkan.h index 3fa28fa09a7bd..4208c510caf0e 100644 --- a/shell/platform/embedder/embedder_surface_vulkan.h +++ b/shell/platform/embedder/embedder_surface_vulkan.h @@ -24,7 +24,10 @@ class EmbedderSurfaceVulkan final : public EmbedderSurface, get_instance_proc_address; // required std::function get_next_image; // required - std::function + std::function present_image; // required }; @@ -51,7 +54,10 @@ class EmbedderSurfaceVulkan final : public EmbedderSurface, FlutterVulkanImage AcquireImage(const SkISize& size) override; // |GPUSurfaceVulkanDelegate| - bool PresentImage(VkImage image, VkFormat format) override; + bool PresentImage(VkImage image, + VkFormat format, + SkIRect image_damage_skrect, + SkIRect frame_damage_skrect) override; private: bool valid_ = false;