Commit e2c42e85 authored by Michael Spang's avatar Michael Spang Committed by Commit Bot

ozone: scenic: Move vulkan surface resources out of browser's Scenic session

This creates a new session with the system compositor (Scenic) and uses
it to create the vulkan surface resources. This is necessary in order to
support vulkan surfaces from the GPU process, since the browser Scenic
session will not be accessible there.

In order for this to work, we need to be able to run platform code when a
gpu::VulkanSurface is destroyed. To accomplish this, this adds a
destruction callback to gpu::VulkanSurface which cleans up the Scenic
resources associated with the surface.

Bug: 861853
Test: run_content_shell --ozone-platform=scenic --disable-gpu --enable-vulkan

Change-Id: If08c25746ba73569afae63040a7f6551861eeaad
Reviewed-on: https://chromium-review.googlesource.com/c/1343238
Commit-Queue: Michael Spang <spang@chromium.org>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611830}
parent 9d0b6c88
......@@ -4,6 +4,7 @@
#include "gpu/vulkan/android/vulkan_implementation_android.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "gpu/vulkan/vulkan_device_queue.h"
......@@ -69,7 +70,8 @@ std::unique_ptr<VulkanSurface> VulkanImplementationAndroid::CreateViewSurface(
return nullptr;
}
return std::make_unique<VulkanSurface>(GetVulkanInstance(), surface);
return std::make_unique<VulkanSurface>(GetVulkanInstance(), surface,
base::DoNothing());
}
bool VulkanImplementationAndroid::GetPhysicalDevicePresentationSupport(
......
......@@ -30,8 +30,12 @@ VulkanSurface::~VulkanSurface() {
DCHECK_EQ(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_);
}
VulkanSurface::VulkanSurface(VkInstance vk_instance, VkSurfaceKHR surface)
: vk_instance_(vk_instance), surface_(surface) {
VulkanSurface::VulkanSurface(VkInstance vk_instance,
VkSurfaceKHR surface,
base::OnceClosure destruction_callback)
: vk_instance_(vk_instance),
surface_(surface),
destruction_callback_(std::move(destruction_callback)) {
DCHECK_NE(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_);
}
......@@ -114,6 +118,7 @@ void VulkanSurface::Destroy() {
swap_chain_->Destroy();
vkDestroySurfaceKHR(vk_instance_, surface_, nullptr);
surface_ = VK_NULL_HANDLE;
std::move(destruction_callback_).Run();
}
gfx::SwapResult VulkanSurface::SwapBuffers() {
......
......@@ -7,6 +7,7 @@
#include <vulkan/vulkan.h>
#include "base/callback.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_export.h"
#include "gpu/vulkan/vulkan_swap_chain.h"
......@@ -29,7 +30,9 @@ class VULKAN_EXPORT VulkanSurface {
DEFAULT_SURFACE_FORMAT = FORMAT_RGBA_32
};
VulkanSurface(VkInstance vk_instance, VkSurfaceKHR surface);
VulkanSurface(VkInstance vk_instance,
VkSurfaceKHR surface,
base::OnceClosure destruction_callback);
~VulkanSurface();
......@@ -55,6 +58,9 @@ class VULKAN_EXPORT VulkanSurface {
VulkanDeviceQueue* device_queue_ = nullptr;
std::unique_ptr<VulkanSwapChain> swap_chain_;
// Called after destruction to clean up platform state, if any.
base::OnceClosure destruction_callback_;
DISALLOW_COPY_AND_ASSIGN(VulkanSurface);
};
......
......@@ -78,7 +78,8 @@ std::unique_ptr<VulkanSurface> VulkanImplementationWin32::CreateViewSurface(
return nullptr;
}
return std::make_unique<VulkanSurface>(GetVulkanInstance(), surface);
return std::make_unique<VulkanSurface>(GetVulkanInstance(), surface,
base::DoNothing());
}
bool VulkanImplementationWin32::GetPhysicalDevicePresentationSupport(
......
......@@ -4,6 +4,7 @@
#include "gpu/vulkan/x/vulkan_implementation_x11.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
......@@ -82,7 +83,8 @@ std::unique_ptr<VulkanSurface> VulkanImplementationX11::CreateViewSurface(
return nullptr;
}
return std::make_unique<VulkanSurface>(GetVulkanInstance(), surface);
return std::make_unique<VulkanSurface>(GetVulkanInstance(), surface,
base::DoNothing());
}
bool VulkanImplementationX11::GetPhysicalDevicePresentationSupport(
......
......@@ -6,6 +6,8 @@
#include <lib/zx/event.h>
#include "base/fuchsia/component_context.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "ui/gfx/native_pixmap.h"
......@@ -108,6 +110,17 @@ ScenicSurfaceFactory::ScenicSurfaceFactory(ScenicWindowManager* window_manager)
ScenicSurfaceFactory::~ScenicSurfaceFactory() = default;
fuchsia::ui::scenic::Scenic* ScenicSurfaceFactory::GetScenic() {
if (!scenic_) {
scenic_ = base::fuchsia::ComponentContext::GetDefault()
->ConnectToService<fuchsia::ui::scenic::Scenic>();
scenic_.set_error_handler([](zx_status_t status) {
ZX_LOG(FATAL, status) << "Scenic connection failed";
});
}
return scenic_.get();
}
std::vector<gl::GLImplementation>
ScenicSurfaceFactory::GetAllowedGLImplementations() {
// TODO(spang): Remove this after crbug.com/897208 is fixed.
......@@ -128,7 +141,7 @@ std::unique_ptr<SurfaceOzoneCanvas> ScenicSurfaceFactory::CreateCanvasForWidget(
ScenicWindow* window = window_manager_->GetWindow(widget);
if (!window)
return nullptr;
return std::make_unique<ScenicWindowCanvas>(window);
return std::make_unique<ScenicWindowCanvas>(GetScenic(), window);
}
scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
......@@ -142,7 +155,8 @@ scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
ScenicSurfaceFactory::CreateVulkanImplementation() {
return std::make_unique<ui::VulkanImplementationScenic>(window_manager_);
return std::make_unique<ui::VulkanImplementationScenic>(window_manager_,
GetScenic());
}
#endif
......
......@@ -5,6 +5,7 @@
#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 <memory>
#include <vector>
......@@ -38,8 +39,11 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
#endif
private:
fuchsia::ui::scenic::Scenic* GetScenic();
ScenicWindowManager* const window_manager_;
std::unique_ptr<GLOzone> egl_implementation_;
fuchsia::ui::scenic::ScenicPtr scenic_;
DISALLOW_COPY_AND_ASSIGN(ScenicSurfaceFactory);
};
......
......@@ -33,8 +33,8 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
scenic_session_(manager_->GetScenic()),
parent_node_(&scenic_session_),
node_(&scenic_session_),
shape_node_(&scenic_session_),
material_(&scenic_session_),
input_node_(&scenic_session_),
render_node_(&scenic_session_),
input_listener_binding_(this) {
scenic_session_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnScenicError));
......@@ -45,13 +45,19 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
zx::eventpair parent_export_token;
parent_node_.BindAsRequest(&parent_export_token);
// Setup entity node for the window.
node_.AddChild(shape_node_);
shape_node_.SetMaterial(material_);
// Subscribe to metrics events from the parent node. These events are used to
// get the device pixel ratio for the screen.
parent_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
parent_node_.AddChild(node_);
// Add input shape.
input_node_.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
node_.AddChild(input_node_);
// Add rendering subtree. Hit testing is disabled to prevent GPU process from
// receiving input.
render_node_.SetHitTestBehavior(fuchsia::ui::gfx::HitTestBehavior::kSuppress);
node_.AddChild(render_node_);
// Create the view.
manager_->GetViewManager()->CreateView2(
......@@ -83,12 +89,15 @@ ScenicWindow::~ScenicWindow() {
manager_->RemoveWindow(window_id_, this);
}
void ScenicWindow::SetTexture(const scenic::Image& image) {
material_.SetTexture(image);
}
void ScenicWindow::ExportRenderingEntity(zx::eventpair export_token) {
scenic::EntityNode export_node(&scenic_session_);
void ScenicWindow::SetTexture(uint32_t image_id) {
material_.SetTexture(image_id);
render_node_.DetachChildren();
render_node_.AddChild(export_node);
export_node.Export(std::move(export_token));
scenic_session_.Present(
/*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
}
gfx::Rect ScenicWindow::GetBounds() {
......@@ -190,10 +199,6 @@ void ScenicWindow::UpdateSize() {
if (screen)
screen->OnWindowBoundsChanged(window_id_, size_rect);
// Set node shape to rectangle that matches size of the view.
scenic::Rectangle rect(&scenic_session_, 1.f, 1.f);
shape_node_.SetShape(rect);
// Translate the node by half of the view dimensions to put it in the center
// of the view.
node_.SetTranslation(size_dips_.width() / 2.0, size_dips_.height() / 2.0,
......
......@@ -40,11 +40,8 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow,
~ScenicWindow() override;
scenic::Session* scenic_session() { return &scenic_session_; }
const scenic::Node& node() const { return node_; }
// Sets texture of the window. |image| must be created in scenic_session().
void SetTexture(const scenic::Image& image);
void SetTexture(uint32_t image_id);
void ExportRenderingEntity(zx::eventpair export_token);
// PlatformWindow implementation.
gfx::Rect GetBounds() override;
......@@ -106,17 +103,17 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow,
// Scenic session used for all drawing operations in this View.
scenic::Session scenic_session_;
// Node ID in |scenic_session_| for the parent view.
// Node in |scenic_session_| for the parent view.
scenic::ImportNode parent_node_;
// Node ID in |scenic_session_| for the view.
// Node in |scenic_session_| for the parent view.
scenic::EntityNode node_;
// Shape and material resources for the view in the context of
// |scenic_session_|. They are used to set shape and texture for the view
// node.
scenic::ShapeNode shape_node_;
scenic::Material material_;
// Node in |scenic_session_| for receiving input that hits within our View.
scenic::ShapeNode input_node_;
// Node in |scenic_session_| for rendering (hit testing disabled).
scenic::EntityNode render_node_;
// The ratio used for translating device-independent coordinates to absolute
// pixel coordinates.
......
......@@ -66,8 +66,21 @@ void ScenicWindowCanvas::Frame::CopyDirtyRegionFrom(const Frame& frame) {
dirty_region.setEmpty();
}
ScenicWindowCanvas::ScenicWindowCanvas(ScenicWindow* window)
: window_(window) {}
ScenicWindowCanvas::ScenicWindowCanvas(fuchsia::ui::scenic::Scenic* scenic,
ScenicWindow* window)
: window_(window),
scenic_session_(scenic),
parent_(&scenic_session_),
material_(&scenic_session_) {
scenic::ShapeNode shape(&scenic_session_);
shape.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
shape.SetMaterial(material_);
zx::eventpair export_token;
parent_.BindAsRequest(&export_token);
parent_.AddChild(shape);
window_->ExportRenderingEntity(std::move(export_token));
}
ScenicWindowCanvas::~ScenicWindowCanvas() = default;
......@@ -75,11 +88,9 @@ void ScenicWindowCanvas::ResizeCanvas(const gfx::Size& viewport_size) {
viewport_size_ = viewport_size;
viewport_size_.SetToMax(gfx::Size(1, 1));
scenic::Session* scenic = window_->scenic_session();
// Allocate new buffers with the new size.
for (int i = 0; i < kNumBuffers; ++i) {
frames_[i].Initialize(viewport_size_, scenic);
frames_[i].Initialize(viewport_size_, &scenic_session_);
}
}
......@@ -140,7 +151,7 @@ void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) {
viewport_size_.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
scenic::Image image(*frames_[current_frame_].scenic_memory, 0,
std::move(info));
window_->SetTexture(image);
material_.SetTexture(image);
// Create release fence for the current buffer or reset it if it already
// exists.
......@@ -161,10 +172,9 @@ void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) {
auto status = frames_[current_frame_].release_fence.duplicate(
ZX_RIGHT_SAME_RIGHTS, &release_fence_dup);
ZX_CHECK(status == ZX_OK, status);
window_->scenic_session()->EnqueueReleaseFence(std::move(release_fence_dup));
window_->scenic_session()->Present(
/*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
scenic_session_.EnqueueReleaseFence(std::move(release_fence_dup));
scenic_session_.Present(/*presentation_time=*/0,
[](fuchsia::images::PresentationInfo info) {});
// Move to the next buffer.
current_frame_ = (current_frame_ + 1) % kNumBuffers;
......
......@@ -12,6 +12,7 @@
#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_factory.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
namespace scenic {
......@@ -28,7 +29,8 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas {
public:
// |window| must outlive the surface. ScenicWindow owns the scenic::Session
// used in this class for all drawing operations.
explicit ScenicWindowCanvas(ScenicWindow* window);
explicit ScenicWindowCanvas(fuchsia::ui::scenic::Scenic* scenic,
ScenicWindow* window);
~ScenicWindowCanvas() override;
// SurfaceOzoneCanvas implementation.
......@@ -81,6 +83,10 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas {
// View size in device pixels.
gfx::Size viewport_size_;
scenic::Session scenic_session_;
scenic::ImportNode parent_;
scenic::Material material_;
DISALLOW_COPY_AND_ASSIGN(ScenicWindowCanvas);
};
......
......@@ -8,8 +8,10 @@
#include <lib/ui/scenic/cpp/session.h>
#include <lib/zx/channel.h>
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/macros.h"
#include "base/native_library.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_instance.h"
......@@ -21,9 +23,62 @@
namespace ui {
namespace {
// Holds resources necessary for presenting to a View using a VkSurfaceKHR.
class ScenicSurface {
public:
ScenicSurface(fuchsia::ui::scenic::Scenic* scenic)
: scenic_(scenic),
parent_(&scenic_),
shape_(&scenic_),
material_(&scenic_) {
shape_.SetShape(scenic::Rectangle(&scenic_, 1.f, 1.f));
shape_.SetMaterial(material_);
}
// Sets the texture of the surface to a new image pipe.
void SetTextureToNewImagePipe(
fidl::InterfaceRequest<fuchsia::images::ImagePipe> image_pipe_request) {
uint32_t image_pipe_id = scenic_.AllocResourceId();
scenic_.Enqueue(scenic::NewCreateImagePipeCmd(
image_pipe_id, std::move(image_pipe_request)));
material_.SetTexture(image_pipe_id);
scenic_.ReleaseResource(image_pipe_id);
}
// Imports a node to attach the surface to and returns its export token.
//
// Scenic does not care about order here; it's totally fine for imports to
// cause exports, and that's what's done here.
zx::eventpair Import() {
zx::eventpair export_token;
parent_.BindAsRequest(&export_token);
parent_.AddChild(shape_);
return export_token;
}
// Flushes commands to scenic & executes them.
void Commit() {
scenic_.Present(
/*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
}
private:
scenic::Session scenic_;
scenic::ImportNode parent_;
scenic::ShapeNode shape_;
scenic::Material material_;
DISALLOW_COPY_AND_ASSIGN(ScenicSurface);
};
} // namespace
VulkanImplementationScenic::VulkanImplementationScenic(
ScenicWindowManager* scenic_window_manager)
: scenic_window_manager_(scenic_window_manager) {}
ScenicWindowManager* scenic_window_manager,
fuchsia::ui::scenic::Scenic* scenic)
: scenic_window_manager_(scenic_window_manager), scenic_(scenic) {}
VulkanImplementationScenic::~VulkanImplementationScenic() = default;
......@@ -74,18 +129,18 @@ VkInstance VulkanImplementationScenic::GetVulkanInstance() {
std::unique_ptr<gpu::VulkanSurface>
VulkanImplementationScenic::CreateViewSurface(gfx::AcceleratedWidget window) {
std::unique_ptr<ScenicSurface> scenic_surface =
std::make_unique<ScenicSurface>(scenic_);
// Attach the surface to the window.
// TODO(spang): Use IPC rather than direct call for this step so that it will
// work from the GPU process.
ScenicWindow* scenic_window = scenic_window_manager_->GetWindow(window);
if (!scenic_window)
return nullptr;
scenic::Session* scenic_session = scenic_window->scenic_session();
if (scenic_window)
scenic_window->ExportRenderingEntity(scenic_surface->Import());
fuchsia::images::ImagePipePtr image_pipe;
uint32_t image_pipe_id = scenic_session->AllocResourceId();
scenic_session->Enqueue(
scenic::NewCreateImagePipeCmd(image_pipe_id, image_pipe.NewRequest()));
scenic_window->SetTexture(image_pipe_id);
scenic_session->ReleaseResource(image_pipe_id);
scenic_session->Present(/*presentation_time=*/0,
[](fuchsia::images::PresentationInfo info) {});
scenic_surface->SetTextureToNewImagePipe(image_pipe.NewRequest());
VkSurfaceKHR surface;
VkMagmaSurfaceCreateInfoKHR surface_create_info = {};
......@@ -102,7 +157,17 @@ VulkanImplementationScenic::CreateViewSurface(gfx::AcceleratedWidget window) {
LOG(FATAL) << "vkCreateMagmaSurfaceKHR failed: " << result;
}
return std::make_unique<gpu::VulkanSurface>(GetVulkanInstance(), surface);
// Execute the initialization commands. Once this is done we won't need to
// make any further changes to ScenicSurface other than to keep it alive; the
// texture can be replaced through the vulkan swapchain API.
scenic_surface->Commit();
auto destruction_callback =
base::BindOnce(base::DoNothing::Once<std::unique_ptr<ScenicSurface>>(),
std::move(scenic_surface));
return std::make_unique<gpu::VulkanSurface>(GetVulkanInstance(), surface,
std::move(destruction_callback));
}
bool VulkanImplementationScenic::GetPhysicalDevicePresentationSupport(
......
......@@ -5,6 +5,7 @@
#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"
......@@ -16,7 +17,8 @@ class ScenicWindowManager;
class VulkanImplementationScenic : public gpu::VulkanImplementation {
public:
VulkanImplementationScenic(ScenicWindowManager* scenic_window_manager);
VulkanImplementationScenic(ScenicWindowManager* scenic_window_manager,
fuchsia::ui::scenic::Scenic* scenic);
~VulkanImplementationScenic() override;
// VulkanImplementation:
......@@ -36,6 +38,7 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation {
private:
ScenicWindowManager* const scenic_window_manager_;
fuchsia::ui::scenic::Scenic* const scenic_;
gpu::VulkanInstance vulkan_instance_;
PFN_vkVoidFunction vkCreateMagmaSurfaceKHR_ = nullptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment