Chromium Code Reviews| Index: components/exo/wayland/clients/motion_events.cc |
| diff --git a/components/exo/wayland/clients/motion_events.cc b/components/exo/wayland/clients/motion_events.cc |
| index 99e38eba2b79c3ddac9e12daf2ca9fc85fdb2ec3..239dadab37f791076f4ebc34c0739b2d1e7d9f82 100644 |
| --- a/components/exo/wayland/clients/motion_events.cc |
| +++ b/components/exo/wayland/clients/motion_events.cc |
| @@ -6,11 +6,27 @@ |
| // buffers when receiving pointer/touch events. RGB contains the lower |
| // 24 bits of the event timestamp and A is 0xff. |
| +#include <fcntl.h> |
| +#include <linux-dmabuf-unstable-v1-client-protocol.h> |
| #include <wayland-client-core.h> |
| #include <wayland-client-protocol.h> |
| +#include "base/at_exit.h" |
| +#include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/memory/shared_memory.h" |
| +#include "ui/gl/gl_bindings.h" |
| +#include "ui/gl/gl_context.h" |
| +#include "ui/gl/gl_enums.h" |
| +#include "ui/gl/gl_surface.h" |
| +#include "ui/gl/gl_surface_egl.h" |
| +#include "ui/gl/init/gl_factory.h" |
| +#include "ui/gl/scoped_make_current.h" |
| + |
| +#if defined(OZONE_PLATFORM_GBM) |
| +#include <drm_fourcc.h> |
| +#include <gbm.h> |
| +#endif |
| // Convenient macro that is used to define default deleters for wayland object |
| // types allowing them to be used with std::unique_ptr. |
| @@ -22,6 +38,11 @@ |
| }; \ |
| } |
| +#if defined(OZONE_PLATFORM_GBM) |
| +DEFAULT_DELETER(gbm_device, gbm_device_destroy) |
| +DEFAULT_DELETER(gbm_bo, gbm_bo_destroy) |
| +#endif |
| + |
| DEFAULT_DELETER(wl_display, wl_display_disconnect) |
| DEFAULT_DELETER(wl_compositor, wl_compositor_destroy) |
| DEFAULT_DELETER(wl_shm, wl_shm_destroy) |
| @@ -35,6 +56,7 @@ DEFAULT_DELETER(wl_seat, wl_seat_destroy) |
| DEFAULT_DELETER(wl_pointer, wl_pointer_destroy) |
| DEFAULT_DELETER(wl_touch, wl_touch_destroy) |
| DEFAULT_DELETER(wl_callback, wl_callback_destroy) |
| +DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy) |
| namespace exo { |
| namespace wayland { |
| @@ -46,7 +68,10 @@ const size_t kWidth = 256; |
| const size_t kHeight = 256; |
| // Buffer format. |
| -const int32_t kFormat = WL_SHM_FORMAT_ABGR8888; |
| +const int32_t kShmFormat = WL_SHM_FORMAT_ABGR8888; |
| +#if defined(OZONE_PLATFORM_GBM) |
| +const int32_t kDrmFormat = DRM_FORMAT_ABGR8888; |
| +#endif |
| const size_t kBytesPerPixel = 4; |
| // Number of buffers. |
| @@ -60,6 +85,7 @@ const size_t kMemorySize = kBufferSize * kBuffers; |
| struct Globals { |
| std::unique_ptr<wl_compositor> compositor; |
| std::unique_ptr<wl_shm> shm; |
| + std::unique_ptr<zwp_linux_dmabuf_v1> linux_dmabuf; |
| std::unique_ptr<wl_shell> shell; |
| std::unique_ptr<wl_seat> seat; |
| }; |
| @@ -83,6 +109,9 @@ void RegistryHandler(void* data, |
| } else if (strcmp(interface, "wl_seat") == 0) { |
| globals->seat.reset(static_cast<wl_seat*>( |
| wl_registry_bind(registry, id, &wl_seat_interface, 5))); |
| + } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) { |
| + globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>( |
| + wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1))); |
| } |
| } |
| @@ -94,6 +123,13 @@ struct BufferState { |
| std::unique_ptr<wl_buffer> buffer; |
| uint8_t* data = nullptr; |
| bool busy = false; |
| +// dmabuf |
| +#if defined(OZONE_PLATFORM_GBM) |
| + std::unique_ptr<gbm_bo> bo = nullptr; |
|
reveman
2016/11/04 22:34:14
remove " = nullptr"
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| +#endif |
| + EGLImageKHR egl_image = 0; |
|
reveman
2016/11/04 22:34:15
can we have a unique_ptr for this too?
Daniele Castagna
2016/11/05 21:05:11
Added a ScopedEglImage that is slightly nicer than
|
| + unsigned gl_texture = 0; |
|
reveman
2016/11/04 22:34:14
s/gl_texture/texture/
can we use GLuint instead o
Daniele Castagna
2016/11/05 21:05:11
Done.
|
| + unsigned fb = 0; |
|
reveman
2016/11/04 22:34:14
s/fb/framebuffer/
and GLuint + ScopedFramebuffer
Daniele Castagna
2016/11/05 21:05:12
This is gone now that we're using skia.
|
| }; |
| void BufferRelease(void* data, wl_buffer* buffer) { |
| @@ -107,6 +143,12 @@ struct MainLoopContext { |
| bool needs_redraw = true; |
| bool shutdown = false; |
| bool throttled = false; |
| + base::SharedMemory shared_memory; |
| + std::unique_ptr<wl_shm_pool> shm_pool; |
| + |
| +#if defined(OZONE_PLATFORM_GBM) |
| + std::unique_ptr<gbm_device> device; |
| +#endif |
| }; |
| void PointerEnter(void* data, |
| @@ -203,15 +245,120 @@ void FrameCallback(void* data, wl_callback* callback, uint32_t time) { |
| context->throttled = false; |
| } |
| +#if defined(OZONE_PLATFORM_GBM) |
| +void LinuxBufferParamsCreated(void* data, |
| + zwp_linux_buffer_params_v1* params, |
| + wl_buffer* buffer) { |
| + std::unique_ptr<wl_buffer>* out_buffer = |
| + static_cast<std::unique_ptr<wl_buffer>*>(data); |
|
reveman
2016/11/04 22:34:14
nit: maybe cleaner to just pass BufferState* as da
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| + out_buffer->reset(buffer); |
| +} |
| + |
| +void LinuxBufferParamsFailed(void* data, zwp_linux_buffer_params_v1* params) { |
| + LOG(ERROR) << "Linux buffer params failed callback"; |
|
reveman
2016/11/04 22:34:14
nit: s/failed callback/failed/
Daniele Castagna
2016/11/05 21:05:11
Done.
|
| +} |
| +#endif |
| + |
| +bool CreateBuffer(MainLoopContext* context, |
| + Globals* globals, |
| + wl_display* display, |
| + size_t index, |
| + BufferState* buffer_state) { |
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch("linux_dmabuf_v1")) { |
|
reveman
2016/11/04 22:34:14
s/linux_dmabuf_v1/use-drm/ and move the string to
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| +#if defined(OZONE_PLATFORM_GBM) |
|
reveman
2016/11/04 22:34:14
move the switch check into this ifdef and just sil
Daniele Castagna
2016/11/05 21:05:11
Done.
|
| + buffer_state->bo.reset( |
| + gbm_bo_create(context->device.get(), kWidth, kHeight, kDrmFormat, |
| + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING)); |
| + if (!buffer_state->bo) { |
| + LOG(ERROR) << "Can't create gbm buffer."; |
| + return false; |
| + } |
| + base::ScopedFD fd(gbm_bo_get_plane_fd(buffer_state->bo.get(), 0)); |
| + zwp_linux_buffer_params_v1_listener params_listener = { |
| + LinuxBufferParamsCreated, LinuxBufferParamsFailed}; |
| + |
| + zwp_linux_buffer_params_v1* params = |
|
reveman
2016/11/04 22:34:14
are we leaking this object?
Daniele Castagna
2016/11/05 21:05:11
Fixed.
|
| + zwp_linux_dmabuf_v1_create_params(globals->linux_dmabuf.get()); |
| + zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, |
| + &buffer_state->buffer); |
| + zwp_linux_buffer_params_v1_add(params, fd.get(), 0, 0, kStride, 0, 0); |
| + zwp_linux_buffer_params_v1_create(params, kWidth, kHeight, kDrmFormat, 0); |
| + wl_display_dispatch(display); |
| + wl_display_roundtrip(display); |
|
reveman
2016/11/04 22:34:14
please move this round trip so we only do it once
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| + |
| + if (!buffer_state->buffer) { |
| + LOG(ERROR) << "Can't create linux dmabuf"; |
| + return false; |
| + } |
| + |
| + const EGLint khr_image_attrs[] = {EGL_DMA_BUF_PLANE0_FD_EXT, |
|
reveman
2016/11/04 22:34:14
nit: not sure about 'const' here
Daniele Castagna
2016/11/05 21:05:12
Removed.
|
| + fd.get(), |
| + EGL_WIDTH, |
| + kWidth, |
| + EGL_HEIGHT, |
| + kHeight, |
| + EGL_LINUX_DRM_FOURCC_EXT, |
| + kDrmFormat, |
| + EGL_DMA_BUF_PLANE0_PITCH_EXT, |
| + kStride, |
| + EGL_DMA_BUF_PLANE0_OFFSET_EXT, |
| + 0, |
| + EGL_NONE}; |
| + |
| + buffer_state->egl_image = eglCreateImageKHR( |
| + eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, |
| + NULL /* no client buffer */, khr_image_attrs); |
|
reveman
2016/11/04 22:34:15
s/NULL/nullptr/
|
| + glGenTextures(1, &buffer_state->gl_texture); |
| + glBindTexture(GL_TEXTURE_2D, buffer_state->gl_texture); |
| + |
| + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, |
| + (GLeglImageOES)buffer_state->egl_image); |
|
reveman
2016/11/04 22:34:14
static_cast
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| + glBindTexture(GL_TEXTURE_2D, 0); |
| + glGenFramebuffersEXT(1, &buffer_state->fb); |
| + glBindFramebufferEXT(GL_FRAMEBUFFER, buffer_state->fb); |
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| + GL_TEXTURE_2D, buffer_state->gl_texture, 0); |
| + CHECK(GL_FRAMEBUFFER_COMPLETE == |
| + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); |
| +#else |
| + LOG(ERROR) << "Ozone GBM is necessary to use --linux_dmabuf_v1 flag"; |
| + return false; |
| +#endif |
| + } else { |
| + buffer_state->buffer.reset(static_cast<wl_buffer*>( |
| + wl_shm_pool_create_buffer(context->shm_pool.get(), index * kBufferSize, |
| + kWidth, kHeight, kStride, kShmFormat))); |
| + if (!buffer_state->buffer) { |
| + LOG(ERROR) << "Can't create buffer"; |
| + return false; |
| + } |
| + buffer_state->data = |
| + static_cast<uint8_t*>(context->shared_memory.memory()) + |
| + kBufferSize * index; |
| + } |
| + return true; |
| +} |
| + |
| } // namespace |
| int MotionEventsMain() { |
| + bool use_dmabuf = |
|
reveman
2016/11/04 22:34:14
use_drm and maybe a good idea to add this to the m
Daniele Castagna
2016/11/05 21:05:11
Done.
|
| + base::CommandLine::ForCurrentProcess()->HasSwitch("linux_dmabuf_v1"); |
| std::unique_ptr<wl_display> display(wl_display_connect(nullptr)); |
| if (!display) { |
| LOG(ERROR) << "wl_display_connect failed"; |
| return 1; |
| } |
| + bool gl_initialized = gl::init::InitializeGLOneOff(); |
| + DCHECK(gl_initialized); |
| + scoped_refptr<gl::GLSurface> gl_surface = |
| + gl::init::CreateOffscreenGLSurface(gfx::Size()); |
| + scoped_refptr<gl::GLContext> gl_context = |
| + gl::init::CreateGLContext(nullptr, // share_group |
| + gl_surface.get(), gl::PreferIntegratedGpu); |
| + ui::ScopedMakeCurrent smc(gl_context.get(), gl_surface.get()); |
| + |
| wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover}; |
| Globals globals; |
| @@ -229,6 +376,12 @@ int MotionEventsMain() { |
| LOG(ERROR) << "Can't find shm interface"; |
| return 1; |
| } |
| + |
| + if (use_dmabuf && !globals.linux_dmabuf) { |
| + LOG(ERROR) << "Can't find linux_dmabuf interface"; |
| + return 1; |
| + } |
| + |
| if (!globals.shell) { |
| LOG(ERROR) << "Can't find shell interface"; |
| return 1; |
| @@ -237,24 +390,31 @@ int MotionEventsMain() { |
| LOG(ERROR) << "Can't find seat interface"; |
| return 1; |
| } |
| + MainLoopContext context; |
| + base::ScopedFD fd(open("/dev/dri/renderD128", O_RDWR)); |
|
reveman
2016/11/04 22:34:14
lets move "/dev/dri/renderD128" to a constant at t
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| + if (fd.get() < 0) { |
|
reveman
2016/11/04 22:34:14
we probably want this in the GBM ifdef below or it
Daniele Castagna
2016/11/05 21:05:12
Done.
|
| + LOG(ERROR) << "Can't open drm device '/dev/dri/renderD128'"; |
| + return 1; |
| + } |
| +#if defined(OZONE_PLATFORM_GBM) |
| + context.device.reset(gbm_create_device(fd.get())); |
| + if (!context.device) { |
| + LOG(ERROR) << "Can't create gbm device."; |
| + return 1; |
| + } |
| +#endif |
| wl_buffer_listener buffer_listener = {BufferRelease}; |
| BufferState buffers[kBuffers]; |
| - base::SharedMemory shared_memory; |
| - shared_memory.CreateAndMapAnonymous(kMemorySize); |
| - std::unique_ptr<wl_shm_pool> shm_pool( |
| - wl_shm_create_pool(globals.shm.get(), shared_memory.handle().fd, |
| - shared_memory.requested_size())); |
| + context.shared_memory.CreateAndMapAnonymous(kMemorySize); |
| + context.shm_pool.reset( |
| + wl_shm_create_pool(globals.shm.get(), context.shared_memory.handle().fd, |
| + context.shared_memory.requested_size())); |
| for (size_t i = 0; i < kBuffers; ++i) { |
| - buffers[i].buffer.reset(static_cast<wl_buffer*>(wl_shm_pool_create_buffer( |
| - shm_pool.get(), i * kBufferSize, kWidth, kHeight, kStride, kFormat))); |
| - if (!buffers[i].buffer) { |
| - LOG(ERROR) << "Can't create buffer"; |
| + if (!CreateBuffer(&context, &globals, display.get(), i, &buffers[i])) { |
| return 1; |
| } |
| - buffers[i].data = |
| - static_cast<uint8_t*>(shared_memory.memory()) + kBufferSize * i; |
| wl_buffer_add_listener(buffers[i].buffer.get(), &buffer_listener, |
| &buffers[i]); |
| } |
| @@ -287,8 +447,6 @@ int MotionEventsMain() { |
| wl_shell_surface_set_title(shell_surface.get(), "Test Client"); |
| wl_shell_surface_set_toplevel(shell_surface.get()); |
| - MainLoopContext context; |
| - |
| std::unique_ptr<wl_pointer> pointer( |
| static_cast<wl_pointer*>(wl_seat_get_pointer(globals.seat.get()))); |
| if (!pointer) { |
| @@ -334,12 +492,24 @@ int MotionEventsMain() { |
| context.needs_redraw = false; |
| - static_assert(sizeof(uint32_t) == kBytesPerPixel, |
| - "uint32_t must be same size as kBytesPerPixel"); |
| - for (size_t y = 0; y < kHeight; y++) { |
| - uint32_t* pixel = reinterpret_cast<uint32_t*>(buffer->data + y * kStride); |
| - for (size_t x = 0; x < kWidth; x++) |
| - *pixel++ = context.color; |
| + if (use_dmabuf) { |
| + glBindFramebufferEXT(GL_FRAMEBUFFER, buffer->fb); |
| + glViewport(0, 0, kWidth, kHeight); |
| + const float toUnitRatio = 1.f / 255.f; |
| + glClearColor(toUnitRatio * (context.color & 0xFF), |
| + toUnitRatio * ((context.color & 0xFF00) >> 8), |
| + toUnitRatio * ((context.color & 0xFF0000) >> 16), 1.0f); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + glFinish(); |
| + } else { |
| + static_assert(sizeof(uint32_t) == kBytesPerPixel, |
| + "uint32_t must be same size as kBytesPerPixel"); |
| + for (size_t y = 0; y < kHeight; y++) { |
| + uint32_t* pixel = |
| + reinterpret_cast<uint32_t*>(buffer->data + y * kStride); |
| + for (size_t x = 0; x < kWidth; x++) |
| + *pixel++ = context.color; |
| + } |
| } |
| wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); |
| @@ -353,6 +523,14 @@ int MotionEventsMain() { |
| wl_display_flush(display.get()); |
| } while (wl_display_dispatch(display.get()) != -1); |
| + glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
| + for (uint32_t i = 0; i < kBuffers; ++i) { |
| + BufferState& buffer = buffers[i]; |
| + glDeleteFramebuffersEXT(1, &buffer.fb); |
| + glDeleteTextures(1, &buffer.gl_texture); |
| + eglDestroyImageKHR(eglGetCurrentDisplay(), buffer.egl_image); |
| + } |
| + |
| return 0; |
| } |
| @@ -360,6 +538,8 @@ int MotionEventsMain() { |
| } // namespace wayland |
| } // namespace exo |
| -int main() { |
| +int main(int argc, char* argv[]) { |
| + base::AtExitManager exit_manager; |
| + base::CommandLine::Init(argc, argv); |
| return exo::wayland::clients::MotionEventsMain(); |
| } |