blob: 9f3a100ccea7619c82fd772d6931d0715585331c [file] [log] [blame]
// 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_