88#include < memory>
99#include < utility>
1010
11+ #include " display_list/dl_builder.h"
1112#include " flow/frame_timings.h"
1213#include " flutter/common/constants.h"
1314#include " flutter/common/graphics/persistent_cache.h"
1718#include " flutter/shell/common/base64.h"
1819#include " flutter/shell/common/serialization_callbacks.h"
1920#include " fml/make_copyable.h"
21+ #include " fml/synchronization/waitable_event.h"
2022#include " third_party/skia/include/core/SkColorSpace.h"
2123#include " third_party/skia/include/core/SkData.h"
2224#include " third_party/skia/include/core/SkImage.h"
3436#include " third_party/skia/include/gpu/GrTypes.h"
3537#include " third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
3638
39+ #if IMPELLER_SUPPORTS_RENDERING
40+ #include " impeller/aiks/aiks_context.h" // nogncheck
41+ #include " impeller/core/formats.h" // nogncheck
42+ #include " impeller/display_list/dl_dispatcher.h" // nogncheck
43+ #endif
44+
3745namespace flutter {
3846
3947// The rasterizer will tell Skia to purge cached resources that have not been
@@ -802,28 +810,143 @@ static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
802810 return recorder.finishRecordingAsPicture ()->serialize (&procs);
803811}
804812
805- sk_sp<SkData> Rasterizer::ScreenshotLayerTreeAsImage (
806- flutter::LayerTree* tree,
813+ static void RenderFrameForScreenshot (
807814 flutter::CompositorContext& compositor_context,
815+ DlCanvas* canvas,
816+ flutter::LayerTree* tree,
808817 GrDirectContext* surface_context,
818+ const std::shared_ptr<impeller::AiksContext>& aiks_context) {
819+ // There is no root surface transformation for the screenshot layer. Reset
820+ // the matrix to identity.
821+ SkMatrix root_surface_transformation;
822+ root_surface_transformation.reset ();
823+
824+ auto frame = compositor_context.AcquireFrame (
825+ surface_context, // skia context
826+ canvas, // canvas
827+ nullptr , // view embedder
828+ root_surface_transformation, // root surface transformation
829+ false , // instrumentation enabled
830+ true , // render buffer readback supported
831+ nullptr , // thread merger
832+ aiks_context.get () // aiks context
833+ );
834+ canvas->Clear (DlColor::kTransparent ());
835+ frame->Raster (*tree, true , nullptr );
836+ canvas->Flush ();
837+ }
838+
839+ #if IMPELLER_SUPPORTS_RENDERING
840+ Rasterizer::ScreenshotFormat ToScreenshotFormat (impeller::PixelFormat format) {
841+ switch (format) {
842+ case impeller::PixelFormat::kUnknown :
843+ case impeller::PixelFormat::kA8UNormInt :
844+ case impeller::PixelFormat::kR8UNormInt :
845+ case impeller::PixelFormat::kR8G8UNormInt :
846+ case impeller::PixelFormat::kR8G8B8A8UNormIntSRGB :
847+ case impeller::PixelFormat::kB8G8R8A8UNormIntSRGB :
848+ case impeller::PixelFormat::kB10G10R10XRSRGB :
849+ case impeller::PixelFormat::kS8UInt :
850+ case impeller::PixelFormat::kD24UnormS8Uint :
851+ case impeller::PixelFormat::kD32FloatS8UInt :
852+ case impeller::PixelFormat::kR32G32B32A32Float :
853+ case impeller::PixelFormat::kB10G10R10XR :
854+ case impeller::PixelFormat::kB10G10R10A10XR :
855+ FML_DCHECK (false );
856+ return Rasterizer::ScreenshotFormat::kUnknown ;
857+ case impeller::PixelFormat::kR8G8B8A8UNormInt :
858+ return Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt ;
859+ case impeller::PixelFormat::kB8G8R8A8UNormInt :
860+ return Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt ;
861+ case impeller::PixelFormat::kR16G16B16A16Float :
862+ return Rasterizer::ScreenshotFormat::kR16G16B16A16Float ;
863+ }
864+ }
865+
866+ static std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
867+ ScreenshotLayerTreeAsImageImpeller (
868+ const std::shared_ptr<impeller::AiksContext>& aiks_context,
869+ flutter::LayerTree* tree,
870+ flutter::CompositorContext& compositor_context,
871+ bool compressed) {
872+ if (compressed) {
873+ FML_LOG (ERROR) << " Compressed screenshots not supported for Impeller" ;
874+ return {nullptr , Rasterizer::ScreenshotFormat::kUnknown };
875+ }
876+
877+ DisplayListBuilder builder (SkRect::MakeSize (
878+ SkSize::Make (tree->frame_size ().fWidth , tree->frame_size ().fHeight )));
879+
880+ RenderFrameForScreenshot (compositor_context, &builder, tree, nullptr ,
881+ aiks_context);
882+
883+ impeller::DlDispatcher dispatcher;
884+ builder.Build ()->Dispatch (dispatcher);
885+ const auto & picture = dispatcher.EndRecordingAsPicture ();
886+ const auto & image = picture.ToImage (
887+ *aiks_context,
888+ impeller::ISize (tree->frame_size ().fWidth , tree->frame_size ().fHeight ));
889+ const auto & texture = image->GetTexture ();
890+ impeller::DeviceBufferDescriptor buffer_desc;
891+ buffer_desc.storage_mode = impeller::StorageMode::kHostVisible ;
892+ buffer_desc.size =
893+ texture->GetTextureDescriptor ().GetByteSizeOfBaseMipLevel ();
894+ auto impeller_context = aiks_context->GetContext ();
895+ auto buffer =
896+ impeller_context->GetResourceAllocator ()->CreateBuffer (buffer_desc);
897+ auto command_buffer = impeller_context->CreateCommandBuffer ();
898+ command_buffer->SetLabel (" BlitTextureToBuffer Command Buffer" );
899+ auto pass = command_buffer->CreateBlitPass ();
900+ pass->AddCopy (texture, buffer);
901+ pass->EncodeCommands (impeller_context->GetResourceAllocator ());
902+ fml::AutoResetWaitableEvent latch;
903+ sk_sp<SkData> sk_data;
904+ auto completion = [buffer, &buffer_desc, &sk_data,
905+ &latch](impeller::CommandBuffer::Status status) {
906+ if (status != impeller::CommandBuffer::Status::kCompleted ) {
907+ FML_LOG (ERROR) << " Failed to complete blit pass." ;
908+ latch.Signal ();
909+ return ;
910+ }
911+ sk_data = SkData::MakeWithCopy (buffer->OnGetContents (), buffer_desc.size );
912+
913+ latch.Signal ();
914+ };
915+
916+ if (!command_buffer->SubmitCommands (completion)) {
917+ FML_LOG (ERROR) << " Failed to submit commands." ;
918+ }
919+ latch.Wait ();
920+ return std::make_pair (
921+ sk_data, ToScreenshotFormat (texture->GetTextureDescriptor ().format ));
922+ }
923+ #endif
924+
925+ std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
926+ Rasterizer::ScreenshotLayerTreeAsImage (
927+ flutter::LayerTree* tree,
928+ flutter::CompositorContext& compositor_context,
809929 bool compressed) {
930+ #if IMPELLER_SUPPORTS_RENDERING
931+ if (delegate_.GetSettings ().enable_impeller ) {
932+ return ScreenshotLayerTreeAsImageImpeller (GetAiksContext (), tree,
933+ compositor_context, compressed);
934+ }
935+ #endif // IMPELLER_SUPPORTS_RENDERING
936+
937+ GrDirectContext* surface_context = GetGrContext ();
810938 // Attempt to create a snapshot surface depending on whether we have access
811939 // to a valid GPU rendering context.
812940 std::unique_ptr<OffscreenSurface> snapshot_surface =
813941 std::make_unique<OffscreenSurface>(surface_context, tree->frame_size ());
814942
815943 if (!snapshot_surface->IsValid ()) {
816944 FML_LOG (ERROR) << " Screenshot: unable to create snapshot surface" ;
817- return nullptr ;
945+ return { nullptr , ScreenshotFormat:: kUnknown } ;
818946 }
819947
820948 // Draw the current layer tree into the snapshot surface.
821- auto * canvas = snapshot_surface->GetCanvas ();
822-
823- // There is no root surface transformation for the screenshot layer. Reset
824- // the matrix to identity.
825- SkMatrix root_surface_transformation;
826- root_surface_transformation.reset ();
949+ DlCanvas* canvas = snapshot_surface->GetCanvas ();
827950
828951 // snapshot_surface->makeImageSnapshot needs the GL context to be set if the
829952 // render context is GL. frame->Raster() pops the gl context in platforms
@@ -832,29 +955,26 @@ sk_sp<SkData> Rasterizer::ScreenshotLayerTreeAsImage(
832955 auto context_switch = surface_->MakeRenderContextCurrent ();
833956 if (!context_switch->GetResult ()) {
834957 FML_LOG (ERROR) << " Screenshot: unable to make image screenshot" ;
835- return nullptr ;
958+ return { nullptr , ScreenshotFormat:: kUnknown } ;
836959 }
837960
838- auto frame = compositor_context.AcquireFrame (
839- surface_context, // skia context
840- canvas, // canvas
841- nullptr , // view embedder
842- root_surface_transformation, // root surface transformation
843- false , // instrumentation enabled
844- true , // render buffer readback supported
845- nullptr , // thread merger
846- nullptr // aiks context
847- );
848- canvas->Clear (DlColor::kTransparent ());
849- frame->Raster (*tree, true , nullptr );
850- canvas->Flush ();
961+ RenderFrameForScreenshot (compositor_context, canvas, tree, surface_context,
962+ nullptr );
851963
852- return snapshot_surface->GetRasterData (compressed);
964+ return std::make_pair (snapshot_surface->GetRasterData (compressed),
965+ ScreenshotFormat::kUnknown );
853966}
854967
855968Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree (
856969 Rasterizer::ScreenshotType type,
857970 bool base64_encode) {
971+ if (delegate_.GetSettings ().enable_impeller &&
972+ type == ScreenshotType::SkiaPicture) {
973+ FML_DCHECK (false );
974+ FML_LOG (ERROR) << " Last layer tree cannot be screenshotted as a "
975+ " SkiaPicture when using Impeller." ;
976+ return {};
977+ }
858978 // TODO(dkwingsmt): Support screenshotting all last layer trees
859979 // when the shell protocol supports multi-views.
860980 // https://github.com/flutter/flutter/issues/135534
@@ -865,48 +985,49 @@ Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
865985 return {};
866986 }
867987
868- sk_sp<SkData> data = nullptr ;
988+ std::pair<sk_sp<SkData>, ScreenshotFormat> data{nullptr ,
989+ ScreenshotFormat::kUnknown };
869990 std::string format;
870991
871- GrDirectContext* surface_context =
872- surface_ ? surface_->GetContext () : nullptr ;
873-
874992 switch (type) {
875993 case ScreenshotType::SkiaPicture:
876994 format = " ScreenshotType::SkiaPicture" ;
877- data = ScreenshotLayerTreeAsPicture (layer_tree, *compositor_context_);
995+ data.first =
996+ ScreenshotLayerTreeAsPicture (layer_tree, *compositor_context_);
878997 break ;
879998 case ScreenshotType::UncompressedImage:
880999 format = " ScreenshotType::UncompressedImage" ;
881- data = ScreenshotLayerTreeAsImage (layer_tree, *compositor_context_,
882- surface_context , false );
1000+ data =
1001+ ScreenshotLayerTreeAsImage (layer_tree, *compositor_context_ , false );
8831002 break ;
8841003 case ScreenshotType::CompressedImage:
8851004 format = " ScreenshotType::CompressedImage" ;
886- data = ScreenshotLayerTreeAsImage (layer_tree, *compositor_context_,
887- surface_context, true );
1005+ data = ScreenshotLayerTreeAsImage (layer_tree, *compositor_context_, true );
8881006 break ;
8891007 case ScreenshotType::SurfaceData: {
8901008 Surface::SurfaceData surface_data = surface_->GetSurfaceData ();
8911009 format = surface_data.pixel_format ;
892- data = surface_data.data ;
1010+ data. first = surface_data.data ;
8931011 break ;
8941012 }
8951013 }
8961014
897- if (data == nullptr ) {
1015+ if (data. first == nullptr ) {
8981016 FML_LOG (ERROR) << " Screenshot data was null." ;
8991017 return {};
9001018 }
9011019
9021020 if (base64_encode) {
903- size_t b64_size = Base64::EncodedSize (data->size ());
1021+ size_t b64_size = Base64::EncodedSize (data. first ->size ());
9041022 auto b64_data = SkData::MakeUninitialized (b64_size);
905- Base64::Encode (data->data (), data->size (), b64_data->writable_data ());
906- return Rasterizer::Screenshot{b64_data, layer_tree->frame_size (), format};
1023+ Base64::Encode (data.first ->data (), data.first ->size (),
1024+ b64_data->writable_data ());
1025+ return Rasterizer::Screenshot{b64_data, layer_tree->frame_size (), format,
1026+ data.second };
9071027 }
9081028
909- return Rasterizer::Screenshot{data, layer_tree->frame_size (), format};
1029+ return Rasterizer::Screenshot{data.first , layer_tree->frame_size (), format,
1030+ data.second };
9101031}
9111032
9121033void Rasterizer::SetNextFrameCallback (const fml::closure& callback) {
@@ -977,8 +1098,12 @@ Rasterizer::Screenshot::Screenshot() {}
9771098
9781099Rasterizer::Screenshot::Screenshot (sk_sp<SkData> p_data,
9791100 SkISize p_size,
980- const std::string& p_format)
981- : data(std::move(p_data)), frame_size(p_size), format(p_format) {}
1101+ const std::string& p_format,
1102+ ScreenshotFormat p_pixel_format)
1103+ : data(std::move(p_data)),
1104+ frame_size(p_size),
1105+ format(p_format),
1106+ pixel_format(p_pixel_format) {}
9821107
9831108Rasterizer::Screenshot::Screenshot (const Screenshot& other) = default;
9841109
0 commit comments