1 // Copyright 2018 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/exo/wayland/clients/fullscreen_shell.h"
6
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/stringprintf.h"
11 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "third_party/skia/include/core/SkRefCnt.h"
13 #include "third_party/skia/include/core/SkSurface.h"
14 #include "third_party/skia/include/gpu/GrBackendSurface.h"
15 #include "third_party/skia/include/gpu/GrContext.h"
16 #include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
17 #include "third_party/skia/include/gpu/gl/GrGLInterface.h"
18 #include "ui/gfx/geometry/rect.h"
19 #include "ui/gfx/skia_util.h"
20 #include "ui/gl/gl_bindings.h"
21
22 namespace exo {
23 namespace wayland {
24 namespace clients {
25
26 namespace {
27
FrameCallback(void * data,wl_callback * callback,uint32_t time)28 void FrameCallback(void* data, wl_callback* callback, uint32_t time) {
29 bool* frame_callback_pending = static_cast<bool*>(data);
30 *frame_callback_pending = false;
31 }
32
33 } // namespace
34
35 ////////////////////////////////////////////////////////////////////////////////
36 // FullscreenClient, public:
37
FullscreenClient()38 FullscreenClient::FullscreenClient() {}
39
~FullscreenClient()40 FullscreenClient::~FullscreenClient() {}
41
Run(const InitParams & params)42 bool FullscreenClient::Run(const InitParams& params) {
43 wl_callback_listener frame_listener = {FrameCallback};
44
45 // Wait for screen mode to be received
46 while (wl_display_dispatch(display_.get()) != -1) {
47 if (done_receiving_modes_ && !has_mode_) {
48 LOG(ERROR) << "Did not receive screen mode";
49 return false;
50 } else if (has_mode_) {
51 break;
52 }
53 }
54
55 AllocateBuffers(params);
56
57 do {
58 if (frame_callback_pending_)
59 continue;
60
61 if (frame_count_ == frames_)
62 break;
63
64 Paint(frame_listener);
65
66 } while (wl_display_dispatch(display_.get()) != -1);
67
68 return true;
69 }
70
71 ////////////////////////////////////////////////////////////////////////////////
72 // FullscreenClient: Private
73
AllocateBuffers(const InitParams & params)74 void FullscreenClient::AllocateBuffers(const InitParams& params) {
75 for (size_t i = 0; i < params.num_buffers; ++i) {
76 auto buffer = CreateBuffer(size_, params.drm_format, params.bo_usage);
77 if (!buffer) {
78 LOG(ERROR) << "Failed to create buffer";
79 return;
80 }
81 buffers_.push_back(std::move(buffer));
82 }
83 }
84
Paint(const wl_callback_listener & frame_listener)85 void FullscreenClient::Paint(const wl_callback_listener& frame_listener) {
86 Buffer* buffer = DequeueBuffer();
87 if (!buffer)
88 return;
89
90 ++frame_count_;
91
92 int left = point_.x();
93 int top = point_.y();
94 int right = point_.x() + square_size_.width();
95 int bottom = point_.y() + square_size_.height();
96
97 if (right >= size_.width() || left <= 0) {
98 dir_x_ *= -1;
99 }
100
101 if (top <= 0 || bottom >= size_.height()) {
102 dir_y_ *= -1;
103 }
104
105 point_.set_x(point_.x() + dir_x_ * step_size_);
106 point_.set_y(point_.y() + dir_y_ * step_size_);
107
108 SkCanvas* canvas = buffer->sk_surface->getCanvas();
109 canvas->clear(color_);
110 const SkRect rect = gfx::RectToSkRect(gfx::Rect{point_, square_size_});
111 const SkPaint paint;
112 canvas->drawRect(rect, paint);
113
114 if (gr_context_) {
115 gr_context_->flush();
116 glFinish();
117 }
118
119 wl_surface_set_buffer_scale(surface_.get(), scale_);
120 wl_surface_set_buffer_transform(surface_.get(), transform_);
121 wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
122 surface_size_.height());
123 wl_surface_attach(surface_.get(), buffer->buffer.get(), 0, 0);
124
125 // Set up the frame callback.
126 frame_callback_pending_ = true;
127 frame_callback_.reset(wl_surface_frame(surface_.get()));
128 wl_callback_add_listener(frame_callback_.get(), &frame_listener,
129 &frame_callback_pending_);
130
131 wl_surface_commit(surface_.get());
132 wl_display_flush(display_.get());
133 }
134
HandleDown(void * data,struct wl_touch * wl_touch,uint32_t serial,uint32_t time,struct wl_surface * surface,int32_t id,wl_fixed_t x,wl_fixed_t y)135 void FullscreenClient::HandleDown(void* data,
136 struct wl_touch* wl_touch,
137 uint32_t serial,
138 uint32_t time,
139 struct wl_surface* surface,
140 int32_t id,
141 wl_fixed_t x,
142 wl_fixed_t y) {
143 if (color_ == SK_ColorBLUE) {
144 color_ = SK_ColorRED;
145 } else {
146 color_ = SK_ColorBLUE;
147 }
148 }
149
HandleMode(void * data,struct wl_output * wl_output,uint32_t flags,int32_t width,int32_t height,int32_t refresh)150 void FullscreenClient::HandleMode(void* data,
151 struct wl_output* wl_output,
152 uint32_t flags,
153 int32_t width,
154 int32_t height,
155 int32_t refresh) {
156 if ((WL_OUTPUT_MODE_CURRENT & flags) != WL_OUTPUT_MODE_CURRENT)
157 return;
158
159 size_.SetSize(width, height);
160 switch (transform_) {
161 case WL_OUTPUT_TRANSFORM_NORMAL:
162 case WL_OUTPUT_TRANSFORM_180:
163 surface_size_.SetSize(width, height);
164 break;
165 case WL_OUTPUT_TRANSFORM_90:
166 case WL_OUTPUT_TRANSFORM_270:
167 surface_size_.SetSize(height, width);
168 break;
169 default:
170 NOTREACHED();
171 break;
172 }
173
174 std::unique_ptr<wl_region> opaque_region(static_cast<wl_region*>(
175 wl_compositor_create_region(globals_.compositor.get())));
176
177 if (!opaque_region) {
178 LOG(ERROR) << "Can't create region";
179 return;
180 }
181
182 wl_region_add(opaque_region.get(), 0, 0, surface_size_.width(),
183 surface_size_.height());
184 wl_surface_set_opaque_region(surface_.get(), opaque_region.get());
185 wl_surface_set_input_region(surface_.get(), opaque_region.get());
186
187 has_mode_ = true;
188 }
189
HandleDone(void * data,struct wl_output * wl_output)190 void FullscreenClient::HandleDone(void* data, struct wl_output* wl_output) {
191 done_receiving_modes_ = true;
192 }
193
194 } // namespace clients
195 } // namespace wayland
196 } // namespace exo
197