zwp_linux_dmabuf.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. #include "components/exo/wayland/zwp_linux_dmabuf.h"
  5. #include <drm_fourcc.h>
  6. #include <linux-dmabuf-unstable-v1-server-protocol.h>
  7. #include "base/bind.h"
  8. #include "base/containers/contains.h"
  9. #include "components/exo/buffer.h"
  10. #include "components/exo/display.h"
  11. #include "components/exo/wayland/server_util.h"
  12. #include "ui/gfx/buffer_format_util.h"
  13. namespace exo {
  14. namespace wayland {
  15. namespace {
  16. ////////////////////////////////////////////////////////////////////////////////
  17. // wl_buffer_interface:
  18. void buffer_destroy(wl_client* client, wl_resource* resource) {
  19. wl_resource_destroy(resource);
  20. }
  21. const struct wl_buffer_interface buffer_implementation = {buffer_destroy};
  22. void HandleBufferReleaseCallback(wl_resource* resource) {
  23. wl_buffer_send_release(resource);
  24. wl_client_flush(wl_resource_get_client(resource));
  25. }
  26. ////////////////////////////////////////////////////////////////////////////////
  27. // linux_buffer_params_interface:
  28. const struct dmabuf_supported_format {
  29. uint32_t dmabuf_format;
  30. gfx::BufferFormat buffer_format;
  31. } kSupportedDmaBufFormats[] = {
  32. {DRM_FORMAT_RGB565, gfx::BufferFormat::BGR_565},
  33. {DRM_FORMAT_XBGR8888, gfx::BufferFormat::RGBX_8888},
  34. {DRM_FORMAT_ABGR8888, gfx::BufferFormat::RGBA_8888},
  35. {DRM_FORMAT_XRGB8888, gfx::BufferFormat::BGRX_8888},
  36. {DRM_FORMAT_ARGB8888, gfx::BufferFormat::BGRA_8888},
  37. {DRM_FORMAT_NV12, gfx::BufferFormat::YUV_420_BIPLANAR},
  38. {DRM_FORMAT_YVU420, gfx::BufferFormat::YVU_420},
  39. {DRM_FORMAT_ABGR2101010, gfx::BufferFormat::RGBA_1010102},
  40. {DRM_FORMAT_ARGB2101010, gfx::BufferFormat::BGRA_1010102}};
  41. struct LinuxBufferParams {
  42. struct Plane {
  43. base::ScopedFD fd;
  44. uint32_t stride;
  45. uint32_t offset;
  46. uint64_t modifier;
  47. };
  48. explicit LinuxBufferParams(Display* display) : display(display) {}
  49. Display* const display;
  50. std::map<uint32_t, Plane> planes;
  51. };
  52. void linux_buffer_params_destroy(wl_client* client, wl_resource* resource) {
  53. wl_resource_destroy(resource);
  54. }
  55. void linux_buffer_params_add(wl_client* client,
  56. wl_resource* resource,
  57. int32_t fd,
  58. uint32_t plane_idx,
  59. uint32_t offset,
  60. uint32_t stride,
  61. uint32_t modifier_hi,
  62. uint32_t modifier_lo) {
  63. LinuxBufferParams* linux_buffer_params =
  64. GetUserDataAs<LinuxBufferParams>(resource);
  65. const uint64_t modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo;
  66. LinuxBufferParams::Plane plane{base::ScopedFD(fd), stride, offset, modifier};
  67. bool inserted = linux_buffer_params->planes
  68. .insert(std::make_pair(plane_idx, std::move(plane)))
  69. .second;
  70. if (!inserted) { // The plane was already there.
  71. wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
  72. "plane already set");
  73. }
  74. }
  75. bool ValidateLinuxBufferParams(wl_resource* resource,
  76. int32_t width,
  77. int32_t height,
  78. gfx::BufferFormat format,
  79. uint32_t flags) {
  80. if (width <= 0 || height <= 0) {
  81. wl_resource_post_error(resource,
  82. ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
  83. "invalid width or height");
  84. return false;
  85. }
  86. if (flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED) {
  87. wl_resource_post_error(resource,
  88. ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
  89. "flags not supported");
  90. return false;
  91. }
  92. LinuxBufferParams* linux_buffer_params =
  93. GetUserDataAs<LinuxBufferParams>(resource);
  94. size_t num_planes = linux_buffer_params->planes.size();
  95. if (num_planes == 0) {
  96. wl_resource_post_error(resource,
  97. ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
  98. "no planes given");
  99. return false;
  100. }
  101. // Validate that we have planes 0..num_planes-1
  102. for (uint32_t i = 0; i < num_planes; ++i) {
  103. if (!base::Contains(linux_buffer_params->planes, i)) {
  104. wl_resource_post_error(resource,
  105. ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
  106. "missing a plane");
  107. return false;
  108. }
  109. }
  110. // All planes must have the same modifier.
  111. uint64_t modifier = linux_buffer_params->planes[0].modifier;
  112. for (uint32_t i = 1; i < num_planes; ++i) {
  113. if (linux_buffer_params->planes[i].modifier != modifier) {
  114. wl_resource_post_error(resource,
  115. ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT,
  116. "all planes must have same modifier");
  117. return false;
  118. }
  119. }
  120. return true;
  121. }
  122. wl_resource* create_buffer(wl_client* client,
  123. wl_resource* resource,
  124. uint32_t buffer_id,
  125. int32_t width,
  126. int32_t height,
  127. uint32_t format,
  128. uint32_t flags) {
  129. const auto* supported_format = std::find_if(
  130. std::begin(kSupportedDmaBufFormats), std::end(kSupportedDmaBufFormats),
  131. [format](const dmabuf_supported_format& supported_format) {
  132. return supported_format.dmabuf_format == format;
  133. });
  134. if (supported_format == std::end(kSupportedDmaBufFormats)) {
  135. wl_resource_post_error(resource,
  136. ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT,
  137. "format not supported");
  138. return nullptr;
  139. }
  140. if (!ValidateLinuxBufferParams(resource, width, height,
  141. supported_format->buffer_format, flags)) {
  142. return nullptr;
  143. }
  144. LinuxBufferParams* linux_buffer_params =
  145. GetUserDataAs<LinuxBufferParams>(resource);
  146. gfx::NativePixmapHandle handle;
  147. // A lot of clients (arc++, arcvm, sommelier etc) pass 0
  148. // (DRM_FORMAT_MOD_LINEAR) when they don't know the format modifier.
  149. // They're supposed to pass DRM_FORMAT_MOD_INVALID, which triggers
  150. // EGL import without an explicit modifier and lets the driver pick
  151. // up the buffer layout from out-of-band channels like kernel ioctls.
  152. //
  153. // We can't fix all the clients in one go, but we can preserve the
  154. // behaviour that 0 means implicit modifier, but only setting the
  155. // handle modifier if we get a non-0 modifier.
  156. //
  157. // TODO(hoegsberg): Once we've fixed all relevant clients, we should
  158. // remove this so as to catch future misuse.
  159. if (linux_buffer_params->planes[0].modifier != 0)
  160. handle.modifier = linux_buffer_params->planes[0].modifier;
  161. for (uint32_t i = 0; i < linux_buffer_params->planes.size(); ++i) {
  162. auto& plane = linux_buffer_params->planes[i];
  163. handle.planes.emplace_back(plane.stride, plane.offset, 0,
  164. std::move(plane.fd));
  165. }
  166. bool y_invert = (flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) != 0;
  167. std::unique_ptr<Buffer> buffer =
  168. linux_buffer_params->display->CreateLinuxDMABufBuffer(
  169. gfx::Size(width, height), supported_format->buffer_format,
  170. std::move(handle), y_invert);
  171. if (!buffer) {
  172. zwp_linux_buffer_params_v1_send_failed(resource);
  173. return nullptr;
  174. }
  175. wl_resource* buffer_resource =
  176. wl_resource_create(client, &wl_buffer_interface, 1, buffer_id);
  177. buffer->set_release_callback(base::BindRepeating(
  178. &HandleBufferReleaseCallback, base::Unretained(buffer_resource)));
  179. SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer));
  180. return buffer_resource;
  181. }
  182. void linux_buffer_params_create(wl_client* client,
  183. wl_resource* resource,
  184. int32_t width,
  185. int32_t height,
  186. uint32_t format,
  187. uint32_t flags) {
  188. wl_resource* buffer_resource =
  189. create_buffer(client, resource, 0, width, height, format, flags);
  190. if (buffer_resource)
  191. zwp_linux_buffer_params_v1_send_created(resource, buffer_resource);
  192. }
  193. void linux_buffer_params_create_immed(wl_client* client,
  194. wl_resource* resource,
  195. uint32_t buffer_id,
  196. int32_t width,
  197. int32_t height,
  198. uint32_t format,
  199. uint32_t flags) {
  200. create_buffer(client, resource, buffer_id, width, height, format, flags);
  201. }
  202. const struct zwp_linux_buffer_params_v1_interface
  203. linux_buffer_params_implementation = {
  204. linux_buffer_params_destroy, linux_buffer_params_add,
  205. linux_buffer_params_create, linux_buffer_params_create_immed};
  206. ////////////////////////////////////////////////////////////////////////////////
  207. // linux_dmabuf_interface:
  208. void linux_dmabuf_destroy(wl_client* client, wl_resource* resource) {
  209. wl_resource_destroy(resource);
  210. }
  211. void linux_dmabuf_create_params(wl_client* client,
  212. wl_resource* resource,
  213. uint32_t id) {
  214. std::unique_ptr<LinuxBufferParams> linux_buffer_params =
  215. std::make_unique<LinuxBufferParams>(GetUserDataAs<Display>(resource));
  216. wl_resource* linux_buffer_params_resource =
  217. wl_resource_create(client, &zwp_linux_buffer_params_v1_interface,
  218. wl_resource_get_version(resource), id);
  219. SetImplementation(linux_buffer_params_resource,
  220. &linux_buffer_params_implementation,
  221. std::move(linux_buffer_params));
  222. }
  223. const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
  224. linux_dmabuf_destroy, linux_dmabuf_create_params};
  225. } // namespace
  226. void bind_linux_dmabuf(wl_client* client,
  227. void* data,
  228. uint32_t version,
  229. uint32_t id) {
  230. wl_resource* resource =
  231. wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
  232. std::min(version, kZwpLinuxDmabufVersion), id);
  233. wl_resource_set_implementation(resource, &linux_dmabuf_implementation, data,
  234. nullptr);
  235. for (const auto& supported_format : kSupportedDmaBufFormats)
  236. zwp_linux_dmabuf_v1_send_format(resource, supported_format.dmabuf_format);
  237. }
  238. } // namespace wayland
  239. } // namespace exo