blob: b02aad794586fb5dba333762e33ddb8baa25937b [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_REQUEST_H_
#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_COPY_OUTPUT_REQUEST_H_
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "base/functional/callback.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "components/viz/common/frame_sinks/blit_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/viz_common_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
namespace viz {
namespace mojom {
class CopyOutputRequestDataView;
}
// Holds all the properties pertaining to a copy of a surface or layer.
// Implementations that execute these requests must provide the requested
// ResultFormat or else an "empty" result. Likewise, this means that any
// transient or permanent errors preventing the successful execution of a
// copy request will result in an "empty" result.
//
// Usage: Client code creates a CopyOutputRequest, optionally sets some/all of
// its properties, and then submits it to the compositing pipeline via one of a
// number of possible entry points (usually methods named RequestCopyOfOutput()
// or RequestCopyOfSurface()). Then, some time later, the given result callback
// will be run and the client processes the CopyOutputResult containing the
// image.
//
// Note: This should be used for one-off screen capture only, and NOT for video
// screen capture use cases (please use FrameSinkVideoCapturer instead).
class VIZ_COMMON_EXPORT CopyOutputRequest {
public:
using ResultFormat = CopyOutputResult::Format;
// Specifies intended destination for the results. For software compositing,
// only the system-memory results are supported - even if the
// CopyOutputRequest is issued with ResultDestination::kNativeTextures, the
// results will still be returned via ResultDestination::kSystemMemory.
using ResultDestination = CopyOutputResult::Destination;
using CopyOutputRequestCallback =
base::OnceCallback<void(std::unique_ptr<CopyOutputResult> result)>;
// Creates new CopyOutputRequest. I420_PLANES format returned via
// kNativeTextures is currently not supported.
CopyOutputRequest(ResultFormat result_format,
ResultDestination result_destination,
CopyOutputRequestCallback result_callback);
CopyOutputRequest(const CopyOutputRequest&) = delete;
CopyOutputRequest& operator=(const CopyOutputRequest&) = delete;
virtual ~CopyOutputRequest();
// Returns the requested result format.
ResultFormat result_format() const { return result_format_; }
// Returns the requested result destination.
ResultDestination result_destination() const { return result_destination_; }
base::TimeDelta send_result_delay() const { return send_result_delay_; }
// Optionally set a delay for sending the result.
// You can use this when you know that the CPU will be busy at the time of
// requesting the output and the result can wait.
// Because holding tasks can be expensive, we limit the number of pending
// tasks to kMaxPendingSendResult. When the limit is reached, results are sent
// immediately.
// There are no guarantees as to the order in which the SendResults are
// called.
//
// To provide ordering guarantees, we would have to include some form of
// queueing and track it across multiple threads. This complexity was not
// worth it when this was first introduced with only one usage with minimal
// delays.
void set_send_result_delay(base::TimeDelta d) { send_result_delay_ = d; }
// Requests that the result callback be run as a task posted to the given
// |task_runner|. If this is not set, the result callback will be run on the
// thread that the `CopyOutputRequest` was created on.
void set_result_task_runner(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
result_task_runner_ = std::move(task_runner);
}
bool has_result_task_runner() const { return !!result_task_runner_; }
// Optionally specify that the result should be scaled. |scale_from| and
// |scale_to| describe the scale ratio in terms of relative sizes: Downscale
// if |scale_from| > |scale_to|, upscale if |scale_from| < |scale_to|, and
// no scaling if |scale_from| == |scale_to|. Neither argument may be zero.
//
// There are two setters: SetScaleRatio() allows for requesting an arbitrary
// scale in each dimension, which is sometimes useful for minor "tweaks" that
// optimize visual quality. SetUniformScaleRatio() scales both dimensions by
// the same amount.
void SetScaleRatio(const gfx::Vector2d& scale_from,
const gfx::Vector2d& scale_to);
void SetUniformScaleRatio(int scale_from, int scale_to);
const gfx::Vector2d& scale_from() const { return scale_from_; }
const gfx::Vector2d& scale_to() const { return scale_to_; }
bool is_scaled() const { return scale_from_ != scale_to_; }
// Optionally specify the source of this copy request. This is used when the
// client plans to make many similar copy requests over short periods of time.
// It is used to: 1) auto-abort prior uncommitted copy requests to avoid
// duplicate copies of the same frame; and 2) hint to the implementation to
// cache resources for more-efficient execution of later copy requests.
void set_source(const base::UnguessableToken& source) { source_ = source; }
bool has_source() const { return source_.has_value(); }
const base::UnguessableToken& source() const { return *source_; }
// Optionally specify the clip rect; meaning that just a portion of the entire
// surface (or layer's subtree output) should be scanned to produce a result.
// This rect is in the same space as the RenderPass output rect, pre-scaling.
// This is related to set_result_selection() (see below).
void set_area(const gfx::Rect& area) { area_ = area; }
bool has_area() const { return area_.has_value(); }
const gfx::Rect& area() const { return *area_; }
// Optionally specify that only a portion of the result be generated. The
// selection rect will be clamped to the result bounds, which always starts at
// 0,0 and spans the post-scaling size of the copy area (see set_area()
// above). Only RGBA format supports odd-sized result selection. Can only be
// called before blit request was set on the copy request.
void set_result_selection(const gfx::Rect& selection) {
DCHECK(result_format_ == ResultFormat::RGBA ||
result_format_ == ResultFormat::RGBAF16 ||
(selection.width() % 2 == 0 && selection.height() % 2 == 0))
<< "CopyOutputRequest supports odd-sized result_selection() only for "
"RGBA and RGBAF16!";
DCHECK(!has_blit_request());
result_selection_ = selection;
}
bool has_result_selection() const { return result_selection_.has_value(); }
const gfx::Rect& result_selection() const { return *result_selection_; }
// Requests that the region copied by the CopyOutputRequest be blitted into
// the caller's textures. Can be called only for CopyOutputRequests that
// target native textures. Requires that result selection was set, in which
// case the caller's textures will be populated with the results of the
// copy request. The region in the caller's textures that will be populated
// is specified by `gfx::Rect(blit_request.destination_region_offset(),
// result_selection().size())`. If blit request is configured to perform
// letterboxing, all contents outside of that region will be overwritten with
// black, otherwise they will be unchanged. If the copy request's result would
// be smaller than `result_selection().size()`, the request will fail (i.e.
// empty result will be sent).
void set_blit_request(BlitRequest blit_request);
bool has_blit_request() const { return blit_request_.has_value(); }
const BlitRequest& blit_request() const { return *blit_request_; }
// Sends the result from executing this request. Called by the internal
// implementation, usually a DirectRenderer.
void SendResult(std::unique_ptr<CopyOutputResult> result);
// Returns true if SendResult() will deliver the CopyOutputResult using the
// same TaskRunner as that to which the current task was posted.
bool SendsResultsInCurrentSequence() const;
// Creates a RGBA request with ResultDestination::kSystemMemory that ignores
// results, for testing purposes.
static std::unique_ptr<CopyOutputRequest> CreateStubForTesting();
std::string ToString() const;
private:
// Note: The StructTraits may "steal" the |result_callback_|, to allow it to
// outlive this CopyOutputRequest (and wait for the result from another
// process).
friend struct mojo::StructTraits<mojom::CopyOutputRequestDataView,
std::unique_ptr<CopyOutputRequest>>;
const ResultFormat result_format_;
const ResultDestination result_destination_;
base::TimeDelta send_result_delay_;
CopyOutputRequestCallback result_callback_;
scoped_refptr<base::SequencedTaskRunner> result_task_runner_;
gfx::Vector2d scale_from_;
gfx::Vector2d scale_to_;
std::optional<base::UnguessableToken> source_;
std::optional<gfx::Rect> area_;
std::optional<gfx::Rect> result_selection_;
std::optional<BlitRequest> blit_request_;
};
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_COPY_OUTPUT_REQUEST_H_