7#include <lib/async/default.h>
8#include <zircon/rights.h>
9#include <zircon/status.h>
10#include <zircon/types.h>
14#include "flutter/fml/logging.h"
15#include "flutter/fml/trace_event.h"
16#include "fuchsia/sysmem/cpp/fidl.h"
23#include "../runtime/dart/utils/inlines.h"
31uint32_t BytesPerRow(
const fuchsia::sysmem::SingleBufferSettings&
settings,
33 uint32_t image_width) {
34 const uint32_t bytes_per_row_divisor =
35 settings.image_format_constraints.bytes_per_row_divisor;
36 const uint32_t min_bytes_per_row =
37 settings.image_format_constraints.min_bytes_per_row;
38 const uint32_t unrounded_bytes_per_row =
40 const uint32_t roundup_bytes =
41 unrounded_bytes_per_row % bytes_per_row_divisor;
43 return unrounded_bytes_per_row + roundup_bytes;
49 fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
50 fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
52 : wait_for_surface_read_finished_(this) {
55 if (!SetupSkiaSurface(sysmem_allocator, flatland_allocator,
size)) {
60 if (!CreateFences()) {
65 wait_for_surface_read_finished_.set_object(release_event_.get());
66 wait_for_surface_read_finished_.set_trigger(ZX_EVENT_SIGNALED);
73 release_image_callback_();
74 wait_for_surface_read_finished_.Cancel();
75 wait_for_surface_read_finished_.set_object(ZX_HANDLE_INVALID);
90bool SoftwareSurface::CreateFences() {
104bool SoftwareSurface::SetupSkiaSurface(
105 fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
106 fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
108 if (
size.isEmpty()) {
109 FML_LOG(
ERROR) <<
"Failed to allocate surface, size is empty.";
115 fuchsia::sysmem::BufferCollectionTokenSyncPtr local_token;
116 zx_status_t allocate_status =
117 sysmem_allocator->AllocateSharedCollection(local_token.NewRequest());
118 if (allocate_status != ZX_OK) {
120 << zx_status_get_string(allocate_status);
126 std::vector<fuchsia::sysmem::BufferCollectionTokenHandle> duplicate_tokens;
127 zx_status_t duplicate_status = local_token->DuplicateSync(
128 std::vector<zx_rights_t>{ZX_RIGHT_SAME_RIGHTS}, &duplicate_tokens);
129 if (duplicate_status != ZX_OK) {
130 FML_LOG(
ERROR) <<
"Failed to duplicate collection token: "
131 << zx_status_get_string(duplicate_status);
134 if (duplicate_tokens.size() != 1u) {
135 FML_LOG(
ERROR) <<
"Failed to duplicate collection token: Incorrect number "
136 "of tokens returned.";
139 auto scenic_token = std::move(duplicate_tokens[0]);
145 fuchsia::ui::composition::BufferCollectionExportToken export_token;
146 zx_status_t token_create_status =
148 if (token_create_status != ZX_OK) {
149 FML_LOG(
ERROR) <<
"Failed to create flatland export token: "
150 << zx_status_get_string(token_create_status);
154 fuchsia::ui::composition::RegisterBufferCollectionArgs
args;
155 args.set_export_token(std::move(export_token));
156 args.set_buffer_collection_token(std::move(scenic_token));
158 fuchsia::ui::composition::RegisterBufferCollectionUsage::DEFAULT);
159 flatland_allocator->RegisterBufferCollection(
161 [](fuchsia::ui::composition::Allocator_RegisterBufferCollection_Result
165 <<
"RegisterBufferCollection call to Scenic Allocator failed.";
170 fuchsia::sysmem::BufferCollectionSyncPtr buffer_collection;
171 zx_status_t bind_status = sysmem_allocator->BindSharedCollection(
172 std::move(local_token), buffer_collection.NewRequest());
173 if (bind_status != ZX_OK) {
175 << zx_status_get_string(bind_status);
181 fuchsia::sysmem::BufferCollectionConstraints constraints;
182 constraints.min_buffer_count = 1;
183 constraints.usage.cpu =
184 fuchsia::sysmem::cpuUsageWrite | fuchsia::sysmem::cpuUsageWriteOften;
185 constraints.has_buffer_memory_constraints =
true;
186 constraints.buffer_memory_constraints.physically_contiguous_required =
false;
187 constraints.buffer_memory_constraints.secure_required =
false;
188 constraints.buffer_memory_constraints.ram_domain_supported =
true;
189 constraints.buffer_memory_constraints.cpu_domain_supported =
true;
190 constraints.buffer_memory_constraints.inaccessible_domain_supported =
false;
191 constraints.image_format_constraints_count = 1;
192 fuchsia::sysmem::ImageFormatConstraints& image_constraints =
193 constraints.image_format_constraints[0];
194 image_constraints = fuchsia::sysmem::ImageFormatConstraints();
195 image_constraints.min_coded_width =
static_cast<uint32_t
>(
size.fWidth);
196 image_constraints.min_coded_height =
static_cast<uint32_t
>(
size.fHeight);
197 image_constraints.min_bytes_per_row =
static_cast<uint32_t
>(
size.fWidth) * 4;
198 image_constraints.pixel_format.type =
199 fuchsia::sysmem::PixelFormatType::R8G8B8A8;
200 image_constraints.color_spaces_count = 1;
201 image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB;
202 image_constraints.pixel_format.has_format_modifier =
true;
203 image_constraints.pixel_format.format_modifier.value =
204 fuchsia::sysmem::FORMAT_MODIFIER_LINEAR;
205 zx_status_t set_constraints_status =
206 buffer_collection->SetConstraints(
true, constraints);
207 if (set_constraints_status != ZX_OK) {
209 << zx_status_get_string(set_constraints_status);
214 fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info;
215 zx_status_t allocation_status = ZX_OK;
216 zx_status_t wait_for_allocated_status =
217 buffer_collection->WaitForBuffersAllocated(&allocation_status,
218 &buffer_collection_info);
219 if (allocation_status != ZX_OK) {
221 << zx_status_get_string(allocation_status);
224 if (wait_for_allocated_status != ZX_OK) {
226 << zx_status_get_string(wait_for_allocated_status);
231 FML_CHECK(buffer_collection_info.settings.buffer_settings.size_bytes != 0);
232 FML_CHECK(buffer_collection_info.buffers[0].vmo != ZX_HANDLE_INVALID);
233 surface_vmo_ = std::move(buffer_collection_info.buffers[0].vmo);
234 surface_size_bytes_ =
235 buffer_collection_info.settings.buffer_settings.size_bytes;
236 if (buffer_collection_info.settings.buffer_settings.coherency_domain ==
237 fuchsia::sysmem::CoherencyDomain::RAM) {
239 needs_cache_clean_ =
true;
243 uint8_t* vmo_base =
nullptr;
244 zx_status_t buffer_map_status = zx::vmar::root_self()->map(
245 ZX_VM_PERM_WRITE | ZX_VM_PERM_READ, 0, surface_vmo_, 0,
246 surface_size_bytes_,
reinterpret_cast<uintptr_t*
>(&vmo_base));
247 if (buffer_map_status != ZX_OK) {
249 << zx_status_get_string(buffer_map_status);
255 zx_status_t close_status = buffer_collection->Close();
256 if (close_status != ZX_OK) {
258 << zx_status_get_string(close_status);
263 const uint64_t vmo_offset =
264 buffer_collection_info.buffers[0].vmo_usable_start;
265 const size_t vmo_stride =
266 BytesPerRow(buffer_collection_info.settings, 4u,
size.width());
271 vmo_base + vmo_offset, vmo_stride, &sk_surface_props);
272 if (!sk_surface_ || sk_surface_->
getCanvas() ==
nullptr) {
282 image_id_ = image_id;
290 return valid_ ? sk_surface_ :
nullptr;
293fuchsia::ui::composition::BufferCollectionImportToken
295 fuchsia::ui::composition::BufferCollectionImportToken import_dup;
296 import_token_.value.duplicate(ZX_RIGHT_SAME_RIGHTS, &import_dup.value);
302 acquire_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
308 release_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
313 release_image_callback_ = release_image_callback;
330 on_surface_read_finished();
334 FML_CHECK(surface_read_finished_callback_ ==
nullptr)
335 <<
"Attempted to signal a write on the surface when the "
336 "previous write has not yet been acknowledged by the "
338 surface_read_finished_callback_ = on_surface_read_finished;
342 if (needs_cache_clean_) {
343 surface_vmo_.op_range(ZX_VMO_OP_CACHE_CLEAN, 0, surface_size_bytes_,
349 zx_status_t signal_status = acquire_event_.signal(0u, ZX_EVENT_SIGNALED);
350 if (signal_status != ZX_OK) {
352 << zx_status_get_string(signal_status);
356void SoftwareSurface::Reset() {
357 if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK ||
358 release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) {
360 FML_LOG(
ERROR) <<
"Could not reset fences. The surface is no longer valid.";
363 wait_for_surface_read_finished_.Begin(async_get_default_dispatcher());
366 auto callback = surface_read_finished_callback_;
367 surface_read_finished_callback_ =
nullptr;
373void SoftwareSurface::OnSurfaceReadFinished(async_dispatcher_t* dispatcher,
374 async::WaitBase* wait,
376 const zx_packet_signal_t* signal) {
377 if (status != ZX_OK) {
380 FML_DCHECK(signal->observed & ZX_EVENT_SIGNALED);
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
@ kUnknown_SkPixelGeometry
static sk_sp< SkColorSpace > MakeSRGB()
bool FlushSessionAcquireAndReleaseEvents() override
bool IsValid() const override
uint32_t GetImageId() override
fuchsia::ui::composition::BufferCollectionImportToken GetBufferCollectionImportToken() override
void SetReleaseImageCallback(ReleaseImageCallback release_image_callback) override
zx::event GetReleaseFence() override
~SoftwareSurface() override
zx::event GetAcquireFence() override
SoftwareSurface(fuchsia::sysmem::AllocatorSyncPtr &sysmem_allocator, fuchsia::ui::composition::AllocatorPtr &flatland_allocator, const SkISize &size)
size_t AdvanceAndGetAge() override
sk_sp< SkSurface > GetSkiaSurface() const override
void SetImageId(uint32_t image_id) override
SkISize GetSize() const override
void SignalWritesFinished(const std::function< void(void)> &on_surface_read_finished) override
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
Dart_NativeFunction function
static float max(float r, float g, float b)
SK_API sk_sp< SkSurface > WrapPixels(const SkImageInfo &imageInfo, void *pixels, size_t rowBytes, const SkSurfaceProps *surfaceProps=nullptr)
std::function< void()> ReleaseImageCallback
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static size_t bytes_per_pixel(skcms_PixelFormat fmt)
static constexpr SkISize Make(int32_t w, int32_t h)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)