Skip to content

Commit

Permalink
[Android] Support SbPlayer via video hole frame
Browse files Browse the repository at this point in the history
The CL was originally uploaded at https://chromium-review.googlesource.com/c/chromium/src/+/5806680.

Replace the video hole draw quad manually in viz. This supports SbPlayer video rendering via punch hole display.

b/352389546
  • Loading branch information
borongc committed Oct 31, 2024
1 parent dab82e0 commit b2076c3
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 10 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/cobalt/ # no owners
/media/starboard/ # no owners
/starboard/ # no owners
/components/viz/service/display/starboard/ # no owners
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ files: |
cobalt/|
media/starboard/|
starboard/|
components/viz/service/display/starboard/|
.pre-commit-config.yaml|
.pylintrc|
docker-compose.yaml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ private void finishInitialization(Bundle savedInstanceState) {
&& savedInstanceState.containsKey(ACTIVE_SHELL_URL_KEY)) {
shellUrl = savedInstanceState.getString(ACTIVE_SHELL_URL_KEY);
}
// Set to overlay video mode.
mShellManager.getContentViewRenderView().setOverlayVideoMode(true);
mShellManager.launchShell(shellUrl);

toggleFullscreenMode(true);
Expand Down
14 changes: 14 additions & 0 deletions components/viz/service/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import("//media/gpu/args.gni")
import("//skia/features.gni")
import("//testing/libfuzzer/fuzzer_test.gni")

if (is_cobalt) {
import("//starboard/build/buildflags.gni")
}

config("viz_service_implementation") {
}

Expand Down Expand Up @@ -341,6 +345,16 @@ viz_component("service") {
]
}

if (is_cobalt && use_starboard_media) {
sources += [
"display/starboard/overlay_strategy_underlay_starboard.cc",
"display/starboard/overlay_strategy_underlay_starboard.h",
]
deps += [
"//starboard/build:starboard_buildflags",
]
}

if (enable_cast_overlay_strategy) {
sources += [
"display/overlay_strategy_underlay_cast.cc",
Expand Down
17 changes: 17 additions & 0 deletions components/viz/service/display/overlay_processor_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
#include "gpu/command_buffer/service/scheduler_sequence.h"
#include "ui/gfx/geometry/rect_conversions.h"

// For BUILDFLAG(USE_STARBOARD_MEDIA)
#if BUILDFLAG(IS_COBALT)
#include "starboard/build/starboard_buildflags.h"
#if BUILDFLAG(USE_STARBOARD_MEDIA)
#include "components/viz/service/display/starboard/overlay_strategy_underlay_starboard.h"
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
#endif // BUILDFLAG(IS_COBALT)

namespace viz {
OverlayProcessorAndroid::OverlayProcessorAndroid(
DisplayCompositorMemoryAndTaskController* display_controller)
Expand Down Expand Up @@ -55,8 +63,17 @@ OverlayProcessorAndroid::OverlayProcessorAndroid(
// the underlying overlay is opaque anyway; the candidate is referring to
// a dummy resource that has no relation to what the overlay contains.
// https://crbug.com/842931 .
#if BUILDFLAG(IS_COBALT)
#if BUILDFLAG(USE_STARBOARD_MEDIA)
strategies_.push_back(std::make_unique<OverlayStrategyUnderlayStarboard>(this));
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(
this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
#else // BUILDFLAG(IS_COBALT)
strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(
this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
#endif // BUILDFLAG(IS_COBALT)

overlay_candidates_.clear();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright 2024 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "components/viz/service/display/starboard/overlay_strategy_underlay_starboard.h"

#include <utility>
#include <vector>

#include "base/containers/adapters.h"
#include "base/logging.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/video_hole_draw_quad.h"
#include "components/viz/service/display/overlay_candidate_factory.h"
#include "ui/gfx/geometry/rect_conversions.h"

namespace viz {

OverlayStrategyUnderlayStarboard::OverlayStrategyUnderlayStarboard(
OverlayProcessorUsingStrategy* capability_checker)
: OverlayStrategyUnderlay(capability_checker) {}

OverlayStrategyUnderlayStarboard::~OverlayStrategyUnderlayStarboard() {}

void OverlayStrategyUnderlayStarboard::Propose(
const SkM44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) {
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
OverlayCandidate candidate;
auto overlay_iter = quad_list.end();
OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
render_pass, resource_provider, surface_damage_rect_list,
&output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane),
&render_pass_filters);

// Original code did reverse iteration.
// Here we do forward but find the last one. which should be the same thing.
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
if (OverlayCandidate::IsInvisibleQuad(*it)) {
continue;
}

// Look for quads that are overlayable and require an overlay. Chromecast
// only supports a video underlay so this can't promote all quads that are
// overlayable, it needs to ensure that the quad requires overlays since
// that quad is side-channeled through a secure path into an overlay
// sitting underneath the primary plane. This is only looking at where the
// quad is supposed to be to replace it with a transparent quad to allow
// the underlay to be visible.
// VIDEO_HOLE implies it requires overlay.
if (it->material == DrawQuad::Material::kVideoHole &&
candidate_factory.FromDrawQuad(*it, candidate) ==
OverlayCandidate::CandidateStatus::kSuccess) {
overlay_iter = it;
}
}

if (overlay_iter != quad_list.end()) {
candidates->emplace_back(overlay_iter, candidate, this);
}
}

bool OverlayStrategyUnderlayStarboard::Attempt(
const SkM44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds,
const OverlayProposedCandidate& proposed_candidate) {
// Before we attempt an overlay strategy, the candidate list should be empty.
DCHECK(candidate_list->empty());
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
bool found_underlay = false;
gfx::Rect content_rect;
OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
render_pass, resource_provider, surface_damage_rect_list,
&output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane),
&render_pass_filters);

for (const auto* quad : base::Reversed(quad_list)) {
if (OverlayCandidate::IsInvisibleQuad(quad)) {
continue;
}

const auto& transform = quad->shared_quad_state->quad_to_target_transform;
gfx::Rect quad_rect = transform.MapRect(quad->rect);

bool is_underlay = false;
if (!found_underlay) {
OverlayCandidate candidate;
// Look for quads that are overlayable and require an overlay. Chromecast
// only supports a video underlay so this can't promote all quads that are
// overlayable, it needs to ensure that the quad requires overlays since
// that quad is side-channeled through a secure path into an overlay
// sitting underneath the primary plane. This is only looking at where the
// quad is supposed to be to replace it with a transparent quad to allow
// the underlay to be visible.
// VIDEO_HOLE implies it requires overlay.
is_underlay = quad->material == DrawQuad::Material::kVideoHole &&
candidate_factory.FromDrawQuad(quad, candidate) ==
OverlayCandidate::CandidateStatus::kSuccess;
found_underlay = is_underlay;
}

if (!found_underlay && quad->material == DrawQuad::Material::kSolidColor) {
const SolidColorDrawQuad* solid = SolidColorDrawQuad::MaterialCast(quad);
if (solid->color == SkColors::kBlack) {
continue;
}
}

if (is_underlay) {
content_rect.Subtract(quad_rect);
} else {
content_rect.Union(quad_rect);
}
}

if (is_using_overlay_ != found_underlay) {
is_using_overlay_ = found_underlay;
LOG(INFO) << (found_underlay ? "Overlay activated" : "Overlay deactivated");
}

if (found_underlay) {
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
OverlayCandidate candidate;
if (it->material != DrawQuad::Material::kVideoHole ||
candidate_factory.FromDrawQuad(*it, candidate) !=
OverlayCandidate::CandidateStatus::kSuccess) {
continue;
}

OverlayProposedCandidate proposed_to_commit(it, candidate, this);
CommitCandidate(proposed_to_commit, render_pass);

break;
}
}

DCHECK(content_bounds && content_bounds->empty());
if (found_underlay) {
content_bounds->push_back(content_rect);
}
return found_underlay;
}

void OverlayStrategyUnderlayStarboard::CommitCandidate(
const OverlayProposedCandidate& proposed_candidate,
AggregatedRenderPass* render_pass) {
if (proposed_candidate.candidate.has_mask_filter) {
render_pass->ReplaceExistingQuadWithSolidColor(
proposed_candidate.quad_iter, SkColors::kBlack, SkBlendMode::kDstOut);
} else {
render_pass->ReplaceExistingQuadWithSolidColor(proposed_candidate.quad_iter,
SkColors::kTransparent,
SkBlendMode::kSrcOver);
}
}

// Turn on blending for the output surface plane so the underlay could show
// through.
void OverlayStrategyUnderlayStarboard::AdjustOutputSurfaceOverlay(
OverlayProcessorInterface::OutputSurfaceOverlayPlane*
output_surface_plane) {
if (output_surface_plane) {
output_surface_plane->enable_blending = true;
}
}

} // namespace viz
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2024 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_STARBOARD_OVERLAY_STRATEGY_UNDERLAY_STARBOARD_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_STARBOARD_OVERLAY_STRATEGY_UNDERLAY_STARBOARD_H_

#include <memory>
#include <vector>

#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "components/viz/service/viz_service_export.h"

namespace viz {

// The underlay strategy looks for a video hole quad, where the underlay
// video can be displayed directly. This is similar to the underlay
// strategy for Cast.
class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayStarboard
: public OverlayStrategyUnderlay {
public:
explicit OverlayStrategyUnderlayStarboard(
OverlayProcessorUsingStrategy* capability_checker);

OverlayStrategyUnderlayStarboard(const OverlayStrategyUnderlayStarboard&) =
delete;
OverlayStrategyUnderlayStarboard& operator=(
const OverlayStrategyUnderlayStarboard&) = delete;

~OverlayStrategyUnderlayStarboard() override;

void Propose(
const SkM44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override;

bool Attempt(
const SkM44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds,
const OverlayProposedCandidate& proposed_candidate) override;

void CommitCandidate(const OverlayProposedCandidate& proposed_candidate,
AggregatedRenderPass* render_pass) override;

void AdjustOutputSurfaceOverlay(
OverlayProcessorInterface::OutputSurfaceOverlayPlane*
output_surface_plane) override;

private:
// Keep track if an overlay is being used on the previous frame.
bool is_using_overlay_ = false;
};

} // namespace viz

#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_STARBOARD_OVERLAY_STRATEGY_UNDERLAY_STARBOARD_H_
Loading

0 comments on commit b2076c3

Please sign in to comment.