blob: 92b38f6de929d7680c6eafb5b159bbbd889387bc [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/test/compositor_frame_helpers.h"
#include <memory>
#include <set>
#include <utility>
#include "base/functional/bind.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/shared_element_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/resources/resource_id.h"
namespace viz {
namespace {
constexpr gfx::Rect kDefaultOutputRect(20, 20);
constexpr gfx::Rect kDefaultDamageRect(0, 0);
constexpr CompositorRenderPassId kInvalidRenderPassId;
// A stub CopyOutputRequest for testing that ignores the result.
class StubCopyOutputRequest : public CopyOutputRequest {
public:
StubCopyOutputRequest()
: CopyOutputRequest(
ResultFormat::RGBA,
ResultDestination::kSystemMemory,
base::BindOnce([](std::unique_ptr<CopyOutputResult>) {})) {}
~StubCopyOutputRequest() override = default;
base::WeakPtr<CopyOutputRequest> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
base::WeakPtrFactory<CopyOutputRequest> weak_factory_{this};
};
} // namespace
RenderPassBuilder::RenderPassBuilder(CompositorRenderPassId id,
const gfx::Size& output_size)
: RenderPassBuilder(id, gfx::Rect(output_size)) {}
RenderPassBuilder::RenderPassBuilder(CompositorRenderPassId id,
const gfx::Rect& output_rect)
: pass_(CompositorRenderPass::Create()) {
CHECK(!output_rect.IsEmpty());
pass_->id = id;
pass_->output_rect = output_rect;
pass_->damage_rect = output_rect; // Full damage by default.
}
RenderPassBuilder::RenderPassBuilder(const gfx::Size& output_size)
: RenderPassBuilder(kInvalidRenderPassId, output_size) {}
RenderPassBuilder::RenderPassBuilder(const gfx::Rect& output_rect)
: RenderPassBuilder(kInvalidRenderPassId, output_rect) {}
RenderPassBuilder::~RenderPassBuilder() = default;
bool RenderPassBuilder::IsValid() const {
return pass_ && !pass_->quad_list.empty();
}
std::unique_ptr<CompositorRenderPass> RenderPassBuilder::Build() {
return std::move(pass_);
}
RenderPassBuilder& RenderPassBuilder::SetDamageRect(
const gfx::Rect& damage_rect) {
CHECK(pass_->output_rect.Contains(damage_rect));
pass_->damage_rect = damage_rect;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetCacheRenderPass(bool val) {
pass_->cache_render_pass = val;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetHasDamageFromContributingContent(
bool val) {
pass_->has_damage_from_contributing_content = val;
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddFilter(
const cc::FilterOperation& filter) {
pass_->filters.Append(filter);
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddBackdropFilter(
const cc::FilterOperation& filter) {
pass_->backdrop_filters.Append(filter);
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddStubCopyOutputRequest(
base::WeakPtr<CopyOutputRequest>* request_out) {
auto request = std::make_unique<StubCopyOutputRequest>();
if (request_out)
*request_out = request->GetWeakPtr();
pass_->copy_requests.push_back(std::move(request));
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddSharedElementQuad(
const gfx::Rect& rect,
const ViewTransitionElementResourceId& id) {
auto* sqs = AppendDefaultSharedQuadState(rect, rect);
auto* quad = pass_->CreateAndAppendDrawQuad<SharedElementDrawQuad>();
quad->SetNew(sqs, rect, rect, id);
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddSolidColorQuad(
const gfx::Rect& rect,
SkColor4f color,
SolidColorQuadParms params) {
return AddSolidColorQuad(rect, rect, color, params);
}
RenderPassBuilder& RenderPassBuilder::AddSolidColorQuad(
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
SkColor4f color,
SolidColorQuadParms params) {
auto* sqs = AppendDefaultSharedQuadState(rect, visible_rect);
auto* quad = pass_->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
quad->SetNew(sqs, rect, visible_rect, color, params.force_anti_aliasing_off);
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddSurfaceQuad(
const gfx::Rect& rect,
const SurfaceRange& surface_range,
const SurfaceQuadParams& params) {
return AddSurfaceQuad(rect, rect, surface_range, params);
}
RenderPassBuilder& RenderPassBuilder::AddSurfaceQuad(
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
const SurfaceRange& surface_range,
const SurfaceQuadParams& params) {
auto* sqs = AppendDefaultSharedQuadState(rect, visible_rect);
auto* quad = pass_->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
// TODO (crbug.com/1308932) Change SurfaceQuadParams to use SKColor4f
quad->SetNew(sqs, rect, visible_rect, surface_range,
params.default_background_color,
params.stretch_content_to_fill_bounds);
quad->is_reflection = params.is_reflection;
quad->allow_merge = params.allow_merge;
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddRenderPassQuad(
const gfx::Rect& rect,
CompositorRenderPassId id,
const RenderPassQuadParams& params) {
return AddRenderPassQuad(rect, rect, id, params);
}
RenderPassBuilder& RenderPassBuilder::AddRenderPassQuad(
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
CompositorRenderPassId id,
const RenderPassQuadParams& params) {
auto* sqs = AppendDefaultSharedQuadState(rect, visible_rect);
auto* quad = pass_->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
quad->SetAll(sqs, rect, visible_rect, params.needs_blending, id,
kInvalidResourceId, gfx::RectF(), gfx::Size(), gfx::Vector2dF(),
gfx::PointF(), gfx::RectF(), params.force_anti_aliasing_off,
/*backdrop_filter_quality=*/1.0f,
params.intersects_damage_under);
return *this;
}
RenderPassBuilder& RenderPassBuilder::AddTextureQuad(
const gfx::Rect& rect,
ResourceId resource_id,
const TextureQuadParams& params) {
return AddTextureQuad(rect, rect, resource_id, params);
}
RenderPassBuilder& RenderPassBuilder::AddTextureQuad(
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
ResourceId resource_id,
const TextureQuadParams& params) {
auto* sqs = AppendDefaultSharedQuadState(rect, visible_rect);
auto* quad = pass_->CreateAndAppendDrawQuad<TextureDrawQuad>();
quad->SetAll(sqs, rect, visible_rect, params.needs_blending, resource_id,
rect.size(), params.premultiplied_alpha, gfx::PointF(0.0f, 0.0f),
gfx::PointF(1.0f, 1.0f), params.background_color,
params.vertex_opacity, params.flipped, params.nearest_neighbor,
params.secure_output_only, gfx::ProtectedVideoType::kClear);
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetQuadToTargetTransform(
const gfx::Transform& transform) {
GetLastQuadSharedQuadState()->quad_to_target_transform = transform;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetQuadToTargetTranslation(
int translate_x,
int translate_y) {
gfx::Transform transform;
transform.Translate(translate_x, translate_y);
return SetQuadToTargetTransform(transform);
}
RenderPassBuilder& RenderPassBuilder::SetQuadOpacity(float opacity) {
CHECK_GE(opacity, 0.0f);
CHECK_LE(opacity, 1.0f);
GetLastQuadSharedQuadState()->opacity = opacity;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetQuadClipRect(
absl::optional<gfx::Rect> clip_rect) {
CHECK(!clip_rect || pass_->output_rect.Contains(*clip_rect));
GetLastQuadSharedQuadState()->clip_rect = clip_rect;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetQuadDamageRect(
const gfx::Rect& damage_rect) {
CHECK(!pass_->quad_list.empty());
DrawQuad* quad = pass_->quad_list.back();
if (quad->material == DrawQuad::Material::kTextureContent) {
auto* texture_quad = static_cast<TextureDrawQuad*>(quad);
texture_quad->damage_rect = damage_rect;
} else if (quad->material == DrawQuad::Material::kYuvVideoContent) {
auto* yuv_video_quad = static_cast<YUVVideoDrawQuad*>(quad);
yuv_video_quad->damage_rect = damage_rect;
} else {
NOTREACHED();
}
pass_->has_per_quad_damage = true;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetBlendMode(SkBlendMode blend_mode) {
GetLastQuadSharedQuadState()->blend_mode = blend_mode;
return *this;
}
RenderPassBuilder& RenderPassBuilder::SetMaskFilter(
const gfx::MaskFilterInfo& mask_filter_info,
bool is_fast_rounded_corner) {
auto* sqs = GetLastQuadSharedQuadState();
sqs->mask_filter_info = mask_filter_info;
sqs->is_fast_rounded_corner = is_fast_rounded_corner;
return *this;
}
SharedQuadState* RenderPassBuilder::AppendDefaultSharedQuadState(
const gfx::Rect rect,
const gfx::Rect visible_rect) {
SharedQuadState* sqs = pass_->CreateAndAppendSharedQuadState();
sqs->SetAll(gfx::Transform(), rect, visible_rect, gfx::MaskFilterInfo(),
/*clip=*/absl::nullopt, /*contents_opaque=*/false,
/*opacity_f=*/1.0f, SkBlendMode::kSrcOver, 0);
return sqs;
}
SharedQuadState* RenderPassBuilder::GetLastQuadSharedQuadState() {
CHECK(!pass_->quad_list.empty());
CHECK(!pass_->shared_quad_state_list.empty());
CHECK(pass_->shared_quad_state_list.back() ==
pass_->quad_list.back()->shared_quad_state);
return pass_->shared_quad_state_list.back();
}
CompositorFrameBuilder::CompositorFrameBuilder() {
frame_ = MakeInitCompositorFrame();
}
CompositorFrameBuilder::~CompositorFrameBuilder() = default;
CompositorFrame CompositorFrameBuilder::Build() {
CompositorFrame temp_frame(std::move(frame_.value()));
frame_ = MakeInitCompositorFrame();
return temp_frame;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddDefaultRenderPass() {
return AddRenderPass(kDefaultOutputRect, kDefaultDamageRect);
}
CompositorFrameBuilder& CompositorFrameBuilder::AddRenderPass(
const gfx::Rect& output_rect,
const gfx::Rect& damage_rect) {
auto pass = CompositorRenderPass::Create();
pass->SetNew(render_pass_id_generator_.GenerateNextId(), output_rect,
damage_rect, gfx::Transform());
frame_->render_pass_list.push_back(std::move(pass));
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddRenderPass(
std::unique_ptr<CompositorRenderPass> render_pass) {
// Give the render pass a unique id if one hasn't been assigned.
if (render_pass->id.is_null())
render_pass->id = render_pass_id_generator_.GenerateNextId();
// Populate referenced_surfaces if there are any SurfaceDrawQuads.
for (auto* quad : render_pass->quad_list) {
if (quad->material == DrawQuad::Material::kSurfaceContent) {
auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
frame_->metadata.referenced_surfaces.push_back(
surface_quad->surface_range);
}
}
frame_->render_pass_list.push_back(std::move(render_pass));
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddRenderPass(
RenderPassBuilder& builder) {
CHECK(builder.IsValid());
AddRenderPass(builder.Build());
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetRenderPassList(
CompositorRenderPassList render_pass_list) {
CHECK(frame_->render_pass_list.empty());
// Call AddRenderPass() for each pass as it contains additional logic.
for (auto& render_pass : render_pass_list)
AddRenderPass(std::move(render_pass));
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddTransferableResource(
TransferableResource resource) {
frame_->resource_list.push_back(std::move(resource));
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetTransferableResources(
std::vector<TransferableResource> resource_list) {
DCHECK(frame_->resource_list.empty());
frame_->resource_list = std::move(resource_list);
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::PopulateResources() {
PopulateTransferableResources(frame_.value());
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetBeginFrameAck(
const BeginFrameAck& ack) {
frame_->metadata.begin_frame_ack = ack;
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetDeviceScaleFactor(
float device_scale_factor) {
frame_->metadata.device_scale_factor = device_scale_factor;
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddLatencyInfo(
ui::LatencyInfo latency_info) {
frame_->metadata.latency_info.push_back(std::move(latency_info));
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddLatencyInfos(
std::vector<ui::LatencyInfo> latency_info) {
if (frame_->metadata.latency_info.empty()) {
frame_->metadata.latency_info.swap(latency_info);
} else {
for (auto& latency : latency_info) {
frame_->metadata.latency_info.push_back(std::move(latency));
}
}
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetActivationDependencies(
std::vector<SurfaceId> activation_dependencies) {
frame_->metadata.activation_dependencies = std::move(activation_dependencies);
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetDeadline(
const FrameDeadline& deadline) {
frame_->metadata.deadline = deadline;
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetReferencedSurfaces(
std::vector<SurfaceRange> referenced_surfaces) {
frame_->metadata.referenced_surfaces = std::move(referenced_surfaces);
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::SetSendFrameTokenToEmbedder(
bool send) {
DCHECK(frame_->metadata.frame_token);
frame_->metadata.send_frame_token_to_embedder = send;
return *this;
}
CompositorFrameBuilder& CompositorFrameBuilder::AddDelegatedInkMetadata(
const gfx::DelegatedInkMetadata& metadata) {
frame_->metadata.delegated_ink_metadata =
std::make_unique<gfx::DelegatedInkMetadata>(metadata);
return *this;
}
CompositorFrame CompositorFrameBuilder::MakeInitCompositorFrame() const {
static FrameTokenGenerator next_token;
CompositorFrame frame;
frame.metadata.begin_frame_ack = BeginFrameAck::CreateManualAckWithDamage();
frame.metadata.device_scale_factor = 1.f;
frame.metadata.frame_token = ++next_token;
return frame;
}
CompositorRenderPassList CopyRenderPasses(
const CompositorRenderPassList& render_pass_list) {
CompositorRenderPassList copy_list;
for (auto& render_pass : render_pass_list)
copy_list.push_back(render_pass->DeepCopy());
return copy_list;
}
CompositorFrame MakeDefaultCompositorFrame() {
return CompositorFrameBuilder().AddDefaultRenderPass().Build();
}
CompositorFrame MakeCompositorFrame(
std::unique_ptr<CompositorRenderPass> render_pass) {
return CompositorFrameBuilder()
.AddRenderPass(std::move(render_pass))
.PopulateResources()
.Build();
}
CompositorFrame MakeCompositorFrame(CompositorRenderPassList render_pass_list) {
return CompositorFrameBuilder()
.SetRenderPassList(std::move(render_pass_list))
.PopulateResources()
.Build();
}
AggregatedFrame MakeDefaultAggregatedFrame(size_t num_render_passes) {
static AggregatedRenderPassId::Generator id_generator;
AggregatedFrame frame;
for (size_t i = 0; i < num_render_passes; ++i) {
frame.render_pass_list.push_back(std::make_unique<AggregatedRenderPass>());
frame.render_pass_list.back()->SetNew(id_generator.GenerateNextId(),
kDefaultOutputRect,
kDefaultDamageRect, gfx::Transform());
}
return frame;
}
CompositorFrame MakeEmptyCompositorFrame() {
return CompositorFrameBuilder().Build();
}
void PopulateTransferableResources(CompositorFrame& frame) {
DCHECK(frame.resource_list.empty());
std::set<ResourceId> resources_added;
for (auto& render_pass : frame.render_pass_list) {
for (auto* quad : render_pass->quad_list) {
for (ResourceId resource_id : quad->resources) {
if (resource_id == kInvalidResourceId)
continue;
// Adds a TransferableResource the first time seeing a ResourceId.
if (resources_added.insert(resource_id).second) {
frame.resource_list.push_back(TransferableResource::MakeSoftware(
SharedBitmap::GenerateId(), quad->rect.size(), RGBA_8888));
frame.resource_list.back().id = resource_id;
}
}
}
}
}
} // namespace viz