diff --git a/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.cpp b/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.cpp index 5b9b6bed1b1..445a1ee0887 100644 --- a/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.cpp +++ b/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.cpp @@ -24,6 +24,8 @@ #include #include +#include "cuttlefish/host/libs/wayland/wayland_utils.h" + namespace wayland { namespace { @@ -63,6 +65,19 @@ void linux_buffer_params_add(wl_client*, << " stride=" << stride << " mod_hi=" << modifier_hi << " mod_lo=" << modifier_lo; + + DmabufParams* dmabuf_params = GetUserData(params); + + DmabufPlane dma_plane = { + .fd = android::base::unique_fd(fd), + .plane = plane, + .offset = offset, + .stride = stride, + .modifier_hi = modifier_hi, + .modifier_lo = modifier_lo, + }; + + dmabuf_params->planes[plane] = std::move(dma_plane); } void linux_buffer_params_create(wl_client* client, @@ -81,8 +96,19 @@ void linux_buffer_params_create(wl_client* client, wl_resource* buffer_resource = wl_resource_create(client, &wl_buffer_interface, 1, 0); + DmabufParams* dmabuf_params = GetUserData(params); + + Dmabuf* dmabuf = new Dmabuf(); + dmabuf->width = w; + dmabuf->height = h; + dmabuf->format = format; + dmabuf->flags = flags; + dmabuf->params = dmabuf_params; + wl_resource_set_implementation(buffer_resource, &buffer_implementation, - nullptr, params_destroy_resource_callback); + dmabuf, params_destroy_resource_callback); + + zwp_linux_buffer_params_v1_send_created(params, buffer_resource); } void linux_buffer_params_create_immed(wl_client* client, @@ -128,12 +154,14 @@ void linux_dmabuf_create_params(wl_client* client, << " display=" << display << " id=" << id; + DmabufParams* dmabuf_params = new DmabufParams(); + wl_resource* buffer_params_resource = wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, 1, id); wl_resource_set_implementation(buffer_params_resource, &zwp_linux_buffer_params_implementation, - nullptr, params_destroy_resource_callback); + dmabuf_params, params_destroy_resource_callback); } const struct zwp_linux_dmabuf_v1_interface @@ -164,4 +192,9 @@ void BindDmabufInterface(wl_display* display) { kLinuxDmabufVersion, nullptr, bind_linux_dmabuf); } +bool IsDmabufResource(struct wl_resource* resource) { + return wl_resource_instance_of(resource, &wl_buffer_interface, + &zwp_linux_dmabuf_v1_interface); +} + } // namespace wayland \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.h b/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.h index ad02f297664..896d64bcf9d 100644 --- a/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.h +++ b/base/cvd/cuttlefish/host/libs/wayland/wayland_dmabuf.h @@ -18,12 +18,43 @@ #pragma once #include +#include + +#include #include namespace wayland { +struct DmabufPlane { + android::base::unique_fd fd; + uint32_t plane = 0; + uint32_t offset = 0; + uint32_t stride = 0; + uint32_t modifier_hi = 0; + uint32_t modifier_lo = 0; +}; + +struct DmabufParams { + DmabufParams() = default; + + DmabufParams(const DmabufParams& rhs) = delete; + DmabufParams& operator=(const DmabufParams& rhs) = delete; + + std::map planes; +}; + +struct Dmabuf { + uint32_t width = 0; + uint32_t height = 0; + uint32_t format = 0; + uint32_t flags = 0; + DmabufParams* params; +}; + // Binds the dmabuf interface to the given wayland server. void BindDmabufInterface(wl_display* display); +bool IsDmabufResource(struct wl_resource* resource); + } // namespace wayland \ No newline at end of file diff --git a/base/cvd/cuttlefish/host/libs/wayland/wayland_surface.cpp b/base/cvd/cuttlefish/host/libs/wayland/wayland_surface.cpp index e8f65949623..c9e22bbfdbe 100644 --- a/base/cvd/cuttlefish/host/libs/wayland/wayland_surface.cpp +++ b/base/cvd/cuttlefish/host/libs/wayland/wayland_surface.cpp @@ -18,9 +18,13 @@ #include #include +#include #include #include "cuttlefish/host/libs/wayland/wayland_surfaces.h" +#include "cuttlefish/host/libs/wayland/wayland_dmabuf.h" +#include "cuttlefish/host/libs/wayland/wayland_surfaces.h" +#include "cuttlefish/host/libs/wayland/wayland_utils.h" namespace wayland { namespace { @@ -70,31 +74,67 @@ void Surface::Commit() { const uint32_t display_number = *state_.virtio_gpu_metadata_.scanout_id; struct wl_shm_buffer* shm_buffer = wl_shm_buffer_get(state_.current_buffer); - CHECK(shm_buffer != nullptr); - - wl_shm_buffer_begin_access(shm_buffer); - const int32_t buffer_w = wl_shm_buffer_get_width(shm_buffer); - CHECK(buffer_w == state_.region.w); - const int32_t buffer_h = wl_shm_buffer_get_height(shm_buffer); - CHECK(buffer_h == state_.region.h); - const int32_t buffer_stride_bytes = wl_shm_buffer_get_stride(shm_buffer); - const std::uint32_t buffer_drm_format = - GetDrmFormat(wl_shm_buffer_get_format(shm_buffer)); + uint32_t buffer_w = 0; + uint32_t buffer_h = 0; + uint32_t buffer_drm_format = 0; + uint32_t buffer_stride_bytes = 0; + uint8_t* buffer_pixels = nullptr; + uint32_t buffer_size = 0; + + if (shm_buffer != nullptr) { + wl_shm_buffer_begin_access(shm_buffer); + buffer_w = wl_shm_buffer_get_width(shm_buffer); + CHECK(buffer_w == state_.region.w); + buffer_h = wl_shm_buffer_get_height(shm_buffer); + CHECK(buffer_h == state_.region.h); + buffer_drm_format = GetDrmFormat(wl_shm_buffer_get_format(shm_buffer)); + buffer_stride_bytes = wl_shm_buffer_get_stride(shm_buffer); + buffer_pixels = + reinterpret_cast(wl_shm_buffer_get_data(shm_buffer)); + } else { + CHECK(IsDmabufResource(state_.current_buffer)); + Dmabuf* dmabuf = GetUserData(state_.current_buffer); + buffer_w = dmabuf->width; + buffer_h = dmabuf->height; + + if (dmabuf->params != nullptr) { + const DmabufParams& dmabuf_params = *dmabuf->params; + + CHECK(dmabuf_params.planes.size() == 1); + const DmabufPlane& dmabuf_plane = dmabuf_params.planes.begin()->second; + + if (dmabuf_plane.fd.ok()) { + buffer_drm_format = dmabuf->format; + buffer_stride_bytes = dmabuf_plane.stride; + buffer_size = buffer_h * buffer_stride_bytes; + auto mapped = mmap(nullptr, buffer_size, PROT_READ | PROT_WRITE, + MAP_SHARED, dmabuf_plane.fd, 0); + if (mapped != MAP_FAILED) { + buffer_pixels = reinterpret_cast(mapped); + } + } + } + } if (!state_.has_notified_surface_create) { surfaces_.HandleSurfaceCreated(display_number, buffer_w, buffer_h); state_.has_notified_surface_create = true; } - uint8_t* buffer_pixels = - reinterpret_cast(wl_shm_buffer_get_data(shm_buffer)); - - surfaces_.HandleSurfaceFrame(display_number, buffer_w, buffer_h, - buffer_drm_format, buffer_stride_bytes, - buffer_pixels); + if (buffer_pixels != nullptr) { + surfaces_.HandleSurfaceFrame(display_number, buffer_w, buffer_h, + buffer_drm_format, buffer_stride_bytes, + buffer_pixels); + } - wl_shm_buffer_end_access(shm_buffer); + if (shm_buffer != nullptr) { + wl_shm_buffer_end_access(shm_buffer); + } else { + if (buffer_pixels != nullptr) { + munmap(buffer_pixels, buffer_size); + } + } } wl_buffer_send_release(state_.current_buffer);