Commit ba2f0e59 authored by kylechar's avatar kylechar Committed by Commit Bot

viz: Make UpdateLayeredWindow() work with OOP-D.

This CL adds a SoftwareOutputDevice implementation for Windows software
compositing to a layered window. The layered window API is required to
support transparency when DWM is disabled. Calling UpdateLayeredWindow()
is also blocked by the GPU sandbox.

To work around this SoftwareOutputDeviceWinProxy in the GPU process
draws into a shared memory buffer and sends an IPC to the browser
process. LayeredWindowUpdaterImpl receives the IPC and calls
UpdateLayeredWindow().

Having the browser process draw into an HWND with pixels produced in the
GPU process shouldn't be a security issue. The GPU process can already
draw into the HWND via other APIs. Drawing is clipped to the HWND size.

It's not ideal having to send an IPC from the GPU to browser process for
each draw. However, layered windows are the only way for an HWND to
guarantee it supports transparency on Windows 7. Having a child window
in the GPU process is not possible as layered windows are incompatible
with child windows for Windows 7.

HWNDs with transparent backgrounds are used infrequently and don't
update quickly so this should hopefully be performant enough. This code
is also only used for Windows 7.

Bug: 826633
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel
Change-Id: I3b2d749b75aed7789b19b3e8dfd7d0371ef6fe73
Reviewed-on: https://chromium-review.googlesource.com/1042283
Commit-Queue: kylechar <kylechar@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558462}
parent 7d6db08d
......@@ -181,6 +181,15 @@ viz_component("common") {
deps += [ "//gpu/vulkan" ]
}
if (is_win) {
sources += [
"display/use_layered_window.cc",
"display/use_layered_window.h",
]
deps += [ "//ui/base" ]
}
public_deps = [
":resource_format",
"//gpu/command_buffer/client",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/display/use_layered_window.h"
#include "base/win/windows_version.h"
#include "ui/base/win/internal_constants.h"
namespace viz {
bool NeedsToUseLayerWindow(HWND hwnd) {
return base::win::GetVersion() <= base::win::VERSION_WIN7 &&
GetProp(hwnd, ui::kWindowTranslucent);
}
} // namespace viz
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_COMMON_DISPLAY_USE_LAYERED_WINDOW_H_
#define COMPONENTS_VIZ_COMMON_DISPLAY_USE_LAYERED_WINDOW_H_
#include <windows.h>
#include "components/viz/common/viz_common_export.h"
namespace viz {
// Layered windows are a legacy way of supporting transparency for HWNDs. With
// Desktop Window Manager (DWM) HWNDs support transparency natively. DWM is
// always enabled on Windows 8 and later. However, for Windows 7 (and earlier)
// DWM might be disabled and layered windows are necessary to guarantee the HWND
// will support transparency.
VIZ_COMMON_EXPORT bool NeedsToUseLayerWindow(HWND hwnd);
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_DISPLAY_USE_LAYERED_WINDOW_H_
......@@ -21,6 +21,13 @@ viz_component("host") {
"viz_host_export.h",
]
if (is_win) {
sources += [
"layered_window_updater_impl.cc",
"layered_window_updater_impl.h",
]
}
deps = [
"//base",
"//components/viz/common",
......
......@@ -12,6 +12,8 @@ include_rules = [
"+services/viz/privileged/interfaces",
"+services/viz/public/interfaces",
"+services/viz/public/interfaces/hit_test",
"+skia",
"+third_party/skia",
]
specific_include_rules = {
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/host/layered_window_updater_impl.h"
#include "base/memory/shared_memory.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace viz {
LayeredWindowUpdaterImpl::LayeredWindowUpdaterImpl(
HWND hwnd,
mojom::LayeredWindowUpdaterRequest request)
: hwnd_(hwnd), binding_(this, std::move(request)) {}
LayeredWindowUpdaterImpl::~LayeredWindowUpdaterImpl() = default;
void LayeredWindowUpdaterImpl::OnAllocatedSharedMemory(
const gfx::Size& pixel_size,
mojo::ScopedSharedBufferHandle scoped_buffer_handle) {
canvas_.reset();
// Make sure |pixel_size| is sane.
size_t expected_bytes;
bool size_result = ResourceSizes::MaybeSizeInBytes(
pixel_size, ResourceFormat::RGBA_8888, &expected_bytes);
if (!size_result)
return;
base::SharedMemoryHandle shm_handle;
MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle(
std::move(scoped_buffer_handle), &shm_handle, nullptr, nullptr);
if (unwrap_result != MOJO_RESULT_OK)
return;
// The SkCanvas maps shared memory on creation and unmaps on destruction.
canvas_ = skia::CreatePlatformCanvasWithSharedSection(
pixel_size.width(), pixel_size.height(), true, shm_handle.GetHandle(),
skia::RETURN_NULL_ON_FAILURE);
shm_handle.Close();
}
void LayeredWindowUpdaterImpl::Draw(DrawCallback draw_callback) {
TRACE_EVENT0("viz", "LayeredWindowUpdaterImpl::Draw");
if (!canvas_) {
std::move(draw_callback).Run();
return;
}
// Set WS_EX_LAYERED extended window style if not already set.
DWORD style = GetWindowLong(hwnd_, GWL_EXSTYLE);
DCHECK(!(style & WS_EX_COMPOSITED));
if (!(style & WS_EX_LAYERED))
SetWindowLong(hwnd_, GWL_EXSTYLE, style | WS_EX_LAYERED);
// Draw to the HWND. If |canvas_| size doesn't match HWND size then it will be
// clipped or guttered accordingly.
RECT wr;
GetWindowRect(hwnd_, &wr);
SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
POINT position = {wr.left, wr.top};
POINT zero = {0, 0};
BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get());
UpdateLayeredWindow(hwnd_, nullptr, &position, &size, dib_dc, &zero,
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
std::move(draw_callback).Run();
}
} // namespace viz
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_HOST_LAYERED_WINDOW_UPDATER_IMPL_H_
#define COMPONENTS_VIZ_HOST_LAYERED_WINDOW_UPDATER_IMPL_H_
#include <windows.h>
#include <memory>
#include "base/macros.h"
#include "components/viz/host/viz_host_export.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h"
#include "ui/gfx/geometry/size.h"
class SkCanvas;
namespace viz {
// Makes layered window drawing syscalls. Updates a layered window from shared
// memory backing buffer that was drawn into by the GPU process. This is
// required as UpdateLayeredWindow() syscall is blocked by the GPU sandbox.
class VIZ_HOST_EXPORT LayeredWindowUpdaterImpl
: public mojom::LayeredWindowUpdater {
public:
LayeredWindowUpdaterImpl(HWND hwnd,
mojom::LayeredWindowUpdaterRequest request);
~LayeredWindowUpdaterImpl() override;
// mojom::LayeredWindowUpdater implementation.
void OnAllocatedSharedMemory(
const gfx::Size& pixel_size,
mojo::ScopedSharedBufferHandle scoped_buffer_handle) override;
void Draw(DrawCallback draw_callback) override;
private:
const HWND hwnd_;
mojo::Binding<mojom::LayeredWindowUpdater> binding_;
std::unique_ptr<SkCanvas> canvas_;
DISALLOW_COPY_AND_ASSIGN(LayeredWindowUpdaterImpl);
};
} // namespace viz
#endif // COMPONENTS_VIZ_HOST_LAYERED_WINDOW_UPDATER_IMPL_H_
......@@ -8,6 +8,7 @@
#include <memory>
#include "gpu/ipc/common/surface_handle.h"
#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
namespace viz {
......@@ -29,6 +30,7 @@ class DisplayProvider {
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) = 0;
......
......@@ -92,6 +92,7 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) {
......@@ -114,7 +115,7 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
if (!gpu_compositing) {
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle));
CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
} else if (renderer_settings.use_skia_renderer &&
renderer_settings.use_skia_deferred_display_list) {
#if defined(OS_MACOSX) || defined(OS_WIN)
......@@ -201,12 +202,14 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
std::unique_ptr<SoftwareOutputDevice>
GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
gpu::SurfaceHandle surface_handle) {
gpu::SurfaceHandle surface_handle,
mojom::DisplayClient* display_client) {
if (headless_)
return std::make_unique<SoftwareOutputDevice>();
#if defined(OS_WIN)
return CreateSoftwareOutputDeviceWin(surface_handle, &output_device_backing_);
return CreateSoftwareOutputDeviceWinGpu(
surface_handle, &output_device_backing_, display_client);
#elif defined(OS_MACOSX)
return std::make_unique<SoftwareOutputDeviceMac>(task_runner_);
#elif defined(OS_ANDROID)
......
......@@ -51,6 +51,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source)
......@@ -58,7 +59,8 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
private:
std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceForPlatform(
gpu::SurfaceHandle surface_handle);
gpu::SurfaceHandle surface_handle,
mojom::DisplayClient* display_client);
const uint32_t restart_id_;
GpuServiceImpl* const gpu_service_impl_;
......
......@@ -6,28 +6,20 @@
#include "base/memory/shared_memory.h"
#include "base/threading/thread_checker.h"
#include "base/win/windows_version.h"
#include "components/viz/common/display/use_layered_window.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/service/display_embedder/output_device_backing.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/win/internal_constants.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/skia_util.h"
namespace viz {
namespace {
bool NeedsToUseLayerWindow(HWND hwnd) {
// Layered windows are a legacy way of supporting transparency for HWNDs. With
// Desktop Window Manager (DWM) HWNDs support transparency natively. DWM is
// always enabled on Windows 8 and later. However, for Windows 7 (and earlier)
// DWM might be disabled and layered windows are necessary to guarantee the
// HWND will support transparency.
return base::win::GetVersion() <= base::win::VERSION_WIN7 &&
GetProp(hwnd, ui::kWindowTranslucent);
}
// Shared base class for Windows SoftwareOutputDevice implementations.
class SoftwareOutputDeviceWinBase : public SoftwareOutputDevice {
public:
......@@ -228,9 +220,121 @@ void SoftwareOutputDeviceWinLayered::EndPaintDelegated(
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
}
// SoftwareOutputDevice implementation that uses layered window API to draw
// indirectly. Since UpdateLayeredWindow() is blocked by the GPU sandbox an
// implementation of mojom::LayeredWindowUpdater in the browser process handles
// calling UpdateLayeredWindow. Pixel backing is in SharedMemory so no copying
// between processes is required.
class SoftwareOutputDeviceWinProxy : public SoftwareOutputDeviceWinBase {
public:
SoftwareOutputDeviceWinProxy(
HWND hwnd,
mojom::LayeredWindowUpdaterPtr layered_window_updater);
~SoftwareOutputDeviceWinProxy() override = default;
// SoftwareOutputDevice implementation.
void OnSwapBuffers(base::OnceClosure swap_ack_callback) override;
// SoftwareOutputDeviceWinBase implementation.
void ResizeDelegated() override;
SkCanvas* BeginPaintDelegated() override;
void EndPaintDelegated(const gfx::Rect& rect) override;
private:
// Runs |swap_ack_callback_| after draw has happened.
void DrawAck();
mojom::LayeredWindowUpdaterPtr layered_window_updater_;
std::unique_ptr<SkCanvas> canvas_;
bool waiting_on_draw_ack_ = false;
base::OnceClosure swap_ack_callback_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinProxy);
};
SoftwareOutputDeviceWinProxy::SoftwareOutputDeviceWinProxy(
HWND hwnd,
mojom::LayeredWindowUpdaterPtr layered_window_updater)
: SoftwareOutputDeviceWinBase(hwnd),
layered_window_updater_(std::move(layered_window_updater)) {
DCHECK(layered_window_updater_.is_bound());
}
void SoftwareOutputDeviceWinProxy::OnSwapBuffers(
base::OnceClosure swap_ack_callback) {
DCHECK(swap_ack_callback_.is_null());
// We aren't waiting on DrawAck() and can immediately run the callback.
if (!waiting_on_draw_ack_) {
task_runner_->PostTask(FROM_HERE, std::move(swap_ack_callback));
return;
}
swap_ack_callback_ = std::move(swap_ack_callback);
}
void SoftwareOutputDeviceWinProxy::ResizeDelegated() {
canvas_.reset();
size_t required_bytes;
if (!ResourceSizes::MaybeSizeInBytes(
viewport_pixel_size_, ResourceFormat::RGBA_8888, &required_bytes)) {
DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString();
return;
}
base::SharedMemory shm;
if (!shm.CreateAnonymous(required_bytes)) {
DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes";
return;
}
// The SkCanvas maps shared memory on creation and unmaps on destruction.
canvas_ = skia::CreatePlatformCanvasWithSharedSection(
viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
shm.handle().GetHandle(), skia::CRASH_ON_FAILURE);
// Transfer handle ownership to the browser process.
mojo::ScopedSharedBufferHandle scoped_handle = mojo::WrapSharedMemoryHandle(
shm.TakeHandle(), required_bytes,
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
layered_window_updater_->OnAllocatedSharedMemory(viewport_pixel_size_,
std::move(scoped_handle));
}
SkCanvas* SoftwareOutputDeviceWinProxy::BeginPaintDelegated() {
return canvas_.get();
}
void SoftwareOutputDeviceWinProxy::EndPaintDelegated(
const gfx::Rect& damage_rect) {
DCHECK(!waiting_on_draw_ack_);
if (!canvas_)
return;
layered_window_updater_->Draw(base::BindOnce(
&SoftwareOutputDeviceWinProxy::DrawAck, base::Unretained(this)));
waiting_on_draw_ack_ = true;
TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceWinProxy::Draw", this);
}
void SoftwareOutputDeviceWinProxy::DrawAck() {
DCHECK(waiting_on_draw_ack_);
DCHECK(!swap_ack_callback_.is_null());
TRACE_EVENT_ASYNC_END0("viz", "SoftwareOutputDeviceWinProxy::Draw", this);
waiting_on_draw_ack_ = false;
std::move(swap_ack_callback_).Run();
}
} // namespace
std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWin(
std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinBrowser(
HWND hwnd,
OutputDeviceBacking* backing) {
if (NeedsToUseLayerWindow(hwnd))
......@@ -239,4 +343,24 @@ std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWin(
return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing);
}
std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinGpu(
HWND hwnd,
OutputDeviceBacking* backing,
mojom::DisplayClient* display_client) {
if (NeedsToUseLayerWindow(hwnd)) {
DCHECK(display_client);
// Setup mojom::LayeredWindowUpdater implementation in the browser process
// to draw to the HWND.
mojom::LayeredWindowUpdaterPtr layered_window_updater;
display_client->CreateLayeredWindowUpdater(
mojo::MakeRequest(&layered_window_updater));
return std::make_unique<SoftwareOutputDeviceWinProxy>(
hwnd, std::move(layered_window_updater));
}
return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing);
}
} // namespace viz
......@@ -11,14 +11,23 @@
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/service/viz_service_export.h"
#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
namespace viz {
class OutputDeviceBacking;
// Creates an appropriate SoftwareOutputDevice implementation.
// Creates an appropriate SoftwareOutputDevice implementation for the browser
// process.
VIZ_SERVICE_EXPORT std::unique_ptr<SoftwareOutputDevice>
CreateSoftwareOutputDeviceWin(HWND hwnd, OutputDeviceBacking* backing);
CreateSoftwareOutputDeviceWinBrowser(HWND hwnd, OutputDeviceBacking* backing);
// Creates an appropriate SoftwareOutputDevice implementation for the GPU
// process.
VIZ_SERVICE_EXPORT std::unique_ptr<SoftwareOutputDevice>
CreateSoftwareOutputDeviceWinGpu(HWND hwnd,
OutputDeviceBacking* backing,
mojom::DisplayClient* display_client);
} // namespace viz
......
......@@ -144,11 +144,13 @@ void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
std::move(params->external_begin_frame_controller_client)));
}
mojom::DisplayClientPtr display_client(std::move(params->display_client));
std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source;
auto display = display_provider_->CreateDisplay(
params->frame_sink_id, params->widget, params->gpu_compositing,
external_begin_frame_controller.get(), params->renderer_settings,
&begin_frame_source);
display_client.get(), external_begin_frame_controller.get(),
params->renderer_settings, &begin_frame_source);
// Creating display failed. Drop the CompositorFrameSink message pipes here
// and let host send a new request, potential with a different compositing
......@@ -164,8 +166,7 @@ void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
std::move(params->compositor_frame_sink),
mojom::CompositorFrameSinkClientPtr(
std::move(params->compositor_frame_sink_client)),
std::move(params->display_private),
mojom::DisplayClientPtr(std::move(params->display_client)));
std::move(params->display_private), std::move(display_client));
}
void FrameSinkManagerImpl::CreateCompositorFrameSink(
......
......@@ -22,6 +22,8 @@ class MockDisplayClient : public mojom::DisplayClient {
MOCK_METHOD1(OnDisplayReceivedCALayerParams, void(const gfx::CALayerParams&));
MOCK_METHOD1(DidSwapAfterSnapshotRequestReceived,
void(const std::vector<ui::LatencyInfo>&));
MOCK_METHOD1(CreateLayeredWindowUpdater,
void(mojom::LayeredWindowUpdaterRequest));
private:
mojo::Binding<mojom::DisplayClient> binding_;
......
......@@ -20,6 +20,7 @@ std::unique_ptr<Display> TestDisplayProvider::CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) {
......
......@@ -24,6 +24,7 @@ class TestDisplayProvider : public DisplayProvider {
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source)
......
......@@ -244,7 +244,7 @@ GpuProcessTransportFactory::CreateSoftwareOutputDevice(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if defined(OS_WIN)
return CreateSoftwareOutputDeviceWin(widget, software_backing_.get());
return CreateSoftwareOutputDeviceWinBrowser(widget, software_backing_.get());
#elif defined(USE_OZONE)
ui::SurfaceFactoryOzone* factory =
ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
......
......@@ -10,11 +10,19 @@
#include "ui/accelerated_widget_mac/ca_layer_frame_sink.h"
#endif
#if defined(OS_WIN)
#include <windows.h>
#include "components/viz/common/display/use_layered_window.h"
#include "components/viz/host/layered_window_updater_impl.h"
#include "ui/base/win/internal_constants.h"
#endif
namespace content {
InProcessDisplayClient::InProcessDisplayClient(gfx::AcceleratedWidget widget)
: binding_(this) {
#if defined(OS_MACOSX)
#if defined(OS_MACOSX) || defined(OS_WIN)
widget_ = widget;
#endif
}
......@@ -47,4 +55,19 @@ void InProcessDisplayClient::DidSwapAfterSnapshotRequestReceived(
RenderWidgetHostImpl::OnGpuSwapBuffersCompleted(latency_info);
}
void InProcessDisplayClient::CreateLayeredWindowUpdater(
viz::mojom::LayeredWindowUpdaterRequest request) {
#if defined(OS_WIN)
if (!viz::NeedsToUseLayerWindow(widget_)) {
DLOG(ERROR) << "HWND shouldn't be using a layered window";
return;
}
layered_window_updater_ = std::make_unique<viz::LayeredWindowUpdaterImpl>(
widget_, std::move(request));
#else
// This should never happen on non-Windows platforms.
#endif
}
} // namespace content
......@@ -5,19 +5,26 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_IN_PROCESS_DISPLAY_CLIENT_H_
#define CONTENT_BROWSER_COMPOSITOR_IN_PROCESS_DISPLAY_CLIENT_H_
#include <memory>
#include <vector>
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
#include "ui/gfx/native_widget_types.h"
namespace viz {
class LayeredWindowUpdaterImpl;
}
namespace content {
// A DisplayClient that can be used to display received
// gfx::CALayerParams in a CALayer tree in this process.
class InProcessDisplayClient : public viz::mojom::DisplayClient {
public:
InProcessDisplayClient(gfx::AcceleratedWidget widget);
explicit InProcessDisplayClient(gfx::AcceleratedWidget widget);
~InProcessDisplayClient() override;
viz::mojom::DisplayClientPtr GetBoundPtr(
......@@ -29,11 +36,17 @@ class InProcessDisplayClient : public viz::mojom::DisplayClient {
const gfx::CALayerParams& ca_layer_params) override;
void DidSwapAfterSnapshotRequestReceived(
const std::vector<ui::LatencyInfo>& latency_info) override;
void CreateLayeredWindowUpdater(
viz::mojom::LayeredWindowUpdaterRequest request) override;
mojo::Binding<viz::mojom::DisplayClient> binding_;
#if defined(OS_MACOSX)
#if defined(OS_MACOSX) || defined(OS_WIN)
gfx::AcceleratedWidget widget_;
#endif
#if defined(OS_WIN)
std::unique_ptr<viz::LayeredWindowUpdaterImpl> layered_window_updater_;
#endif
};
} // namespace content
......
......@@ -10,6 +10,7 @@ mojom("compositing") {
"external_begin_frame_controller.mojom",
"frame_sink_manager.mojom",
"frame_sink_video_capture.mojom",
"layered_window_updater.mojom",
"renderer_settings.mojom",
]
......
......@@ -9,6 +9,7 @@ import "ui/gfx/mojo/ca_layer_params.mojom";
import "ui/gfx/mojo/color_space.mojom";
import "ui/gfx/mojo/transform.mojom";
import "ui/latency/mojo/latency_info.mojom";
import "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom";
// See ui/compositor/compositor.h: ContextFactoryPrivate.
// The DisplayPrivate is used by privileged clients to talk to Display.
......@@ -42,4 +43,10 @@ interface DisplayClient {
// Notifies that a swap has occured after some latency info with snapshot
// component reached the display.
DidSwapAfterSnapshotRequestReceived(array<ui.mojom.LatencyInfo> latency_info);
// WINDOWS ONLY: Create a LayeredWindowUpdater implementation to draw into
// layered window.
// Note: This will only be used when running Windows 7 and earlier with
// software compositing and a transparent HWND.
CreateLayeredWindowUpdater(LayeredWindowUpdater& layered_window_updater);
};
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module viz.mojom;
import "ui/gfx/geometry/mojo/geometry.mojom";
// The syscalls needed to update a layered window are blocked by the GPU
// sandbox. This interface lets the GPU draw into shared memory and then send
// an IPC to the browser to call UpdateLayeredWindow().
interface LayeredWindowUpdater {
// A new shared memory buffer has been allocated for |pixel_size|. The shared
// memory buffer must be at least big enough to contain |pixel_size| in
// RGBA_8888. The shared memory buffer will be used with subsequent calls to
// Draw().
OnAllocatedSharedMemory(
gfx.mojom.Size pixel_size,
handle<shared_buffer> scoped_buffer_handle
);
// Draws to the HWND by copying pixels from shared memory. Callback must be
// called after draw operation is complete to signal shared memory can be
// modified.
Draw() => ();
};
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