0

[fuchsia][ozone] Remove "scenic" ozone platform

This change also:
- removes dependency on lib/ui/scenic
- moves //ui/ozone/platform/scenic/mojom to //ui/ozone/platform/flatland/mojom

Fixed: 1424577
Change-Id: I03358d62019dfe70171ef16ec5d4f1ca31f65567
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4774544
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Nico Weber <thakis@chromium.org>
Commit-Queue: Caroline Liu <carolineliu@google.com>
Cr-Commit-Position: refs/heads/main@{#1189558}
This commit is contained in:
Caroline Liu
2023-08-29 16:19:07 +00:00
committed by Chromium LUCI CQ
parent 53dd4f8be5
commit ca634cb03b
66 changed files with 155 additions and 5440 deletions

@ -1617,8 +1617,7 @@
'ui/gl/gl_.*ozone'
},
'ozone_fuchsia': {
'filepath': 'ui/ozone/platform/flatland/|'\
'ui/ozone/platform/scenic/'
'filepath': 'ui/ozone/platform/flatland/',
},
'page_info' : {
'filepath': 'chrome/browser/ui/page_info/'\

@ -48,9 +48,6 @@ declare_args() {
# Compile the 'headless' platform.
ozone_platform_headless = false
# Compile the 'scenic' platform.
ozone_platform_scenic = false
# Compile the 'flatland' platform.
ozone_platform_flatland = false
@ -93,7 +90,6 @@ declare_args() {
ozone_platform_x11 = true
} else if (is_fuchsia) {
ozone_platform = "flatland"
ozone_platform_scenic = true
ozone_platform_flatland = true
}
}
@ -113,11 +109,11 @@ _ozone_extra_directory = get_path_info(ozone_extra_path, "dir")
ozone_external_platform_visibility = [ "$_ozone_extra_directory/*" ]
if (is_a_target_toolchain) {
assert(use_ozone || !(ozone_platform_cast || ozone_platform_drm ||
ozone_platform_flatland ||
ozone_platform_headless || ozone_platform_x11 ||
ozone_platform_wayland || ozone_platform_scenic),
"Must set use_ozone to select ozone platforms")
assert(
use_ozone || !(ozone_platform_cast || ozone_platform_drm ||
ozone_platform_flatland || ozone_platform_headless ||
ozone_platform_x11 || ozone_platform_wayland),
"Must set use_ozone to select ozone platforms")
}
# TODO(petermcneeley): Backwards compatiblity support for VM images.

@ -357,7 +357,7 @@ ninja -C out/OzoneCaca content_shell
### drm
Ash-chrome client implementation.
### flatland / scenic
### flatland
For fuchsia.
## Communication

@ -614,8 +614,6 @@ test("web_engine_browsertests") {
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mediacodec:fuchsia.mediacodec_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem:fuchsia.mem_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.input3:fuchsia.ui.input3_cpp",
"//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
"//ui/gfx",
"//ui/ozone",
]

@ -11,7 +11,6 @@
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <lib/fpromise/result.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <limits>
@ -79,6 +78,7 @@
#include "ui/compositor/compositor.h"
#include "ui/gfx/switches.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/platform_window/fuchsia/view_ref_pair.h"
#include "ui/wm/core/base_focus_rules.h"
#include "url/gurl.h"
#include "url/origin.h"
@ -810,7 +810,7 @@ void FrameImpl::CreateView(fuchsia::ui::views::ViewToken view_token) {
TRACE_EVENT(kWebEngineFidlCategory, "fuchsia.web/Frame.CreateView",
perfetto::Flow::FromPointer(this));
auto view_ref_pair = scenic::ViewRefPair::New();
auto view_ref_pair = ui::ViewRefPair::New();
CreateViewImpl(std::move(view_token), std::move(view_ref_pair.control_ref),
std::move(view_ref_pair.view_ref));
}
@ -844,7 +844,7 @@ void FrameImpl::CreateViewImpl(fuchsia::ui::views::ViewToken view_token,
// If a View to this Frame is already active then disconnect it.
DestroyWindowTreeHost();
scenic::ViewRefPair view_ref_pair;
ui::ViewRefPair view_ref_pair;
view_ref_pair.control_ref = std::move(control_ref);
view_ref_pair.view_ref = std::move(view_ref);
SetupWindowTreeHost(std::move(view_token), std::move(view_ref_pair));
@ -872,7 +872,7 @@ void FrameImpl::CreateView2(fuchsia::web::CreateView2Args view_args) {
// If a View to this Frame is already active then disconnect it.
DestroyWindowTreeHost();
scenic::ViewRefPair view_ref_pair = scenic::ViewRefPair::New();
auto view_ref_pair = ui::ViewRefPair::New();
SetupWindowTreeHost(std::move(*view_args.mutable_view_creation_token()),
std::move(view_ref_pair));
@ -1125,7 +1125,7 @@ void FrameImpl::EnableHeadlessRendering() {
return;
}
scenic::ViewRefPair view_ref_pair = scenic::ViewRefPair::New();
auto view_ref_pair = ui::ViewRefPair::New();
SetupWindowTreeHost(fuchsia::ui::views::ViewToken(),
std::move(view_ref_pair));
@ -1159,7 +1159,7 @@ void FrameImpl::DisableHeadlessRendering() {
}
void FrameImpl::SetupWindowTreeHost(fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair) {
ui::ViewRefPair view_ref_pair) {
DCHECK(!window_tree_host_);
window_tree_host_ = std::make_unique<FrameWindowTreeHost>(
@ -1172,7 +1172,7 @@ void FrameImpl::SetupWindowTreeHost(fuchsia::ui::views::ViewToken view_token,
void FrameImpl::SetupWindowTreeHost(
fuchsia::ui::views::ViewCreationToken view_creation_token,
scenic::ViewRefPair view_ref_pair) {
ui::ViewRefPair view_ref_pair) {
DCHECK(!window_tree_host_);
window_tree_host_ = std::make_unique<FrameWindowTreeHost>(

@ -10,7 +10,6 @@
#include <fuchsia/web/cpp/fidl.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/inspect/cpp/vmo/types.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <lib/zx/channel.h>
#include <list>
@ -40,6 +39,7 @@
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "ui/accessibility/platform/fuchsia/accessibility_bridge_fuchsia_impl.h"
#include "ui/aura/window_tree_host.h"
#include "ui/platform_window/fuchsia/view_ref_pair.h"
#include "ui/wm/core/focus_controller.h"
#include "url/gurl.h"
@ -187,14 +187,14 @@ class WEB_ENGINE_EXPORT FrameImpl : public fuchsia::web::Frame,
// Creates and initializes WindowTreeHost for the view with the specified
// |view_token|. |view_token| may be uninitialized in headless mode.
void SetupWindowTreeHost(fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair);
ui::ViewRefPair view_ref_pair);
// Creates and initializes WindowTreeHost for the view with the specified
// |view_creation_token|. |view_creation_token| may be uninitialized in
// headless mode.
void SetupWindowTreeHost(
fuchsia::ui::views::ViewCreationToken view_creation_token,
scenic::ViewRefPair view_ref_pair);
ui::ViewRefPair view_ref_pair);
// Initializes WindowTreeHost.
void InitWindowTreeHost();

@ -4,7 +4,6 @@
#include <fuchsia/element/cpp/fidl.h>
#include <lib/ui/scenic/cpp/view_creation_tokens.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <lib/zx/time.h>
#include "base/fuchsia/fuchsia_logging.h"
@ -96,15 +95,6 @@ std::string GetDocumentVisibilityState(fuchsia::web::Frame* frame) {
return visibility->data;
}
::fuchsia::ui::views::ViewRef CloneViewRef(
const ::fuchsia::ui::views::ViewRef& view_ref) {
::fuchsia::ui::views::ViewRef dup;
zx_status_t status =
view_ref.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
return dup;
}
} // namespace
// Defines a suite of tests that exercise Frame-level functionality, such as
@ -330,8 +320,11 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, ContextDeletedBeforeFrameWithView) {
base::RunLoop().RunUntilIdle();
FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame.ptr());
auto view_tokens = scenic::ViewTokenPair::New();
frame->CreateView(std::move(view_tokens.view_token));
scenic::ViewCreationTokenPair token_pair =
scenic::ViewCreationTokenPair::New();
fuchsia::web::CreateView2Args create_view_args;
create_view_args.set_view_creation_token(std::move(token_pair.view_token));
frame->CreateView2(std::move(create_view_args));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(frame_impl->has_view_for_test());
@ -878,17 +871,16 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, Stop) {
#define MAYBE_SetPageScale DISABLED_SetPageScale
#endif
IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_SetPageScale) {
// This test uses the `fuchsia.ui.gfx` variant of `Frame.CreateView*()`.
ASSERT_EQ(ui::OzonePlatform::GetInstance()->GetPlatformNameForTest(),
"scenic");
"flatland");
auto frame = FrameForTest::Create(context(), {});
auto view_tokens = scenic::ViewTokenPair::New();
auto view_ref_pair = scenic::ViewRefPair::New();
frame->CreateViewWithViewRef(std::move(view_tokens.view_token),
std::move(view_ref_pair.control_ref),
CloneViewRef(view_ref_pair.view_ref));
scenic::ViewCreationTokenPair token_pair =
scenic::ViewCreationTokenPair::New();
fuchsia::web::CreateView2Args create_view_args;
create_view_args.set_view_creation_token(std::move(token_pair.view_token));
frame->CreateView2(std::move(create_view_args));
// Attach the View to a Presenter, the page should be visible.
auto presenter = base::ComponentContextForProcess()
@ -900,8 +892,8 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_SetPageScale) {
});
::fuchsia::element::ViewSpec view_spec;
view_spec.set_view_holder_token(std::move(view_tokens.view_holder_token));
view_spec.set_view_ref(std::move(view_ref_pair.view_ref));
view_spec.set_viewport_creation_token(std::move(token_pair.viewport_token));
view_spec.set_annotations({});
::fuchsia::element::ViewControllerPtr view_controller;
presenter->PresentView(std::move(view_spec), nullptr,
view_controller.NewRequest(),
@ -979,15 +971,12 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_SetPageScale) {
// Create another frame. Verify that the scale factor is not applied to the
// new frame.
auto frame2 = FrameForTest::Create(context(), {});
token_pair = scenic::ViewCreationTokenPair::New();
create_view_args.set_view_creation_token(std::move(token_pair.view_token));
frame2->CreateView2(std::move(create_view_args));
view_tokens = scenic::ViewTokenPair::New();
view_ref_pair = scenic::ViewRefPair::New();
frame2->CreateViewWithViewRef(std::move(view_tokens.view_token),
std::move(view_ref_pair.control_ref),
CloneViewRef(view_ref_pair.view_ref));
view_spec.set_view_holder_token(std::move(view_tokens.view_holder_token));
view_spec.set_view_ref(std::move(view_ref_pair.view_ref));
view_spec.set_viewport_creation_token(std::move(token_pair.viewport_token));
view_spec.set_annotations({});
presenter->PresentView(std::move(view_spec), nullptr,
view_controller.NewRequest(), [](auto) {});
@ -1024,8 +1013,11 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, RecreateView) {
frame.navigation_listener().RunUntilUrlAndTitleEquals(page1_url, kPage1Title);
// Request a View from the Frame, and pump the loop to process the request.
auto view_tokens = scenic::ViewTokenPair::New();
frame->CreateView(std::move(view_tokens.view_token));
scenic::ViewCreationTokenPair token_pair =
scenic::ViewCreationTokenPair::New();
fuchsia::web::CreateView2Args create_view_args;
create_view_args.set_view_creation_token(std::move(token_pair.view_token));
frame->CreateView2(std::move(create_view_args));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(frame_impl->has_view_for_test());
@ -1037,8 +1029,9 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, RecreateView) {
frame.navigation_listener().RunUntilUrlAndTitleEquals(page2_url, kPage2Title);
// Create new View tokens and request a new view.
auto view_tokens2 = scenic::ViewTokenPair::New();
frame->CreateView(std::move(view_tokens2.view_token));
token_pair = scenic::ViewCreationTokenPair::New();
create_view_args.set_view_creation_token(std::move(token_pair.view_token));
frame->CreateView2(std::move(create_view_args));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(frame_impl->has_view_for_test());

@ -25,7 +25,7 @@ fuchsia::ui::views::ViewRef DupViewRef(
}
ui::PlatformWindowInitProperties CreatePlatformWindowInitProperties(
scenic::ViewRefPair view_ref_pair,
ui::ViewRefPair view_ref_pair,
ui::ScenicWindowDelegate* scenic_window_delegate) {
ui::PlatformWindowInitProperties properties;
properties.view_ref_pair = std::move(view_ref_pair);
@ -66,7 +66,7 @@ class FrameWindowTreeHost::WindowParentingClientImpl
FrameWindowTreeHost::FrameWindowTreeHost(
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
ui::ViewRefPair view_ref_pair,
content::WebContents* web_contents,
OnPixelScaleUpdateCallback on_pixel_scale_update)
: view_ref_(DupViewRef(view_ref_pair.view_ref)),
@ -85,7 +85,7 @@ FrameWindowTreeHost::FrameWindowTreeHost(
FrameWindowTreeHost::FrameWindowTreeHost(
fuchsia::ui::views::ViewCreationToken view_creation_token,
scenic::ViewRefPair view_ref_pair,
ui::ViewRefPair view_ref_pair,
content::WebContents* web_contents,
OnPixelScaleUpdateCallback on_pixel_scale_update)
: view_ref_(DupViewRef(view_ref_pair.view_ref)),

@ -5,11 +5,12 @@
#ifndef FUCHSIA_WEB_WEBENGINE_BROWSER_FRAME_WINDOW_TREE_HOST_H_
#define FUCHSIA_WEB_WEBENGINE_BROWSER_FRAME_WINDOW_TREE_HOST_H_
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include "fuchsia_web/webengine/web_engine_export.h"
#include "ui/aura/window_tree_host_platform.h"
#include "ui/platform_window/fuchsia/scenic_window_delegate.h"
#include "ui/platform_window/fuchsia/view_ref_pair.h"
namespace content {
class WebContents;
@ -24,11 +25,11 @@ class WEB_ENGINE_EXPORT FrameWindowTreeHost final
using OnPixelScaleUpdateCallback = base::RepeatingCallback<void(float)>;
FrameWindowTreeHost(fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
ui::ViewRefPair view_ref_pair,
content::WebContents* web_contents,
OnPixelScaleUpdateCallback on_pixel_scale_update);
FrameWindowTreeHost(fuchsia::ui::views::ViewCreationToken view_creation_token,
scenic::ViewRefPair view_ref_pair,
ui::ViewRefPair view_ref_pair,
content::WebContents* web_contents,
OnPixelScaleUpdateCallback on_pixel_scale_update);
~FrameWindowTreeHost() override;

@ -653,8 +653,9 @@ void FuchsiaVideoDecoder::OnStreamProcessorOutputPacket(
// luma (see fxbug.dev/13677). Assume they are cosited with luma. YCbCr info
// here must match the values passed for the same buffer in
// ui::SysmemBufferCollection::CreateVkImage() (see
// ui/ozone/platform/scenic/sysmem_buffer_collection.cc). |format_features|
// are resolved later in the GPU process before this info is passed to Skia.
// ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.cc).
// |format_features| are resolved later in the GPU process before this info is
// passed to Skia.
frame->set_ycbcr_info(gpu::VulkanYCbCrInfo(
vk_format, /*external_format=*/0, ycbcr_conversion,
VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, VK_CHROMA_LOCATION_COSITED_EVEN,

@ -65,11 +65,6 @@ if (ozone_platform_x11) {
ozone_platform_ui_test_support_deps += [ "platform/x11:test_support" ]
}
if (ozone_platform_scenic) {
ozone_platforms += [ "scenic" ]
ozone_platform_deps += [ "platform/scenic" ]
}
if (ozone_platform_flatland) {
ozone_platforms += [ "flatland" ]
ozone_platform_deps += [ "platform/flatland" ]

@ -70,12 +70,12 @@ source_set("flatland") {
"//ui/events/ozone/layout",
"//ui/ozone:ozone_base",
"//ui/ozone/common",
"//ui/ozone/platform/scenic/mojom",
"//ui/ozone/platform/flatland/mojom",
]
public_deps = [
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.element:fuchsia.element_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.composition:fuchsia.ui.composition_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.gfx:fuchsia.ui.gfx_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.input3:fuchsia.ui.input3_cpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.pointer:fuchsia.ui.pointer_cpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.pointer:fuchsia.ui.pointer_cpp_hlcpp_conversion",

@ -13,8 +13,8 @@
#include "mojo/public/cpp/system/message_pipe.h"
#include "ui/ozone/platform/flatland/flatland_window.h"
#include "ui/ozone/platform/flatland/flatland_window_manager.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_service.mojom.h"
namespace {

@ -14,8 +14,8 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
namespace ui {

@ -10,8 +10,8 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_service.mojom.h"
namespace ui {

@ -16,7 +16,7 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/handle.h"
#include "ui/ozone/platform/flatland/flatland_sysmem_buffer_manager.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/public/gl_ozone.h"
#include "ui/ozone/public/surface_factory_ozone.h"

@ -6,9 +6,9 @@
#define UI_OZONE_PLATFORM_FLATLAND_FLATLAND_WINDOW_H_
#include <fidl/fuchsia.ui.input3/cpp/fidl.h>
#include <fuchsia/element/cpp/fidl.h>
#include <fuchsia/ui/composition/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <memory>
#include <string>

@ -11,7 +11,7 @@
#include <lib/ui/scenic/cpp/testing/fake_flatland.h>
#include <lib/ui/scenic/cpp/testing/fake_touch_source.h>
#include <lib/ui/scenic/cpp/testing/fake_view_ref_focused.h>
#include <lib/ui/scenic/cpp/view_creation_tokens.h>
#include <lib/zx/channel.h>
#include <memory>
#include <string>
@ -25,6 +25,7 @@
#include "ui/events/fuchsia/util/pointer_event_utility.h"
#include "ui/ozone/platform/flatland/flatland_window_manager.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
#include "ui/platform_window/fuchsia/view_ref_pair.h"
using ::scenic::FakeGraph;
using ::scenic::FakeTransform;
@ -126,15 +127,19 @@ class FlatlandWindowTest : public ::testing::Test {
void CreateWindow() {
EXPECT_FALSE(flatland_window_);
auto token_pair = scenic::ViewCreationTokenPair::New();
viewport_token_ = std::move(token_pair.viewport_token);
fuchsia::ui::views::ViewCreationToken view_token;
fuchsia::ui::views::ViewportCreationToken viewport_token;
auto status =
zx::channel::create(0, &viewport_token.value, &view_token.value);
CHECK_EQ(ZX_OK, status);
viewport_token_ = std::move(viewport_token);
EXPECT_CALL(window_delegate_, OnAcceleratedWidgetAvailable(_))
.WillOnce(SaveArg<0>(&window_widget_));
PlatformWindowInitProperties properties;
properties.view_ref_pair = scenic::ViewRefPair::New();
properties.view_creation_token = std::move(token_pair.view_token);
properties.view_ref_pair = ViewRefPair::New();
properties.view_creation_token = std::move(view_token);
flatland_window_ = std::make_unique<FlatlandWindow>(
&window_manager_, &window_delegate_, std::move(properties));
}
@ -330,8 +335,12 @@ TEST_F(FlatlandWindowTest, WaitsForNonZeroSizeToAttachSurfaceContent) {
task_environment_.RunUntilIdle();
// Try attaching the content. It should only be a closure.
auto token_pair = scenic::ViewCreationTokenPair::New();
flatland_window_->AttachSurfaceContent(std::move(token_pair.viewport_token));
fuchsia::ui::views::ViewCreationToken view_token;
fuchsia::ui::views::ViewportCreationToken viewport_token;
auto status =
zx::channel::create(0, &viewport_token.value, &view_token.value);
CHECK_EQ(ZX_OK, status);
flatland_window_->AttachSurfaceContent(std::move(viewport_token));
EXPECT_TRUE(HasPendingAttachSurfaceContentClosure());
// Setting layout info should trigger the closure and delegate calls.
@ -363,9 +372,8 @@ TEST_F(FlatlandWindowTest, WaitsForNonZeroSizeToAttachSurfaceContent) {
task_environment_.RunUntilIdle();
EXPECT_EQ(2u, presents_called);
EXPECT_THAT(fake_flatland_.graph(),
IsWindowGraph(
parent_viewport_watcher(), viewport_token_,
Contains(IsViewport(token_pair.view_token, expected_size))));
IsWindowGraph(parent_viewport_watcher(), viewport_token_,
Contains(IsViewport(view_token, expected_size))));
}
// Verify that surface is cleared when the window is disconnected from the
@ -378,8 +386,12 @@ TEST_F(FlatlandWindowTest, ResetSurfaceOnDisconnect) {
task_environment_.RunUntilIdle();
// Try attaching the content. It should only be a closure.
auto token_pair = scenic::ViewCreationTokenPair::New();
flatland_window_->AttachSurfaceContent(std::move(token_pair.viewport_token));
fuchsia::ui::views::ViewCreationToken view_token;
fuchsia::ui::views::ViewportCreationToken viewport_token;
auto status =
zx::channel::create(0, &viewport_token.value, &view_token.value);
CHECK_EQ(ZX_OK, status);
flatland_window_->AttachSurfaceContent(std::move(viewport_token));
SetWindowStatus(
fuchsia::ui::composition::ParentViewportStatus::CONNECTED_TO_DISPLAY);
@ -434,8 +446,12 @@ TEST_F(FlatlandWindowTest, SurfaceHasHitTestHitShield) {
// Spin the loop to propagate layout.
task_environment_.RunUntilIdle();
auto token_pair = scenic::ViewCreationTokenPair::New();
flatland_window_->AttachSurfaceContent(std::move(token_pair.viewport_token));
fuchsia::ui::views::ViewCreationToken view_token;
fuchsia::ui::views::ViewportCreationToken viewport_token;
auto status =
zx::channel::create(0, &viewport_token.value, &view_token.value);
CHECK_EQ(ZX_OK, status);
flatland_window_->AttachSurfaceContent(std::move(viewport_token));
// Show() the window, to trigger creation of the scene graph, including
// surface and hit shield.
@ -449,12 +465,12 @@ TEST_F(FlatlandWindowTest, SurfaceHasHitTestHitShield) {
task_environment_.RunUntilIdle();
// Surface should be accompanied by input shield, in that order.
EXPECT_THAT(fake_flatland_.graph(),
Field("root_transform", &FakeGraph::root_transform,
Pointee(Field("children", &FakeTransform::children,
ElementsAre(IsViewport(token_pair.view_token,
expected_size),
IsHitShield())))));
EXPECT_THAT(
fake_flatland_.graph(),
Field("root_transform", &FakeGraph::root_transform,
Pointee(Field("children", &FakeTransform::children,
ElementsAre(IsViewport(view_token, expected_size),
IsHitShield())))));
}
class ParameterizedViewInsetTest : public FlatlandWindowTest,

@ -4,7 +4,7 @@
module ui.mojom;
import "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom";
import "ui/ozone/platform/flatland/mojom/scenic_gpu_host.mojom";
// GPU process service that enables presentation to Scenic.
interface ScenicGpuService {

@ -33,14 +33,15 @@
#include "ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.h"
#include "ui/ozone/platform/flatland/flatland_window.h"
#include "ui/ozone/platform/flatland/flatland_window_manager.h"
#include "ui/ozone/platform/flatland/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform/flatland/overlay_manager_flatland.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform_selection.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/ozone/public/system_input_injector.h"
#include "ui/platform_window/fuchsia/view_ref_pair.h"
#include "ui/platform_window/platform_window_init_properties.h"
#if BUILDFLAG(IS_FUCHSIA)
@ -105,7 +106,7 @@ class OzonePlatformFlatland : public OzonePlatform,
zx::channel::create(0, &parent_token.value, &child_token.value);
CHECK_EQ(ZX_OK, status) << "zx_channel_create";
properties.view_creation_token = std::move(child_token);
properties.view_ref_pair = scenic::ViewRefPair::New();
properties.view_ref_pair = ::ui::ViewRefPair::New();
properties.view_controller =
::ui::fuchsia::GetFlatlandViewPresenter().Run(
std::move(parent_token));

@ -1,100 +0,0 @@
# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
assert(is_fuchsia)
import("//build/config/dcheck_always_on.gni")
import("//gpu/vulkan/features.gni")
assert(enable_vulkan)
visibility = [ "//ui/ozone/*" ]
source_set("scenic") {
sources = [
"client_native_pixmap_factory_scenic.cc",
"client_native_pixmap_factory_scenic.h",
"overlay_manager_scenic.cc",
"overlay_manager_scenic.h",
"ozone_platform_scenic.cc",
"ozone_platform_scenic.h",
"safe_presenter.cc",
"safe_presenter.h",
"scenic_gpu_host.cc",
"scenic_gpu_host.h",
"scenic_gpu_service.cc",
"scenic_gpu_service.h",
"scenic_overlay_view.cc",
"scenic_overlay_view.h",
"scenic_screen.cc",
"scenic_screen.h",
"scenic_surface.cc",
"scenic_surface.h",
"scenic_surface_factory.cc",
"scenic_surface_factory.h",
"scenic_window.cc",
"scenic_window.h",
"scenic_window_canvas.cc",
"scenic_window_canvas.h",
"scenic_window_manager.cc",
"scenic_window_manager.h",
"sysmem_buffer_collection.cc",
"sysmem_buffer_collection.h",
"sysmem_buffer_manager.cc",
"sysmem_buffer_manager.h",
"sysmem_native_pixmap.cc",
"sysmem_native_pixmap.h",
"vulkan_implementation_scenic.cc",
"vulkan_implementation_scenic.h",
]
defines = [
"OZONE_IMPLEMENTATION",
"VK_USE_PLATFORM_FUCHSIA",
"VK_USE_PLATFORM_MAGMA_KHR",
]
deps = [
"//base",
"//gpu/ipc/common:vulkan_ycbcr_info",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//skia",
"//third_party/angle/src/common/fuchsia_egl",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.element:fuchsia.element_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.images:fuchsia.images_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem:fuchsia.mem_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.sysmem:fuchsia.sysmem_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.pointer:fuchsia.ui.pointer_cpp_hlcpp_conversion",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.views:fuchsia.ui.views_cpp_hlcpp_conversion",
"//third_party/fuchsia-sdk/sdk/pkg/component_incoming_cpp",
"//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
"//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
"//ui/base",
"//ui/base/cursor",
"//ui/base/ime/fuchsia",
"//ui/events:dom_keycode_converter",
"//ui/events/ozone/layout",
"//ui/ozone:ozone_base",
"//ui/ozone/common",
"//ui/ozone/platform/scenic/mojom",
]
public_deps = [
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.gfx:fuchsia.ui.gfx_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.input:fuchsia.ui.input_hlcpp",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.scenic:fuchsia.ui.scenic_hlcpp",
"//ui/gfx/geometry",
"//ui/platform_window",
]
data_deps = [ "//third_party/fuchsia-sdk/sdk/pkg/vulkan" ]
# VulkanInstance enables validation layer in Debug builds and when DCHECKs
# are enabled in Release builds. In these cases the validation layer
# libraries and configs need to be included in the generated Fuchsia
# package.
if (is_debug || dcheck_always_on) {
data_deps += [ "//third_party/fuchsia-sdk/sdk/pkg/vulkan_layers:VkLayer_khronos_validation" ]
}
}

@ -1,6 +0,0 @@
include_rules = [
"+gpu/ipc/common",
"+mojo/public",
"+third_party/angle/src/common/fuchsia_egl",
"+third_party/skia/include",
]

@ -1 +0,0 @@
mixins: "//build/fuchsia/COMMON_METADATA"

@ -1 +0,0 @@
file://build/fuchsia/OWNERS

@ -1,251 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/client_native_pixmap_factory_scenic.h"
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <vector>
#include "base/bits.h"
#include "base/check_op.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/koid.h"
#include "base/numerics/safe_conversions.h"
#include "base/system/sys_info.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/gfx/native_pixmap_handle.h"
namespace ui {
namespace {
bool AlignUpToPageSizeChecked(size_t size, size_t* aligned_size) {
static_assert(base::IsValueInRangeForNumericType<size_t>(ZX_PAGE_SIZE) &&
base::bits::IsPowerOfTwo(ZX_PAGE_SIZE),
"The page size must fit in a size_t and be a power of 2.");
constexpr size_t kPageSizeMinusOne = ZX_PAGE_SIZE - 1;
base::CheckedNumeric<size_t> aligned_size_checked =
base::CheckAdd(size, kPageSizeMinusOne) & (~kPageSizeMinusOne);
if (!aligned_size_checked.IsValid()) {
return false;
}
*aligned_size = aligned_size_checked.ValueOrDie();
return true;
}
} // namespace
class ClientNativePixmapFuchsia : public gfx::ClientNativePixmap {
public:
explicit ClientNativePixmapFuchsia(gfx::NativePixmapHandle handle)
: handle_(std::move(handle)) {}
ClientNativePixmapFuchsia(const ClientNativePixmapFuchsia&) = delete;
ClientNativePixmapFuchsia& operator=(const ClientNativePixmapFuchsia&) =
delete;
~ClientNativePixmapFuchsia() override {
if (mapping_) {
// Flush the cache if Unmap is not called before the pixmap is destroyed.
if (logically_mapped_) {
Unmap();
}
zx_status_t status = zx::vmar::root_self()->unmap(
reinterpret_cast<uintptr_t>(mapping_), mapping_size_);
ZX_DCHECK(status == ZX_OK, status) << "zx_vmar_unmap";
}
}
bool Map() override {
if (mapping_) {
logically_mapped_ = true;
return true;
}
if (handle_.planes.empty() || !handle_.planes[0].vmo) {
return false;
}
// Assume that the last plane is at the end of the VMO. If this assumption
// is violated, we shouldn't get here because
// ScenicClientNativePixmapFactory::ImportFromHandle() validates (through
// CanFitImageForSizeAndFormat()) that the (offset + size) for each plane is
// less than or equal to |last_plane_end|.
//
// Note: the |last_plane_end| computation has been determined to not
// overflow in ScenicClientNativePixmapFactory::ImportFromHandle() (through
// CanFitImageForSizeAndFormat()).
const size_t last_plane_end =
base::CheckAdd(handle_.planes.back().offset, handle_.planes.back().size)
.ValueOrDie<size_t>();
#if DCHECK_IS_ON()
// All planes should fall within the range that ends with the last plane.
// This has been verified by
// ScenicClientNativePixmapFactory::ImportFromHandle() (through
// CanFitImageForSizeAndFormat()).
for (auto& plane : handle_.planes) {
DCHECK(base::CheckAdd(plane.offset, plane.size).ValueOrDie<size_t>() <=
last_plane_end);
}
#endif
// Round mapping size to align with the page size. Mapping
// |aligned_mapping_size| bytes should be safe because
// FlatlandClientNativePixmapFactory::ImportFromHandle() ensures that
// |last_plane_end| <= <size of the VMO> where <size of the VMO> is
// page_aligned which implies that |aligned_mapping_size| <= <size of the
// VMO>.
size_t aligned_mapping_size;
if (!AlignUpToPageSizeChecked(last_plane_end, &aligned_mapping_size)) {
return false;
}
mapping_size_ = aligned_mapping_size;
// Pre-commit the pages of the pixmap, since it is likely that every page
// will be touched. This is also necessary to successfully pre-fill the page
// table entries during the subsequent map operation.
zx_status_t status = handle_.planes[0].vmo.op_range(
ZX_VMO_OP_COMMIT, 0, mapping_size_, nullptr, 0);
ZX_DCHECK(status == ZX_OK, status) << "zx_vmo_op_range";
// ZX_VM_MAP_RANGE pre-fills the page table entries for committed pages to
// avoid unnecessary page faults.
zx_vaddr_t addr;
status = zx::vmar::root_self()->map(
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_MAP_RANGE, 0,
handle_.planes[0].vmo, 0, mapping_size_, &addr);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_vmar_map";
return false;
}
mapping_ = reinterpret_cast<uint8_t*>(addr);
logically_mapped_ = true;
return true;
}
void Unmap() override {
DCHECK(mapping_);
DCHECK(logically_mapped_);
// Flush the CPu cache in case the GPU reads the data directly from RAM.
// Keep the mapping to avoid unnecessary overhead when later reusing the
// pixmap. The actual unmap happens when the pixmap is destroyed.
if (handle_.ram_coherency) {
zx_status_t status =
zx_cache_flush(mapping_, mapping_size_,
ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE);
ZX_DCHECK(status == ZX_OK, status) << "zx_cache_flush";
}
logically_mapped_ = false;
}
size_t GetNumberOfPlanes() const override { return handle_.planes.size(); }
void* GetMemoryAddress(size_t plane) const override {
DCHECK_LT(plane, handle_.planes.size());
DCHECK(mapping_);
return mapping_ + handle_.planes[plane].offset;
}
int GetStride(size_t plane) const override {
DCHECK_LT(plane, handle_.planes.size());
return base::checked_cast<int>(handle_.planes[plane].stride);
}
gfx::NativePixmapHandle CloneHandleForIPC() const override {
return gfx::CloneHandleForIPC(handle_);
}
private:
gfx::NativePixmapHandle handle_;
bool logically_mapped_ = false;
uint8_t* mapping_ = nullptr;
size_t mapping_size_ = 0;
};
class ScenicClientNativePixmapFactory : public gfx::ClientNativePixmapFactory {
public:
ScenicClientNativePixmapFactory() = default;
ScenicClientNativePixmapFactory(const ScenicClientNativePixmapFactory&) =
delete;
ScenicClientNativePixmapFactory& operator=(
const ScenicClientNativePixmapFactory&) = delete;
~ScenicClientNativePixmapFactory() override = default;
std::unique_ptr<gfx::ClientNativePixmap> ImportFromHandle(
gfx::NativePixmapHandle handle,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage) override {
// |planes| may be empty for non-mappable pixmaps. No need to validate the
// handle in that case.
if (handle.planes.empty()) {
return std::make_unique<ClientNativePixmapFuchsia>(std::move(handle));
}
// Validate that all planes refer to a single memory object.
const absl::optional<zx_koid_t> first_plane_koid =
base::GetKoid(handle.planes[0].vmo);
if (!first_plane_koid) {
return nullptr;
}
for (const auto& plane : handle.planes) {
const absl::optional<zx_koid_t> plane_koid = base::GetKoid(plane.vmo);
DCHECK(plane.vmo.is_valid() || !plane_koid);
if (plane_koid != first_plane_koid) {
return nullptr;
}
}
if (!CanFitImageForSizeAndFormat(handle, size, format,
/*assume_single_memory_object=*/true)) {
return nullptr;
}
// The |last_plane_end| computation should not overflow if the
// CanFitImageForSizeAndFormat() check passed.
const size_t last_plane_end =
base::CheckAdd(handle.planes.back().offset, handle.planes.back().size)
.ValueOrDie<size_t>();
uint64_t vmo_size;
if (handle.planes.back().vmo.get_size(&vmo_size) != ZX_OK ||
!base::IsValueInRangeForNumericType<size_t>(vmo_size) ||
base::checked_cast<size_t>(vmo_size) < last_plane_end) {
return nullptr;
}
#if DCHECK_IS_ON()
// zx_vmo_get_size() should return a page-aligned size. This is important
// because we request a page-aligned size in
// ClientNativePixmapFuchsia::Map().
DCHECK_EQ(vmo_size % ZX_PAGE_SIZE, 0u);
// The CanFitImageForSizeAndFormat() call above should guarantee that the
// (offset + size) for each plane is <= |last_plane_end|, and since we now
// know that |last_plane_end| <= |vmo_size|, then (offset + size) for each
// plane <= |vmo_size|.
for (const auto& plane : handle.planes) {
DCHECK_LE(plane.offset + plane.size, vmo_size);
}
#endif
return std::make_unique<ClientNativePixmapFuchsia>(std::move(handle));
}
};
gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryScenic() {
return new ScenicClientNativePixmapFactory();
}
} // namespace ui

@ -1,20 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_CLIENT_NATIVE_PIXMAP_FACTORY_SCENIC_H_
#define UI_OZONE_PLATFORM_SCENIC_CLIENT_NATIVE_PIXMAP_FACTORY_SCENIC_H_
namespace gfx {
class ClientNativePixmapFactory;
} // namespace gfx
namespace ui {
// Scenic-platform constructor hook, for use by the auto-generated platform
// constructor-list.
gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryScenic();
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_CLIENT_NATIVE_PIXMAP_FACTORY_SCENIC_H_

@ -1,43 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/overlay_manager_scenic.h"
#include "base/logging.h"
#include "ui/ozone/platform/scenic/sysmem_native_pixmap.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
namespace ui {
namespace {
class OverlayCandidatesScenic : public OverlayCandidatesOzone {
public:
OverlayCandidatesScenic() = default;
void CheckOverlaySupport(OverlaySurfaceCandidateList* candidates) override {
for (auto& candidate : *candidates) {
if (!candidate.native_pixmap)
continue;
SysmemNativePixmap* sysmem_native_pixmap =
reinterpret_cast<SysmemNativePixmap*>(candidate.native_pixmap.get());
candidate.overlay_handled = sysmem_native_pixmap->SupportsOverlayPlane();
}
}
};
} // namespace
OverlayManagerScenic::OverlayManagerScenic() {
// Fuchsia overlays rely on ShouldUseRealBuffersForPageFlipTest.
allow_sync_and_real_buffer_page_flip_testing_ = true;
}
OverlayManagerScenic::~OverlayManagerScenic() = default;
std::unique_ptr<OverlayCandidatesOzone>
OverlayManagerScenic::CreateOverlayCandidates(gfx::AcceleratedWidget widget) {
return std::make_unique<OverlayCandidatesScenic>();
}
} // namespace ui

@ -1,29 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_OVERLAY_MANAGER_SCENIC_H_
#define UI_OZONE_PLATFORM_SCENIC_OVERLAY_MANAGER_SCENIC_H_
#include <memory>
#include "ui/ozone/public/overlay_manager_ozone.h"
namespace ui {
class OverlayManagerScenic : public OverlayManagerOzone {
public:
OverlayManagerScenic();
~OverlayManagerScenic() override;
OverlayManagerScenic(const OverlayManagerScenic&) = delete;
OverlayManagerScenic& operator=(const OverlayManagerScenic&) = delete;
// OverlayManagerOzone implementation
std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
gfx::AcceleratedWidget widget) override;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_OVERLAY_MANAGER_SCENIC_H_

@ -1,271 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/ozone_platform_scenic.h"
#include <memory>
#include <utility>
#include <vector>
#include <fidl/fuchsia.ui.views/cpp/hlcpp_conversion.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include "base/check.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_pump_type.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/ime/fuchsia/input_method_fuchsia.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/bitmap_cursor_factory.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform/scenic/overlay_manager_scenic.h"
#include "ui/ozone/platform/scenic/scenic_gpu_host.h"
#include "ui/ozone/platform/scenic/scenic_gpu_service.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
#include "ui/ozone/platform_selection.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/ozone/public/system_input_injector.h"
#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
namespace {
::fuchsia::ui::views::ViewRef CloneViewRef(
const ::fuchsia::ui::views::ViewRef& view_ref) {
::fuchsia::ui::views::ViewRef dup;
zx_status_t status =
view_ref.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
return dup;
}
class ScenicPlatformEventSource : public ui::PlatformEventSource {
public:
ScenicPlatformEventSource() = default;
ScenicPlatformEventSource(const ScenicPlatformEventSource&) = delete;
ScenicPlatformEventSource& operator=(const ScenicPlatformEventSource&) =
delete;
~ScenicPlatformEventSource() override = default;
};
// OzonePlatform for Scenic.
class OzonePlatformScenic : public OzonePlatform,
public base::CurrentThread::DestructionObserver {
public:
OzonePlatformScenic() = default;
OzonePlatformScenic(const OzonePlatformScenic&) = delete;
OzonePlatformScenic& operator=(const OzonePlatformScenic&) = delete;
~OzonePlatformScenic() override = default;
// OzonePlatform implementation.
ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
return surface_factory_.get();
}
OverlayManagerOzone* GetOverlayManager() override {
return overlay_manager_.get();
}
CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); }
InputController* GetInputController() override {
return input_controller_.get();
}
GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
return scenic_gpu_host_.get();
}
std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
NOTIMPLEMENTED();
return nullptr;
}
std::unique_ptr<PlatformWindow> CreatePlatformWindow(
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties) override {
BindInMainProcessIfNecessary();
if (!properties.view_token.value) {
auto view_tokens = scenic::ViewTokenPair::New();
properties.view_token = std::move(view_tokens.view_token);
properties.view_ref_pair = scenic::ViewRefPair::New();
properties.view_controller = ::ui::fuchsia::GetScenicViewPresenter().Run(
std::move(view_tokens.view_holder_token),
CloneViewRef(properties.view_ref_pair.view_ref));
}
return std::make_unique<ScenicWindow>(window_manager_.get(), delegate,
std::move(properties));
}
const PlatformProperties& GetPlatformProperties() override {
static base::NoDestructor<OzonePlatform::PlatformProperties> properties;
static bool initialised = false;
if (!initialised) {
properties->message_pump_type_for_gpu = base::MessagePumpType::IO;
properties->supports_vulkan_swap_chain = true;
initialised = true;
}
return *properties;
}
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
override {
NOTIMPLEMENTED();
return nullptr;
}
std::unique_ptr<PlatformScreen> CreateScreen() override {
return window_manager_->CreateScreen();
}
void InitScreen(PlatformScreen* screen) override {}
std::unique_ptr<InputMethod> CreateInputMethod(
ImeKeyEventDispatcher* ime_key_event_dispatcher,
gfx::AcceleratedWidget widget) override {
return std::make_unique<InputMethodFuchsia>(
window_manager_->GetWindow(widget)->is_virtual_keyboard_enabled(),
ime_key_event_dispatcher,
fidl::HLCPPToNatural(
window_manager_->GetWindow(widget)->CloneViewRef()));
}
bool InitializeUI(const InitParams& params) override {
if (!PlatformEventSource::GetInstance())
platform_event_source_ = std::make_unique<ScenicPlatformEventSource>();
keyboard_layout_engine_ = std::make_unique<StubKeyboardLayoutEngine>();
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
keyboard_layout_engine_.get());
window_manager_ = std::make_unique<ScenicWindowManager>();
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = CreateStubInputController();
cursor_factory_ = std::make_unique<BitmapCursorFactory>();
scenic_gpu_host_ = std::make_unique<ScenicGpuHost>(window_manager_.get());
// SurfaceFactory is configured here to use a ui-process remote for software
// output.
if (!surface_factory_)
surface_factory_ = std::make_unique<ScenicSurfaceFactory>();
if (base::SingleThreadTaskRunner::HasCurrentDefault())
BindInMainProcessIfNecessary();
return true;
}
void InitializeGPU(const InitParams& params) override {
DCHECK(!surface_factory_ || params.single_process);
if (!surface_factory_)
surface_factory_ = std::make_unique<ScenicSurfaceFactory>();
if (!params.single_process) {
mojo::PendingRemote<mojom::ScenicGpuHost> scenic_gpu_host_remote;
scenic_gpu_service_ = std::make_unique<ScenicGpuService>(
scenic_gpu_host_remote.InitWithNewPipeAndPassReceiver());
// SurfaceFactory is configured here to use a gpu-process remote. The
// other end of the pipe will be attached through ScenicGpuService.
surface_factory_->Initialize(std::move(scenic_gpu_host_remote));
}
overlay_manager_ = std::make_unique<OverlayManagerScenic>();
}
const PlatformRuntimeProperties& GetPlatformRuntimeProperties() override {
static OzonePlatform::PlatformRuntimeProperties properties;
properties.supports_native_pixmaps = true;
properties.supports_overlays = true;
return properties;
}
void AddInterfaces(mojo::BinderMap* binders) override {
binders->Add<mojom::ScenicGpuService>(
scenic_gpu_service_->GetBinderCallback(),
base::SingleThreadTaskRunner::GetCurrentDefault());
}
bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
gfx::BufferUsage usage) const override {
return SysmemBufferCollection::IsNativePixmapConfigSupported(format, usage);
}
private:
// Binds main process surface factory to main process ScenicGpuHost
void BindInMainProcessIfNecessary() {
if (bound_in_main_process_)
return;
mojo::PendingRemote<mojom::ScenicGpuHost> gpu_host_remote;
scenic_gpu_host_->Initialize(
gpu_host_remote.InitWithNewPipeAndPassReceiver());
surface_factory_->Initialize(std::move(gpu_host_remote));
bound_in_main_process_ = true;
base::CurrentThread::Get()->AddDestructionObserver(this);
}
void ShutdownInMainProcess() {
DCHECK(bound_in_main_process_);
surface_factory_->Shutdown();
scenic_gpu_host_->Shutdown();
window_manager_->Shutdown();
bound_in_main_process_ = false;
}
// base::CurrentThread::DestructionObserver implementation.
void WillDestroyCurrentMessageLoop() override { ShutdownInMainProcess(); }
std::unique_ptr<ScenicWindowManager> window_manager_;
std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_;
std::unique_ptr<PlatformEventSource> platform_event_source_;
std::unique_ptr<CursorFactory> cursor_factory_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
std::unique_ptr<ScenicGpuHost> scenic_gpu_host_;
std::unique_ptr<ScenicGpuService> scenic_gpu_service_;
std::unique_ptr<ScenicSurfaceFactory> surface_factory_;
// Whether the main process has initialized mojo bindings.
bool bound_in_main_process_ = false;
};
} // namespace
OzonePlatform* CreateOzonePlatformScenic() {
return new OzonePlatformScenic();
}
} // namespace ui

@ -1,17 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_OZONE_PLATFORM_SCENIC_H_
#define UI_OZONE_PLATFORM_SCENIC_OZONE_PLATFORM_SCENIC_H_
namespace ui {
class OzonePlatform;
// Constructor hook for use in ozone_platform_list.cc
OzonePlatform* CreateOzonePlatformScenic();
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_OZONE_PLATFORM_SCENIC_H_

@ -1,60 +0,0 @@
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/safe_presenter.h"
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include "base/check.h"
namespace ui {
SafePresenter::SafePresenter(scenic::Session* session) : session_(session) {
DCHECK(session_);
session_->set_on_frame_presented_handler(
fit::bind_member(this, &SafePresenter::OnFramePresented));
}
SafePresenter::~SafePresenter() {
// Clear the OnFramePresented callback, in case the `session_` outlives
// SafePresenter.
session_->set_on_frame_presented_handler({});
}
void SafePresenter::QueuePresent() {
// Present to Scenic immediately, if we can.
if (presents_allowed_) {
QueuePresentHelper();
return;
}
// We cannot present immediately, so queue for later.
present_queued_ = true;
}
void SafePresenter::QueuePresentHelper() {
DCHECK(session_);
DCHECK(presents_allowed_);
presents_allowed_ = false;
present_queued_ = false;
session_->Present2(/*requested_presentation_time=*/0,
/*requested_prediction_span=*/0, [](auto) {});
}
void SafePresenter::OnFramePresented(
fuchsia::scenic::scheduling::FramePresentedInfo info) {
presents_allowed_ = info.num_presents_allowed > 0;
// Since we only have one Present2 call in progress at once, this must
// be true.
DCHECK(presents_allowed_);
if (present_queued_ && presents_allowed_) {
QueuePresentHelper();
}
}
} // namespace ui

@ -1,52 +0,0 @@
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SAFE_PRESENTER_H_
#define UI_OZONE_PLATFORM_SCENIC_SAFE_PRESENTER_H_
#include <lib/ui/scenic/cpp/session.h>
namespace ui {
using QueuePresentCallback = fit::function<void()>;
// Helper class used to call Present2() in fuchsia.ui.scenic.Session. By
// limiting the number of Present2 calls, SafePresenter ensures that the Session
// will not be shut down, thus, users of SafePresenter should not call Present2
// on their own.
//
// More information can be found in the fuchsia.scenic.scheduling FIDL library,
// in the prediction_info.fidl file.
class SafePresenter {
public:
explicit SafePresenter(scenic::Session* session);
~SafePresenter();
SafePresenter(const SafePresenter&) = delete;
SafePresenter& operator=(const SafePresenter&) = delete;
// If possible, QueuePresent() immediately presents to the underlying Session.
// If the maximum amount of pending Present2()s has been reached,
// SafePresenter presents at the next earliest possible time. QueuePresent()
// ensures that callbacks get processed in FIFO order.
void QueuePresent();
private:
void QueuePresentHelper();
void OnFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info);
scenic::Session* const session_ = nullptr;
// |presents_allowed_| is true if Scenic allows at least one more Present2()
// call. Scenic ensures a session will have a Present2 budget of at least 1 to
// begin with.
bool presents_allowed_ = true;
// |present_queued_| is true if there are unhandled QueuePresent() calls.
bool present_queued_ = false;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SAFE_PRESENTER_H_

@ -1,94 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_gpu_host.h"
#include <inttypes.h>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/task/single_thread_task_runner.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
namespace {
using BinderCallback =
base::RepeatingCallback<void(const std::string&,
mojo::ScopedMessagePipeHandle)>;
template <typename Interface>
void BindInterface(mojo::PendingReceiver<Interface> receiver,
const BinderCallback& binder_callback) {
binder_callback.Run(Interface::Name_, receiver.PassPipe());
}
} // namespace
namespace ui {
ScenicGpuHost::ScenicGpuHost(ScenicWindowManager* scenic_window_manager)
: scenic_window_manager_(scenic_window_manager) {
DETACH_FROM_THREAD(io_thread_checker_);
}
ScenicGpuHost::~ScenicGpuHost() {
Shutdown();
}
void ScenicGpuHost::Initialize(
mojo::PendingReceiver<mojom::ScenicGpuHost> host_receiver) {
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
DCHECK(!ui_thread_runner_);
ui_thread_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
DCHECK(ui_thread_runner_);
host_receiver_.Bind(std::move(host_receiver));
}
void ScenicGpuHost::Shutdown() {
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
ui_thread_runner_ = nullptr;
host_receiver_.reset();
gpu_receiver_.reset();
gpu_service_.reset();
}
void ScenicGpuHost::AttachSurfaceToWindow(
int32_t window_id,
mojo::PlatformHandle surface_view_holder_token_mojo) {
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
ScenicWindow* scenic_window = scenic_window_manager_->GetWindow(window_id);
if (!scenic_window)
return;
fuchsia::ui::views::ViewHolderToken surface_view_holder_token;
surface_view_holder_token.value =
zx::eventpair(surface_view_holder_token_mojo.TakeHandle());
scenic_window->AttachSurfaceView(std::move(surface_view_holder_token));
}
void ScenicGpuHost::OnChannelDestroyed(int host_id) {}
void ScenicGpuHost::OnGpuServiceLaunched(
int host_id,
GpuHostBindInterfaceCallback binder,
GpuHostTerminateCallback terminate_callback) {
DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
mojo::PendingRemote<mojom::ScenicGpuService> scenic_gpu_service;
BindInterface(scenic_gpu_service.InitWithNewPipeAndPassReceiver(), binder);
gpu_receiver_.reset();
gpu_service_.reset();
gpu_service_.Bind(std::move(scenic_gpu_service));
gpu_service_->Initialize(gpu_receiver_.BindNewPipeAndPassRemote());
}
} // namespace ui

@ -1,79 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_HOST_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_HOST_H_
#include <inttypes.h>
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
namespace ui {
class ScenicWindowManager;
// Browser process object which supports a GPU process host.
//
// Once a GPU process starts, this objects binds to it over mojo and
// enables exchange of Scenic resources with it. In particular, we must
// exchange export tokens for each view surface, so that the surface can
// present to Scenic views managed by the browser.
class ScenicGpuHost : public mojom::ScenicGpuHost,
public GpuPlatformSupportHost {
public:
ScenicGpuHost(ScenicWindowManager* scenic_window_manager);
ScenicGpuHost(const ScenicGpuHost&) = delete;
ScenicGpuHost& operator=(const ScenicGpuHost&) = delete;
~ScenicGpuHost() override;
// Binds the receiver for the main process surface factory.
void Initialize(mojo::PendingReceiver<mojom::ScenicGpuHost> pending_receiver);
// Shuts down mojo service. After calling shutdown, it's safe to call
// Initialize() again.
void Shutdown();
// mojom::ScenicGpuHost:
void AttachSurfaceToWindow(
int32_t window_id,
mojo::PlatformHandle surface_view_holder_token_mojo) override;
// GpuPlatformSupportHost:
void OnChannelDestroyed(int host_id) override;
void OnGpuServiceLaunched(
int host_id,
GpuHostBindInterfaceCallback binder,
GpuHostTerminateCallback terminate_callback) override;
private:
void UpdateReceiver(uint32_t service_launch_count,
mojo::PendingReceiver<mojom::ScenicGpuHost> receiver);
ScenicWindowManager* const scenic_window_manager_;
mojo::Receiver<mojom::ScenicGpuHost> host_receiver_{this};
mojo::Receiver<mojom::ScenicGpuHost> gpu_receiver_{this};
mojo::Remote<mojom::ScenicGpuService> gpu_service_;
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_runner_;
THREAD_CHECKER(ui_thread_checker_);
THREAD_CHECKER(io_thread_checker_);
base::WeakPtrFactory<ScenicGpuHost> weak_ptr_factory_{this};
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_HOST_H_

@ -1,42 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_gpu_service.h"
#include "base/functional/bind.h"
#include "mojo/public/c/system/message_pipe.h"
namespace ui {
ScenicGpuService::ScenicGpuService(
mojo::PendingReceiver<mojom::ScenicGpuHost> gpu_host_receiver)
: gpu_host_receiver_(std::move(gpu_host_receiver)) {}
ScenicGpuService::~ScenicGpuService() {}
base::RepeatingCallback<void(mojo::PendingReceiver<mojom::ScenicGpuService>)>
ScenicGpuService::GetBinderCallback() {
return base::BindRepeating(&ScenicGpuService::AddReceiver,
weak_ptr_factory_.GetWeakPtr());
}
void ScenicGpuService::Initialize(
mojo::PendingRemote<mojom::ScenicGpuHost> gpu_host) {
// The ScenicGpuService acts as a bridge to bind the
// Remote<mojom::ScenicGpuHost>, owned by ScenicSurfaceFactory and
// received in the constructor, and the mojo::Receiver<mojom::ScenicGpuHost>,
// owned by ScenicGpuHost and received as a parameter in this function. Using
// mojo::FusePipes is the only way to "bind" a pending remote with a
// pending receiver.
bool result =
mojo::FusePipes(std::move(gpu_host_receiver_), std::move(gpu_host));
DCHECK(result);
}
void ScenicGpuService::AddReceiver(
mojo::PendingReceiver<mojom::ScenicGpuService> receiver) {
receiver_set_.Add(this, std::move(receiver));
}
} // namespace ui

@ -1,52 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_SERVICE_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_SERVICE_H_
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_service.mojom.h"
namespace ui {
// GPU process service that enables presentation to Scenic.
//
// This object exposes a mojo service to the browser process from the GPU
// process. The browser binds it to enable exchange of Scenic resources.
// In particular, we must exchange export tokens for each view surface,
// so that surfaces can present to Scenic views managed by the browser.
class ScenicGpuService : public mojom::ScenicGpuService {
public:
ScenicGpuService(
mojo::PendingReceiver<mojom::ScenicGpuHost> gpu_host_receiver);
ScenicGpuService(const ScenicGpuService&) = delete;
ScenicGpuService& operator=(const ScenicGpuService&) = delete;
~ScenicGpuService() override;
base::RepeatingCallback<void(mojo::PendingReceiver<mojom::ScenicGpuService>)>
GetBinderCallback();
// mojom::ScenicGpuService:
void Initialize(mojo::PendingRemote<mojom::ScenicGpuHost> gpu_host) override;
private:
void AddReceiver(mojo::PendingReceiver<mojom::ScenicGpuService> receiver);
mojo::PendingReceiver<mojom::ScenicGpuHost> gpu_host_receiver_;
mojo::ReceiverSet<mojom::ScenicGpuService> receiver_set_;
base::WeakPtrFactory<ScenicGpuService> weak_ptr_factory_{this};
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_SERVICE_H_

@ -1,114 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_overlay_view.h"
#include <lib/ui/scenic/cpp/commands.h>
#include "base/fuchsia/fuchsia_logging.h"
#include "base/location.h"
namespace ui {
namespace {
// |buffer_collection_id| that is passed to ImagePipe::AddBufferCollection() if
// SysmemBufferCollection instance is registered with one.
static const uint32_t kImagePipeBufferCollectionId = 1;
static const std::string kSessionDebugName = "chromium scenic overlay";
} // namespace
ScenicOverlayView::ScenicOverlayView(
scenic::SessionPtrAndListenerRequest session_and_listener_request)
: scenic_session_(std::move(session_and_listener_request)),
safe_presenter_(&scenic_session_),
image_material_(&scenic_session_) {
scenic_session_.SetDebugName(kSessionDebugName);
scenic_session_.set_error_handler(
base::LogFidlErrorAndExitProcess(FROM_HERE, "ScenicSession"));
}
ScenicOverlayView::~ScenicOverlayView() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Releasing |image_pipe_| implicitly also enforces cleanup.
image_pipe_->RemoveBufferCollection(kImagePipeBufferCollectionId);
}
void ScenicOverlayView::Initialize(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
collection_token) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
uint32_t image_pipe_id = scenic_session_.AllocResourceId();
scenic_session_.Enqueue(
scenic::NewCreateImagePipe2Cmd(image_pipe_id, image_pipe_.NewRequest()));
image_pipe_.set_error_handler(
base::LogFidlErrorAndExitProcess(FROM_HERE, "ImagePipe"));
image_material_.SetTexture(image_pipe_id);
safe_presenter_.QueuePresent();
// Since there is one ImagePipe for each BufferCollection, it is ok to use a
// fixed buffer_collection_id.
// TODO(emircan): Consider using one ImagePipe per video decoder instead.
image_pipe_->AddBufferCollection(kImagePipeBufferCollectionId,
std::move(collection_token));
}
uint32_t ScenicOverlayView::AddImage(uint32_t buffer_index,
const gfx::Size& size) {
uint32_t id = next_image_id_++;
fuchsia::sysmem::ImageFormat_2 image_format = {};
image_format.coded_width = size.width();
image_format.coded_height = size.height();
image_pipe_->AddImage(id, kImagePipeBufferCollectionId, buffer_index,
image_format);
return id;
}
void ScenicOverlayView::RemoveImage(uint32_t image_id) {
image_pipe_->RemoveImage(image_id);
}
bool ScenicOverlayView::PresentImage(uint32_t image_id,
std::vector<zx::event> acquire_fences,
std::vector<zx::event> release_fences) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
image_pipe_->PresentImage(image_id, zx_clock_get_monotonic(),
std::move(acquire_fences),
std::move(release_fences), [](auto) {});
return true;
}
void ScenicOverlayView::SetBlendMode(bool enable_blend) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (enable_blend_ == enable_blend)
return;
enable_blend_ = enable_blend;
// Setting alpha as |255| marks the image as opaque and no content below would
// be seen. Anything lower than 255 allows blending.
image_material_.SetColor(255, 255, 255, enable_blend ? 254 : 255);
safe_presenter_.QueuePresent();
}
void ScenicOverlayView::AttachToScenicSurface(
fuchsia::ui::views::ViewToken view_token) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
view_.emplace(&scenic_session_, std::move(view_token), kSessionDebugName);
scenic::ShapeNode shape(&scenic_session_);
shape.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
shape.SetMaterial(image_material_);
view_->AddChild(shape);
safe_presenter_.QueuePresent();
}
} // namespace ui

@ -1,75 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_OVERLAY_VIEW_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_OVERLAY_VIEW_H_
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include "base/threading/thread_checker.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/platform/scenic/safe_presenter.h"
#include "ui/ozone/platform/scenic/scenic_surface.h"
namespace ui {
// Holder for scenic::Session and scenic::View that owns an Image Pipe.
//
// This class allows the callers to access an ImagePipe and a scenic::View that
// displays only that ImagePipe. This is used inside SysmemBufferCollection
// instances to display overlays.
class ScenicOverlayView {
public:
explicit ScenicOverlayView(
scenic::SessionPtrAndListenerRequest session_and_listener_request);
~ScenicOverlayView();
ScenicOverlayView(const ScenicOverlayView&) = delete;
ScenicOverlayView& operator=(const ScenicOverlayView&) = delete;
// Calls ImagePipe2::AddBufferCollection() using |collection_token|. All
// |image_pipe| interactions in this class is then associated with this
// BufferCollection.
void Initialize(fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
collection_token);
// Adds an image to the ImagePipe using the specified `buffer_index` and
// `size`. Returns a non-zero `image_id` that may be used in `PresentImage()`
// and `RemoveImage()`.
uint32_t AddImage(uint32_t buffer_index, const gfx::Size& size);
// Removes image with the `image_id_` from the ImagePipe.
void RemoveImage(uint32_t image_id);
// Calls `ImagePipe2::PresentImage()` on `image_pipe_` for the `image_id`
// corresponding to |buffer_index| from the initialized BufferCollection.
bool PresentImage(uint32_t image_id,
std::vector<zx::event> acquire_fences,
std::vector<zx::event> release_fences);
// If |enable_blend| is true, sets |image_pipe_| as non-opaque.
void SetBlendMode(bool enable_blend);
// Attaches the view using the specified token.
void AttachToScenicSurface(fuchsia::ui::views::ViewToken view_token);
private:
scenic::Session scenic_session_;
// Used for safely queueing Present() operations on |scenic_session_|.
SafePresenter safe_presenter_;
absl::optional<scenic::View> view_;
fuchsia::images::ImagePipe2Ptr image_pipe_;
scenic::Material image_material_;
uint32_t next_image_id_ = 1;
bool enable_blend_ = false;
THREAD_CHECKER(thread_checker_);
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_OVERLAY_VIEW_H_

@ -1,57 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_screen.h"
#include "base/notreached.h"
#include "ui/display/display.h"
#include "ui/display/display_observer.h"
#include "ui/gfx/geometry/point.h"
namespace ui {
ScenicScreen::ScenicScreen()
: displays_({display::Display::GetDefaultDisplay()}) {}
ScenicScreen::~ScenicScreen() = default;
const std::vector<display::Display>& ScenicScreen::GetAllDisplays() const {
return displays_;
}
display::Display ScenicScreen::GetPrimaryDisplay() const {
return displays_[0];
}
display::Display ScenicScreen::GetDisplayForAcceleratedWidget(
gfx::AcceleratedWidget widget) const {
return displays_[0];
}
gfx::Point ScenicScreen::GetCursorScreenPoint() const {
NOTIMPLEMENTED_LOG_ONCE();
return gfx::Point();
}
gfx::AcceleratedWidget ScenicScreen::GetAcceleratedWidgetAtScreenPoint(
const gfx::Point& point) const {
NOTIMPLEMENTED_LOG_ONCE();
return gfx::kNullAcceleratedWidget;
}
display::Display ScenicScreen::GetDisplayNearestPoint(
const gfx::Point& point) const {
return displays_[0];
}
display::Display ScenicScreen::GetDisplayMatching(
const gfx::Rect& match_rect) const {
return displays_[0];
}
void ScenicScreen::AddObserver(display::DisplayObserver* observer) {}
void ScenicScreen::RemoveObserver(display::DisplayObserver* observer) {}
} // namespace ui

@ -1,48 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_SCREEN_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SCREEN_H_
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/platform_screen.h"
namespace ui {
// A PlatformScreen implementation for Scenic.
class ScenicScreen : public PlatformScreen {
public:
ScenicScreen();
ScenicScreen(const ScenicScreen&) = delete;
ScenicScreen& operator=(const ScenicScreen&) = delete;
~ScenicScreen() override;
// display::Screen implementation.
const std::vector<display::Display>& GetAllDisplays() const override;
display::Display GetPrimaryDisplay() const override;
display::Display GetDisplayForAcceleratedWidget(
gfx::AcceleratedWidget widget) const override;
gfx::Point GetCursorScreenPoint() const override;
gfx::AcceleratedWidget GetAcceleratedWidgetAtScreenPoint(
const gfx::Point& point) const override;
display::Display GetDisplayNearestPoint(
const gfx::Point& point) const override;
display::Display GetDisplayMatching(
const gfx::Rect& match_rect) const override;
void AddObserver(display::DisplayObserver* observer) override;
void RemoveObserver(display::DisplayObserver* observer) override;
private:
std::vector<display::Display> displays_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_SCREEN_H_

@ -1,608 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_surface.h"
#include <lib/sys/cpp/component_context.h>
#include <lib/ui/scenic/cpp/commands.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <lib/zx/eventpair.h>
#include <zircon/types.h>
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/koid.h"
#include "base/fuchsia/process_context.h"
#include "base/numerics/math_constants.h"
#include "base/process/process_handle.h"
#include "base/trace_event/trace_event.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "sysmem_native_pixmap.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/ozone/platform/scenic/scenic_gpu_host.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
namespace ui {
namespace {
// Scenic has z-fighting problems in 3D API, so we add tiny z plane increments
// to elevate content. ViewProperties set by ScenicWindow sets z-plane to
// [-0.5f, 0.5f] range, so 0.01f is small enough to make a difference.
constexpr float kElevationStep = 0.01f;
std::vector<zx::event> GpuFenceHandlesToZxEvents(
std::vector<gfx::GpuFenceHandle> handles) {
std::vector<zx::event> events;
events.reserve(handles.size());
for (auto& handle : handles)
events.push_back(std::move(handle.owned_event));
return events;
}
zx::event DuplicateZxEvent(const zx::event& event) {
zx::event result;
zx_status_t status = event.duplicate(ZX_RIGHT_SAME_RIGHTS, &result);
ZX_DCHECK(status == ZX_OK, status);
return result;
}
std::vector<gfx::GpuFence> DuplicateGpuFences(
const std::vector<gfx::GpuFenceHandle>& fence_handles) {
std::vector<gfx::GpuFence> fences;
fences.reserve(fence_handles.size());
for (const auto& handle : fence_handles)
fences.emplace_back(handle.Clone());
return fences;
}
// Converts OverlayTransform enum to angle in radians.
float OverlayTransformToRadians(gfx::OverlayTransform plane_transform) {
switch (plane_transform) {
case gfx::OVERLAY_TRANSFORM_NONE:
case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
return 0;
case gfx::OVERLAY_TRANSFORM_ROTATE_90:
return base::kPiFloat * .5f;
case gfx::OVERLAY_TRANSFORM_ROTATE_180:
return base::kPiFloat;
case gfx::OVERLAY_TRANSFORM_ROTATE_270:
return base::kPiFloat * 1.5f;
case gfx::OVERLAY_TRANSFORM_INVALID:
NOTREACHED();
return 0;
}
NOTREACHED();
return 0;
}
} // namespace
ScenicSurface::ScenicSurface(
ScenicSurfaceFactory* scenic_surface_factory,
SysmemBufferManager* sysmem_buffer_manager,
gfx::AcceleratedWidget window,
scenic::SessionPtrAndListenerRequest sesion_and_listener_request)
: scenic_session_(std::move(sesion_and_listener_request)),
safe_presenter_(&scenic_session_),
main_shape_(&scenic_session_),
main_material_(&scenic_session_),
scenic_surface_factory_(scenic_surface_factory),
sysmem_buffer_manager_(sysmem_buffer_manager),
window_(window) {
// Setting alpha to 0 makes this transparent.
scenic::Material transparent_material(&scenic_session_);
transparent_material.SetColor(0, 0, 0, 0);
main_shape_.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
main_shape_.SetMaterial(transparent_material);
main_shape_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
scenic_surface_factory->AddSurface(window, this);
scenic_session_.SetDebugName("Chromium ScenicSurface");
scenic_session_.set_event_handler(
fit::bind_member(this, &ScenicSurface::OnScenicEvents));
}
ScenicSurface::~ScenicSurface() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Signal release fences that were submitted in the last PresentImage(). This
// is necessary because ExternalVkImageBacking destructor will wait for the
// corresponding semaphores, while they may not be signaled by the ImagePipe.
for (auto& fence : release_fences_from_last_present_) {
auto status =
fence.signal(/*clear_mask=*/0, /*set_mask=*/ZX_EVENT_SIGNALED);
ZX_DCHECK(status == ZX_OK, status);
}
scenic_surface_factory_->RemoveSurface(window_);
}
ScenicSurface::OverlayViewInfo::OverlayViewInfo(
scenic::Session* scenic_session,
fuchsia::ui::views::ViewHolderToken view_holder_token)
: view_holder(scenic_session,
std::move(view_holder_token),
"OverlayViewHolder"),
entity_node(scenic_session) {
view_holder.SetHitTestBehavior(fuchsia::ui::gfx::HitTestBehavior::kSuppress);
entity_node.AddChild(view_holder);
}
void ScenicSurface::OnScenicEvents(
std::vector<fuchsia::ui::scenic::Event> events) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (const auto& event : events) {
DCHECK(event.is_gfx());
switch (event.gfx().Which()) {
case fuchsia::ui::gfx::Event::kMetrics: {
DCHECK_EQ(event.gfx().metrics().node_id, main_shape_.id());
// This is enough to track size because |main_shape_| is 1x1.
const auto& metrics = event.gfx().metrics().metrics;
main_shape_size_.set_width(metrics.scale_x);
main_shape_size_.set_height(metrics.scale_y);
// Update layout only if Present() was called at least once, i.e. we
// have a frame to display.
if (last_frame_present_time_ != base::TimeTicks())
UpdateViewHolderScene();
break;
}
case fuchsia::ui::gfx::Event::kViewDetachedFromScene: {
DCHECK(event.gfx().view_detached_from_scene().view_id == parent_->id());
// Present an empty frame to ensure that the outdated content doesn't
// become visible if the view is attached again.
PresentEmptyImage();
break;
}
default:
break;
}
}
}
void ScenicSurface::Present(
scoped_refptr<gfx::NativePixmap> primary_plane_pixmap,
std::vector<ui::OverlayPlane> overlays_to_present,
std::vector<gfx::GpuFenceHandle> acquire_fences,
std::vector<gfx::GpuFenceHandle> release_fences,
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) {
if (!image_pipe_) {
std::move(completion_callback)
.Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_SKIPPED));
return;
}
auto& handle = static_cast<SysmemNativePixmap*>(primary_plane_pixmap.get())
->PeekHandle();
DCHECK_EQ(handle.buffer_index, 0u);
zx_koid_t buffer_collection_id =
base::GetKoid(handle.buffer_collection_handle).value();
DCHECK(buffer_collection_to_image_id_.contains(buffer_collection_id));
uint32_t image_id = buffer_collection_to_image_id_.at(buffer_collection_id);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("viz", "ScenicSurface::PresentFrame",
TRACE_ID_LOCAL(this), "image_id", image_id);
// Always update layout for the first frame.
bool layout_update_required = last_frame_present_time_ == base::TimeTicks();
for (auto& overlay_view : overlay_views_) {
overlay_view.second.should_be_visible = false;
}
for (auto& overlay : overlays_to_present) {
overlay.pixmap->ScheduleOverlayPlane(window_, overlay.overlay_plane_data,
DuplicateGpuFences(acquire_fences),
/*release_fences=*/{});
auto* pixmap = static_cast<SysmemNativePixmap*>(overlay.pixmap.get());
auto& overlay_handle = pixmap->PeekHandle();
zx_koid_t overlay_id =
base::GetKoid(overlay_handle.buffer_collection_handle).value();
auto it = overlay_views_.find(overlay_id);
// If this is a new overlay then attach it.
if (it == overlay_views_.end()) {
auto token_pair = scenic::ViewTokenPair::New();
pixmap->GetScenicOverlayView()->AttachToScenicSurface(
std::move(token_pair.view_token));
auto emplace_result = overlay_views_.emplace(
std::piecewise_construct, std::forward_as_tuple(overlay_id),
std::forward_as_tuple(&scenic_session_,
std::move(token_pair.view_holder_token)));
it = emplace_result.first;
layout_update_required = true;
}
auto& overlay_view_info = it->second;
overlay_view_info.should_be_visible = true;
auto& overlay_data = overlay.overlay_plane_data;
auto rounded_bounds = gfx::ToRoundedRect(overlay_data.display_bounds);
auto transform =
absl::get<gfx::OverlayTransform>(overlay_data.plane_transform);
if (overlay_view_info.plane_z_order != overlay_data.z_order ||
overlay_view_info.display_bounds != rounded_bounds ||
overlay_view_info.crop_rect != overlay_data.crop_rect ||
overlay_view_info.plane_transform != transform) {
overlay_view_info.plane_z_order = overlay_data.z_order;
overlay_view_info.display_bounds = rounded_bounds;
overlay_view_info.crop_rect = overlay_data.crop_rect;
overlay_view_info.plane_transform = transform;
layout_update_required = true;
}
}
// Hide all overlays views that are not in `overlays_to_present`.
auto it = overlay_views_.begin();
while (it != overlay_views_.end()) {
auto& overlay_view = it->second;
if (!overlay_view.should_be_visible) {
layout_update_required = true;
parent_->DetachChild(overlay_view.entity_node);
it = overlay_views_.erase(it);
continue;
}
it++;
}
if (layout_update_required) {
for (auto& fence : acquire_fences) {
scenic_session_.EnqueueAcquireFence(std::move(fence.Clone().owned_event));
}
UpdateViewHolderScene();
}
pending_frames_.emplace_back(
next_frame_ordinal_++, image_id, std::move(primary_plane_pixmap),
std::move(completion_callback), std::move(presentation_callback));
auto now = base::TimeTicks::Now();
auto present_time = now;
// If we have PresentationState frame a previously displayed frame then use it
// to calculate target timestamp for the new frame.
if (presentation_state_) {
uint32_t relative_position = pending_frames_.back().ordinal -
presentation_state_->presented_frame_ordinal;
present_time = presentation_state_->presentation_time +
presentation_state_->interval * relative_position -
base::Milliseconds(1);
present_time = std::max(present_time, now);
}
// Ensure that the target timestamp is not decreasing from the previous frame,
// since Scenic doesn't allow it (see crbug.com/1181528).
present_time = std::max(present_time, last_frame_present_time_);
last_frame_present_time_ = present_time;
release_fences_from_last_present_.clear();
for (auto& fence : release_fences) {
release_fences_from_last_present_.push_back(
DuplicateZxEvent(fence.owned_event));
}
image_pipe_->PresentImage(
image_id, present_time.ToZxTime(),
GpuFenceHandlesToZxEvents(std::move(acquire_fences)),
GpuFenceHandlesToZxEvents(std::move(release_fences)),
fit::bind_member(this, &ScenicSurface::OnPresentComplete));
}
scoped_refptr<gfx::NativePixmap> ScenicSurface::AllocatePrimaryPlanePixmap(
VkDevice vk_device,
const gfx::Size& size,
gfx::BufferFormat buffer_format) {
if (!image_pipe_)
InitializeImagePipe();
// Create buffer collection with 2 extra tokens: one for Vulkan and one for
// the ImagePipe.
fuchsia::sysmem::BufferCollectionTokenSyncPtr collection_token;
zx_status_t status =
sysmem_buffer_manager_->GetAllocator()->AllocateSharedCollection(
collection_token.NewRequest());
if (status != ZX_OK) {
ZX_DLOG(ERROR, status)
<< "fuchsia.sysmem.Allocator.AllocateSharedCollection()";
return {};
}
collection_token->SetName(100u, "ChromiumPrimaryPlaneOutput");
collection_token->SetDebugClientInfo("vulkan", 0u);
fuchsia::sysmem::BufferCollectionTokenSyncPtr token_for_scenic;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
token_for_scenic.NewRequest());
token_for_scenic->SetDebugClientInfo("scenic", 0u);
// Register the new buffer collection with the ImagePipe. Since there will
// only be a single buffer in the buffer collection we use the same value for
// both buffer collection id and image ids.
const uint32_t image_id = ++next_unique_id_;
image_pipe_->AddBufferCollection(image_id, std::move(token_for_scenic));
// Register the new buffer collection with sysmem.
gfx::NativePixmapHandle pixmap_handle;
zx::eventpair service_handle;
status = zx::eventpair::create(0, &pixmap_handle.buffer_collection_handle,
&service_handle);
ZX_DCHECK(status == ZX_OK, status);
zx_koid_t buffer_collection_id =
base::GetKoid(pixmap_handle.buffer_collection_handle).value();
buffer_collection_to_image_id_[buffer_collection_id] = image_id;
auto buffer_collection = sysmem_buffer_manager_->ImportSysmemBufferCollection(
vk_device, std::move(service_handle),
collection_token.Unbind().TakeChannel(), size, buffer_format,
gfx::BufferUsage::SCANOUT, 1,
/*register_with_image_pipe=*/false);
if (!buffer_collection) {
ZX_DLOG(ERROR, status) << "Failed to allocate sysmem buffer collection";
return {};
}
buffer_collection->AddOnReleasedCallback(
base::BindOnce(&ScenicSurface::RemoveBufferCollection,
weak_ptr_factory_.GetWeakPtr(), buffer_collection_id));
fuchsia::sysmem::ImageFormat_2 image_format;
image_format.coded_width = size.width();
image_format.coded_height = size.height();
image_pipe_->AddImage(image_id, image_id, 0, image_format);
return buffer_collection->CreateNativePixmap(std::move(pixmap_handle), size);
}
void ScenicSurface::SetTextureToNewImagePipe(
fidl::InterfaceRequest<fuchsia::images::ImagePipe2> image_pipe_request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
uint32_t image_pipe_id = scenic_session_.AllocResourceId();
scenic_session_.Enqueue(scenic::NewCreateImagePipe2Cmd(
image_pipe_id, std::move(image_pipe_request)));
main_material_.SetTexture(image_pipe_id);
main_shape_.SetMaterial(main_material_);
scenic_session_.ReleaseResource(image_pipe_id);
safe_presenter_.QueuePresent();
}
void ScenicSurface::SetTextureToImage(const scenic::Image& image) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
main_material_.SetTexture(image);
main_shape_.SetMaterial(main_material_);
}
mojo::PlatformHandle ScenicSurface::CreateView() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Scenic will associate the View and ViewHolder regardless of which it
// learns about first, so we don't need to synchronize View creation with
// attachment into the scene graph by the caller.
auto tokens = scenic::ViewTokenPair::New();
parent_ = std::make_unique<scenic::View>(
&scenic_session_, std::move(tokens.view_token), "chromium surface");
parent_->AddChild(main_shape_);
// Defer first Present call to SetTextureToNewImagePipe().
return mojo::PlatformHandle(std::move(tokens.view_holder_token.value));
}
void ScenicSurface::InitializeImagePipe() {
DCHECK(!image_pipe_);
SetTextureToNewImagePipe(image_pipe_.NewRequest());
image_pipe_.set_error_handler([this](zx_status_t status) {
ZX_LOG(ERROR, status) << "ImagePipe disconnected";
for (auto& frame : pending_frames_) {
std::move(frame.completion_callback)
.Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_FAILED));
}
pending_frames_.clear();
});
}
void ScenicSurface::RemoveBufferCollection(zx_koid_t buffer_collection_id) {
DCHECK(image_pipe_);
auto iter = buffer_collection_to_image_id_.find(buffer_collection_id);
DCHECK(iter != buffer_collection_to_image_id_.end());
image_pipe_->RemoveBufferCollection(iter->second);
buffer_collection_to_image_id_.erase(iter);
}
void ScenicSurface::OnPresentComplete(
fuchsia::images::PresentationInfo presentation_info) {
TRACE_EVENT_NESTABLE_ASYNC_END1("viz", "ScenicSurface::PresentFrame",
TRACE_ID_LOCAL(this), "image_id",
pending_frames_.front().image_id);
auto presentation_time =
base::TimeTicks::FromZxTime(presentation_info.presentation_time);
auto presentation_interval =
base::TimeDelta::FromZxDuration(presentation_info.presentation_interval);
auto& frame = pending_frames_.front();
std::move(frame.completion_callback)
.Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
std::move(frame.presentation_callback)
.Run(gfx::PresentationFeedback(presentation_time, presentation_interval,
gfx::PresentationFeedback::kVSync));
presentation_state_ =
PresentationState{static_cast<int>(frame.ordinal), presentation_time,
presentation_interval};
pending_frames_.pop_front();
}
void ScenicSurface::UpdateViewHolderScene() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Layout will be updated once we receive view size.
if (main_shape_size_.IsEmpty())
return;
// |plane_z_order| for main surface is 0.
int min_z_order = 0;
for (auto& item : overlay_views_) {
auto& overlay_view = item.second;
min_z_order = std::min(overlay_view.plane_z_order, min_z_order);
}
for (auto& item : overlay_views_) {
auto& overlay_view = item.second;
// No-op if the node is already attached.
parent_->AddChild(overlay_view.entity_node);
// Apply view bound clipping around the ImagePipe that has size 1x1 and
// centered at (0, 0).
fuchsia::ui::gfx::ViewProperties view_properties;
const float left_bound = -0.5f + overlay_view.crop_rect.x();
const float top_bound = -0.5f + overlay_view.crop_rect.y();
view_properties.bounding_box = {
{left_bound, top_bound, 0.f},
{left_bound + overlay_view.crop_rect.width(),
top_bound + overlay_view.crop_rect.height(), 0.f}};
view_properties.focus_change = false;
overlay_view.view_holder.SetViewProperties(std::move(view_properties));
// We receive |display_bounds| in screen coordinates. Convert them to fit
// 1x1 View, which is later scaled up by the browser process.
float scaled_width =
overlay_view.display_bounds.width() /
(overlay_view.crop_rect.width() * main_shape_size_.width());
float scaled_height =
overlay_view.display_bounds.height() /
(overlay_view.crop_rect.height() * main_shape_size_.height());
const float scaled_x =
overlay_view.display_bounds.x() / main_shape_size_.width();
const float scaled_y =
overlay_view.display_bounds.y() / main_shape_size_.height();
// Position ImagePipe based on the display bounds given.
overlay_view.entity_node.SetTranslation(
-0.5f + scaled_x + scaled_width / 2,
-0.5f + scaled_y + scaled_height / 2,
(min_z_order - overlay_view.plane_z_order) * kElevationStep);
// Apply rotation if given. Scenic expects rotation passed as Quaternion.
const float angle = OverlayTransformToRadians(overlay_view.plane_transform);
overlay_view.entity_node.SetRotation(
{0.f, 0.f, sinf(angle * .5f), cosf(angle * .5f)});
// Scenic applies scaling before rotation.
if (overlay_view.plane_transform == gfx::OVERLAY_TRANSFORM_ROTATE_90 ||
overlay_view.plane_transform == gfx::OVERLAY_TRANSFORM_ROTATE_270) {
std::swap(scaled_width, scaled_height);
}
// Scenic expects flip as negative scaling.
if (overlay_view.plane_transform ==
gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL) {
scaled_width = -scaled_width;
} else if (overlay_view.plane_transform ==
gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL) {
scaled_height = -scaled_height;
}
// Scale ImagePipe based on the display bounds and clip rect given.
overlay_view.entity_node.SetScale(scaled_width, scaled_height, 1.f);
}
main_material_.SetColor(255, 255, 255, 0 > min_z_order ? 254 : 255);
main_shape_.SetTranslation(0.f, 0.f, min_z_order * kElevationStep);
safe_presenter_.QueuePresent();
}
void ScenicSurface::PresentEmptyImage() {
if (last_frame_present_time_ == base::TimeTicks())
return;
fuchsia::sysmem::BufferCollectionTokenSyncPtr dummy_collection_token;
zx_status_t status =
sysmem_buffer_manager_->GetAllocator()->AllocateSharedCollection(
dummy_collection_token.NewRequest());
if (status != ZX_OK) {
ZX_DLOG(ERROR, status)
<< "fuchsia.sysmem.Allocator.AllocateSharedCollection()";
return;
}
dummy_collection_token->SetName(100u, "DummyImageCollection");
dummy_collection_token->SetDebugClientInfo("chromium", 0u);
fuchsia::sysmem::BufferCollectionTokenSyncPtr token_for_scenic;
dummy_collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
token_for_scenic.NewRequest());
token_for_scenic->SetDebugClientInfo("scenic", 0u);
const uint32_t image_id = ++next_unique_id_;
image_pipe_->AddBufferCollection(image_id, std::move(token_for_scenic));
// Synchroniously wait for the collection to be allocated before proceeding.
fuchsia::sysmem::BufferCollectionSyncPtr dummy_collection;
status = sysmem_buffer_manager_->GetAllocator()->BindSharedCollection(
std::move(dummy_collection_token), dummy_collection.NewRequest());
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.Allocator.BindSharedCollection()";
return;
}
fuchsia::sysmem::BufferCollectionConstraints constraints;
constraints.usage.none = fuchsia::sysmem::noneUsage;
constraints.min_buffer_count = 1;
constraints.image_format_constraints_count = 0;
status = dummy_collection->SetConstraints(/*has_constraints=*/true,
std::move(constraints));
zx_status_t wait_status;
fuchsia::sysmem::BufferCollectionInfo_2 buffers_info;
status =
dummy_collection->WaitForBuffersAllocated(&wait_status, &buffers_info);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollection failed";
return;
}
dummy_collection->Close();
// Present the first image from the collection.
fuchsia::sysmem::ImageFormat_2 image_format;
image_format.coded_width = 1;
image_format.coded_height = 1;
image_pipe_->AddImage(image_id, image_id, 0, image_format);
image_pipe_->PresentImage(image_id, last_frame_present_time_.ToZxTime(), {},
{}, [](fuchsia::images::PresentationInfo) {});
image_pipe_->RemoveBufferCollection(image_id);
}
ScenicSurface::PresentedFrame::PresentedFrame(
uint32_t ordinal,
uint32_t image_id,
scoped_refptr<gfx::NativePixmap> primary_plane,
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback)
: ordinal(ordinal),
image_id(image_id),
primary_plane(std::move(primary_plane)),
completion_callback(std::move(completion_callback)),
presentation_callback(std::move(presentation_callback)) {}
ScenicSurface::PresentedFrame::~PresentedFrame() = default;
ScenicSurface::PresentedFrame::PresentedFrame(PresentedFrame&&) = default;
ScenicSurface::PresentedFrame& ScenicSurface::PresentedFrame::operator=(
PresentedFrame&&) = default;
} // namespace ui

@ -1,204 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_H_
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include <vulkan/vulkan.h>
#include <memory>
#include <unordered_map>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/native_pixmap_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/scenic/safe_presenter.h"
#include "ui/ozone/public/platform_window_surface.h"
namespace ui {
class ScenicSurfaceFactory;
class SysmemBufferManager;
// Holder for Scenic resources backing rendering surface.
//
// This object creates some simple Scenic resources for containing a window's
// texture, and attaches them to the parent View (by sending an IPC to the
// browser process).
//
// The texture is updated through an image pipe.
class ScenicSurface : public PlatformWindowSurface {
public:
ScenicSurface(
ScenicSurfaceFactory* scenic_surface_factory,
SysmemBufferManager* sysmem_buffer_manager,
gfx::AcceleratedWidget window,
scenic::SessionPtrAndListenerRequest sesion_and_listener_request);
ScenicSurface(const ScenicSurface&) = delete;
ScenicSurface& operator=(const ScenicSurface&) = delete;
~ScenicSurface() override;
// PlatformWindowSurface overrides.
void Present(scoped_refptr<gfx::NativePixmap> primary_plane_pixmap,
std::vector<ui::OverlayPlane> overlays,
std::vector<gfx::GpuFenceHandle> acquire_fences,
std::vector<gfx::GpuFenceHandle> release_fences,
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) override;
// Allocates a new NativePixmap for the primary plane. The first time is
// invoked |image_pipe_| will be initialized.
scoped_refptr<gfx::NativePixmap> AllocatePrimaryPlanePixmap(
VkDevice vk_device,
const gfx::Size& size,
gfx::BufferFormat buffer_format);
// Sets the texture of the surface to a new image pipe.
void SetTextureToNewImagePipe(
fidl::InterfaceRequest<fuchsia::images::ImagePipe2> image_pipe_request);
// Sets the texture of the surface to an image resource.
void SetTextureToImage(const scenic::Image& image);
// Creates a View for this surface, and returns a ViewHolderToken handle
// that can be used to attach it into a scene graph.
mojo::PlatformHandle CreateView();
void OnScenicEvents(std::vector<fuchsia::ui::scenic::Event> events);
void AssertBelongsToCurrentThread() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
scenic::Session* scenic_session() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return &scenic_session_;
}
SafePresenter* safe_presenter() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return &safe_presenter_;
}
private:
struct PresentationState {
int presented_frame_ordinal;
base::TimeTicks presentation_time;
base::TimeDelta interval;
};
struct PresentedFrame {
PresentedFrame(uint32_t ordinal,
uint32_t image_id,
scoped_refptr<gfx::NativePixmap> primary_plane,
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback);
PresentedFrame(PresentedFrame&& other);
PresentedFrame& operator=(PresentedFrame&& other);
~PresentedFrame();
uint32_t ordinal;
uint32_t image_id;
// Ensures the pixmap is not destroyed until after frame is presented.
scoped_refptr<gfx::NativePixmap> primary_plane;
SwapCompletionCallback completion_callback;
BufferPresentedCallback presentation_callback;
};
void InitializeImagePipe();
// Removes a buffer collection registered with |image_pipe_| when it's no
// longer needed.
void RemoveBufferCollection(zx_koid_t buffer_collection_id);
void OnPresentComplete(fuchsia::images::PresentationInfo presentation_info);
void UpdateViewHolderScene();
void PresentEmptyImage();
scenic::Session scenic_session_;
std::unique_ptr<scenic::View> parent_;
// Used for safely queueing Present() operations on |scenic_session_|.
SafePresenter safe_presenter_;
fuchsia::images::ImagePipe2Ptr image_pipe_;
// Unique ids to be used as both image and uint32_t buffer collection ids.
uint32_t next_unique_id_ = 0;
// Mapping between the SysmemBufferCollectionId stored in NativePixmapHandles
// and uint32_t id registered with image pipe.
base::flat_map<zx_koid_t, uint32_t> buffer_collection_to_image_id_;
// Ordinal that will be assigned to the next frame. Ordinals are used to
// calculate frame position relative to the current frame stored in
// |presentation_state_|. They will wrap around when reaching 2^32, but the
// math used to calculate relative position will still work as expected.
uint32_t next_frame_ordinal_ = 0;
// Presentation information received from ImagePipe after rendering a frame.
// Used to calculate target presentation time for the frames presented in the
// future.
absl::optional<PresentationState> presentation_state_;
base::TimeTicks last_frame_present_time_;
base::circular_deque<PresentedFrame> pending_frames_;
std::vector<zx::event> release_fences_from_last_present_;
// Scenic resources used for the primary plane, that is not an overlay.
scenic::ShapeNode main_shape_;
scenic::Material main_material_;
gfx::SizeF main_shape_size_;
ScenicSurfaceFactory* const scenic_surface_factory_;
SysmemBufferManager* const sysmem_buffer_manager_;
const gfx::AcceleratedWidget window_;
struct OverlayViewInfo {
OverlayViewInfo(scenic::Session* scenic_session,
fuchsia::ui::views::ViewHolderToken view_holder_token);
scenic::ViewHolder view_holder;
scenic::EntityNode entity_node;
int plane_z_order = 0;
gfx::Rect display_bounds;
gfx::RectF crop_rect;
gfx::OverlayTransform plane_transform;
// Used only in `Present()` in order to update `visible`.
bool should_be_visible = false;
};
// Current set of overlays. Identified by koid of the buffer collection
// handle.
std::unordered_map<zx_koid_t, OverlayViewInfo> overlay_views_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<ScenicSurface> weak_ptr_factory_{this};
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_H_

@ -1,294 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include <lib/sys/cpp/component_context.h>
#include <lib/zx/event.h>
#include <memory>
#include "base/containers/contains.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/task/single_thread_task_runner.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "third_party/angle/src/common/fuchsia_egl/fuchsia_egl.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h"
#include "ui/ozone/platform/scenic/scenic_gpu_service.h"
#include "ui/ozone/platform/scenic/scenic_surface.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_canvas.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
#include "ui/ozone/platform/scenic/vulkan_implementation_scenic.h"
namespace ui {
namespace {
fuchsia::ui::scenic::ScenicPtr ConnectToScenic() {
fuchsia::ui::scenic::ScenicPtr scenic =
base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::ui::scenic::Scenic>();
scenic.set_error_handler(
base::LogFidlErrorAndExitProcess(FROM_HERE, "fuchsia.ui.scenic.Scenic"));
return scenic;
}
class GLOzoneEGLScenic : public GLOzoneEGL {
public:
GLOzoneEGLScenic() {}
GLOzoneEGLScenic(const GLOzoneEGLScenic&) = delete;
GLOzoneEGLScenic& operator=(const GLOzoneEGLScenic&) = delete;
~GLOzoneEGLScenic() override = default;
// GLOzone:
scoped_refptr<gl::GLSurface> CreateViewGLSurface(
gl::GLDisplay* display,
gfx::AcceleratedWidget window) override {
// GL rendering to Flatland views is not supported. This function is
// used only for unittests. Return an off-screen surface, so the tests pass.
// TODO(crbug.com/1271760): Use Vulkan in unittests and remove this hack.
return gl::InitializeGLSurface(base::MakeRefCounted<gl::SurfacelessEGL>(
display->GetAs<gl::GLDisplayEGL>(), gfx::Size(100, 100)));
}
scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface(
gl::GLDisplay* display,
const gfx::Size& size) override {
return gl::InitializeGLSurface(
base::MakeRefCounted<gl::PbufferGLSurfaceEGL>(
display->GetAs<gl::GLDisplayEGL>(), size));
}
gl::EGLDisplayPlatform GetNativeDisplay() override {
return gl::EGLDisplayPlatform(EGL_DEFAULT_DISPLAY);
}
protected:
bool LoadGLES2Bindings(
const gl::GLImplementationParts& implementation) override {
return LoadDefaultEGLGLES2Bindings(implementation);
}
};
fuchsia::sysmem::AllocatorHandle ConnectSysmemAllocator() {
fuchsia::sysmem::AllocatorHandle allocator;
base::ComponentContextForProcess()->svc()->Connect(allocator.NewRequest());
return allocator;
}
} // namespace
ScenicSurfaceFactory::ScenicSurfaceFactory()
: egl_implementation_(std::make_unique<GLOzoneEGLScenic>()),
sysmem_buffer_manager_(this),
weak_ptr_factory_(this) {}
ScenicSurfaceFactory::~ScenicSurfaceFactory() {
Shutdown();
}
void ScenicSurfaceFactory::Initialize(
mojo::PendingRemote<mojom::ScenicGpuHost> gpu_host) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::AutoLock lock(surface_lock_);
DCHECK(surface_map_.empty());
main_thread_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
DCHECK(main_thread_task_runner_);
DCHECK(!gpu_host_);
gpu_host_.Bind(std::move(gpu_host));
sysmem_buffer_manager_.Initialize(ConnectSysmemAllocator());
// Scenic is lazily connected to avoid a dependency in headless mode.
DCHECK(!scenic_);
}
void ScenicSurfaceFactory::Shutdown() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::AutoLock lock(surface_lock_);
DCHECK(surface_map_.empty());
main_thread_task_runner_ = nullptr;
gpu_host_.reset();
sysmem_buffer_manager_.Shutdown();
scenic_ = nullptr;
}
std::vector<gl::GLImplementationParts>
ScenicSurfaceFactory::GetAllowedGLImplementations() {
return std::vector<gl::GLImplementationParts>{
gl::GLImplementationParts(gl::kGLImplementationEGLANGLE),
gl::GLImplementationParts(gl::kGLImplementationEGLGLES2),
gl::GLImplementationParts(gl::kGLImplementationStubGL),
};
}
GLOzone* ScenicSurfaceFactory::GetGLOzone(
const gl::GLImplementationParts& implementation) {
switch (implementation.gl) {
case gl::kGLImplementationEGLGLES2:
case gl::kGLImplementationEGLANGLE:
return egl_implementation_.get();
default:
return nullptr;
}
}
std::unique_ptr<PlatformWindowSurface>
ScenicSurfaceFactory::CreatePlatformWindowSurface(
gfx::AcceleratedWidget window) {
DCHECK_NE(window, gfx::kNullAcceleratedWidget);
auto surface = std::make_unique<ScenicSurface>(this, &sysmem_buffer_manager_,
window, CreateScenicSession());
main_thread_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ScenicSurfaceFactory::AttachSurfaceToWindow,
weak_ptr_factory_.GetWeakPtr(), window,
surface->CreateView()));
return surface;
}
std::unique_ptr<SurfaceOzoneCanvas> ScenicSurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget) {
ScenicSurface* surface = GetSurface(widget);
return std::make_unique<ScenicWindowCanvas>(surface);
}
scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
gfx::AcceleratedWidget widget,
gpu::VulkanDeviceQueue* device_queue,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
absl::optional<gfx::Size> framebuffer_size) {
DCHECK(!framebuffer_size || framebuffer_size == size);
VkDevice vk_device = device_queue->GetVulkanDevice();
if (widget != gfx::kNullAcceleratedWidget &&
usage == gfx::BufferUsage::SCANOUT) {
// The usage SCANOUT is for a primary plane buffer.
auto* surface = GetSurface(widget);
CHECK(surface);
return surface->AllocatePrimaryPlanePixmap(vk_device, size, format);
}
return sysmem_buffer_manager_.CreateNativePixmap(vk_device, size, format,
usage);
}
void ScenicSurfaceFactory::CreateNativePixmapAsync(
gfx::AcceleratedWidget widget,
gpu::VulkanDeviceQueue* device_queue,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
NativePixmapCallback callback) {
std::move(callback).Run(
CreateNativePixmap(widget, device_queue, size, format, usage));
}
scoped_refptr<gfx::NativePixmap>
ScenicSurfaceFactory::CreateNativePixmapFromHandle(
gfx::AcceleratedWidget widget,
gfx::Size size,
gfx::BufferFormat format,
gfx::NativePixmapHandle handle) {
auto collection = sysmem_buffer_manager_.GetCollectionByHandle(
handle.buffer_collection_handle);
if (!collection)
return nullptr;
return collection->CreateNativePixmap(std::move(handle), size);
}
std::unique_ptr<gpu::VulkanImplementation>
ScenicSurfaceFactory::CreateVulkanImplementation(bool use_swiftshader,
bool allow_protected_memory) {
return std::make_unique<ui::VulkanImplementationScenic>(
this, &sysmem_buffer_manager_, use_swiftshader, allow_protected_memory);
}
std::vector<gfx::BufferFormat>
ScenicSurfaceFactory::GetSupportedFormatsForTexturing() const {
return {
gfx::BufferFormat::R_8,
gfx::BufferFormat::RG_88,
gfx::BufferFormat::RGBA_8888,
gfx::BufferFormat::RGBX_8888,
gfx::BufferFormat::BGRA_8888,
gfx::BufferFormat::BGRX_8888,
gfx::BufferFormat::YUV_420_BIPLANAR,
};
}
void ScenicSurfaceFactory::AddSurface(gfx::AcceleratedWidget widget,
ScenicSurface* surface) {
base::AutoLock lock(surface_lock_);
DCHECK(!base::Contains(surface_map_, widget));
surface->AssertBelongsToCurrentThread();
surface_map_.emplace(widget, surface);
}
void ScenicSurfaceFactory::RemoveSurface(gfx::AcceleratedWidget widget) {
base::AutoLock lock(surface_lock_);
auto it = surface_map_.find(widget);
DCHECK(it != surface_map_.end());
ScenicSurface* surface = it->second;
surface->AssertBelongsToCurrentThread();
surface_map_.erase(it);
}
ScenicSurface* ScenicSurfaceFactory::GetSurface(gfx::AcceleratedWidget widget) {
base::AutoLock lock(surface_lock_);
auto it = surface_map_.find(widget);
if (it == surface_map_.end())
return nullptr;
ScenicSurface* surface = it->second;
surface->AssertBelongsToCurrentThread();
return surface;
}
scenic::SessionPtrAndListenerRequest
ScenicSurfaceFactory::CreateScenicSession() {
fuchsia::ui::scenic::SessionPtr session;
fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener_handle;
auto listener_request = listener_handle.NewRequest();
{
// Cache Scenic connection for main thread. For other treads create
// one-shot connection.
fuchsia::ui::scenic::ScenicPtr local_scenic;
fuchsia::ui::scenic::ScenicPtr* scenic =
main_thread_task_runner_->BelongsToCurrentThread() ? &scenic_
: &local_scenic;
if (!*scenic)
*scenic = ConnectToScenic();
(*scenic)->CreateSession(session.NewRequest(), std::move(listener_handle));
}
return {std::move(session), std::move(listener_request)};
}
void ScenicSurfaceFactory::AttachSurfaceToWindow(
gfx::AcceleratedWidget window,
mojo::PlatformHandle surface_view_holder_token_mojo) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
gpu_host_->AttachSurfaceToWindow(window,
std::move(surface_view_holder_token_mojo));
}
} // namespace ui

@ -1,125 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_FACTORY_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_FACTORY_H_
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/ui/scenic/cpp/session.h>
#include <memory>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/task/single_thread_task_runner.h"
#include "base/thread_annotations.h"
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/handle.h"
#include "ui/ozone/platform/scenic/mojom/scenic_gpu_host.mojom.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_manager.h"
#include "ui/ozone/public/gl_ozone.h"
#include "ui/ozone/public/surface_factory_ozone.h"
namespace ui {
class ScenicSurface;
class ScenicSurfaceFactory : public SurfaceFactoryOzone {
public:
ScenicSurfaceFactory();
ScenicSurfaceFactory(const ScenicSurfaceFactory&) = delete;
ScenicSurfaceFactory& operator=(const ScenicSurfaceFactory&) = delete;
~ScenicSurfaceFactory() override;
// Initializes the surface factory. Binds the surface factory to the
// current thread (and thus must run with a message loop).
void Initialize(mojo::PendingRemote<mojom::ScenicGpuHost> gpu_host);
// Disconnects from ScenicGpuHost and detaches from the current thread.
// After shutting down, it is safe to call Initialize() again.
void Shutdown();
// SurfaceFactoryOzone implementation.
std::vector<gl::GLImplementationParts> GetAllowedGLImplementations() override;
GLOzone* GetGLOzone(const gl::GLImplementationParts& implementation) override;
std::unique_ptr<PlatformWindowSurface> CreatePlatformWindowSurface(
gfx::AcceleratedWidget widget) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
gpu::VulkanDeviceQueue* device_queue,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
absl::optional<gfx::Size> framebuffer_size = absl::nullopt) override;
void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
gpu::VulkanDeviceQueue* device_queue,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
NativePixmapCallback callback) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
gfx::AcceleratedWidget widget,
gfx::Size size,
gfx::BufferFormat format,
gfx::NativePixmapHandle handle) override;
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
bool use_swiftshader,
bool allow_protected_memory) override;
std::vector<gfx::BufferFormat> GetSupportedFormatsForTexturing()
const override;
// Registers a surface for a |widget|.
//
// Must be called on the thread that owns the surface.
void AddSurface(gfx::AcceleratedWidget widget, ScenicSurface* surface)
LOCKS_EXCLUDED(surface_lock_);
// Removes a surface for a |widget|.
//
// Must be called on the thread that owns the surface.
void RemoveSurface(gfx::AcceleratedWidget widget)
LOCKS_EXCLUDED(surface_lock_);
// Returns the surface for a |widget|.
//
// Must be called on the thread that owns the surface.
ScenicSurface* GetSurface(gfx::AcceleratedWidget widget)
LOCKS_EXCLUDED(surface_lock_);
// Creates a new scenic session on any thread.
scenic::SessionPtrAndListenerRequest CreateScenicSession();
private:
// Links a surface to its parent window in the host process.
void AttachSurfaceToWindow(
gfx::AcceleratedWidget window,
mojo::PlatformHandle surface_view_holder_token_mojo);
base::flat_map<gfx::AcceleratedWidget, ScenicSurface*> surface_map_
GUARDED_BY(surface_lock_);
base::Lock surface_lock_;
mojo::Remote<mojom::ScenicGpuHost> gpu_host_;
std::unique_ptr<GLOzone> egl_implementation_;
fuchsia::ui::scenic::ScenicPtr scenic_;
// Task runner for thread that |scenic_| and |gpu_host_| are bound on.
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
SysmemBufferManager sysmem_buffer_manager_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<ScenicSurfaceFactory> weak_ptr_factory_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_FACTORY_H_

@ -1,495 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_window.h"
#include <fidl/fuchsia.ui.pointer/cpp/hlcpp_conversion.h>
#include <fidl/fuchsia.ui.views/cpp/hlcpp_conversion.h>
#include <lib/async/default.h>
#include <lib/sys/cpp/component_context.h>
#include <algorithm>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/fuchsia/fuchsia_component_connect.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/memory/scoped_refptr.h"
#include "ui/base/cursor/platform_cursor.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
#include "ui/platform_window/fuchsia/scenic_window_delegate.h"
namespace ui {
namespace {
// Converts Scenic's rect-based representation of insets to gfx::Insets.
// Returns zero-width insets if |inset_from_min| and |inset_from_max| are
// uninitialized (indicating that no insets were provided from Scenic).
gfx::Insets ConvertInsets(
float device_pixel_ratio,
const fuchsia::ui::gfx::ViewProperties& view_properties) {
return gfx::Insets::TLBR(
device_pixel_ratio * view_properties.inset_from_min.y,
device_pixel_ratio * view_properties.inset_from_min.x,
device_pixel_ratio * view_properties.inset_from_max.y,
device_pixel_ratio * view_properties.inset_from_max.x);
}
} // namespace
ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties)
: manager_(window_manager),
delegate_(delegate),
scenic_window_delegate_(properties.scenic_window_delegate),
window_id_(manager_->AddWindow(this)),
view_ref_(std::move(properties.view_ref_pair.view_ref)),
view_controller_(std::move(properties.view_controller)),
bounds_(delegate_->ConvertRectToPixels(properties.bounds)) {
{
// Send graphics and input endpoints to Scenic. The endpoints are dormant
// until the Session's Present call, at the bottom of this block.
fuchsia::ui::scenic::SessionEndpoints endpoints;
fuchsia::ui::scenic::SessionPtr session_ptr;
endpoints.set_session(session_ptr.NewRequest());
fuchsia::ui::scenic::SessionListenerHandle listener_handle;
auto listener_request = listener_handle.NewRequest();
endpoints.set_session_listener(std::move(listener_handle));
auto touch_source_endpoints =
fidl::CreateEndpoints<fuchsia_ui_pointer::TouchSource>();
ZX_CHECK(touch_source_endpoints.is_ok(),
touch_source_endpoints.status_value());
endpoints.set_touch_source(
fidl::NaturalToHLCPP(std::move(touch_source_endpoints->server)));
auto mouse_source_endpoints =
fidl::CreateEndpoints<fuchsia_ui_pointer::MouseSource>();
ZX_CHECK(mouse_source_endpoints.is_ok(),
mouse_source_endpoints.status_value());
endpoints.set_mouse_source(
fidl::NaturalToHLCPP(std::move(mouse_source_endpoints->server)));
endpoints.set_view_ref_focused(view_ref_focused_.NewRequest());
manager_->GetScenic()->CreateSessionT(std::move(endpoints), [] {});
// Set up pointer and focus event processors.
pointer_handler_.emplace(std::move(touch_source_endpoints->client),
std::move(mouse_source_endpoints->client));
pointer_handler_->StartWatching(base::BindRepeating(
&ScenicWindow::DispatchEvent,
// This is safe since |pointer_handler_| is a class member.
base::Unretained(this)));
view_ref_focused_->Watch(
fit::bind_member(this, &ScenicWindow::OnViewRefFocusedWatchResult));
view_ref_focused_.set_error_handler([](zx_status_t status) {
ZX_LOG(ERROR, status) << "Focus listener disconnected.";
});
// Set up GFX Session and scene resources.
scenic_session_.emplace(std::move(session_ptr),
std::move(listener_request));
scenic_session_->set_error_handler(
fit::bind_member(this, &ScenicWindow::OnScenicError));
scenic_session_->set_event_handler(
fit::bind_member(this, &ScenicWindow::OnScenicEvents));
scenic_session_->SetDebugName("Chromium ScenicWindow");
view_.emplace(&scenic_session_.value(), std::move(properties.view_token),
std::move(properties.view_ref_pair.control_ref),
CloneViewRef(), "chromium window");
node_.emplace(&scenic_session_.value());
// Subscribe to metrics events from the node. Metrics events provide the
// device pixel ratio for the screen.
node_->SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
// To receive metrics events on this node, attach it to the scene graph.
view_->AddChild(*node_);
input_node_.emplace(&scenic_session_.value());
render_node_.emplace(&scenic_session_.value());
safe_presenter_.emplace(&scenic_session_.value());
safe_presenter_->QueuePresent();
}
if (view_controller_) {
view_controller_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnViewControllerDisconnected));
}
delegate_->OnAcceleratedWidgetAvailable(window_id_);
if (properties.enable_keyboard) {
is_virtual_keyboard_enabled_ = properties.enable_virtual_keyboard;
auto keyboard_client_end =
base::fuchsia_component::Connect<fuchsia_ui_input3::Keyboard>();
CHECK(keyboard_client_end.is_ok())
<< base::FidlConnectionErrorMessage(keyboard_client_end);
keyboard_fidl_client_.Bind(std::move(keyboard_client_end.value()),
async_get_default_dispatcher(),
&fidl_error_event_logger_);
keyboard_client_ = std::make_unique<KeyboardClient>(
keyboard_fidl_client_, fidl::HLCPPToNatural(CloneViewRef()), this);
} else {
DCHECK(!properties.enable_virtual_keyboard);
}
}
ScenicWindow::~ScenicWindow() {
manager_->RemoveWindow(window_id_, this);
}
fuchsia::ui::views::ViewRef ScenicWindow::CloneViewRef() {
fuchsia::ui::views::ViewRef dup;
zx_status_t status =
view_ref_.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
return dup;
}
gfx::Rect ScenicWindow::GetBoundsInPixels() const {
return bounds_;
}
void ScenicWindow::SetBoundsInPixels(const gfx::Rect& bounds) {
// This path should only be reached in tests.
bounds_ = bounds;
}
gfx::Rect ScenicWindow::GetBoundsInDIP() const {
return delegate_->ConvertRectToDIP(bounds_);
}
void ScenicWindow::SetBoundsInDIP(const gfx::Rect& bounds) {
// This path should only be reached in tests.
bounds_ = delegate_->ConvertRectToPixels(bounds);
}
void ScenicWindow::SetTitle(const std::u16string& title) {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::Show(bool inactive) {
if (is_visible_)
return;
is_visible_ = true;
UpdateRootNodeVisibility();
// Call Present2() to ensure that the scenic session commands are processed,
// which is necessary to receive metrics event from Scenic.
safe_presenter_->QueuePresent();
}
void ScenicWindow::Hide() {
if (!is_visible_)
return;
is_visible_ = false;
UpdateRootNodeVisibility();
}
void ScenicWindow::Close() {
if (view_controller_) {
view_controller_->Dismiss();
view_controller_ = nullptr;
}
Hide();
delegate_->OnClosed();
}
bool ScenicWindow::IsVisible() const {
return is_visible_;
}
void ScenicWindow::PrepareForShutdown() {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::SetCapture() {
// TODO(crbug.com/1231516): Use Scenic capture APIs.
NOTIMPLEMENTED_LOG_ONCE();
has_capture_ = true;
}
void ScenicWindow::ReleaseCapture() {
// TODO(crbug.com/1231516): Use Scenic capture APIs.
NOTIMPLEMENTED_LOG_ONCE();
has_capture_ = false;
}
bool ScenicWindow::HasCapture() const {
// TODO(crbug.com/1231516): Use Scenic capture APIs.
NOTIMPLEMENTED_LOG_ONCE();
return has_capture_;
}
void ScenicWindow::SetFullscreen(bool fullscreen, int64_t target_display_id) {
NOTIMPLEMENTED_LOG_ONCE();
DCHECK_EQ(target_display_id, display::kInvalidDisplayId);
is_fullscreen_ = fullscreen;
}
void ScenicWindow::Maximize() {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::Minimize() {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::Restore() {
NOTIMPLEMENTED_LOG_ONCE();
}
PlatformWindowState ScenicWindow::GetPlatformWindowState() const {
if (is_fullscreen_)
return PlatformWindowState::kFullScreen;
if (!is_view_attached_)
return PlatformWindowState::kMinimized;
// TODO(crbug.com/1241868): We cannot tell what portion of the screen is
// occupied by the View, so report is as maximized to reduce the space used
// by any browser chrome.
return PlatformWindowState::kMaximized;
}
void ScenicWindow::Activate() {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::Deactivate() {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::SetUseNativeFrame(bool use_native_frame) {}
bool ScenicWindow::ShouldUseNativeFrame() const {
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
void ScenicWindow::SetCursor(scoped_refptr<PlatformCursor> cursor) {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::MoveCursorTo(const gfx::Point& location) {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::SetRestoredBoundsInDIP(const gfx::Rect& bounds) {
NOTIMPLEMENTED_LOG_ONCE();
}
gfx::Rect ScenicWindow::GetRestoredBoundsInDIP() const {
NOTIMPLEMENTED_LOG_ONCE();
return gfx::Rect();
}
void ScenicWindow::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::SizeConstraintsChanged() {
NOTIMPLEMENTED_LOG_ONCE();
}
void ScenicWindow::AttachSurfaceView(
fuchsia::ui::views::ViewHolderToken token) {
surface_view_holder_ = std::make_unique<scenic::ViewHolder>(
&scenic_session_.value(), std::move(token), "chromium window surface");
// Configure the ViewHolder not to be focusable, or hit-testable, to ensure
// that it cannot receive input.
fuchsia::ui::gfx::ViewProperties view_properties;
view_properties.bounding_box = {{-0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, 0.5f}};
view_properties.focus_change = false;
surface_view_holder_->SetViewProperties(std::move(view_properties));
surface_view_holder_->SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior::kSuppress);
render_node_->DetachChildren();
render_node_->AddChild(*surface_view_holder_);
safe_presenter_->QueuePresent();
}
void ScenicWindow::DispatchEvent(ui::Event* event) {
if (event->IsLocatedEvent()) {
ui::LocatedEvent* located_event = event->AsLocatedEvent();
gfx::PointF location = located_event->location_f();
location.Scale(device_pixel_ratio_);
located_event->set_location_f(location);
}
delegate_->DispatchEvent(event);
}
void ScenicWindow::OnScenicError(zx_status_t status) {
LOG(ERROR) << "scenic::Session failed with code " << status << ".";
delegate_->OnCloseRequest();
}
void ScenicWindow::OnScenicEvents(
std::vector<fuchsia::ui::scenic::Event> events) {
for (const auto& event : events) {
if (event.is_gfx()) {
switch (event.gfx().Which()) {
case fuchsia::ui::gfx::Event::kMetrics: {
if (event.gfx().metrics().node_id != node_->id())
continue;
OnViewMetrics(event.gfx().metrics().metrics);
break;
}
case fuchsia::ui::gfx::Event::kViewPropertiesChanged: {
DCHECK(event.gfx().view_properties_changed().view_id == view_->id());
OnViewProperties(event.gfx().view_properties_changed().properties);
break;
}
case fuchsia::ui::gfx::Event::kViewAttachedToScene: {
DCHECK(event.gfx().view_attached_to_scene().view_id == view_->id());
OnViewAttachedChanged(true);
break;
}
case fuchsia::ui::gfx::Event::kViewDetachedFromScene: {
DCHECK(event.gfx().view_detached_from_scene().view_id == view_->id());
OnViewAttachedChanged(false);
// Detach the surface view. This is necessary to ensure that the
// current content doesn't become visible when the view is attached
// again.
render_node_->DetachChildren();
surface_view_holder_.reset();
safe_presenter_->QueuePresent();
// Destroy and recreate AcceleratedWidget. This will force the
// compositor drop the current LayerTreeFrameSink together with the
// corresponding ScenicSurface. They will be created again only after
// the window becomes visible again.
delegate_->OnAcceleratedWidgetDestroyed();
delegate_->OnAcceleratedWidgetAvailable(window_id_);
break;
}
default:
break;
}
}
}
}
void ScenicWindow::OnViewAttachedChanged(bool is_view_attached) {
PlatformWindowState old_state = GetPlatformWindowState();
is_view_attached_ = is_view_attached;
PlatformWindowState new_state = GetPlatformWindowState();
if (old_state != new_state) {
delegate_->OnWindowStateChanged(old_state, new_state);
}
}
void ScenicWindow::OnViewMetrics(const fuchsia::ui::gfx::Metrics& metrics) {
device_pixel_ratio_ = std::max(metrics.scale_x, metrics.scale_y);
if (scenic_window_delegate_)
scenic_window_delegate_->OnScenicPixelScale(this, device_pixel_ratio_);
if (view_properties_)
UpdateSize();
}
void ScenicWindow::OnViewProperties(
const fuchsia::ui::gfx::ViewProperties& properties) {
view_properties_ = properties;
if (device_pixel_ratio_ > 0.0)
UpdateSize();
}
void ScenicWindow::OnViewRefFocusedWatchResult(
fuchsia::ui::views::FocusState focus_state) {
delegate_->OnActivationChanged(focus_state.focused());
view_ref_focused_->Watch(
fit::bind_member(this, &ScenicWindow::OnViewRefFocusedWatchResult));
}
void ScenicWindow::UpdateSize() {
DCHECK_GT(device_pixel_ratio_, 0.0);
DCHECK(view_properties_);
const float width = view_properties_->bounding_box.max.x -
view_properties_->bounding_box.min.x;
const float height = view_properties_->bounding_box.max.y -
view_properties_->bounding_box.min.y;
const gfx::Point old_origin = bounds_.origin();
bounds_ = gfx::Rect(ceilf(width * device_pixel_ratio_),
ceilf(height * device_pixel_ratio_));
// Update the root node to be shown, or hidden, based on the View state.
// If the root node is not visible then skip resizing content, etc.
if (!UpdateRootNodeVisibility())
return;
// Translate the node by half of the view dimensions to put it in the center
// of the view.
node_->SetTranslation(width / 2.0, height / 2.0, 0.f);
// Scale the render node so that surface rect can always be 1x1.
render_node_->SetScale(width, height, 1.f);
// Resize input node to cover the whole surface.
scenic::Rectangle window_rect(&scenic_session_.value(), width, height);
input_node_->SetShape(window_rect);
// This is necessary when using vulkan because ImagePipes are presented
// separately and we need to make sure our sizes change is committed.
safe_presenter_->QueuePresent();
PlatformWindowDelegate::BoundsChange bounds(old_origin != bounds_.origin());
bounds.system_ui_overlap =
ConvertInsets(device_pixel_ratio_, *view_properties_);
delegate_->OnBoundsChanged(bounds);
}
bool ScenicWindow::UpdateRootNodeVisibility() {
bool should_show_root_node = is_visible_ && !is_zero_sized();
if (should_show_root_node != is_root_node_shown_) {
is_root_node_shown_ = should_show_root_node;
if (should_show_root_node) {
// Attach nodes to render content and receive input.
node_->AddChild(*input_node_);
node_->AddChild(*render_node_);
} else {
node_->DetachChildren();
}
}
return is_root_node_shown_;
}
void ScenicWindow::OnViewControllerDisconnected(zx_status_t status) {
view_controller_ = nullptr;
delegate_->OnCloseRequest();
}
} // namespace ui

@ -1,227 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
#include <fidl/fuchsia.ui.input3/cpp/fidl.h>
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/input/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <memory>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/fuchsia/fidl_event_handler.h"
#include "ui/base/ime/fuchsia/keyboard_client.h"
#include "ui/events/fuchsia/input_event_sink.h"
#include "ui/events/fuchsia/pointer_events_handler.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/scenic/safe_presenter.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
class ScenicWindowDelegate;
class ScenicWindowManager;
class COMPONENT_EXPORT(OZONE) ScenicWindow final : public PlatformWindow,
public InputEventSink {
public:
// Both |window_manager| and |delegate| must outlive the ScenicWindow.
// |view_token| is passed to Scenic to attach the view to the view tree.
// |view_ref_pair| will be associated with this window's View, and used to
// identify it when calling out to other services (e.g. the SemanticsManager).
ScenicWindow(ScenicWindowManager* window_manager,
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties);
~ScenicWindow() override;
ScenicWindow(const ScenicWindow&) = delete;
ScenicWindow& operator=(const ScenicWindow&) = delete;
// Returns a ViewRef that may be used to refer to this window's View, when
// interacting with View-based services such as the SemanticsManager.
fuchsia::ui::views::ViewRef CloneViewRef();
// ui::PlatformWindow implementation.
gfx::Rect GetBoundsInPixels() const override;
void SetBoundsInPixels(const gfx::Rect& bounds) override;
gfx::Rect GetBoundsInDIP() const override;
void SetBoundsInDIP(const gfx::Rect& bounds) override;
void SetTitle(const std::u16string& title) override;
void Show(bool inactive) override;
void Hide() override;
void Close() override;
bool IsVisible() const override;
void PrepareForShutdown() override;
void SetCapture() override;
void ReleaseCapture() override;
bool HasCapture() const override;
void SetFullscreen(bool fullscreen, int64_t target_display_id) override;
void Maximize() override;
void Minimize() override;
void Restore() override;
PlatformWindowState GetPlatformWindowState() const override;
void Activate() override;
void Deactivate() override;
void SetUseNativeFrame(bool use_native_frame) override;
bool ShouldUseNativeFrame() const override;
void SetCursor(scoped_refptr<PlatformCursor> cursor) override;
void MoveCursorTo(const gfx::Point& location) override;
void ConfineCursorToBounds(const gfx::Rect& bounds) override;
void SetRestoredBoundsInDIP(const gfx::Rect& bounds) override;
gfx::Rect GetRestoredBoundsInDIP() const override;
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
void SizeConstraintsChanged() override;
// Used by ScenicGpuHost to embed the View identified by |token| into the
// render node, causing its contents to be displayed in this window.
void AttachSurfaceView(fuchsia::ui::views::ViewHolderToken token);
// Used by OzoneScenicPlatform to determine whether to enable on-screen
// keyboard features when creating the InputMethod for the window.
bool is_virtual_keyboard_enabled() const {
return is_virtual_keyboard_enabled_;
}
private:
// ui::InputEventSink implementation, used to scale input event locations
// according to the View's current device pixel ratio.
void DispatchEvent(ui::Event* event) override;
// Callbacks for |scenic_session_|.
void OnScenicError(zx_status_t status);
void OnScenicEvents(std::vector<fuchsia::ui::scenic::Event> events);
// Called from OnScenicEvents() to handle view properties and metrics changes.
void OnViewAttachedChanged(bool is_view_attached);
void OnViewMetrics(const fuchsia::ui::gfx::Metrics& metrics);
void OnViewProperties(const fuchsia::ui::gfx::ViewProperties& properties);
// Called from OnScenicEvents() to handle focus change and input events.
void OnInputEvent(const fuchsia::ui::input::InputEvent& event);
// Hanging gets from |view_ref_focused_|.
void OnViewRefFocusedWatchResult(fuchsia::ui::views::FocusState focus_state);
// Sizes the Scenic nodes based on the View dimensions, and device pixel
// ratio, and signals the dimensions change to the window delegate.
void UpdateSize();
// Attaches or detaches the root node to match the visibility and dimensions
// of the window's View. Returns true if the root node is currently visible.
bool UpdateRootNodeVisibility();
// Returns true if the View has zero-sized dimensions set.
bool is_zero_sized() const {
return view_properties_ && ((view_properties_->bounding_box.max.x ==
view_properties_->bounding_box.min.x) ||
(view_properties_->bounding_box.max.y ==
view_properties_->bounding_box.min.y));
}
void OnViewControllerDisconnected(zx_status_t status);
ScenicWindowManager* const manager_;
PlatformWindowDelegate* const delegate_;
ScenicWindowDelegate* const scenic_window_delegate_;
gfx::AcceleratedWidget const window_id_;
// Handle to a kernel object which identifies this window's View
// across the system. ViewRef consumers can access the handle by
// calling CloneViewRef().
const fuchsia::ui::views::ViewRef view_ref_;
// Used to coordinate window closure requests with the shell.
fuchsia::element::ViewControllerPtr view_controller_;
fidl::Client<fuchsia_ui_input3::Keyboard> keyboard_fidl_client_;
base::FidlErrorEventLogger<fuchsia_ui_input3::Keyboard>
fidl_error_event_logger_;
std::unique_ptr<KeyboardClient> keyboard_client_;
// React to view-focus coming and going.
fuchsia::ui::views::ViewRefFocusedPtr view_ref_focused_;
// Accept touch and mouse events.
absl::optional<PointerEventsHandler> pointer_handler_;
// Scenic session used for all drawing operations in this View.
absl::optional<scenic::Session> scenic_session_;
// Used for safely queueing Present() operations on |scenic_session_|.
absl::optional<SafePresenter> safe_presenter_;
// The view resource in |scenic_session_|.
absl::optional<scenic::View> view_;
// Entity node for the |view_|.
absl::optional<scenic::EntityNode> node_;
// Node in |scenic_session_| for receiving input that hits within our View.
absl::optional<scenic::ShapeNode> input_node_;
// Node in |scenic_session_| for rendering (hit testing disabled).
absl::optional<scenic::EntityNode> render_node_;
// Holds the View into which the GPU processes composites the window's
// contents.
std::unique_ptr<scenic::ViewHolder> surface_view_holder_;
// The scale between logical pixels and physical pixels, set based on the
// fuchsia::ui::gfx::Metrics event. It's used to calculate dimensions of the
// view in physical pixels in UpdateSize(). This value doesn't affect the
// device_scale_factor reported by ScenicScreen for the corresponding display
// (currently always 1.0, see crbug.com/1215330).
float device_pixel_ratio_ = 0.f;
// Current view size in DIPs.
gfx::SizeF size_dips_;
// Current view size in device pixels. The size is set to
// |PlatformWindowInitProperties.bounds.size()| value until Show() is called
// for the first time. After that the size is set to the size of the
// corresponding Scenic view.
gfx::Rect bounds_;
// Holds the contents of the fuchsia.ui.gfx.Event.view_properties_changed
// most recently received for the View, if any.
absl::optional<fuchsia::ui::gfx::ViewProperties> view_properties_;
// False if the View for this window is detached from the View tree, in which
// case it is definitely not visible.
bool is_visible_ = false;
// True if the View occupies the full screen.
bool is_fullscreen_ = false;
// True if the on-screen virtual keyboard is available for this window.
bool is_virtual_keyboard_enabled_ = false;
// True if the root node is attached to the View, to be rendered.
bool is_root_node_shown_ = false;
// True if |view_| is currently attached to a scene.
bool is_view_attached_ = false;
// True if SetCapture() was called. Currently does not reflect capture state
// in Scenic.
// TODO(crbug.com/1231516): Use Scenic capture APIs.
bool has_capture_ = false;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_

@ -1,182 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_window_canvas.h"
#include <memory>
#include "base/fuchsia/fuchsia_logging.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/writable_shared_memory_region.h"
#include "skia/ext/legacy_display_globals.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
namespace ui {
// How long we want to wait for release-fence from scenic for previous frames.
constexpr base::TimeDelta kFrameReleaseTimeout = base::Milliseconds(500);
ScenicWindowCanvas::Frame::Frame() = default;
ScenicWindowCanvas::Frame::~Frame() = default;
void ScenicWindowCanvas::Frame::Initialize(gfx::Size size,
scenic::Session* scenic) {
size_t bytes_per_row =
size.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
size_t buffer_size = bytes_per_row * size.height();
base::WritableSharedMemoryRegion memory_region =
base::WritableSharedMemoryRegion::Create(buffer_size);
memory_mapping = memory_region.Map();
if (!memory_mapping.IsValid()) {
LOG(WARNING) << "Failed to map memory for ScenicWindowCanvas.";
memory_mapping = base::WritableSharedMemoryMapping();
surface.reset();
return;
}
auto read_only_memory = base::WritableSharedMemoryRegion::ConvertToReadOnly(
std::move(memory_region));
auto memory_handle =
base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
std::move(read_only_memory));
scenic_memory = std::make_unique<scenic::Memory>(
scenic, memory_handle.PassPlatformHandle(), buffer_size,
fuchsia::images::MemoryType::HOST_MEMORY);
SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
surface = SkSurfaces::WrapPixels(
SkImageInfo::MakeN32Premul(size.width(), size.height()),
memory_mapping.memory(), bytes_per_row, &props);
dirty_region.setRect(gfx::RectToSkIRect(gfx::Rect(size)));
}
void ScenicWindowCanvas::Frame::CopyDirtyRegionFrom(const Frame& frame) {
int stride = surface->width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
for (SkRegion::Iterator i(dirty_region); !i.done(); i.next()) {
uint8_t* dst_ptr =
static_cast<uint8_t*>(memory_mapping.memory()) +
i.rect().x() * SkColorTypeBytesPerPixel(kN32_SkColorType) +
i.rect().y() * stride;
frame.surface->readPixels(
SkImageInfo::MakeN32Premul(i.rect().width(), i.rect().height()),
dst_ptr, stride, i.rect().x(), i.rect().y());
}
dirty_region.setEmpty();
}
ScenicWindowCanvas::ScenicWindowCanvas(ScenicSurface* scenic_surface)
: scenic_surface_(scenic_surface) {}
ScenicWindowCanvas::~ScenicWindowCanvas() = default;
void ScenicWindowCanvas::ResizeCanvas(const gfx::Size& viewport_size,
float scale) {
viewport_size_ = viewport_size;
viewport_size_.SetToMax(gfx::Size(1, 1));
// Allocate new buffers with the new size.
for (int i = 0; i < kNumBuffers; ++i) {
frames_[i].Initialize(viewport_size_, scenic_surface_->scenic_session());
}
}
SkCanvas* ScenicWindowCanvas::GetCanvas() {
if (viewport_size_.IsEmpty() || frames_[current_frame_].is_empty())
return nullptr;
// Wait for the buffer to become available. This call has to be blocking
// because GetSurface() and PresentCanvas() are synchronous.
//
// TODO(sergeyu): Consider updating SurfaceOzoneCanvas interface to allow
// asynchronous PresentCanvas() and then wait for release-fence before
// PresentCanvas() completes.
if (frames_[current_frame_].release_fence) {
auto status = frames_[current_frame_].release_fence.wait_one(
ZX_EVENT_SIGNALED,
zx::deadline_after(zx::duration(kFrameReleaseTimeout.InNanoseconds())),
nullptr);
if (status == ZX_ERR_TIMED_OUT) {
// Timeout here indicates that Scenic is most likely broken. If it still
// works, then in the worst case returning before |release_fence| is
// signaled will cause screen tearing.
LOG(WARNING) << "Release fence from previous frame timed out after 500ms";
} else {
ZX_CHECK(status == ZX_OK, status);
}
}
return frames_[current_frame_].surface->getCanvas();
}
void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) {
// Subtract |damage| from the dirty region in the current frame since it's
// been repainted.
SkIRect sk_damage = gfx::RectToSkIRect(damage);
frames_[current_frame_].dirty_region.op(sk_damage, SkRegion::kDifference_Op);
// Copy dirty region from the previous buffer to make sure the whole frame
// is up to date.
int prev_frame =
current_frame_ == 0 ? (kNumBuffers - 1) : (current_frame_ - 1);
frames_[current_frame_].CopyDirtyRegionFrom(frames_[prev_frame]);
// |damage| rect was updated in the current frame. It means that the rect is
// no longer valid in all other buffers. Add |damage| to |dirty_region| in all
// buffers except the current one.
for (int i = 0; i < kNumBuffers; ++i) {
if (i != current_frame_) {
frames_[i].dirty_region.op(sk_damage, SkRegion::kUnion_Op);
}
}
// Create image that wraps the buffer and attach it as texture for the node.
fuchsia::images::ImageInfo info;
info.width = viewport_size_.width();
info.height = viewport_size_.height();
info.stride =
viewport_size_.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
scenic::Image image(*frames_[current_frame_].scenic_memory, 0,
std::move(info));
// TODO(spang): Consider using ImagePipe for consistency with vulkan path.
scenic_surface_->SetTextureToImage(image);
// Create release fence for the current buffer or reset it if it already
// exists.
if (!frames_[current_frame_].release_fence) {
auto status = zx::event::create(
/*options=*/0u, &(frames_[current_frame_].release_fence));
ZX_CHECK(status == ZX_OK, status);
} else {
auto status = frames_[current_frame_].release_fence.signal(
/*clear_mask=*/ZX_EVENT_SIGNALED, /*set_maks=*/0);
ZX_CHECK(status == ZX_OK, status);
}
// Add release-fence for the Present2() call below. The fence is used in
// GetCanvas() to ensure that we reuse the buffer only after it's released
// from scenic.
zx::event release_fence_dup;
auto status = frames_[current_frame_].release_fence.duplicate(
ZX_RIGHT_SAME_RIGHTS, &release_fence_dup);
ZX_CHECK(status == ZX_OK, status);
scenic_surface_->scenic_session()->EnqueueReleaseFence(
std::move(release_fence_dup));
scenic_surface_->safe_presenter()->QueuePresent();
// Move to the next buffer.
current_frame_ = (current_frame_ + 1) % kNumBuffers;
}
std::unique_ptr<gfx::VSyncProvider> ScenicWindowCanvas::CreateVSyncProvider() {
// TODO(crbug.com/829980): Implement VSyncProvider. It can be implemented by
// observing FuturePresentationTimes returned from
// scenic::Session::Present2().
return nullptr;
}
} // namespace ui

@ -1,95 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_CANVAS_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_CANVAS_H_
#include <lib/ui/scenic/cpp/resources.h>
#include <memory>
#include "base/memory/shared_memory_mapping.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/platform/scenic/scenic_surface.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
class SkSurface;
namespace scenic {
class Session;
} // namespace scenic
namespace ui {
class ScenicWindow;
// SurfaceOzoneCanvas implementation for ScenicWindow. It allows to draw on a
// ScenicWindow.
class ScenicWindowCanvas : public SurfaceOzoneCanvas {
public:
// |scenic_surface| must outlive the canvas. ScenicSurface owns the
// scenic::Session used in this class for all drawing operations.
explicit ScenicWindowCanvas(ScenicSurface* scenic_surface);
ScenicWindowCanvas(const ScenicWindowCanvas&) = delete;
ScenicWindowCanvas& operator=(const ScenicWindowCanvas&) = delete;
~ScenicWindowCanvas() override;
// SurfaceOzoneCanvas implementation.
void ResizeCanvas(const gfx::Size& viewport_size, float scale) override;
SkCanvas* GetCanvas() override;
void PresentCanvas(const gfx::Rect& damage) override;
std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() override;
private:
// Use 2 buffers: one is shown on the screen while the other is used to render
// the next frame.
static const int kNumBuffers = 2;
struct Frame {
Frame();
~Frame();
// Allocates and maps memory for a frame of |size| (in physical in pixels)
// and then registers it with |scenic|.
void Initialize(gfx::Size size, scenic::Session* scenic);
// Copies pixels covered by |dirty_region| from another |frame|.
void CopyDirtyRegionFrom(const Frame& frame);
bool is_empty() { return !surface; }
// Shared memory for the buffer.
base::WritableSharedMemoryMapping memory_mapping;
// Scenic Memory resource for |memory_region|.
std::unique_ptr<scenic::Memory> scenic_memory;
// SkSurface that wraps |memory_mapping|.
sk_sp<SkSurface> surface;
// Fence that will be released by Scenic when it stops using this frame.
zx::event release_fence;
// The region of the frame that's not up-to-date.
SkRegion dirty_region;
};
Frame frames_[kNumBuffers];
// Buffer index in |frames_| for the frame that's currently being rendered.
int current_frame_ = 0;
// View size in device pixels.
gfx::Size viewport_size_;
ScenicSurface* const scenic_surface_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_CANVAS_H_

@ -1,57 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
#include <lib/sys/cpp/component_context.h>
#include <memory>
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "ui/ozone/platform/scenic/ozone_platform_scenic.h"
namespace ui {
ScenicWindowManager::ScenicWindowManager() = default;
ScenicWindowManager::~ScenicWindowManager() {
Shutdown();
}
void ScenicWindowManager::Shutdown() {
DCHECK(windows_.IsEmpty());
scenic_ = nullptr;
}
std::unique_ptr<PlatformScreen> ScenicWindowManager::CreateScreen() {
DCHECK(windows_.IsEmpty());
return std::make_unique<ScenicScreen>();
}
fuchsia::ui::scenic::Scenic* ScenicWindowManager::GetScenic() {
if (!scenic_) {
scenic_ = base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::ui::scenic::Scenic>();
scenic_.set_error_handler(base::LogFidlErrorAndExitProcess(
FROM_HERE, "fuchsia.ui.scenic.Scenic"));
}
return scenic_.get();
}
int32_t ScenicWindowManager::AddWindow(ScenicWindow* window) {
return windows_.Add(window);
}
void ScenicWindowManager::RemoveWindow(int32_t window_id,
ScenicWindow* window) {
DCHECK_EQ(window, windows_.Lookup(window_id));
windows_.Remove(window_id);
}
ScenicWindow* ScenicWindowManager::GetWindow(int32_t window_id) {
return windows_.Lookup(window_id);
}
} // namespace ui

@ -1,66 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_MANAGER_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_MANAGER_H_
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <stdint.h>
#include <memory>
#include "base/component_export.h"
#include "base/containers/id_map.h"
#include "base/threading/thread_checker.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/scenic/scenic_screen.h"
#include "ui/ozone/public/surface_factory_ozone.h"
namespace ui {
class ScenicWindow;
// Window manager is responsible for mapping window IDs to ScenicWindow
// instances. Window IDs are integer values that are passed around as
// gpu::AcceleratedWidget. The manager is created and owned by
// OzonePlatformScenic.
//
// TODO(sergeyu): Consider updating AcceleratedWidget to store ScenicWindow*
// which would remove the need for the IDMap.
class COMPONENT_EXPORT(OZONE) ScenicWindowManager {
public:
ScenicWindowManager();
ScenicWindowManager(const ScenicWindowManager&) = delete;
ScenicWindowManager& operator=(const ScenicWindowManager&) = delete;
~ScenicWindowManager();
// Shuts down the window manager.
void Shutdown();
std::unique_ptr<PlatformScreen> CreateScreen();
// Scenic interface that is used by ScenicWindow instances. The interface
// is initialized lazily on the first call and it don't change afterwards.
// ScenicWindowManager keeps the ownership.
fuchsia::ui::scenic::Scenic* GetScenic();
// Called by ScenicWindow when a new window instance is created. Returns
// window ID for the |window|.
int32_t AddWindow(ScenicWindow* window);
// Called by ScenicWindow destructor to unregister |window|.
void RemoveWindow(int32_t window_id, ScenicWindow* window);
ScenicWindow* GetWindow(int32_t window_id);
private:
base::IDMap<ScenicWindow*> windows_;
fuchsia::ui::scenic::ScenicPtr scenic_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_MANAGER_H_

@ -1,650 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
#include <fuchsia/sysmem/cpp/fidl.h>
#include <tuple>
#include "base/bits.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/koid.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/platform/scenic/sysmem_native_pixmap.h"
namespace ui {
namespace {
size_t RoundUp(size_t value, size_t alignment) {
return ((value + alignment - 1) / alignment) * alignment;
}
VkFormat VkFormatForBufferFormat(gfx::BufferFormat buffer_format) {
switch (buffer_format) {
case gfx::BufferFormat::YVU_420:
return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
case gfx::BufferFormat::YUV_420_BIPLANAR:
return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
case gfx::BufferFormat::R_8:
return VK_FORMAT_R8_UNORM;
case gfx::BufferFormat::RG_88:
return VK_FORMAT_R8G8_UNORM;
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::BGRX_8888:
return VK_FORMAT_B8G8R8A8_UNORM;
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::RGBX_8888:
return VK_FORMAT_R8G8B8A8_UNORM;
default:
NOTREACHED();
return VK_FORMAT_UNDEFINED;
}
}
size_t GetBytesPerPixel(gfx::BufferFormat buffer_format) {
switch (buffer_format) {
case gfx::BufferFormat::YVU_420:
case gfx::BufferFormat::YUV_420_BIPLANAR:
case gfx::BufferFormat::R_8:
return 1U;
case gfx::BufferFormat::RG_88:
return 2U;
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::BGRX_8888:
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::RGBX_8888:
return 4U;
default:
NOTREACHED();
return 1;
}
}
bool IsYuvVkFormat(VkFormat format) {
switch (format) {
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
return true;
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R8G8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R8G8B8A8_UNORM:
return false;
default:
NOTREACHED();
return false;
}
}
VkFormatFeatureFlags GetFormatFeatureFlagsFromUsage(VkImageUsageFlags usage) {
VkFormatFeatureFlags result = {};
if (usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
result |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
}
if (usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
result |= VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
}
if (usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
result |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
}
if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
result |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
}
if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
result |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
if (usage & VK_IMAGE_USAGE_STORAGE_BIT) {
result |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
}
return result;
}
VkImageFormatConstraintsInfoFUCHSIA GetDefaultImageFormatConstraintsInfo(
const VkImageCreateInfo& create_info) {
DCHECK(create_info.format != VK_FORMAT_UNDEFINED);
DCHECK(create_info.usage != 0);
static const VkSysmemColorSpaceFUCHSIA kSrgbColorSpace = {
VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA, nullptr,
static_cast<uint32_t>(fuchsia::sysmem::ColorSpaceType::SRGB)};
static const VkSysmemColorSpaceFUCHSIA kYuvDefaultColorSpaces[] = {
{VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA, nullptr,
static_cast<uint32_t>(fuchsia::sysmem::ColorSpaceType::REC709)},
{VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA, nullptr,
static_cast<uint32_t>(fuchsia::sysmem::ColorSpaceType::REC601_NTSC)},
{VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA, nullptr,
static_cast<uint32_t>(
fuchsia::sysmem::ColorSpaceType::REC601_NTSC_FULL_RANGE)},
{VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA, nullptr,
static_cast<uint32_t>(fuchsia::sysmem::ColorSpaceType::REC601_PAL)},
{VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA, nullptr,
static_cast<uint32_t>(
fuchsia::sysmem::ColorSpaceType::REC601_PAL_FULL_RANGE)},
};
bool is_yuv = IsYuvVkFormat(create_info.format);
VkImageFormatConstraintsInfoFUCHSIA format_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA,
.pNext = nullptr,
.imageCreateInfo = create_info,
.requiredFormatFeatures =
GetFormatFeatureFlagsFromUsage(create_info.usage),
.sysmemPixelFormat = 0u,
.colorSpaceCount = static_cast<uint32_t>(
is_yuv ? std::size(kYuvDefaultColorSpaces) : 1u),
.pColorSpaces = is_yuv ? kYuvDefaultColorSpaces : &kSrgbColorSpace,
};
return format_info;
}
struct ImageConstraintsInfo {
VkImageConstraintsInfoFUCHSIA image_constraints;
VkImageFormatConstraintsInfoFUCHSIA format_constraints;
ImageConstraintsInfo(
const VkImageConstraintsInfoFUCHSIA& image_constraints_in,
const VkImageFormatConstraintsInfoFUCHSIA& format_constraints_in)
: image_constraints(image_constraints_in),
format_constraints(format_constraints_in) {
image_constraints.pFormatConstraints = &format_constraints;
image_constraints.formatConstraintsCount = 1u;
}
ImageConstraintsInfo(ImageConstraintsInfo&& from) = delete;
ImageConstraintsInfo(const ImageConstraintsInfo&) = delete;
ImageConstraintsInfo& operator=(const ImageConstraintsInfo&) = delete;
};
std::unique_ptr<ImageConstraintsInfo> InitializeImageConstraintsInfo(
const VkImageCreateInfo& vk_image_info,
bool allow_protected_memory) {
VkImageFormatConstraintsInfoFUCHSIA format_constraints =
GetDefaultImageFormatConstraintsInfo(vk_image_info);
VkImageConstraintsInfoFUCHSIA image_constraints = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA,
.pNext = nullptr,
.bufferCollectionConstraints =
VkBufferCollectionConstraintsInfoFUCHSIA{
.sType =
VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA,
.pNext = nullptr,
.minBufferCount = 1u,
// Using the default value (0) for the fields below means that
// there is no other constraints except for the minimum buffer
// count.
.maxBufferCount = 0u,
.minBufferCountForCamping = 0u,
.minBufferCountForDedicatedSlack = 0u,
.minBufferCountForSharedSlack = 0u,
},
// TODO(crbug.com/1289315): Instead of always allowing protected
// memory, Chrome should query if the Vulkan physical device
// supports protected memory and only set the flag if it is
// supported.
.flags = allow_protected_memory
? VK_IMAGE_CONSTRAINTS_INFO_PROTECTED_OPTIONAL_FUCHSIA
: 0u,
};
return std::make_unique<ImageConstraintsInfo>(image_constraints,
format_constraints);
}
} // namespace
// static
bool SysmemBufferCollection::IsNativePixmapConfigSupported(
gfx::BufferFormat format,
gfx::BufferUsage usage) {
switch (format) {
case gfx::BufferFormat::YUV_420_BIPLANAR:
case gfx::BufferFormat::R_8:
case gfx::BufferFormat::RG_88:
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::RGBX_8888:
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::BGRX_8888:
break;
default:
return false;
}
switch (usage) {
case gfx::BufferUsage::SCANOUT:
case gfx::BufferUsage::GPU_READ:
break;
case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
break;
default:
return false;
}
return true;
}
SysmemBufferCollection::SysmemBufferCollection() = default;
bool SysmemBufferCollection::Initialize(
fuchsia::sysmem::Allocator_Sync* allocator,
ScenicSurfaceFactory* scenic_surface_factory,
zx::eventpair handle,
zx::channel sysmem_token,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
VkDevice vk_device,
size_t min_buffer_count,
bool register_with_image_pipe) {
DCHECK(IsNativePixmapConfigSupported(format, usage));
DCHECK(!collection_);
DCHECK(!vk_buffer_collection_);
handle_ = std::move(handle);
auto koid = base::GetKoid(handle_);
if (!koid)
return false;
id_ = koid.value();
// Currently all supported |usage| values require GPU access, which requires
// a valid VkDevice.
if (vk_device == VK_NULL_HANDLE)
return false;
if (size.IsEmpty()) {
// Buffer collection that doesn't have explicit size is expected to be
// shared with other participants, who will determine the actual image size.
DCHECK(sysmem_token);
// Set nominal size of 1x1, which will be used only for
// vkSetBufferCollectionConstraintsFUCHSIA(). The actual size of the
// allocated buffers is determined by constraints set by other sysmem
// clients for the same collection. Size of the Vulkan image is determined
// by the values passed to CreateVkImage().
min_size_ = gfx::Size(1, 1);
} else {
min_size_ = size;
}
format_ = format;
usage_ = usage;
vk_device_ = vk_device;
is_protected_ = false;
if (register_with_image_pipe) {
overlay_view_task_runner_ =
base::SingleThreadTaskRunner::GetCurrentDefault();
scenic_overlay_view_ = std::make_unique<ScenicOverlayView>(
scenic_surface_factory->CreateScenicSession());
}
fuchsia::sysmem::BufferCollectionTokenSyncPtr collection_token;
if (sysmem_token) {
collection_token.Bind(std::move(sysmem_token));
} else {
zx_status_t status =
allocator->AllocateSharedCollection(collection_token.NewRequest());
if (status != ZX_OK) {
ZX_DLOG(ERROR, status)
<< "fuchsia.sysmem.Allocator.AllocateSharedCollection()";
return false;
}
}
return InitializeInternal(allocator, std::move(collection_token),
min_buffer_count);
}
scoped_refptr<gfx::NativePixmap> SysmemBufferCollection::CreateNativePixmap(
gfx::NativePixmapHandle handle,
gfx::Size size) {
CHECK_LT(handle.buffer_index, num_buffers());
DCHECK_EQ(base::GetRelatedKoid(handle.buffer_collection_handle).value(), id_);
handle.ram_coherency =
buffers_info_.settings.buffer_settings.coherency_domain ==
fuchsia::sysmem::CoherencyDomain::RAM;
// `handle.planes` need to be filled in only for mappable buffers.
if (!is_mappable())
return new SysmemNativePixmap(this, std::move(handle), size);
zx::vmo main_plane_vmo;
DCHECK(buffers_info_.buffers[handle.buffer_index].vmo.is_valid());
zx_status_t status = buffers_info_.buffers[handle.buffer_index].vmo.duplicate(
ZX_RIGHT_SAME_RIGHTS, &main_plane_vmo);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
return nullptr;
}
const fuchsia::sysmem::ImageFormatConstraints& format =
buffers_info_.settings.image_format_constraints;
// The logic should match LogicalBufferCollection::Allocate().
size_t stride =
RoundUp(std::max(static_cast<size_t>(format.min_bytes_per_row),
size.width() * GetBytesPerPixel(format_)),
format.bytes_per_row_divisor);
size_t plane_offset =
buffers_info_.buffers[handle.buffer_index].vmo_usable_start;
size_t plane_size = stride * size.height();
handle.planes.emplace_back(stride, plane_offset, plane_size,
std::move(main_plane_vmo));
// For YUV images add a second plane.
if (format_ == gfx::BufferFormat::YUV_420_BIPLANAR) {
size_t uv_plane_offset = plane_offset + plane_size;
size_t uv_plane_size = plane_size / 2;
zx::vmo uv_plane_vmo;
status =
handle.planes[0].vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &uv_plane_vmo);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
return nullptr;
}
handle.planes.emplace_back(stride, uv_plane_offset, uv_plane_size,
std::move(uv_plane_vmo));
DCHECK_LE(uv_plane_offset + uv_plane_size, buffer_size_);
}
return new SysmemNativePixmap(this, std::move(handle), size);
}
bool SysmemBufferCollection::CreateVkImage(size_t buffer_index,
VkDevice vk_device,
gfx::Size size,
VkImage* vk_image,
VkImageCreateInfo* vk_image_info,
VkDeviceMemory* vk_device_memory,
VkDeviceSize* mem_allocation_size) {
DCHECK_CALLED_ON_VALID_THREAD(vulkan_thread_checker_);
if (vk_device_ != vk_device) {
DLOG(FATAL) << "Tried to import NativePixmap that was created for a "
"different VkDevice.";
return false;
}
VkBufferCollectionPropertiesFUCHSIA properties = {
VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA};
if (vkGetBufferCollectionPropertiesFUCHSIA(vk_device_, vk_buffer_collection_,
&properties) != VK_SUCCESS) {
DLOG(ERROR) << "vkGetBufferCollectionPropertiesFUCHSIA failed";
return false;
}
InitializeImageCreateInfo(vk_image_info, size);
VkBufferCollectionImageCreateInfoFUCHSIA image_format_fuchsia = {
VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA,
};
image_format_fuchsia.collection = vk_buffer_collection_;
image_format_fuchsia.index = buffer_index;
vk_image_info->pNext = &image_format_fuchsia;
if (vkCreateImage(vk_device_, vk_image_info, nullptr, vk_image) !=
VK_SUCCESS) {
DLOG(ERROR) << "Failed to create VkImage.";
return false;
}
vk_image_info->pNext = nullptr;
VkMemoryRequirements requirements;
vkGetImageMemoryRequirements(vk_device, *vk_image, &requirements);
uint32_t viable_memory_types =
properties.memoryTypeBits & requirements.memoryTypeBits;
uint32_t memory_type = base::bits::CountTrailingZeroBits(viable_memory_types);
VkMemoryDedicatedAllocateInfoKHR dedicated_allocate = {
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
dedicated_allocate.image = *vk_image;
VkImportMemoryBufferCollectionFUCHSIA buffer_collection_info = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA,
&dedicated_allocate};
buffer_collection_info.collection = vk_buffer_collection_;
buffer_collection_info.index = buffer_index;
VkMemoryAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
&buffer_collection_info};
alloc_info.allocationSize = requirements.size;
alloc_info.memoryTypeIndex = memory_type;
if (vkAllocateMemory(vk_device_, &alloc_info, nullptr, vk_device_memory) !=
VK_SUCCESS) {
DLOG(ERROR) << "Failed to create VkMemory from sysmem buffer.";
vkDestroyImage(vk_device_, *vk_image, nullptr);
*vk_image = VK_NULL_HANDLE;
return false;
}
if (vkBindImageMemory(vk_device_, *vk_image, *vk_device_memory, 0u) !=
VK_SUCCESS) {
DLOG(ERROR) << "Failed to bind sysmem buffer to a VkImage.";
vkDestroyImage(vk_device_, *vk_image, nullptr);
*vk_image = VK_NULL_HANDLE;
vkFreeMemory(vk_device_, *vk_device_memory, nullptr);
*vk_device_memory = VK_NULL_HANDLE;
return false;
}
*mem_allocation_size = requirements.size;
return true;
}
void SysmemBufferCollection::AddOnReleasedCallback(
base::OnceClosure on_released) {
on_released_.push_back(std::move(on_released));
}
SysmemBufferCollection::~SysmemBufferCollection() {
if (vk_buffer_collection_ != VK_NULL_HANDLE) {
vkDestroyBufferCollectionFUCHSIA(vk_device_, vk_buffer_collection_,
nullptr);
}
if (collection_)
collection_->Close();
if (scenic_overlay_view_ &&
!overlay_view_task_runner_->BelongsToCurrentThread()) {
overlay_view_task_runner_->DeleteSoon(FROM_HERE,
std::move(scenic_overlay_view_));
}
}
bool SysmemBufferCollection::InitializeInternal(
fuchsia::sysmem::Allocator_Sync* allocator,
fuchsia::sysmem::BufferCollectionTokenSyncPtr collection_token,
size_t min_buffer_count) {
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
collection_token_for_vulkan;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_vulkan.NewRequest());
// Duplicate one more token for Scenic if this collection can be used as an
// overlay.
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
collection_token_for_scenic;
if (scenic_overlay_view_) {
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_scenic.NewRequest());
}
zx_status_t status = collection_token->Sync();
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollectionToken.Sync()";
return false;
}
if (scenic_overlay_view_) {
scenic_overlay_view_->Initialize(std::move(collection_token_for_scenic));
}
status = allocator->BindSharedCollection(std::move(collection_token),
collection_.NewRequest());
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.Allocator.BindSharedCollection()";
return false;
}
fuchsia::sysmem::BufferCollectionConstraints constraints;
if (is_mappable()) {
constraints.usage.cpu =
fuchsia::sysmem::cpuUsageRead | fuchsia::sysmem::cpuUsageWrite;
constraints.has_buffer_memory_constraints = true;
constraints.buffer_memory_constraints.ram_domain_supported = true;
constraints.buffer_memory_constraints.cpu_domain_supported = true;
} else {
constraints.usage.none = fuchsia::sysmem::noneUsage;
}
constraints.min_buffer_count = min_buffer_count;
constraints.image_format_constraints_count = 0;
status = collection_->SetConstraints(/*has_constraints=*/true,
std::move(constraints));
if (status != ZX_OK) {
ZX_DLOG(ERROR, status)
<< "fuchsia.sysmem.BufferCollection.SetConstraints()";
return false;
}
zx::channel token_channel = collection_token_for_vulkan.TakeChannel();
VkBufferCollectionCreateInfoFUCHSIA buffer_collection_create_info = {
VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA};
buffer_collection_create_info.collectionToken = token_channel.get();
if (vkCreateBufferCollectionFUCHSIA(vk_device_,
&buffer_collection_create_info, nullptr,
&vk_buffer_collection_) != VK_SUCCESS) {
vk_buffer_collection_ = VK_NULL_HANDLE;
DLOG(ERROR) << "vkCreateBufferCollectionFUCHSIA() failed";
return false;
}
// vkCreateBufferCollectionFUCHSIA() takes ownership of the token on success.
std::ignore = token_channel.release();
VkImageCreateInfo image_create_info;
InitializeImageCreateInfo(&image_create_info, min_size_);
// TODO(crbug.com/1289315): Instead of always allowing protected memory,
// Chrome should query if the Vulkan physical device supports protected
// memory and only set the flag if it is supported.
auto image_constraints_info = InitializeImageConstraintsInfo(
image_create_info, /* allow_protected_memory */ true);
if (vkSetBufferCollectionImageConstraintsFUCHSIA(
vk_device_, vk_buffer_collection_,
&image_constraints_info->image_constraints) != VK_SUCCESS) {
DLOG(ERROR) << "vkSetBufferCollectionConstraintsFUCHSIA() failed";
return false;
}
zx_status_t wait_status;
status = collection_->WaitForBuffersAllocated(&wait_status, &buffers_info_);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollection failed";
return false;
}
if (wait_status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollection::"
"WaitForBuffersAllocated() failed.";
return false;
}
DCHECK_GE(buffers_info_.buffer_count, min_buffer_count);
DCHECK(buffers_info_.settings.has_image_format_constraints);
buffer_size_ = buffers_info_.settings.buffer_settings.size_bytes;
is_protected_ = buffers_info_.settings.buffer_settings.is_secure;
handle_watch_ =
std::make_unique<base::MessagePumpForIO::ZxHandleWatchController>(
FROM_HERE);
bool watch_result = base::CurrentIOThread::Get()->WatchZxHandle(
handle_.get(), /*persistent=*/false, ZX_EVENTPAIR_PEER_CLOSED,
handle_watch_.get(), this);
if (!watch_result) {
DLOG(ERROR) << "Failed to add a watcher for sysmem buffer token";
return false;
}
// CreateVkImage() should always be called on the same thread, but it may be
// different from the thread that called Initialize().
DETACH_FROM_THREAD(vulkan_thread_checker_);
return true;
}
void SysmemBufferCollection::InitializeImageCreateInfo(
VkImageCreateInfo* vk_image_info,
gfx::Size size) {
*vk_image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
vk_image_info->flags = is_protected_ ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u;
vk_image_info->imageType = VK_IMAGE_TYPE_2D;
vk_image_info->format = VkFormatForBufferFormat(format_);
vk_image_info->extent = VkExtent3D{static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height()), 1};
vk_image_info->mipLevels = 1;
vk_image_info->arrayLayers = 1;
vk_image_info->samples = VK_SAMPLE_COUNT_1_BIT;
vk_image_info->tiling =
is_mappable() ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
vk_image_info->usage = VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (usage_ == gfx::BufferUsage::SCANOUT) {
vk_image_info->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
vk_image_info->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vk_image_info->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
void SysmemBufferCollection::OnZxHandleSignalled(zx_handle_t handle,
zx_signals_t signals) {
DCHECK_EQ(handle, handle_.get());
DCHECK_EQ(signals, ZX_EVENTPAIR_PEER_CLOSED);
// Keep a reference to `this` to ensure it's not destroyed while calling the
// callbacks.
scoped_refptr<SysmemBufferCollection> self(this);
for (auto& callback : on_released_) {
std::move(callback).Run();
}
on_released_.clear();
}
} // namespace ui

@ -1,162 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_COLLECTION_H_
#define UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_COLLECTION_H_
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/zx/eventpair.h>
#include <vulkan/vulkan_core.h>
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_pump_for_io.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap_handle.h"
#include "ui/ozone/platform/scenic/scenic_overlay_view.h"
namespace gfx {
class NativePixmap;
} // namespace gfx
namespace ui {
class ScenicSurfaceFactory;
// SysmemBufferCollection keeps sysmem.BufferCollection interface along with the
// corresponding VkBufferCollectionFUCHSIA. It allows to create either
// gfx::NativePixmap or VkImage from the buffers in the collection.
// A collection can be initialized and used on any thread. CreateVkImage() must
// be called on the same thread (because it may be be safe to use
// VkBufferCollectionFUCHSIA concurrently on different threads).
class SysmemBufferCollection
: public base::RefCountedThreadSafe<SysmemBufferCollection>,
public base::MessagePumpForIO::ZxHandleWatcher {
public:
static bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
gfx::BufferUsage usage);
SysmemBufferCollection();
SysmemBufferCollection(const SysmemBufferCollection&) = delete;
SysmemBufferCollection& operator=(const SysmemBufferCollection&) = delete;
// Initializes the buffer collection and registers it with Vulkan using the
// specified |vk_device|. If |token_handle| is null then a new collection
// collection is created. |size| may be empty. In that case |token_handle|
// must not be null and the image size is determined by the other sysmem
// participants.
// If |register_with_image_pipe| is true, new ScenicOverlayView instance is
// created and |token_handle| gets duplicated to be added to its ImagePipe.
bool Initialize(fuchsia::sysmem::Allocator_Sync* allocator,
ScenicSurfaceFactory* scenic_surface_factory,
zx::eventpair handle,
zx::channel sysmem_token,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
VkDevice vk_device,
size_t min_buffer_count,
bool register_with_image_pipe);
void AddOnReleasedCallback(base::OnceClosure on_released);
// Creates a NativePixmap the buffer with the specified index. Returned
// NativePixmap holds a reference to the collection, so the collection is not
// deleted until all NativePixmap are destroyed.
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::NativePixmapHandle handle,
gfx::Size size);
// Creates a new Vulkan image for the buffer with the specified index.
bool CreateVkImage(size_t buffer_index,
VkDevice vk_device,
gfx::Size size,
VkImage* vk_image,
VkImageCreateInfo* vk_image_info,
VkDeviceMemory* vk_device_memory,
VkDeviceSize* mem_allocation_size);
zx_koid_t id() const { return id_; }
size_t num_buffers() const { return buffers_info_.buffer_count; }
gfx::BufferFormat format() const { return format_; }
size_t buffer_size() const {
return buffers_info_.settings.buffer_settings.size_bytes;
}
ScenicOverlayView* scenic_overlay_view() {
return scenic_overlay_view_ ? scenic_overlay_view_.get() : nullptr;
}
private:
friend class base::RefCountedThreadSafe<SysmemBufferCollection>;
~SysmemBufferCollection() override;
bool InitializeInternal(
fuchsia::sysmem::Allocator_Sync* allocator,
fuchsia::sysmem::BufferCollectionTokenSyncPtr collection_token,
size_t buffers_for_camping);
void InitializeImageCreateInfo(VkImageCreateInfo* vk_image_info,
gfx::Size size);
bool is_mappable() const {
return usage_ == gfx::BufferUsage::SCANOUT_CPU_READ_WRITE ||
usage_ == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
}
// base::MessagePumpForIO::ZxHandleWatcher implementation.
void OnZxHandleSignalled(zx_handle_t handle, zx_signals_t signals) override;
zx::eventpair handle_;
zx_koid_t id_ = 0;
std::unique_ptr<base::MessagePumpForIO::ZxHandleWatchController>
handle_watch_;
// Image size passed to vkSetBufferCollectionConstraintsFUCHSIA(). The actual
// buffers size may be larger depending on constraints set by other
// sysmem clients. Size of the image is passed to CreateVkImage().
gfx::Size min_size_;
gfx::BufferFormat format_ = gfx::BufferFormat::RGBA_8888;
gfx::BufferUsage usage_ = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
fuchsia::sysmem::BufferCollectionSyncPtr collection_;
fuchsia::sysmem::BufferCollectionInfo_2 buffers_info_;
// Vulkan device for which the collection was initialized.
VkDevice vk_device_ = VK_NULL_HANDLE;
// Handle for the Vulkan object that holds the same logical buffer collection
// that is referenced by |collection_|.
VkBufferCollectionFUCHSIA vk_buffer_collection_ = VK_NULL_HANDLE;
// |scenic_overlay_view_| view should be used and deleted on the same thread
// as creation.
scoped_refptr<base::SingleThreadTaskRunner> overlay_view_task_runner_;
// If ScenicOverlayView is created and its ImagePipe is added as a participant
// in buffer allocation negotiations, the associated images can be displayed
// as overlays.
std::unique_ptr<ScenicOverlayView> scenic_overlay_view_;
// Thread checker used to verify that CreateVkImage() is always called from
// the same thread. It may be unsafe to use vk_buffer_collection_ on different
// threads.
THREAD_CHECKER(vulkan_thread_checker_);
size_t buffer_size_ = 0;
bool is_protected_ = false;
std::vector<base::OnceClosure> on_released_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_COLLECTION_H_

@ -1,139 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/sysmem_buffer_manager.h"
#include <lib/zx/eventpair.h>
#include <zircon/rights.h>
#include <zircon/types.h>
#include "base/containers/contains.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/koid.h"
#include "base/functional/bind.h"
#include "ui/gfx/native_pixmap_handle.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
namespace ui {
namespace {
std::string GetProcessName() {
char name[ZX_MAX_NAME_LEN] = {};
zx_status_t status =
zx::process::self()->get_property(ZX_PROP_NAME, name, sizeof(name));
return (status == ZX_OK) ? std::string(name) : "";
}
} // namespace
SysmemBufferManager::SysmemBufferManager(
ScenicSurfaceFactory* scenic_surface_factory)
: scenic_surface_factory_(scenic_surface_factory) {}
SysmemBufferManager::~SysmemBufferManager() {
Shutdown();
}
void SysmemBufferManager::Initialize(
fuchsia::sysmem::AllocatorHandle allocator) {
base::AutoLock auto_lock(collections_lock_);
DCHECK(collections_.empty());
DCHECK(!allocator_);
allocator_.Bind(std::move(allocator));
allocator_->SetDebugClientInfo(GetProcessName() + "-SysmemBufferManager",
base::GetCurrentProcId());
}
void SysmemBufferManager::Shutdown() {
base::AutoLock auto_lock(collections_lock_);
DCHECK(collections_.empty());
allocator_ = nullptr;
}
fuchsia::sysmem::Allocator_Sync* SysmemBufferManager::GetAllocator() {
DCHECK(allocator_);
return allocator_.get();
}
scoped_refptr<gfx::NativePixmap> SysmemBufferManager::CreateNativePixmap(
VkDevice vk_device,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage) {
gfx::NativePixmapHandle pixmap_handle;
zx::eventpair service_handle;
auto status = zx::eventpair::create(
0, &pixmap_handle.buffer_collection_handle, &service_handle);
ZX_DCHECK(status == ZX_OK, status);
auto collection = base::MakeRefCounted<SysmemBufferCollection>();
if (!collection->Initialize(allocator_.get(), scenic_surface_factory_,
std::move(service_handle),
/*token_channel=*/zx::channel(), size, format,
usage, vk_device, /*min_buffer_count=*/1,
/*register_with_image_pipe=*/false)) {
return nullptr;
}
auto result = collection->CreateNativePixmap(std::move(pixmap_handle), size);
if (result)
RegisterCollection(collection);
return result;
}
scoped_refptr<SysmemBufferCollection>
SysmemBufferManager::ImportSysmemBufferCollection(
VkDevice vk_device,
zx::eventpair service_handle,
zx::channel sysmem_token,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
size_t min_buffer_count,
bool register_with_image_pipe) {
auto result = base::MakeRefCounted<SysmemBufferCollection>();
if (!result->Initialize(allocator_.get(), scenic_surface_factory_,
std::move(service_handle), std::move(sysmem_token),
size, format, usage, vk_device, min_buffer_count,
register_with_image_pipe)) {
return nullptr;
}
RegisterCollection(result);
return result;
}
void SysmemBufferManager::RegisterCollection(
scoped_refptr<SysmemBufferCollection> collection) {
{
base::AutoLock auto_lock(collections_lock_);
DCHECK(!base::Contains(collections_, collection->id()));
collections_[collection->id()] = collection;
}
collection->AddOnReleasedCallback(
base::BindOnce(&SysmemBufferManager::OnCollectionReleased,
base::Unretained(this), collection->id()));
}
scoped_refptr<SysmemBufferCollection>
SysmemBufferManager::GetCollectionByHandle(const zx::eventpair& token) {
auto koid = base::GetRelatedKoid(token);
if (!koid)
return nullptr;
base::AutoLock auto_lock(collections_lock_);
auto it = collections_.find(koid.value());
return it == collections_.end() ? nullptr : it->second;
}
void SysmemBufferManager::OnCollectionReleased(zx_koid_t id) {
base::AutoLock auto_lock(collections_lock_);
int erased = collections_.erase(id);
DCHECK_EQ(erased, 1);
}
} // namespace ui

@ -1,84 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_MANAGER_H_
#define UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_MANAGER_H_
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/zx/eventpair.h>
#include <unordered_map>
#include "base/containers/small_map.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/lock.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap.h"
namespace ui {
class SysmemBufferCollection;
class ScenicSurfaceFactory;
class SysmemBufferManager {
public:
explicit SysmemBufferManager(ScenicSurfaceFactory* scenic_surface_factory);
SysmemBufferManager(const SysmemBufferManager&) = delete;
SysmemBufferManager& operator=(const SysmemBufferManager&) = delete;
~SysmemBufferManager();
// Initializes the buffer manager with a connection to the sysmem service.
void Initialize(fuchsia::sysmem::AllocatorHandle allocator);
// Disconnects from the sysmem service. After disconnecting, it's safe to call
// Initialize() again.
void Shutdown();
// Returns sysmem allocator. Should only be called after `Initialize()` and
// before `Shutdown()`.
fuchsia::sysmem::Allocator_Sync* GetAllocator();
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(VkDevice vk_device,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage);
scoped_refptr<SysmemBufferCollection> ImportSysmemBufferCollection(
VkDevice vk_device,
zx::eventpair service_handle,
zx::channel sysmem_token,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
size_t min_buffer_count,
bool register_with_image_pipe);
// Returns `SysmemBufferCollection` that corresnponds to the specified
// buffer collection `handle`, which should be the other end of the eventpair
// passed to `ImportSysmemBufferCollection()`.
scoped_refptr<SysmemBufferCollection> GetCollectionByHandle(
const zx::eventpair& handle);
private:
void RegisterCollection(scoped_refptr<SysmemBufferCollection> collection);
void OnCollectionReleased(zx_koid_t id);
ScenicSurfaceFactory* const scenic_surface_factory_;
fuchsia::sysmem::AllocatorSyncPtr allocator_;
base::small_map<
std::unordered_map<zx_koid_t, scoped_refptr<SysmemBufferCollection>>>
collections_ GUARDED_BY(collections_lock_);
base::Lock collections_lock_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_MANAGER_H_

@ -1,131 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/sysmem_native_pixmap.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/overlay_plane_data.h"
namespace ui {
namespace {
zx::event GpuFenceToZxEvent(gfx::GpuFence fence) {
DCHECK(!fence.GetGpuFenceHandle().is_null());
return fence.GetGpuFenceHandle().Clone().owned_event;
}
} // namespace
SysmemNativePixmap::SysmemNativePixmap(
scoped_refptr<SysmemBufferCollection> collection,
gfx::NativePixmapHandle handle,
gfx::Size size)
: collection_(collection), handle_(std::move(handle)), size_(size) {}
SysmemNativePixmap::~SysmemNativePixmap() {
if (overlay_image_id_)
collection_->scenic_overlay_view()->RemoveImage(overlay_image_id_);
}
bool SysmemNativePixmap::AreDmaBufFdsValid() const {
return false;
}
int SysmemNativePixmap::GetDmaBufFd(size_t plane) const {
NOTREACHED();
return -1;
}
uint32_t SysmemNativePixmap::GetDmaBufPitch(size_t plane) const {
NOTREACHED();
return 0u;
}
size_t SysmemNativePixmap::GetDmaBufOffset(size_t plane) const {
NOTREACHED();
return 0u;
}
size_t SysmemNativePixmap::GetDmaBufPlaneSize(size_t plane) const {
NOTREACHED();
return 0;
}
size_t SysmemNativePixmap::GetNumberOfPlanes() const {
NOTREACHED();
return 0;
}
bool SysmemNativePixmap::SupportsZeroCopyWebGPUImport() const {
NOTREACHED();
return false;
}
uint64_t SysmemNativePixmap::GetBufferFormatModifier() const {
NOTREACHED();
return 0;
}
gfx::BufferFormat SysmemNativePixmap::GetBufferFormat() const {
return collection_->format();
}
gfx::Size SysmemNativePixmap::GetBufferSize() const {
return size_;
}
uint32_t SysmemNativePixmap::GetUniqueId() const {
return 0;
}
bool SysmemNativePixmap::ScheduleOverlayPlane(
gfx::AcceleratedWidget widget,
const gfx::OverlayPlaneData& overlay_plane_data,
std::vector<gfx::GpuFence> acquire_fences,
std::vector<gfx::GpuFence> release_fences) {
DCHECK(collection_->scenic_overlay_view());
ScenicOverlayView* overlay_view = collection_->scenic_overlay_view();
// Convert gfx::GpuFence to zx::event for PresentImage call.
std::vector<zx::event> acquire_events;
for (auto& fence : acquire_fences)
acquire_events.push_back(GpuFenceToZxEvent(std::move(fence)));
std::vector<zx::event> release_events;
for (auto& fence : release_fences)
release_events.push_back(GpuFenceToZxEvent(std::move(fence)));
overlay_view->SetBlendMode(overlay_plane_data.enable_blend);
if (!overlay_image_id_)
overlay_image_id_ = overlay_view->AddImage(handle_.buffer_index, size_);
overlay_view->PresentImage(overlay_image_id_, std::move(acquire_events),
std::move(release_events));
return true;
}
gfx::NativePixmapHandle SysmemNativePixmap::ExportHandle() {
return gfx::CloneHandleForIPC(handle_);
}
const gfx::NativePixmapHandle& SysmemNativePixmap::PeekHandle() const {
return handle_;
}
bool SysmemNativePixmap::SupportsOverlayPlane() const {
// We can display an overlay as long as we have a ScenicOverlayView. Note that
// ScenicOverlayView can migrate from one surface to another, but it can't
// be used across multiple surfaces similtaneously. But on Fuchsia each buffer
// collection is allocated (in FuchsiaVideoDecoder) for a specific web frame,
// and each frame can be displayed only on one specific surface.
return !!collection_->scenic_overlay_view();
}
ScenicOverlayView* SysmemNativePixmap::GetScenicOverlayView() {
return collection_->scenic_overlay_view();
}
} // namespace ui

@ -1,67 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_SYSMEM_NATIVE_PIXMAP_H_
#define UI_OZONE_PLATFORM_SCENIC_SYSMEM_NATIVE_PIXMAP_H_
#include <lib/zx/eventpair.h>
#include "ui/gfx/native_pixmap.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
namespace ui {
class ScenicOverlayView;
class SysmemNativePixmap : public gfx::NativePixmap {
public:
SysmemNativePixmap(scoped_refptr<SysmemBufferCollection> collection,
gfx::NativePixmapHandle handle,
gfx::Size size);
SysmemNativePixmap(const SysmemNativePixmap&) = delete;
SysmemNativePixmap& operator=(const SysmemNativePixmap&) = delete;
// gfx::NativePixmap implementation.
bool AreDmaBufFdsValid() const override;
int GetDmaBufFd(size_t plane) const override;
uint32_t GetDmaBufPitch(size_t plane) const override;
size_t GetDmaBufOffset(size_t plane) const override;
size_t GetDmaBufPlaneSize(size_t plane) const override;
size_t GetNumberOfPlanes() const override;
bool SupportsZeroCopyWebGPUImport() const override;
uint64_t GetBufferFormatModifier() const override;
gfx::BufferFormat GetBufferFormat() const override;
gfx::Size GetBufferSize() const override;
uint32_t GetUniqueId() const override;
bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
const gfx::OverlayPlaneData& overlay_plane_data,
std::vector<gfx::GpuFence> acquire_fences,
std::vector<gfx::GpuFence> release_fences) override;
gfx::NativePixmapHandle ExportHandle() override;
const gfx::NativePixmapHandle& PeekHandle() const;
// Returns true if overlay planes are supported and ScheduleOverlayPlane() can
// be called.
bool SupportsOverlayPlane() const;
// Returns true ScenicOverlayView for the pixmap if any.
ScenicOverlayView* GetScenicOverlayView();
private:
~SysmemNativePixmap() override;
scoped_refptr<SysmemBufferCollection> collection_;
gfx::NativePixmapHandle handle_;
gfx::Size size_;
// ID of the image registered with the `ImagePipe` owned by the
// `ScenicOverlayView` that corresponds to the `collection_`.
uint32_t overlay_image_id_ = 0;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_SYSMEM_NATIVE_PIXMAP_H_

@ -1,256 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/scenic/vulkan_implementation_scenic.h"
#include <lib/ui/scenic/cpp/commands.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/zx/channel.h>
#include <vulkan/vulkan.h>
#include <memory>
#include <tuple>
#include "base/files/file_path.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_image.h"
#include "gpu/vulkan/vulkan_instance.h"
#include "gpu/vulkan/vulkan_surface.h"
#include "gpu/vulkan/vulkan_util.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/ozone/platform/scenic/scenic_surface.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
#include "ui/ozone/platform/scenic/sysmem_buffer_collection.h"
namespace ui {
namespace {
constexpr char kFuchsiaSwapchainLayerName[] =
"VK_LAYER_FUCHSIA_imagepipe_swapchain";
} // namespace
VulkanImplementationScenic::VulkanImplementationScenic(
ScenicSurfaceFactory* scenic_surface_factory,
SysmemBufferManager* sysmem_buffer_manager,
bool use_swiftshader,
bool allow_protected_memory)
: VulkanImplementation(use_swiftshader, allow_protected_memory),
scenic_surface_factory_(scenic_surface_factory),
sysmem_buffer_manager_(sysmem_buffer_manager) {}
VulkanImplementationScenic::~VulkanImplementationScenic() = default;
bool VulkanImplementationScenic::InitializeVulkanInstance(bool using_surface) {
using_surface_ = using_surface;
base::FilePath path(use_swiftshader() ? "libvk_swiftshader.so"
: "libvulkan.so");
vulkan_instance_.BindUnassignedFunctionPointers(path);
std::vector<const char*> required_extensions;
std::vector<const char*> required_layers;
if (using_surface) {
required_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
// Enable ImagePipe swapchain (not supported in swiftshader).
if (!use_swiftshader()) {
required_layers.push_back(kFuchsiaSwapchainLayerName);
required_extensions.push_back(
VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME);
}
};
return vulkan_instance_.InitializeInstance(required_extensions,
required_layers);
}
gpu::VulkanInstance* VulkanImplementationScenic::GetVulkanInstance() {
return &vulkan_instance_;
}
std::unique_ptr<gpu::VulkanSurface>
VulkanImplementationScenic::CreateViewSurface(gfx::AcceleratedWidget window) {
DCHECK(using_surface_);
ScenicSurface* scenic_surface = scenic_surface_factory_->GetSurface(window);
fuchsia::images::ImagePipe2Ptr image_pipe;
scenic_surface->SetTextureToNewImagePipe(image_pipe.NewRequest());
zx_handle_t image_pipe_handle = image_pipe.Unbind().TakeChannel().release();
VkSurfaceKHR surface;
VkImagePipeSurfaceCreateInfoFUCHSIA surface_create_info = {};
surface_create_info.sType =
VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA;
surface_create_info.flags = 0;
surface_create_info.imagePipeHandle = image_pipe_handle;
VkResult result = vkCreateImagePipeSurfaceFUCHSIA(
vulkan_instance_.vk_instance(), &surface_create_info, nullptr, &surface);
if (result != VK_SUCCESS) {
// This shouldn't fail, and we don't know whether imagePipeHandle was closed
// if it does.
LOG(FATAL) << "vkCreateImagePipeSurfaceFUCHSIA failed: " << result;
}
return std::make_unique<gpu::VulkanSurface>(vulkan_instance_.vk_instance(),
window, surface);
}
bool VulkanImplementationScenic::GetPhysicalDevicePresentationSupport(
VkPhysicalDevice physical_device,
const std::vector<VkQueueFamilyProperties>& queue_family_properties,
uint32_t queue_family_index) {
return true;
}
std::vector<const char*>
VulkanImplementationScenic::GetRequiredDeviceExtensions() {
std::vector<const char*> result = {
VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
};
// Following extensions are not supported by Swiftshader.
if (!use_swiftshader()) {
result.push_back(VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME);
result.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
if (using_surface_)
result.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
return result;
}
std::vector<const char*>
VulkanImplementationScenic::GetOptionalDeviceExtensions() {
return {};
}
VkFence VulkanImplementationScenic::CreateVkFenceForGpuFence(
VkDevice vk_device) {
NOTIMPLEMENTED();
return VK_NULL_HANDLE;
}
std::unique_ptr<gfx::GpuFence>
VulkanImplementationScenic::ExportVkFenceToGpuFence(VkDevice vk_device,
VkFence vk_fence) {
NOTIMPLEMENTED();
return nullptr;
}
VkExternalMemoryHandleTypeFlagBits
VulkanImplementationScenic::GetExternalImageHandleType() {
return VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
}
VkExternalSemaphoreHandleTypeFlagBits
VulkanImplementationScenic::GetExternalSemaphoreHandleType() {
return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA;
}
bool VulkanImplementationScenic::CanImportGpuMemoryBuffer(
gpu::VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferType memory_buffer_type) {
return memory_buffer_type == gfx::NATIVE_PIXMAP;
}
std::unique_ptr<gpu::VulkanImage>
VulkanImplementationScenic::CreateImageFromGpuMemoryHandle(
gpu::VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferHandle gmb_handle,
gfx::Size size,
VkFormat vk_format,
const gfx::ColorSpace& color_space) {
if (gmb_handle.type != gfx::NATIVE_PIXMAP)
return nullptr;
if (!gmb_handle.native_pixmap_handle.buffer_collection_handle) {
DLOG(ERROR) << "NativePixmapHandle.buffer_collection_handle is not set.";
return nullptr;
}
auto collection = sysmem_buffer_manager_->GetCollectionByHandle(
gmb_handle.native_pixmap_handle.buffer_collection_handle);
if (!collection) {
DLOG(ERROR) << "Tried to use an unknown buffer collection ID.";
return nullptr;
}
VkImage vk_image = VK_NULL_HANDLE;
VkImageCreateInfo vk_image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkDeviceMemory vk_device_memory = VK_NULL_HANDLE;
VkDeviceSize vk_device_size = 0;
if (!collection->CreateVkImage(gmb_handle.native_pixmap_handle.buffer_index,
device_queue->GetVulkanDevice(), size,
&vk_image, &vk_image_info, &vk_device_memory,
&vk_device_size)) {
DLOG(ERROR) << "CreateVkImage failed.";
return nullptr;
}
absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info;
if (collection->format() == gfx::BufferFormat::YUV_420_BIPLANAR) {
VkSamplerYcbcrModelConversion ycbcr_conversion =
(color_space.GetMatrixID() == gfx::ColorSpace::MatrixID::BT709)
? VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709
: VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
// Currently sysmem doesn't specify location of chroma samples relative to
// luma (see fxbug.dev/13677). Assume they are cosited with luma. Y'CbCr
// info here must match the values passed for the same buffer in
// FuchsiaVideoDecoder. |format_features| are resolved later in the GPU
// process before the ycbcr info is passed to Skia.
ycbcr_info = gpu::VulkanYCbCrInfo(
vk_image_info.format, /*external_format=*/0, ycbcr_conversion,
VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, VK_CHROMA_LOCATION_COSITED_EVEN,
VK_CHROMA_LOCATION_COSITED_EVEN, /*format_features=*/0);
}
auto image = gpu::VulkanImage::Create(
device_queue, vk_image, vk_device_memory, size, vk_image_info.format,
vk_image_info.tiling, vk_device_size, 0 /* memory_type_index */,
ycbcr_info, vk_image_info.usage, vk_image_info.flags);
if (image->format() != vk_format) {
DLOG(ERROR) << "Unexpected format " << vk_format << " vs "
<< image->format();
image->Destroy();
return nullptr;
}
image->set_queue_family_index(VK_QUEUE_FAMILY_EXTERNAL);
image->set_native_pixmap(collection->CreateNativePixmap(
std::move(gmb_handle.native_pixmap_handle), size));
return image;
}
void VulkanImplementationScenic::RegisterSysmemBufferCollection(
VkDevice device,
zx::eventpair service_handle,
zx::channel sysmem_token,
gfx::BufferFormat format,
gfx::BufferUsage usage,
gfx::Size size,
size_t min_buffer_count,
bool register_with_image_pipe) {
fuchsia::images::ImagePipe2Ptr image_pipe = nullptr;
sysmem_buffer_manager_->ImportSysmemBufferCollection(
device, std::move(service_handle), std::move(sysmem_token), size, format,
usage, min_buffer_count, register_with_image_pipe);
}
} // namespace ui

@ -1,79 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_SCENIC_VULKAN_IMPLEMENTATION_SCENIC_H_
#define UI_OZONE_PLATFORM_SCENIC_VULKAN_IMPLEMENTATION_SCENIC_H_
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <memory>
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_instance.h"
namespace ui {
class ScenicSurfaceFactory;
class SysmemBufferManager;
class VulkanImplementationScenic : public gpu::VulkanImplementation {
public:
VulkanImplementationScenic(ScenicSurfaceFactory* scenic_surface_factory,
SysmemBufferManager* sysmem_buffer_manager,
bool use_swiftshader,
bool allow_protected_memory);
VulkanImplementationScenic(const VulkanImplementationScenic&) = delete;
VulkanImplementationScenic& operator=(const VulkanImplementationScenic&) =
delete;
~VulkanImplementationScenic() override;
// VulkanImplementation:
bool InitializeVulkanInstance(bool using_surface) override;
gpu::VulkanInstance* GetVulkanInstance() override;
std::unique_ptr<gpu::VulkanSurface> CreateViewSurface(
gfx::AcceleratedWidget window) override;
bool GetPhysicalDevicePresentationSupport(
VkPhysicalDevice device,
const std::vector<VkQueueFamilyProperties>& queue_family_properties,
uint32_t queue_family_index) override;
std::vector<const char*> GetRequiredDeviceExtensions() override;
std::vector<const char*> GetOptionalDeviceExtensions() override;
VkFence CreateVkFenceForGpuFence(VkDevice vk_device) override;
std::unique_ptr<gfx::GpuFence> ExportVkFenceToGpuFence(
VkDevice vk_device,
VkFence vk_fence) override;
VkExternalMemoryHandleTypeFlagBits GetExternalImageHandleType() override;
VkExternalSemaphoreHandleTypeFlagBits GetExternalSemaphoreHandleType()
override;
bool CanImportGpuMemoryBuffer(
gpu::VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferType memory_buffer_type) override;
std::unique_ptr<gpu::VulkanImage> CreateImageFromGpuMemoryHandle(
gpu::VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferHandle gmb_handle,
gfx::Size size,
VkFormat vk_format,
const gfx::ColorSpace& color_space) override;
void RegisterSysmemBufferCollection(VkDevice device,
zx::eventpair service_handle,
zx::channel sysmem_token,
gfx::BufferFormat format,
gfx::BufferUsage usage,
gfx::Size size,
size_t min_buffer_count,
bool register_with_image_pipe) override;
private:
ScenicSurfaceFactory* const scenic_surface_factory_;
SysmemBufferManager* const sysmem_buffer_manager_;
gpu::VulkanInstance vulkan_instance_;
bool using_surface_ = false;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_SCENIC_VULKAN_IMPLEMENTATION_SCENIC_H_

@ -32,6 +32,8 @@ component("platform_window") {
"fuchsia/initialize_presenter_api_view.cc",
"fuchsia/initialize_presenter_api_view.h",
"fuchsia/scenic_window_delegate.h",
"fuchsia/view_ref_pair.cc",
"fuchsia/view_ref_pair.h",
]
public_deps += [

@ -5,8 +5,6 @@
#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
#include <lib/sys/cpp/component_context.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <zircon/rights.h>
#include <utility>

@ -0,0 +1,21 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/platform_window/fuchsia/view_ref_pair.h"
namespace ui {
ViewRefPair ViewRefPair::New() {
ViewRefPair ref_pair;
zx::eventpair::create(/*options*/ 0u, &ref_pair.control_ref.reference,
&ref_pair.view_ref.reference);
ref_pair.control_ref.reference.replace(
ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
&ref_pair.control_ref.reference);
ref_pair.view_ref.reference.replace(ZX_RIGHTS_BASIC,
&ref_pair.view_ref.reference);
return ref_pair;
}
} // namespace ui

@ -0,0 +1,27 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_PLATFORM_WINDOW_FUCHSIA_VIEW_REF_PAIR_H_
#define UI_PLATFORM_WINDOW_FUCHSIA_VIEW_REF_PAIR_H_
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/zx/eventpair.h>
#include <utility>
#include "base/component_export.h"
namespace ui {
struct COMPONENT_EXPORT(PLATFORM_WINDOW) ViewRefPair {
// ViewRef creation for the legacy graphics API. For Flatland, use
// scenic::NewViewIdentityOnCreation().
static ViewRefPair New();
fuchsia::ui::views::ViewRefControl control_ref;
fuchsia::ui::views::ViewRef view_ref;
};
} // namespace ui
#endif // UI_PLATFORM_WINDOW_FUCHSIA_VIEW_REF_PAIR_H_

@ -20,7 +20,7 @@
#include <fuchsia/element/cpp/fidl.h>
#include <fuchsia/ui/composition/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <ui/platform_window/fuchsia/view_ref_pair.h>
#endif
namespace gfx {
@ -91,7 +91,7 @@ struct COMPONENT_EXPORT(PLATFORM_WINDOW) PlatformWindowInitProperties {
fuchsia::ui::views::ViewToken view_token;
fuchsia::ui::views::ViewCreationToken view_creation_token;
scenic::ViewRefPair view_ref_pair;
ViewRefPair view_ref_pair;
// Used to coordinate window closure requests with the shell.
fuchsia::element::ViewControllerPtr view_controller;