| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_EMBEDDER_SOFTWARE_SURFACE_H_ |
| #define SRC_EMBEDDER_SOFTWARE_SURFACE_H_ |
| |
| #include <fuchsia/sysmem/cpp/fidl.h> |
| #include <fuchsia/ui/composition/cpp/fidl.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/ui/scenic/cpp/id.h> |
| #include <lib/ui/scenic/cpp/resources.h> |
| #include <lib/zx/event.h> |
| #include <lib/zx/vmo.h> |
| |
| #include <array> |
| #include <cstdint> |
| #include <memory> |
| |
| namespace embedder { |
| |
| using ReleaseImageCallback = std::function<void()>; |
| |
| struct Size { |
| uint32_t width; |
| uint32_t height; |
| }; |
| |
| /// Manages the state of a single surface acquired for software |
| /// rendering. |
| class SoftwareSurface final { |
| public: |
| SoftwareSurface(fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator, |
| fuchsia::ui::composition::AllocatorPtr& flatland_allocator, const Size size); |
| ~SoftwareSurface(); |
| SoftwareSurface(const SoftwareSurface&) = delete; |
| SoftwareSurface& operator=(const SoftwareSurface&) = delete; |
| |
| /// Signal to Scenic that we've finished writing a surface, setting |
| /// up a callback to be fired once Scenic has finished reading from |
| /// the surface. |
| void SignalWritesFinished(const std::function<void(void)>& on_read_finished); |
| |
| /// Sets the callback that should be called when the surface is |
| /// destroyed. |
| void SetReleaseImageCallback(ReleaseImageCallback release_image_callback); |
| |
| /// Associates a Flatland image with this surface by Flatland ID. |
| /// |
| /// This should only ever be called once once an image has been created. |
| /// If you need a new image ID, create a new surface. |
| void SetImageId(uint32_t image_id); |
| /// Gets the Flatland image ID associated with this surface. |
| /// |
| /// Returns 0 if `SetImageId()` has never been called. |
| uint32_t GetImageId() const; |
| |
| /// Returns the width and height of the surface in pixels. |
| Size GetSize() const; |
| /// Get a pointer to the start of the memory allocated for the surface. |
| uint8_t* GetAllocation() const; |
| /// Returns the size of the surface in bytes. |
| size_t GetAllocationSize() const; |
| /// Get the number of bytes per row of the surface. |
| uint32_t GetBytesPerRow() const; |
| |
| /// Returns whether the surface was initialized successfully. |
| bool IsValid() const; |
| |
| /// Gets the event that should be signalled before Flatland |
| /// will present the surface. |
| zx::event GetAcquireFence(); |
| /// Gets the event that should be signalled by Flatland when |
| /// Flatland is finished with the shared buffer from presenting. |
| zx::event GetReleaseFence(); |
| |
| /// Gets the token that represents our client's view of the |
| /// buffer collection. |
| /// |
| /// Terminology note: The import token is our handle for the |
| /// buffer collection while the export token is Scenic's |
| /// handle for the buffer collection. |
| fuchsia::ui::composition::BufferCollectionImportToken GetBufferCollectionImportToken(); |
| |
| private: |
| /// Called when Scenic has finished reading from the surface. |
| /// |
| /// See |
| /// https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/zircon/system/ulib/async/include/lib/async/wait.h |
| /// for an explanation of the arguments. |
| void OnReadFinished(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, |
| const zx_packet_signal_t* signal); |
| |
| /// Acquire a surface with the given |size|. |
| /// |
| /// We use sysmem to grab a surface with CPU access. For high-level details |
| /// on sysmem and an explanation of the allocation process, see |
| /// https://fuchsia.dev/fuchsia-src/development/graphics/sysmem/concepts/sysmem. |
| bool AcquireSurface(fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator, |
| fuchsia::ui::composition::AllocatorPtr& flatland_allocator, const Size size); |
| |
| /// Create the acquire and release fences for this surface. The acquire |
| /// fence signals to Scenic that we've finished writing. The release fence |
| /// is signalled by Scenic when they've finished using shared resources. |
| bool CreateFences(); |
| |
| void Reset(); |
| |
| /// This is associated with `release_event_` and allows detection of when |
| /// Scenic has finished reading from the surface (and thus it is safe to |
| /// re-use for writing). |
| async::WaitMethod<SoftwareSurface, &SoftwareSurface::OnReadFinished> wait_for_read_finished_; |
| /// Called when Scenic has finished reading from the surface, to allow |
| /// `SoftwareSurfaceProducer` to re-use the surface. |
| std::function<void()> read_finished_callback_; |
| /// Called when the surface is destroyed, to allow |
| /// `FlatlandExternalViewEmbedder` to release the associated Flatland image. |
| ReleaseImageCallback release_image_callback_; |
| |
| /// Allows Flatland to associate this surface with a Flatland Image. |
| fuchsia::ui::composition::BufferCollectionImportToken import_token_; |
| |
| /// Signals to Scenic that writing is finished. |
| zx::event acquire_event_; |
| /// Signalled by Scenic that reading is finished. |
| zx::event release_event_; |
| |
| /// Virtual Memory Object (VMO) that is backing the surface memory. |
| /// https://fuchsia.dev/fuchsia-src/reference/kernel_objects/vm_object |
| zx::vmo vmo_; |
| /// vmo_ mapped to the CPU. |
| uint8_t* allocation_; |
| /// Size of the surface memory, in bytes. |
| uint32_t size_bytes_; |
| /// How many bytes there are per row of the surface. |
| uint32_t bytes_per_row_; |
| /// The width of the surface in pixels. |
| uint32_t width_; |
| /// The height of the surface in pixels. |
| uint32_t height_; |
| |
| /// The Flatland Image ID of the surface. |
| uint32_t image_id_ = 0; |
| |
| /// On some platforms, the sysmem driver is not able to handle |
| /// flushing the cache lines after writing to a CPU-accessible |
| /// sysmem surface. To handle this, we unconditionally clean |
| /// the cache ourselves when doing software rendering. |
| bool needs_cache_clean_ = false; |
| |
| /// The surface can become invalid after making calls. Examples |
| /// include failing to acquire memory and failing to signal fences. |
| bool valid_ = false; |
| }; |
| |
| } // namespace embedder |
| |
| #endif // SRC_EMBEDDER_SOFTWARE_SURFACE_H_ |