Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
vulkan_screenshotter.mm
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/impeller/golden_tests/vulkan_screenshotter.h"
6
7#include "flutter/fml/synchronization/waitable_event.h"
8#include "flutter/impeller/golden_tests/metal_screenshot.h"
9#define GLFW_INCLUDE_NONE
10#include "third_party/glfw/include/GLFW/glfw3.h"
11
12namespace impeller {
13namespace testing {
14
15namespace {
16
17using CGContextPtr = std::unique_ptr<std::remove_pointer<CGContextRef>::type,
18 decltype(&CGContextRelease)>;
19using CGImagePtr = std::unique_ptr<std::remove_pointer<CGImageRef>::type,
20 decltype(&CGImageRelease)>;
21using CGColorSpacePtr =
22 std::unique_ptr<std::remove_pointer<CGColorSpaceRef>::type,
23 decltype(&CGColorSpaceRelease)>;
24
25std::unique_ptr<Screenshot> ReadTexture(
26 const std::shared_ptr<Context>& surface_context,
27 const std::shared_ptr<Texture>& texture) {
28 DeviceBufferDescriptor buffer_desc;
29 buffer_desc.storage_mode = StorageMode::kHostVisible;
30 buffer_desc.size =
31 texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
32 buffer_desc.readback = true;
33 std::shared_ptr<DeviceBuffer> device_buffer =
34 surface_context->GetResourceAllocator()->CreateBuffer(buffer_desc);
35 FML_CHECK(device_buffer);
36
37 auto command_buffer = surface_context->CreateCommandBuffer();
38 auto blit_pass = command_buffer->CreateBlitPass();
39 bool success = blit_pass->AddCopy(texture, device_buffer);
40 FML_CHECK(success);
41
42 success = blit_pass->EncodeCommands(surface_context->GetResourceAllocator());
43 FML_CHECK(success);
44
46 success =
47 surface_context->GetCommandQueue()
48 ->Submit({command_buffer},
49 [&latch](CommandBuffer::Status status) {
51 latch.Signal();
52 })
53 .ok();
54 FML_CHECK(success);
55 latch.Wait();
56 device_buffer->Invalidate();
57
58 // TODO(gaaclarke): Replace CoreImage requirement with something
59 // crossplatform.
60
61 CGColorSpacePtr color_space(CGColorSpaceCreateDeviceRGB(),
62 &CGColorSpaceRelease);
63 CGBitmapInfo bitmap_info =
64 texture->GetTextureDescriptor().format == PixelFormat::kB8G8R8A8UNormInt
65 ? kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
66 : kCGImageAlphaPremultipliedLast;
67 CGContextPtr context(
68 CGBitmapContextCreate(
69 device_buffer->OnGetContents(), texture->GetSize().width,
70 texture->GetSize().height,
71 /*bitsPerComponent=*/8,
72 /*bytesPerRow=*/texture->GetTextureDescriptor().GetBytesPerRow(),
73 color_space.get(), bitmap_info),
74 &CGContextRelease);
75 FML_CHECK(context);
76 CGImagePtr image(CGBitmapContextCreateImage(context.get()), &CGImageRelease);
78
79 // TODO(https://github.com/flutter/flutter/issues/142641): Perform the flip at
80 // the blit stage to avoid this slow copy.
81 if (texture->GetYCoordScale() == -1) {
82 CGContextPtr flipped_context(
83 CGBitmapContextCreate(
84 nullptr, texture->GetSize().width, texture->GetSize().height,
85 /*bitsPerComponent=*/8,
86 /*bytesPerRow=*/0, color_space.get(), bitmap_info),
87 &CGContextRelease);
88 CGContextTranslateCTM(flipped_context.get(), 0, texture->GetSize().height);
89 CGContextScaleCTM(flipped_context.get(), 1.0, -1.0);
90 CGContextDrawImage(
91 flipped_context.get(),
92 CGRectMake(0, 0, texture->GetSize().width, texture->GetSize().height),
93 image.get());
94 CGImagePtr flipped_image(CGBitmapContextCreateImage(flipped_context.get()),
95 &CGImageRelease);
96 image.swap(flipped_image);
97 }
98
99 return std::make_unique<MetalScreenshot>(image.release());
100}
101} // namespace
102
104 const std::unique_ptr<PlaygroundImpl>& playground)
105 : playground_(playground) {
106 FML_CHECK(playground_);
107}
108
109std::unique_ptr<Screenshot> VulkanScreenshotter::MakeScreenshot(
110 AiksContext& aiks_context,
111 const Picture& picture,
112 const ISize& size,
113 bool scale_content) {
114 Vector2 content_scale =
115 scale_content ? playground_->GetContentScale() : Vector2{1, 1};
116 std::shared_ptr<Image> image = picture.ToImage(
117 aiks_context,
118 ISize(size.width * content_scale.x, size.height * content_scale.y));
119 std::shared_ptr<Texture> texture = image->GetTexture();
120 return ReadTexture(aiks_context.GetContext(), texture);
121}
122
123} // namespace testing
124} // namespace impeller
static bool ok(int result)
std::shared_ptr< Context > GetContext() const
VulkanScreenshotter(const std::unique_ptr< PlaygroundImpl > &playground)
std::unique_ptr< Screenshot > MakeScreenshot(AiksContext &aiks_context, const Picture &picture, const ISize &size={300, 300}, bool scale_content=true) override
void swap(sk_sp< T > &that)
Definition SkRefCnt.h:330
T * get() const
Definition SkRefCnt.h:303
T * release()
Definition SkRefCnt.h:324
sk_sp< SkImage > image
Definition examples.cpp:29
#define FML_CHECK(condition)
Definition logging.h:85
FlTexture * texture
TSize< int64_t > ISize
Definition size.h:138