1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/viz/service/display_embedder/skia_output_device_x11.h"
6
7 #include <utility>
8
9 #include "base/logging.h"
10 #include "base/memory/ref_counted_memory.h"
11 #include "third_party/skia/include/core/SkSurface.h"
12 #include "third_party/skia/include/gpu/GrBackendSurface.h"
13 #include "third_party/skia/include/gpu/vk/GrVkTypes.h"
14 #include "ui/base/x/x11_util.h"
15 #include "ui/gfx/geometry/rect.h"
16 #include "ui/gfx/x/xproto.h"
17
18 namespace viz {
19
20 namespace {
21
CreateGC(x11::Connection * connection,x11::Window window)22 x11::GraphicsContext CreateGC(x11::Connection* connection, x11::Window window) {
23 auto gc = connection->GenerateId<x11::GraphicsContext>();
24 connection->CreateGC({gc, window});
25 return gc;
26 }
27
28 } // namespace
29
SkiaOutputDeviceX11(scoped_refptr<gpu::SharedContextState> context_state,gfx::AcceleratedWidget widget,gpu::MemoryTracker * memory_tracker,DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)30 SkiaOutputDeviceX11::SkiaOutputDeviceX11(
31 scoped_refptr<gpu::SharedContextState> context_state,
32 gfx::AcceleratedWidget widget,
33 gpu::MemoryTracker* memory_tracker,
34 DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
35 : SkiaOutputDeviceOffscreen(context_state,
36 gfx::SurfaceOrigin::kTopLeft,
37 true /* has_alpha */,
38 memory_tracker,
39 did_swap_buffer_complete_callback),
40 connection_(x11::Connection::Get()),
41 window_(static_cast<x11::Window>(widget)),
42 gc_(CreateGC(connection_, window_)) {
43 if (auto attributes = connection_->GetWindowAttributes({window_}).Sync()) {
44 visual_ = attributes->visual;
45 } else {
46 LOG(FATAL) << "Failed to get attributes for window "
47 << static_cast<uint32_t>(window_);
48 }
49
50 // |capabilities_| should be set by SkiaOutputDeviceOffscreen.
51 DCHECK_EQ(capabilities_.output_surface_origin, gfx::SurfaceOrigin::kTopLeft);
52 DCHECK(capabilities_.supports_post_sub_buffer);
53 }
54
~SkiaOutputDeviceX11()55 SkiaOutputDeviceX11::~SkiaOutputDeviceX11() {
56 connection_->FreeGC({gc_});
57 }
58
Reshape(const gfx::Size & size,float device_scale_factor,const gfx::ColorSpace & color_space,gfx::BufferFormat format,gfx::OverlayTransform transform)59 bool SkiaOutputDeviceX11::Reshape(const gfx::Size& size,
60 float device_scale_factor,
61 const gfx::ColorSpace& color_space,
62 gfx::BufferFormat format,
63 gfx::OverlayTransform transform) {
64 if (!SkiaOutputDeviceOffscreen::Reshape(size, device_scale_factor,
65 color_space, format, transform)) {
66 return false;
67 }
68 auto ii =
69 SkImageInfo::MakeN32(size.width(), size.height(), kOpaque_SkAlphaType);
70 std::vector<uint8_t> mem(ii.computeMinByteSize());
71 pixels_ = base::RefCountedBytes::TakeVector(&mem);
72 return true;
73 }
74
SwapBuffers(BufferPresentedCallback feedback,std::vector<ui::LatencyInfo> latency_info)75 void SkiaOutputDeviceX11::SwapBuffers(
76 BufferPresentedCallback feedback,
77 std::vector<ui::LatencyInfo> latency_info) {
78 return PostSubBuffer(
79 gfx::Rect(0, 0, sk_surface_->width(), sk_surface_->height()),
80 std::move(feedback), std::move(latency_info));
81 }
82
PostSubBuffer(const gfx::Rect & rect,BufferPresentedCallback feedback,std::vector<ui::LatencyInfo> latency_info)83 void SkiaOutputDeviceX11::PostSubBuffer(
84 const gfx::Rect& rect,
85 BufferPresentedCallback feedback,
86 std::vector<ui::LatencyInfo> latency_info) {
87 StartSwapBuffers(std::move(feedback));
88 if (!rect.IsEmpty()) {
89 auto ii =
90 SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType);
91 DCHECK_GE(pixels_->size(), ii.computeMinByteSize());
92 SkPixmap sk_pixmap(ii, pixels_->data(), ii.minRowBytes());
93 bool result = sk_surface_->readPixels(sk_pixmap, rect.x(), rect.y());
94 LOG_IF(FATAL, !result) << "Failed to read pixels from offscreen SkSurface.";
95
96 // TODO(penghuang): Switch to XShmPutImage.
97 ui::DrawPixmap(x11::Connection::Get(), visual_, window_, gc_, sk_pixmap,
98 0 /* src_x */, 0 /* src_y */, rect.x() /* dst_x */,
99 rect.y() /* dst_y */, rect.width(), rect.height());
100
101 connection_->Flush();
102 }
103 FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
104 gfx::Size(sk_surface_->width(), sk_surface_->height()),
105 std::move(latency_info));
106 }
107
108 } // namespace viz
109