| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Implementation of a client that produces output in the form of RGBA | 5 // Implementation of a client that produces output in the form of RGBA |
| 6 // buffers when receiving pointer/touch events. RGB contains the lower | 6 // buffers when receiving pointer/touch events. RGB contains the lower |
| 7 // 24 bits of the event timestamp and A is 0xff. | 7 // 24 bits of the event timestamp and A is 0xff. |
| 8 | 8 |
| 9 #include <fcntl.h> | |
| 10 #include <linux-dmabuf-unstable-v1-client-protocol.h> | |
| 11 #include <wayland-client-core.h> | 9 #include <wayland-client-core.h> |
| 12 #include <wayland-client-protocol.h> | 10 #include <wayland-client-protocol.h> |
| 13 | 11 |
| 14 #include <iostream> | 12 #include <iostream> |
| 15 #include <vector> | 13 #include <vector> |
| 16 | 14 |
| 17 #include "base/at_exit.h" | |
| 18 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 19 #include "base/logging.h" | 16 #include "base/logging.h" |
| 20 #include "base/macros.h" | 17 #include "base/macros.h" |
| 21 #include "base/memory/shared_memory.h" | 18 #include "base/memory/shared_memory.h" |
| 22 #include "base/scoped_generic.h" | |
| 23 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 24 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 25 #include "third_party/skia/include/core/SkCanvas.h" | 21 #include "third_party/skia/include/core/SkCanvas.h" |
| 26 #include "third_party/skia/include/core/SkRefCnt.h" | 22 #include "third_party/skia/include/core/SkRefCnt.h" |
| 27 #include "third_party/skia/include/core/SkSurface.h" | 23 #include "third_party/skia/include/core/SkSurface.h" |
| 28 #include "third_party/skia/include/gpu/GrContext.h" | |
| 29 #include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h" | |
| 30 #include "third_party/skia/include/gpu/gl/GrGLInterface.h" | |
| 31 #include "ui/gl/gl_bindings.h" | |
| 32 #include "ui/gl/gl_context.h" | |
| 33 #include "ui/gl/gl_enums.h" | |
| 34 #include "ui/gl/gl_surface.h" | |
| 35 #include "ui/gl/gl_surface_egl.h" | |
| 36 #include "ui/gl/init/gl_factory.h" | |
| 37 #include "ui/gl/scoped_make_current.h" | |
| 38 | 24 |
| 39 #if defined(OZONE_PLATFORM_GBM) | 25 // Convenient macro that is used to define default deleters for wayland object |
| 40 #include <drm_fourcc.h> | |
| 41 #include <gbm.h> | |
| 42 #endif | |
| 43 | |
| 44 // Convenient macro that is used to define default deleters for object | |
| 45 // types allowing them to be used with std::unique_ptr. | 26 // types allowing them to be used with std::unique_ptr. |
| 46 #define DEFAULT_DELETER(TypeName, DeleteFunction) \ | 27 #define DEFAULT_DELETER(TypeName, DeleteFunction) \ |
| 47 namespace std { \ | 28 namespace std { \ |
| 48 template <> \ | 29 template <> \ |
| 49 struct default_delete<TypeName> { \ | 30 struct default_delete<TypeName> { \ |
| 50 void operator()(TypeName* ptr) { DeleteFunction(ptr); } \ | 31 void operator()(TypeName* ptr) { DeleteFunction(ptr); } \ |
| 51 }; \ | 32 }; \ |
| 52 } | 33 } |
| 53 | 34 |
| 54 DEFAULT_DELETER(wl_display, wl_display_disconnect) | 35 DEFAULT_DELETER(wl_display, wl_display_disconnect) |
| 55 DEFAULT_DELETER(wl_compositor, wl_compositor_destroy) | 36 DEFAULT_DELETER(wl_compositor, wl_compositor_destroy) |
| 56 DEFAULT_DELETER(wl_shm, wl_shm_destroy) | 37 DEFAULT_DELETER(wl_shm, wl_shm_destroy) |
| 57 DEFAULT_DELETER(wl_shm_pool, wl_shm_pool_destroy) | 38 DEFAULT_DELETER(wl_shm_pool, wl_shm_pool_destroy) |
| 58 DEFAULT_DELETER(wl_buffer, wl_buffer_destroy) | 39 DEFAULT_DELETER(wl_buffer, wl_buffer_destroy) |
| 59 DEFAULT_DELETER(wl_surface, wl_surface_destroy) | 40 DEFAULT_DELETER(wl_surface, wl_surface_destroy) |
| 60 DEFAULT_DELETER(wl_region, wl_region_destroy) | 41 DEFAULT_DELETER(wl_region, wl_region_destroy) |
| 61 DEFAULT_DELETER(wl_shell, wl_shell_destroy) | 42 DEFAULT_DELETER(wl_shell, wl_shell_destroy) |
| 62 DEFAULT_DELETER(wl_shell_surface, wl_shell_surface_destroy) | 43 DEFAULT_DELETER(wl_shell_surface, wl_shell_surface_destroy) |
| 63 DEFAULT_DELETER(wl_seat, wl_seat_destroy) | 44 DEFAULT_DELETER(wl_seat, wl_seat_destroy) |
| 64 DEFAULT_DELETER(wl_pointer, wl_pointer_destroy) | 45 DEFAULT_DELETER(wl_pointer, wl_pointer_destroy) |
| 65 DEFAULT_DELETER(wl_touch, wl_touch_destroy) | 46 DEFAULT_DELETER(wl_touch, wl_touch_destroy) |
| 66 DEFAULT_DELETER(wl_callback, wl_callback_destroy) | 47 DEFAULT_DELETER(wl_callback, wl_callback_destroy) |
| 67 DEFAULT_DELETER(zwp_linux_buffer_params_v1, zwp_linux_buffer_params_v1_destroy) | |
| 68 DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy) | |
| 69 | |
| 70 #if defined(OZONE_PLATFORM_GBM) | |
| 71 DEFAULT_DELETER(gbm_device, gbm_device_destroy) | |
| 72 DEFAULT_DELETER(gbm_bo, gbm_bo_destroy) | |
| 73 #endif | |
| 74 | 48 |
| 75 namespace exo { | 49 namespace exo { |
| 76 namespace wayland { | 50 namespace wayland { |
| 77 namespace clients { | 51 namespace clients { |
| 78 namespace { | 52 namespace { |
| 79 | 53 |
| 80 // Title for the wayland client. | |
| 81 const char kClientTitle[] = "Motion Event Client"; | |
| 82 | |
| 83 // Buffer format. | 54 // Buffer format. |
| 84 const int32_t kShmFormat = WL_SHM_FORMAT_ARGB8888; | 55 const int32_t kFormat = WL_SHM_FORMAT_ARGB8888; |
| 85 const SkColorType kColorType = kBGRA_8888_SkColorType; | 56 const SkColorType kColorType = kBGRA_8888_SkColorType; |
| 86 #if defined(OZONE_PLATFORM_GBM) | |
| 87 const GrPixelConfig kGrPixelConfig = kBGRA_8888_GrPixelConfig; | |
| 88 const int32_t kDrmFormat = DRM_FORMAT_ABGR8888; | |
| 89 #endif | |
| 90 const size_t kBytesPerPixel = 4; | 57 const size_t kBytesPerPixel = 4; |
| 91 | 58 |
| 92 #if defined(OZONE_PLATFORM_GBM) | |
| 93 // DRI render node path. | |
| 94 const char kDriRenderNode[] = "/dev/dri/renderD128"; | |
| 95 #endif | |
| 96 | |
| 97 // Number of buffers. | 59 // Number of buffers. |
| 98 const size_t kBuffers = 3; | 60 const size_t kBuffers = 2; |
| 99 | 61 |
| 100 // Rotation speed (degrees/second). | 62 // Rotation speed (degrees/second). |
| 101 const double kRotationSpeed = 360.0; | 63 const double kRotationSpeed = 360.0; |
| 102 | 64 |
| 103 // Benchmark interval in seconds. | 65 // Benchmark interval in seconds. |
| 104 const int kBenchmarkInterval = 5; | 66 const int kBenchmarkInterval = 5; |
| 105 | 67 |
| 106 struct Globals { | 68 struct Globals { |
| 107 std::unique_ptr<wl_compositor> compositor; | 69 std::unique_ptr<wl_compositor> compositor; |
| 108 std::unique_ptr<wl_shm> shm; | 70 std::unique_ptr<wl_shm> shm; |
| 109 std::unique_ptr<zwp_linux_dmabuf_v1> linux_dmabuf; | |
| 110 std::unique_ptr<wl_shell> shell; | 71 std::unique_ptr<wl_shell> shell; |
| 111 std::unique_ptr<wl_seat> seat; | 72 std::unique_ptr<wl_seat> seat; |
| 112 }; | 73 }; |
| 113 | 74 |
| 114 void RegistryHandler(void* data, | 75 void RegistryHandler(void* data, |
| 115 wl_registry* registry, | 76 wl_registry* registry, |
| 116 uint32_t id, | 77 uint32_t id, |
| 117 const char* interface, | 78 const char* interface, |
| 118 uint32_t version) { | 79 uint32_t version) { |
| 119 Globals* globals = static_cast<Globals*>(data); | 80 Globals* globals = static_cast<Globals*>(data); |
| 120 | 81 |
| 121 if (strcmp(interface, "wl_compositor") == 0) { | 82 if (strcmp(interface, "wl_compositor") == 0) { |
| 122 globals->compositor.reset(static_cast<wl_compositor*>( | 83 globals->compositor.reset(static_cast<wl_compositor*>( |
| 123 wl_registry_bind(registry, id, &wl_compositor_interface, 3))); | 84 wl_registry_bind(registry, id, &wl_compositor_interface, 3))); |
| 124 } else if (strcmp(interface, "wl_shm") == 0) { | 85 } else if (strcmp(interface, "wl_shm") == 0) { |
| 125 globals->shm.reset(static_cast<wl_shm*>( | 86 globals->shm.reset(static_cast<wl_shm*>( |
| 126 wl_registry_bind(registry, id, &wl_shm_interface, 1))); | 87 wl_registry_bind(registry, id, &wl_shm_interface, 1))); |
| 127 } else if (strcmp(interface, "wl_shell") == 0) { | 88 } else if (strcmp(interface, "wl_shell") == 0) { |
| 128 globals->shell.reset(static_cast<wl_shell*>( | 89 globals->shell.reset(static_cast<wl_shell*>( |
| 129 wl_registry_bind(registry, id, &wl_shell_interface, 1))); | 90 wl_registry_bind(registry, id, &wl_shell_interface, 1))); |
| 130 } else if (strcmp(interface, "wl_seat") == 0) { | 91 } else if (strcmp(interface, "wl_seat") == 0) { |
| 131 globals->seat.reset(static_cast<wl_seat*>( | 92 globals->seat.reset(static_cast<wl_seat*>( |
| 132 wl_registry_bind(registry, id, &wl_seat_interface, 5))); | 93 wl_registry_bind(registry, id, &wl_seat_interface, 5))); |
| 133 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) { | |
| 134 globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>( | |
| 135 wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1))); | |
| 136 } | 94 } |
| 137 } | 95 } |
| 138 | 96 |
| 139 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { | 97 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { |
| 140 LOG(WARNING) << "Got a registry losing event for " << id; | 98 LOG(WARNING) << "Got a registry losing event for " << id; |
| 141 } | 99 } |
| 142 | 100 |
| 143 #if defined(OZONE_PLATFORM_GBM) | |
| 144 struct DeleteTextureTraits { | |
| 145 static GLuint InvalidValue() { return 0; } | |
| 146 static void Free(GLuint texture) { glDeleteTextures(1, &texture); } | |
| 147 }; | |
| 148 using ScopedTexture = base::ScopedGeneric<GLuint, DeleteTextureTraits>; | |
| 149 | |
| 150 struct DeleteEglImageTraits { | |
| 151 static EGLImageKHR InvalidValue() { return 0; } | |
| 152 static void Free(EGLImageKHR image) { | |
| 153 eglDestroyImageKHR(eglGetCurrentDisplay(), image); | |
| 154 } | |
| 155 }; | |
| 156 using ScopedEglImage = base::ScopedGeneric<EGLImageKHR, DeleteEglImageTraits>; | |
| 157 #endif | |
| 158 | |
| 159 struct Buffer { | 101 struct Buffer { |
| 160 std::unique_ptr<wl_buffer> buffer; | 102 std::unique_ptr<wl_buffer> buffer; |
| 103 sk_sp<SkSurface> sk_surface; |
| 161 bool busy = false; | 104 bool busy = false; |
| 162 #if defined(OZONE_PLATFORM_GBM) | |
| 163 std::unique_ptr<gbm_bo> bo; | |
| 164 std::unique_ptr<ScopedEglImage> egl_image; | |
| 165 std::unique_ptr<ScopedTexture> texture; | |
| 166 #endif | |
| 167 std::unique_ptr<zwp_linux_buffer_params_v1> params; | |
| 168 base::SharedMemory shared_memory; | |
| 169 std::unique_ptr<wl_shm_pool> shm_pool; | |
| 170 sk_sp<SkSurface> sk_surface; | |
| 171 }; | 105 }; |
| 172 | 106 |
| 173 void BufferRelease(void* data, wl_buffer* /* buffer */) { | 107 void BufferRelease(void* data, wl_buffer* /* buffer */) { |
| 174 Buffer* buffer = static_cast<Buffer*>(data); | 108 Buffer* buffer = static_cast<Buffer*>(data); |
| 175 | 109 |
| 176 buffer->busy = false; | 110 buffer->busy = false; |
| 177 } | 111 } |
| 178 | 112 |
| 179 using EventTimeStack = std::vector<uint32_t>; | 113 using EventTimeStack = std::vector<uint32_t>; |
| 180 | 114 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 }; | 197 }; |
| 264 | 198 |
| 265 void FrameCallback(void* data, wl_callback* callback, uint32_t time) { | 199 void FrameCallback(void* data, wl_callback* callback, uint32_t time) { |
| 266 Frame* frame = static_cast<Frame*>(data); | 200 Frame* frame = static_cast<Frame*>(data); |
| 267 | 201 |
| 268 static uint32_t initial_time = time; | 202 static uint32_t initial_time = time; |
| 269 frame->time = time - initial_time; | 203 frame->time = time - initial_time; |
| 270 frame->callback_pending = false; | 204 frame->callback_pending = false; |
| 271 } | 205 } |
| 272 | 206 |
| 273 #if defined(OZONE_PLATFORM_GBM) | |
| 274 void LinuxBufferParamsCreated(void* data, | |
| 275 zwp_linux_buffer_params_v1* params, | |
| 276 wl_buffer* new_buffer) { | |
| 277 Buffer* buffer = static_cast<Buffer*>(data); | |
| 278 buffer->buffer.reset(new_buffer); | |
| 279 } | |
| 280 | |
| 281 void LinuxBufferParamsFailed(void* data, zwp_linux_buffer_params_v1* params) { | |
| 282 LOG(ERROR) << "Linux buffer params failed"; | |
| 283 } | |
| 284 | |
| 285 const GrGLInterface* GrGLCreateNativeInterface() { | |
| 286 return GrGLAssembleInterface(nullptr, [](void* ctx, const char name[]) { | |
| 287 return eglGetProcAddress(name); | |
| 288 }); | |
| 289 } | |
| 290 #endif | |
| 291 | |
| 292 } // namespace | 207 } // namespace |
| 293 | 208 |
| 294 class MotionEvents { | 209 class MotionEvents { |
| 295 public: | 210 public: |
| 296 MotionEvents(size_t width, | 211 MotionEvents(size_t width, |
| 297 size_t height, | 212 size_t height, |
| 298 int scale, | 213 int scale, |
| 299 size_t num_rects, | 214 size_t num_rects, |
| 300 bool use_drm, | |
| 301 bool fullscreen) | 215 bool fullscreen) |
| 302 : width_(width), | 216 : width_(width), |
| 303 height_(height), | 217 height_(height), |
| 304 scale_(scale), | 218 scale_(scale), |
| 305 num_rects_(num_rects), | 219 num_rects_(num_rects), |
| 306 use_drm_(use_drm), | |
| 307 fullscreen_(fullscreen) {} | 220 fullscreen_(fullscreen) {} |
| 308 | 221 |
| 309 // Initialize and run client main loop. | 222 // Initialize and run client main loop. |
| 310 int Run(); | 223 int Run(); |
| 311 | 224 |
| 312 private: | 225 private: |
| 313 bool CreateBuffer(Buffer* buffer); | |
| 314 size_t stride() const { return width_ * kBytesPerPixel; } | 226 size_t stride() const { return width_ * kBytesPerPixel; } |
| 315 size_t buffer_size() const { return stride() * height_; } | 227 size_t buffer_size() const { return stride() * height_; } |
| 316 | 228 |
| 317 const size_t width_; | 229 const size_t width_; |
| 318 const size_t height_; | 230 const size_t height_; |
| 319 const int scale_; | 231 const int scale_; |
| 320 const size_t num_rects_; | 232 const size_t num_rects_; |
| 321 const bool use_drm_; | |
| 322 const bool fullscreen_; | 233 const bool fullscreen_; |
| 323 | 234 |
| 324 Globals globals_; | |
| 325 std::unique_ptr<wl_display> display_; | |
| 326 | |
| 327 #if defined(OZONE_PLATFORM_GBM) | |
| 328 base::ScopedFD drm_fd_; | |
| 329 std::unique_ptr<gbm_device> device_; | |
| 330 #endif | |
| 331 | |
| 332 scoped_refptr<gl::GLSurface> gl_surface_; | |
| 333 scoped_refptr<gl::GLContext> gl_context_; | |
| 334 std::unique_ptr<ui::ScopedMakeCurrent> make_current_; | |
| 335 | |
| 336 Buffer buffers_[kBuffers]; | |
| 337 sk_sp<GrContext> gr_context_; | |
| 338 | |
| 339 DISALLOW_COPY_AND_ASSIGN(MotionEvents); | 235 DISALLOW_COPY_AND_ASSIGN(MotionEvents); |
| 340 }; | 236 }; |
| 341 | 237 |
| 342 int MotionEvents::Run() { | 238 int MotionEvents::Run() { |
| 343 display_.reset(wl_display_connect(nullptr)); | 239 std::unique_ptr<wl_display> display(wl_display_connect(nullptr)); |
| 344 if (!display_) { | 240 if (!display) { |
| 345 LOG(ERROR) << "wl_display_connect failed"; | 241 LOG(ERROR) << "wl_display_connect failed"; |
| 346 return 1; | 242 return 1; |
| 347 } | 243 } |
| 348 | 244 |
| 349 bool gl_initialized = gl::init::InitializeGLOneOff(); | |
| 350 DCHECK(gl_initialized); | |
| 351 gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); | |
| 352 gl_context_ = | |
| 353 gl::init::CreateGLContext(nullptr, // share_group | |
| 354 gl_surface_.get(), gl::PreferIntegratedGpu); | |
| 355 | |
| 356 make_current_.reset( | |
| 357 new ui::ScopedMakeCurrent(gl_context_.get(), gl_surface_.get())); | |
| 358 wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover}; | 245 wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover}; |
| 359 | 246 |
| 360 wl_registry* registry = wl_display_get_registry(display_.get()); | 247 Globals globals; |
| 361 wl_registry_add_listener(registry, ®istry_listener, &globals_); | 248 wl_registry* registry = wl_display_get_registry(display.get()); |
| 249 wl_registry_add_listener(registry, ®istry_listener, &globals); |
| 362 | 250 |
| 363 wl_display_roundtrip(display_.get()); | 251 wl_display_roundtrip(display.get()); |
| 364 | 252 |
| 365 if (!globals_.compositor) { | 253 if (!globals.compositor) { |
| 366 LOG(ERROR) << "Can't find compositor interface"; | 254 LOG(ERROR) << "Can't find compositor interface"; |
| 367 return 1; | 255 return 1; |
| 368 } | 256 } |
| 369 if (!globals_.shm) { | 257 if (!globals.shm) { |
| 370 LOG(ERROR) << "Can't find shm interface"; | 258 LOG(ERROR) << "Can't find shm interface"; |
| 371 return 1; | 259 return 1; |
| 372 } | 260 } |
| 373 if (use_drm_ && !globals_.linux_dmabuf) { | 261 if (!globals.shell) { |
| 374 LOG(ERROR) << "Can't find linux_dmabuf interface"; | |
| 375 return 1; | |
| 376 } | |
| 377 if (!globals_.shell) { | |
| 378 LOG(ERROR) << "Can't find shell interface"; | 262 LOG(ERROR) << "Can't find shell interface"; |
| 379 return 1; | 263 return 1; |
| 380 } | 264 } |
| 381 if (!globals_.seat) { | 265 if (!globals.seat) { |
| 382 LOG(ERROR) << "Can't find seat interface"; | 266 LOG(ERROR) << "Can't find seat interface"; |
| 383 return 1; | 267 return 1; |
| 384 } | 268 } |
| 385 | 269 |
| 386 #if defined(OZONE_PLATFORM_GBM) | |
| 387 drm_fd_.reset(open(kDriRenderNode, O_RDWR)); | |
| 388 if (drm_fd_.get() < 0) { | |
| 389 LOG(ERROR) << "Can't open drm device '" << kDriRenderNode << "'"; | |
| 390 return 1; | |
| 391 } | |
| 392 | |
| 393 device_.reset(gbm_create_device(drm_fd_.get())); | |
| 394 if (!device_) { | |
| 395 LOG(ERROR) << "Can't create gbm device"; | |
| 396 return 1; | |
| 397 } | |
| 398 sk_sp<const GrGLInterface> native_interface(GrGLCreateNativeInterface()); | |
| 399 DCHECK(native_interface); | |
| 400 gr_context_ = sk_sp<GrContext>(GrContext::Create( | |
| 401 kOpenGL_GrBackend, | |
| 402 reinterpret_cast<GrBackendContext>(native_interface.get()))); | |
| 403 DCHECK(gr_context_); | |
| 404 #endif | |
| 405 | |
| 406 wl_buffer_listener buffer_listener = {BufferRelease}; | 270 wl_buffer_listener buffer_listener = {BufferRelease}; |
| 407 | 271 |
| 272 Buffer buffers[kBuffers]; |
| 273 base::SharedMemory shared_memory; |
| 274 shared_memory.CreateAndMapAnonymous(buffer_size() * kBuffers); |
| 275 std::unique_ptr<wl_shm_pool> shm_pool( |
| 276 wl_shm_create_pool(globals.shm.get(), shared_memory.handle().fd, |
| 277 shared_memory.requested_size())); |
| 408 for (size_t i = 0; i < kBuffers; ++i) { | 278 for (size_t i = 0; i < kBuffers; ++i) { |
| 409 if (!CreateBuffer(&buffers_[i])) | 279 buffers[i].buffer.reset(static_cast<wl_buffer*>( |
| 280 wl_shm_pool_create_buffer(shm_pool.get(), i * buffer_size(), width_, |
| 281 height_, stride(), kFormat))); |
| 282 if (!buffers[i].buffer) { |
| 283 LOG(ERROR) << "Can't create buffer"; |
| 410 return 1; | 284 return 1; |
| 411 } | 285 } |
| 412 wl_display_roundtrip(display_.get()); | 286 buffers[i].sk_surface = SkSurface::MakeRasterDirect( |
| 413 for (size_t i = 0; i < kBuffers; ++i) { | 287 SkImageInfo::Make(width_, height_, kColorType, kOpaque_SkAlphaType), |
| 414 if (!buffers_[i].buffer) | 288 static_cast<uint8_t*>(shared_memory.memory()) + buffer_size() * i, |
| 289 stride()); |
| 290 if (!buffers[i].sk_surface) { |
| 291 LOG(ERROR) << "Can't create SkSurface"; |
| 415 return 1; | 292 return 1; |
| 416 | 293 } |
| 417 wl_buffer_add_listener(buffers_[i].buffer.get(), &buffer_listener, | 294 wl_buffer_add_listener(buffers[i].buffer.get(), &buffer_listener, |
| 418 &buffers_[i]); | 295 &buffers[i]); |
| 419 } | 296 } |
| 420 | 297 |
| 421 std::unique_ptr<wl_surface> surface(static_cast<wl_surface*>( | 298 std::unique_ptr<wl_surface> surface(static_cast<wl_surface*>( |
| 422 wl_compositor_create_surface(globals_.compositor.get()))); | 299 wl_compositor_create_surface(globals.compositor.get()))); |
| 423 if (!surface) { | 300 if (!surface) { |
| 424 LOG(ERROR) << "Can't create surface"; | 301 LOG(ERROR) << "Can't create surface"; |
| 425 return 1; | 302 return 1; |
| 426 } | 303 } |
| 427 | 304 |
| 428 std::unique_ptr<wl_region> opaque_region(static_cast<wl_region*>( | 305 std::unique_ptr<wl_region> opaque_region(static_cast<wl_region*>( |
| 429 wl_compositor_create_region(globals_.compositor.get()))); | 306 wl_compositor_create_region(globals.compositor.get()))); |
| 430 if (!opaque_region) { | 307 if (!opaque_region) { |
| 431 LOG(ERROR) << "Can't create region"; | 308 LOG(ERROR) << "Can't create region"; |
| 432 return 1; | 309 return 1; |
| 433 } | 310 } |
| 434 | 311 |
| 435 wl_region_add(opaque_region.get(), 0, 0, width_, height_); | 312 wl_region_add(opaque_region.get(), 0, 0, width_, height_); |
| 436 wl_surface_set_opaque_region(surface.get(), opaque_region.get()); | 313 wl_surface_set_opaque_region(surface.get(), opaque_region.get()); |
| 437 | 314 |
| 438 std::unique_ptr<wl_shell_surface> shell_surface( | 315 std::unique_ptr<wl_shell_surface> shell_surface( |
| 439 static_cast<wl_shell_surface*>( | 316 static_cast<wl_shell_surface*>( |
| 440 wl_shell_get_shell_surface(globals_.shell.get(), surface.get()))); | 317 wl_shell_get_shell_surface(globals.shell.get(), surface.get()))); |
| 441 if (!shell_surface) { | 318 if (!shell_surface) { |
| 442 LOG(ERROR) << "Can't get shell surface"; | 319 LOG(ERROR) << "Can't get shell surface"; |
| 443 return 1; | 320 return 1; |
| 444 } | 321 } |
| 445 | 322 |
| 446 wl_shell_surface_set_title(shell_surface.get(), kClientTitle); | 323 wl_shell_surface_set_title(shell_surface.get(), "Test Client"); |
| 447 | |
| 448 if (fullscreen_) { | 324 if (fullscreen_) { |
| 449 wl_shell_surface_set_fullscreen(shell_surface.get(), | 325 wl_shell_surface_set_fullscreen(shell_surface.get(), |
| 450 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, | 326 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, |
| 451 0, nullptr); | 327 0, nullptr); |
| 452 } else { | 328 } else { |
| 453 wl_shell_surface_set_toplevel(shell_surface.get()); | 329 wl_shell_surface_set_toplevel(shell_surface.get()); |
| 454 } | 330 } |
| 455 | 331 |
| 456 EventTimeStack event_times; | 332 EventTimeStack event_times; |
| 457 | 333 |
| 458 std::unique_ptr<wl_pointer> pointer( | 334 std::unique_ptr<wl_pointer> pointer( |
| 459 static_cast<wl_pointer*>(wl_seat_get_pointer(globals_.seat.get()))); | 335 static_cast<wl_pointer*>(wl_seat_get_pointer(globals.seat.get()))); |
| 460 if (!pointer) { | 336 if (!pointer) { |
| 461 LOG(ERROR) << "Can't get pointer"; | 337 LOG(ERROR) << "Can't get pointer"; |
| 462 return 1; | 338 return 1; |
| 463 } | 339 } |
| 464 | 340 |
| 465 wl_pointer_listener pointer_listener = { | 341 wl_pointer_listener pointer_listener = { |
| 466 PointerEnter, PointerLeave, PointerMotion, | 342 PointerEnter, PointerLeave, PointerMotion, |
| 467 PointerButton, PointerAxis, PointerFrame, | 343 PointerButton, PointerAxis, PointerFrame, |
| 468 PointerAxisSource, PointerAxisStop, PointerDiscrete}; | 344 PointerAxisSource, PointerAxisStop, PointerDiscrete}; |
| 469 wl_pointer_add_listener(pointer.get(), &pointer_listener, &event_times); | 345 wl_pointer_add_listener(pointer.get(), &pointer_listener, &event_times); |
| 470 | 346 |
| 471 std::unique_ptr<wl_touch> touch( | 347 std::unique_ptr<wl_touch> touch( |
| 472 static_cast<wl_touch*>(wl_seat_get_touch(globals_.seat.get()))); | 348 static_cast<wl_touch*>(wl_seat_get_touch(globals.seat.get()))); |
| 473 if (!touch) { | 349 if (!touch) { |
| 474 LOG(ERROR) << "Can't get touch"; | 350 LOG(ERROR) << "Can't get touch"; |
| 475 return 1; | 351 return 1; |
| 476 } | 352 } |
| 477 | 353 |
| 478 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, | 354 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, |
| 479 TouchFrame, TouchCancel}; | 355 TouchFrame, TouchCancel}; |
| 480 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); | 356 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); |
| 481 | 357 |
| 482 Frame frame; | 358 Frame frame; |
| 483 std::unique_ptr<wl_callback> frame_callback; | 359 std::unique_ptr<wl_callback> frame_callback; |
| 484 wl_callback_listener frame_listener = {FrameCallback}; | 360 wl_callback_listener frame_listener = {FrameCallback}; |
| 485 | 361 |
| 486 uint32_t frames = 0; | 362 uint32_t frames = 0; |
| 487 base::TimeTicks benchmark_time = base::TimeTicks::Now(); | 363 base::TimeTicks benchmark_time = base::TimeTicks::Now(); |
| 488 base::TimeDelta benchmark_interval = | 364 base::TimeDelta benchmark_interval = |
| 489 base::TimeDelta::FromSeconds(kBenchmarkInterval); | 365 base::TimeDelta::FromSeconds(kBenchmarkInterval); |
| 490 | 366 |
| 491 do { | 367 do { |
| 492 if (frame.callback_pending) | 368 if (frame.callback_pending) |
| 493 continue; | 369 continue; |
| 494 | 370 |
| 495 Buffer* buffer = | 371 Buffer* buffer = |
| 496 std::find_if(std::begin(buffers_), std::end(buffers_), | 372 std::find_if(std::begin(buffers), std::end(buffers), |
| 497 [](const Buffer& buffer) { return !buffer.busy; }); | 373 [](const Buffer& buffer) { return !buffer.busy; }); |
| 498 if (buffer == std::end(buffers_)) | 374 if (buffer == std::end(buffers)) |
| 499 continue; | 375 continue; |
| 500 | 376 |
| 501 base::TimeTicks current_time = base::TimeTicks::Now(); | 377 base::TimeTicks current_time = base::TimeTicks::Now(); |
| 502 if ((current_time - benchmark_time) > benchmark_interval) { | 378 if ((current_time - benchmark_time) > benchmark_interval) { |
| 503 std::cout << frames << " frames in " << benchmark_interval.InSeconds() | 379 std::cout << frames << " frames in " << benchmark_interval.InSeconds() |
| 504 << " seconds: " | 380 << " seconds: " |
| 505 << static_cast<double>(frames) / benchmark_interval.InSeconds() | 381 << static_cast<double>(frames) / benchmark_interval.InSeconds() |
| 506 << " fps" << std::endl; | 382 << " fps" << std::endl; |
| 507 benchmark_time = current_time; | 383 benchmark_time = current_time; |
| 508 frames = 0; | 384 frames = 0; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 canvas->translate(half_width, half_height); | 418 canvas->translate(half_width, half_height); |
| 543 for (size_t i = 0; i < num_rects_; ++i) { | 419 for (size_t i = 0; i < num_rects_; ++i) { |
| 544 const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, | 420 const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, |
| 545 SK_ColorRED, SK_ColorYELLOW, | 421 SK_ColorRED, SK_ColorYELLOW, |
| 546 SK_ColorCYAN, SK_ColorMAGENTA}; | 422 SK_ColorCYAN, SK_ColorMAGENTA}; |
| 547 paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); | 423 paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); |
| 548 canvas->rotate(rotation / num_rects_); | 424 canvas->rotate(rotation / num_rects_); |
| 549 canvas->drawIRect(rect, paint); | 425 canvas->drawIRect(rect, paint); |
| 550 } | 426 } |
| 551 canvas->restore(); | 427 canvas->restore(); |
| 552 if (gr_context_) { | 428 |
| 553 gr_context_->flush(); | |
| 554 glFinish(); | |
| 555 } | |
| 556 wl_surface_set_buffer_scale(surface.get(), scale_); | 429 wl_surface_set_buffer_scale(surface.get(), scale_); |
| 557 wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); | 430 wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); |
| 558 buffer->busy = true; | 431 buffer->busy = true; |
| 559 | 432 |
| 560 frame_callback.reset(wl_surface_frame(surface.get())); | 433 frame_callback.reset(wl_surface_frame(surface.get())); |
| 561 wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); | 434 wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); |
| 562 frame.callback_pending = true; | 435 frame.callback_pending = true; |
| 563 | 436 |
| 564 ++frames; | 437 ++frames; |
| 565 | 438 |
| 566 wl_surface_commit(surface.get()); | 439 wl_surface_commit(surface.get()); |
| 567 } while (wl_display_dispatch(display_.get()) != -1); | 440 } while (wl_display_dispatch(display.get()) != -1); |
| 568 | 441 |
| 569 return 0; | 442 return 0; |
| 570 } | 443 } |
| 571 | 444 |
| 572 bool MotionEvents::CreateBuffer(Buffer* buffer) { | |
| 573 #if defined(OZONE_PLATFORM_GBM) | |
| 574 if (use_drm_) { | |
| 575 buffer->bo.reset(gbm_bo_create(device_.get(), width_, height_, kDrmFormat, | |
| 576 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING)); | |
| 577 if (!buffer->bo) { | |
| 578 LOG(ERROR) << "Can't create gbm buffer"; | |
| 579 return false; | |
| 580 } | |
| 581 base::ScopedFD fd(gbm_bo_get_plane_fd(buffer->bo.get(), 0)); | |
| 582 static const zwp_linux_buffer_params_v1_listener params_listener = { | |
| 583 LinuxBufferParamsCreated, LinuxBufferParamsFailed}; | |
| 584 | |
| 585 buffer->params.reset( | |
| 586 zwp_linux_dmabuf_v1_create_params(globals_.linux_dmabuf.get())); | |
| 587 zwp_linux_buffer_params_v1_add_listener(buffer->params.get(), | |
| 588 ¶ms_listener, buffer); | |
| 589 zwp_linux_buffer_params_v1_add(buffer->params.get(), fd.get(), 0, 0, | |
| 590 stride(), 0, 0); | |
| 591 zwp_linux_buffer_params_v1_create(buffer->params.get(), width_, height_, | |
| 592 kDrmFormat, 0); | |
| 593 | |
| 594 EGLint khr_image_attrs[] = {EGL_DMA_BUF_PLANE0_FD_EXT, | |
| 595 fd.get(), | |
| 596 EGL_WIDTH, | |
| 597 width_, | |
| 598 EGL_HEIGHT, | |
| 599 height_, | |
| 600 EGL_LINUX_DRM_FOURCC_EXT, | |
| 601 kDrmFormat, | |
| 602 EGL_DMA_BUF_PLANE0_PITCH_EXT, | |
| 603 stride(), | |
| 604 EGL_DMA_BUF_PLANE0_OFFSET_EXT, | |
| 605 0, | |
| 606 EGL_NONE}; | |
| 607 EGLImageKHR image = eglCreateImageKHR( | |
| 608 eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, | |
| 609 nullptr /* no client buffer */, khr_image_attrs); | |
| 610 | |
| 611 buffer->egl_image.reset(new ScopedEglImage(image)); | |
| 612 GLuint texture = 0; | |
| 613 glGenTextures(1, &texture); | |
| 614 buffer->texture.reset(new ScopedTexture(texture)); | |
| 615 glBindTexture(GL_TEXTURE_2D, buffer->texture->get()); | |
| 616 glEGLImageTargetTexture2DOES( | |
| 617 GL_TEXTURE_2D, static_cast<GLeglImageOES>(buffer->egl_image->get())); | |
| 618 glBindTexture(GL_TEXTURE_2D, 0); | |
| 619 | |
| 620 GrGLTextureInfo texture_info; | |
| 621 texture_info.fID = buffer->texture->get(); | |
| 622 texture_info.fTarget = GL_TEXTURE_2D; | |
| 623 GrBackendTextureDesc desc; | |
| 624 desc.fFlags = kRenderTarget_GrBackendTextureFlag; | |
| 625 desc.fWidth = width_; | |
| 626 desc.fHeight = height_; | |
| 627 desc.fConfig = kGrPixelConfig; | |
| 628 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 629 desc.fTextureHandle = reinterpret_cast<GrBackendObject>(&texture_info); | |
| 630 | |
| 631 buffer->sk_surface = SkSurface::MakeFromBackendTextureAsRenderTarget( | |
| 632 gr_context_.get(), desc, nullptr); | |
| 633 DCHECK(buffer->sk_surface); | |
| 634 return true; | |
| 635 } | |
| 636 #endif | |
| 637 buffer->shared_memory.CreateAndMapAnonymous(buffer_size()); | |
| 638 buffer->shm_pool.reset( | |
| 639 wl_shm_create_pool(globals_.shm.get(), buffer->shared_memory.handle().fd, | |
| 640 buffer->shared_memory.requested_size())); | |
| 641 | |
| 642 buffer->buffer.reset(static_cast<wl_buffer*>(wl_shm_pool_create_buffer( | |
| 643 buffer->shm_pool.get(), 0, width_, height_, stride(), kShmFormat))); | |
| 644 if (!buffer->buffer) { | |
| 645 LOG(ERROR) << "Can't create buffer"; | |
| 646 return false; | |
| 647 } | |
| 648 | |
| 649 buffer->sk_surface = SkSurface::MakeRasterDirect( | |
| 650 SkImageInfo::Make(width_, height_, kColorType, kOpaque_SkAlphaType), | |
| 651 static_cast<uint8_t*>(buffer->shared_memory.memory()), stride()); | |
| 652 DCHECK(buffer->sk_surface); | |
| 653 return true; | |
| 654 } | |
| 655 | |
| 656 } // namespace clients | 445 } // namespace clients |
| 657 } // namespace wayland | 446 } // namespace wayland |
| 658 } // namespace exo | 447 } // namespace exo |
| 659 | 448 |
| 660 namespace switches { | 449 namespace switches { |
| 661 | 450 |
| 662 // Specifies the client buffer size. | 451 // Specifies the client buffer size. |
| 663 const char kSize[] = "size"; | 452 const char kSize[] = "size"; |
| 664 | 453 |
| 665 // Specifies the client scale factor (ie. number of physical pixels per DIP). | 454 // Specifies the client scale factor (ie. number of physical pixels per DIP). |
| 666 const char kScale[] = "scale"; | 455 const char kScale[] = "scale"; |
| 667 | 456 |
| 668 // Specifies the number of rotating rects to draw. | 457 // Specifies the number of rotating rects to draw. |
| 669 const char kNumRects[] = "num-rects"; | 458 const char kNumRects[] = "num-rects"; |
| 670 | 459 |
| 671 // Use drm buffer instead of shared memory. | |
| 672 const char kUseDrm[] = "use-drm"; | |
| 673 | |
| 674 // Specifies if client should be fullscreen. | 460 // Specifies if client should be fullscreen. |
| 675 const char kFullscreen[] = "fullscreen"; | 461 const char kFullscreen[] = "fullscreen"; |
| 676 | 462 |
| 677 } // namespace switches | 463 } // namespace switches |
| 678 | 464 |
| 679 int main(int argc, char* argv[]) { | 465 int main(int argc, char* argv[]) { |
| 680 base::AtExitManager exit_manager; | 466 base::CommandLine command_line(argc, argv); |
| 681 base::CommandLine::Init(argc, argv); | |
| 682 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 683 | 467 |
| 684 int width = 256; | 468 int width = 256; |
| 685 int height = 256; | 469 int height = 256; |
| 686 if (command_line->HasSwitch(switches::kSize)) { | 470 if (command_line.HasSwitch(switches::kSize)) { |
| 687 std::string size_str = command_line->GetSwitchValueASCII(switches::kSize); | 471 std::string size_str = command_line.GetSwitchValueASCII(switches::kSize); |
| 688 if (sscanf(size_str.c_str(), "%dx%d", &width, &height) != 2) { | 472 if (sscanf(size_str.c_str(), "%dx%d", &width, &height) != 2) { |
| 689 LOG(ERROR) << "Invalid value for " << switches::kSize; | 473 LOG(ERROR) << "Invalid value for " << switches::kSize; |
| 690 return 1; | 474 return 1; |
| 691 } | 475 } |
| 692 } | 476 } |
| 693 | 477 |
| 694 int scale = 1; | 478 int scale = 1; |
| 695 if (command_line->HasSwitch(switches::kScale) && | 479 if (command_line.HasSwitch(switches::kScale) && |
| 696 !base::StringToInt(command_line->GetSwitchValueASCII(switches::kScale), | 480 !base::StringToInt(command_line.GetSwitchValueASCII(switches::kScale), |
| 697 &scale)) { | 481 &scale)) { |
| 698 LOG(ERROR) << "Invalid value for " << switches::kScale; | 482 LOG(ERROR) << "Invalid value for " << switches::kScale; |
| 699 return 1; | 483 return 1; |
| 700 } | 484 } |
| 701 | 485 |
| 702 size_t num_rects = 1; | 486 size_t num_rects = 1; |
| 703 if (command_line->HasSwitch(switches::kNumRects) && | 487 if (command_line.HasSwitch(switches::kNumRects) && |
| 704 !base::StringToSizeT( | 488 !base::StringToSizeT( |
| 705 command_line->GetSwitchValueASCII(switches::kNumRects), &num_rects)) { | 489 command_line.GetSwitchValueASCII(switches::kNumRects), &num_rects)) { |
| 706 LOG(ERROR) << "Invalid value for " << switches::kNumRects; | 490 LOG(ERROR) << "Invalid value for " << switches::kNumRects; |
| 707 return 1; | 491 return 1; |
| 708 } | 492 } |
| 709 | 493 |
| 710 bool use_drm = command_line->HasSwitch(switches::kUseDrm); | 494 bool fullscreen = command_line.HasSwitch(switches::kFullscreen); |
| 711 bool fullscreen = command_line->HasSwitch(switches::kFullscreen); | |
| 712 | 495 |
| 713 exo::wayland::clients::MotionEvents client(width, height, scale, num_rects, | 496 exo::wayland::clients::MotionEvents client(width, height, scale, num_rects, |
| 714 use_drm, fullscreen); | 497 fullscreen); |
| 715 return client.Run(); | 498 return client.Run(); |
| 716 } | 499 } |
| OLD | NEW |