1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/libs/wayland/wayland_surface.h"
18
19 #include <android-base/logging.h>
20 #include <drm/drm_fourcc.h>
21 #include <wayland-server-protocol.h>
22
23 #include "host/libs/wayland/wayland_surfaces.h"
24
25 namespace wayland {
26 namespace {
27
GetDrmFormat(std::uint32_t wl_shm_format)28 std::uint32_t GetDrmFormat(std::uint32_t wl_shm_format) {
29 switch (wl_shm_format) {
30 case WL_SHM_FORMAT_ARGB8888:
31 return DRM_FORMAT_ARGB8888;
32 case WL_SHM_FORMAT_XRGB8888:
33 return DRM_FORMAT_XRGB8888;
34 default:
35 return wl_shm_format;
36 }
37 }
38
39 } // namespace
40
Surface(Surfaces & surfaces)41 Surface::Surface(Surfaces& surfaces) : surfaces_(surfaces) {}
42
~Surface()43 Surface::~Surface() {
44 if (state_.virtio_gpu_metadata_.scanout_id.has_value()) {
45 const uint32_t display_number = *state_.virtio_gpu_metadata_.scanout_id;
46 surfaces_.HandleSurfaceDestroyed(display_number);
47 }
48 }
49
SetRegion(const Region & region)50 void Surface::SetRegion(const Region& region) {
51 std::unique_lock<std::mutex> lock(state_mutex_);
52 state_.region = region;
53 }
54
Attach(struct wl_resource * buffer)55 void Surface::Attach(struct wl_resource* buffer) {
56 std::unique_lock<std::mutex> lock(state_mutex_);
57 state_.pending_buffer = buffer;
58 }
59
Commit()60 void Surface::Commit() {
61 std::unique_lock<std::mutex> lock(state_mutex_);
62 state_.current_buffer = state_.pending_buffer;
63 state_.pending_buffer = nullptr;
64
65 if (state_.current_buffer == nullptr) {
66 return;
67 }
68
69 if (state_.virtio_gpu_metadata_.scanout_id.has_value()) {
70 const uint32_t display_number = *state_.virtio_gpu_metadata_.scanout_id;
71
72 struct wl_shm_buffer* shm_buffer = wl_shm_buffer_get(state_.current_buffer);
73 CHECK(shm_buffer != nullptr);
74
75 wl_shm_buffer_begin_access(shm_buffer);
76
77 const int32_t buffer_w = wl_shm_buffer_get_width(shm_buffer);
78 CHECK(buffer_w == state_.region.w);
79 const int32_t buffer_h = wl_shm_buffer_get_height(shm_buffer);
80 CHECK(buffer_h == state_.region.h);
81 const int32_t buffer_stride_bytes = wl_shm_buffer_get_stride(shm_buffer);
82 const std::uint32_t buffer_drm_format =
83 GetDrmFormat(wl_shm_buffer_get_format(shm_buffer));
84
85 if (!state_.has_notified_surface_create) {
86 surfaces_.HandleSurfaceCreated(display_number, buffer_w, buffer_h);
87 state_.has_notified_surface_create = true;
88 }
89
90 uint8_t* buffer_pixels =
91 reinterpret_cast<uint8_t*>(wl_shm_buffer_get_data(shm_buffer));
92
93 surfaces_.HandleSurfaceFrame(display_number, buffer_w, buffer_h,
94 buffer_drm_format, buffer_stride_bytes,
95 buffer_pixels);
96
97 wl_shm_buffer_end_access(shm_buffer);
98 }
99
100 wl_buffer_send_release(state_.current_buffer);
101 wl_client_flush(wl_resource_get_client(state_.current_buffer));
102
103 state_.current_buffer = nullptr;
104 state_.current_frame_number++;
105 }
106
SetVirtioGpuScanoutId(uint32_t scanout_id)107 void Surface::SetVirtioGpuScanoutId(uint32_t scanout_id) {
108 std::unique_lock<std::mutex> lock(state_mutex_);
109 state_.virtio_gpu_metadata_.scanout_id = scanout_id;
110 }
111
112 } // namespace wayland