blob: dc681e0b72c1c39baefb02c5b7fe21510fa727d0 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_COMMON_FRAME_SINKS_COPY_OUTPUT_RESULT_H_
#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_COPY_OUTPUT_RESULT_H_
#include <array>
#include <vector>
#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/threading/thread_checker.h"
#include "components/viz/common/resources/release_callback.h"
#include "components/viz/common/viz_common_export.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
class SkBitmap;
namespace viz {
// Base class for providing the result of a CopyOutputRequest. Implementations
// that execute CopyOutputRequests will use a subclass implementation to define
// data storage, access and ownership semantics relative to the lifetime of the
// CopyOutputResult instance.
class VIZ_COMMON_EXPORT CopyOutputResult {
public:
enum class Format : uint8_t {
// A normal bitmap. When the results are returned in system memory, the
// AsSkBitmap() will return a bitmap in "N32Premul" form. When the results
// are returned in a texture, it will be a SharedImageFormat::kRGBA_8888
// texture referred to by a gpu::Mailbox. Client code can optionally take
// ownership of the texture (via a call to `TakeSharedImageOwnership()`) if
// it is needed beyond the lifetime of the CopyOutputResult.
RGBA,
// I420 format planes. This is intended to be used internally within the VIZ
// component to support video capture. When requesting this format, results
// can only be delivered on the same task runner sequence that runs the
// DirectRenderer implementation. For now, I420 format can be requested only
// for system memory.
I420_PLANES,
// An NV12 image. This is intended to be used internally within the VIZ
// component to support video capture. When requesting this format, results
// can only be delivered on the same task runner sequence that runs the
// DirectRenderer implementation.
NV12,
// A RGBAF16 shared texture. Results should be returned in a texture, will
// be a SharedImageFormat::kRGBA_F16.
RGBAF16,
};
// Specifies how the results are delivered to the issuer of the request.
// This should usually (but not always!) correspond to the value found in
// `CopyOutputRequest::result_destination()` of the request that caused this
// result to be produced. For details, see the comment on
// `CopyOutputRequest::ResultDestination`.
enum class Destination : uint8_t {
// Place the results in system memory.
kSystemMemory,
// Place the results in a shared image. The caller can use
// `GetSharedImageResult()` and `TakeSharedImageOwnership()` to access the
// results.
kSharedImage,
};
// Maximum number of planes allowed when returning software NV12 results.
static constexpr size_t kNV12MaxPlanes = 2;
// Defines the default usage for shared images which are the destination of a
// `CopyOutputRequest`. Since these shared images will eventually make it back
// to the client that issued that request, the usage here needs to capture the
// variety of clients' eventual allowed usages. Note that CopyOutputRequests
// are not writable via raster (by contract).
static constexpr gpu::SharedImageUsageSet kDefaultSharedImageUsage =
gpu::SHARED_IMAGE_USAGE_RASTER_READ |
gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
gpu::SHARED_IMAGE_USAGE_DISPLAY_WRITE;
CopyOutputResult(Format format,
Destination destination,
const gfx::Rect& rect,
bool needs_lock_for_bitmap);
CopyOutputResult(const CopyOutputResult&) = delete;
CopyOutputResult& operator=(const CopyOutputResult&) = delete;
virtual ~CopyOutputResult();
// Returns false if the request succeeded and the data accessors will return
// valid references.
bool IsEmpty() const;
// Returns the format of this result.
Format format() const { return format_; }
// Returns the destination of this result.
Destination destination() const { return destination_; }
// Returns the result Rect, which is the position and size of the image data
// within the surface/layer (see CopyOutputRequest::set_area()). If a scale
// ratio was set in the request, this will be in the scaled, NOT the original,
// coordinate space.
const gfx::Rect& rect() const { return rect_; }
const gfx::Size& size() const { return rect_.size(); }
class ScopedSkBitmap;
// Return a ScopedSkBitmap object. The scoped_sk_bitmap.bitmap() can be used
// to access the SkBitmap. The API user should not keep a copy of
// scoped_sk_bitmap.bitmap(), since the content SkBitmap could become invalid
// after ScopedSkBitmap is released.
ScopedSkBitmap ScopedAccessSkBitmap() const;
// Get the shared image referencing a texture-backed result, or null if this
// is not a texture-backed result.
// Clients can either:
// 1. Let CopyOutputResult retain ownership and the texture will only be
// valid for use during the CopyOutputResult's lifetime.
// 2. Take over ownership by calling `TakeSharedImageOwnership()`, and the
// client must guarantee that all release callbacks will be run.
virtual scoped_refptr<gpu::ClientSharedImage> GetSharedImage();
using ReleaseCallbacks = std::vector<ReleaseCallback>;
// Returns a vector of release callbacks for the contained shared image. The
// vector will be empty iff the CopyOutputResult `IsEmpty()` is true.
virtual ReleaseCallbacks TakeSharedImageOwnership();
//
// Subsampled YUV format result description
// (valid for I420 and for NV12 formats)
//
// Since I420 and NV12 pixel formats subsample chroma planes and the results
// are returned in a planar manner, care must be taken when interpreting the
// results and when calculating sizes of memory regions for `ReadI420Planes()`
// and `ReadNV12()` methods.
//
// Callers should follow the memory region size requirements specified in
// `ReadI420Planes()` and `ReadNV12()` methods, and are advised to call
// `set_result_selection()` with an even-sized, even-offset gfx::Rect
// if they intend to "stitch" the results into a subregion of an existing
// buffer by copying them. Memory region size calculation helpers are
// available in copy_output_util.h.
//
// Copies the image planes of an I420_PLANES result to the caller-provided
// memory. Returns true if successful, or false if: 1) this result is empty,
// or 2) the result format is not I420_PLANES and does not provide a
// conversion implementation.
//
// |y_out|, |u_out| and |v_out| point to the start of the memory regions to
// receive each plane. These memory regions must have the following sizes:
//
// Y plane: y_out_stride * size().height() bytes, with
// y_out_stride >= size().width()
// U plane: u_out_stride * CEIL(size().height() / 2) bytes, with
// u_out_stride >= CEIL(size().width() / 2)
// V plane: v_out_stride * CEIL(size().height() / 2) bytes, with
// v_out_stride >= CEIL(size().width() / 2)
//
// The color space is always Rec.709 (see gfx::ColorSpace::CreateREC709()).
virtual bool ReadI420Planes(base::span<uint8_t> y_out,
int y_out_stride,
base::span<uint8_t> u_out,
int u_out_stride,
base::span<uint8_t> v_out,
int v_out_stride) const;
// Copies the image planes of an NV12 result to the caller-provided memory.
// Returns true if successful, or false if: 1) this result is empty, or 2) the
// result format is not NV12 and does not provide a conversion implementation.
//
// |y_out| and |uv_out| point to the start of the memory regions to
// receive each plane. These memory regions must have the following sizes:
//
// Y plane: y_out_stride * size().height() bytes, with
// y_out_stride >= size().width()
// UV plane: uv_out_stride * CEIL(size().height() / 2) bytes, with
// uv_out_stride >= 2 * CEIL(size().width() / 2)
//
// The color space is always Rec.709 (see gfx::ColorSpace::CreateREC709()).
virtual bool ReadNV12Planes(base::span<uint8_t> y_out,
int y_out_stride,
base::span<uint8_t> uv_out,
int uv_out_stride) const;
// Copies the result into |dest|. The result is in N32Premul form. Returns
// true if successful, or false if: 1) the result is empty, or 2) the result
// format is not RGBA and conversion is not implemented.
bool ReadRGBAPlane(base::span<uint8_t> dest, int stride) const;
// Returns the color space of the image data returned by ReadRGBAPlane().
virtual gfx::ColorSpace GetRGBAColorSpace() const;
protected:
// Lock the content of SkBitmap returned from AsSkBitmap() call.
// Return true, if lock operation is successful, implementations should
// keep SkBitmap content validate until UnlockSkBitmap() is called.
virtual bool LockSkBitmap() const;
// Unlock the content of SkBitmap returned from AsSkBitmap() call.
virtual void UnlockSkBitmap() const;
// Convenience to provide this result in SkBitmap form. Returns a
// !readyToDraw() bitmap if this result is empty or if a conversion is not
// possible in the current implementation. The returned SkBitmap also carries
// its color space information.
virtual const SkBitmap& AsSkBitmap() const;
// Accessor for subclasses to initialize the cached SkBitmap.
SkBitmap* cached_bitmap() const { return &cached_bitmap_; }
private:
const Format format_;
const Destination destination_;
const gfx::Rect rect_;
const bool needs_lock_for_bitmap_;
// Cached bitmap returned by the default implementation of AsSkBitmap().
mutable SkBitmap cached_bitmap_;
};
// Subclass of CopyOutputResult that provides a RGBA result from an
// SkBitmap (or an I420_PLANES result based on a SkBitmap). Implies that the
// destination is kSystemMemory.
class VIZ_COMMON_EXPORT CopyOutputSkBitmapResult : public CopyOutputResult {
public:
CopyOutputSkBitmapResult(Format format,
const gfx::Rect& rect,
SkBitmap bitmap);
CopyOutputSkBitmapResult(const gfx::Rect& rect, SkBitmap bitmap);
CopyOutputSkBitmapResult(const CopyOutputSkBitmapResult&) = delete;
CopyOutputSkBitmapResult& operator=(const CopyOutputSkBitmapResult&) = delete;
~CopyOutputSkBitmapResult() override;
const SkBitmap& AsSkBitmap() const override;
};
// Subclass of `CopyOutputResult` that holds `ClientSharedImage`. The owner of
// the result must take ownership of the shared images if it wants to use them
// by calling `TakeSharedImageOwnership()`, and then call the `ReleaseCallbacks`
// when the shared images will no longer be used to release ownership and allow
// the shared images to be reused or destroyed. If ownership is not claimed, it
// will be released when this class is destroyed.
class VIZ_COMMON_EXPORT CopyOutputSharedImageResult : public CopyOutputResult {
public:
// Construct a non-empty shared-image result;
// will create unowned `ClientSharedImage` with the provided metadata.
CopyOutputSharedImageResult(Format format,
const gfx::Rect& rect,
const gpu::Mailbox& mailbox,
const gfx::ColorSpace& color_space,
std::string_view debug_label,
ReleaseCallbacks release_callbacks);
// Construct a non-empty shared-image result; `shared_image` must be non-null.
CopyOutputSharedImageResult(
Format format,
const gfx::Rect& rect,
scoped_refptr<gpu::ClientSharedImage> shared_image,
ReleaseCallbacks release_callbacks);
CopyOutputSharedImageResult(const CopyOutputSharedImageResult&) = delete;
CopyOutputSharedImageResult& operator=(const CopyOutputSharedImageResult&) =
delete;
~CopyOutputSharedImageResult() override;
scoped_refptr<gpu::ClientSharedImage> GetSharedImage() override;
ReleaseCallbacks TakeSharedImageOwnership() override;
private:
scoped_refptr<gpu::ClientSharedImage> shared_image_;
ReleaseCallbacks release_callbacks_;
};
// Scoped class for accessing SkBitmap in CopyOutputRequest.
// It cannot be used across threads.
class VIZ_COMMON_EXPORT CopyOutputResult::ScopedSkBitmap {
public:
ScopedSkBitmap();
ScopedSkBitmap(ScopedSkBitmap&& other);
~ScopedSkBitmap();
ScopedSkBitmap& operator=(ScopedSkBitmap&& other);
void reset();
// Accesses SkBitmap which can only be used in the scope of the
// ScopedSkBitmap.
const SkBitmap bitmap() const {
return result_ ? result_->AsSkBitmap() : SkBitmap();
}
// Returns a SkBitmap which can be used out the scope of the ScopedSkBitmap.
// It makes a copy of the content in CopyOutputResult if it is needed.
SkBitmap GetOutScopedBitmap() const;
private:
friend class CopyOutputResult;
explicit ScopedSkBitmap(const CopyOutputResult* result);
raw_ptr<const CopyOutputResult> result_ = nullptr;
THREAD_CHECKER(thread_checker_);
};
// Translate `CopyOutputResult::Format` to `SharedImageFormat`
VIZ_COMMON_EXPORT SharedImageFormat
GetSharedImageFormatFor(CopyOutputResult::Format format);
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_COPY_OUTPUT_RESULT_H_