1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "wl_dma_buffer_factory.h"
17
18 #include <cinttypes>
19 #include <map>
20
21 #include <display_type.h>
22 #include <drm_fourcc.h>
23 #include <promise.h>
24
25 #include "wayland-util.h"
26 #include "window_manager_hilog.h"
27 #include "wl_display.h"
28
29 namespace OHOS {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0, "WMWlDMABufferFactory" };
32 std::map<struct zwp_linux_buffer_params_v1 *, sptr<Promise<struct wl_buffer *>>> g_bufferPromises;
33 constexpr int32_t STRIDE_NUM = 4;
34 constexpr int32_t MODIFY_OFFSET = 32;
35 constexpr int32_t BITS_OFFSET_32 = 32;
36 }
37
GetInstance()38 sptr<WlDMABufferFactory> WlDMABufferFactory::GetInstance()
39 {
40 if (instance == nullptr) {
41 static std::mutex mutex;
42 std::lock_guard<std::mutex> lock(mutex);
43 if (instance == nullptr) {
44 instance = new WlDMABufferFactory();
45 }
46 }
47 return instance;
48 }
49
Init()50 void WlDMABufferFactory::Init()
51 {
52 delegator.Dep<WaylandService>()->OnAppear(&WlDMABufferFactory::OnAppear);
53 }
54
Deinit()55 void WlDMABufferFactory::Deinit()
56 {
57 if (dmabuf != nullptr) {
58 zwp_linux_dmabuf_v1_destroy(dmabuf);
59 dmabuf = nullptr;
60 }
61 }
62
OnAppear(const GetServiceFunc get,const std::string & iname,uint32_t ver)63 void WlDMABufferFactory::OnAppear(const GetServiceFunc get, const std::string &iname, uint32_t ver)
64 {
65 if (iname == "zwp_linux_dmabuf_v1") {
66 constexpr uint32_t dmabufVersion = 3;
67 auto ret = get(&zwp_linux_dmabuf_v1_interface, dmabufVersion);
68 dmabuf = static_cast<struct zwp_linux_dmabuf_v1 *>(ret);
69 }
70 }
71
72 namespace {
Success(void *,struct zwp_linux_buffer_params_v1 * param,struct wl_buffer * buffer)73 void Success(void *, struct zwp_linux_buffer_params_v1 *param, struct wl_buffer *buffer)
74 {
75 WMLOGFI("Success");
76 g_bufferPromises[param]->Resolve(buffer);
77 }
78
Failure(void *,struct zwp_linux_buffer_params_v1 * param)79 void Failure(void *, struct zwp_linux_buffer_params_v1 *param)
80 {
81 WMLOGFI("Failure");
82 g_bufferPromises[param]->Resolve(nullptr);
83 }
84 } // namespace
85
CreateParam(BufferHandle * handle)86 struct zwp_linux_buffer_params_v1 *WlDMABufferFactory::CreateParam(BufferHandle *handle)
87 {
88 auto display = delegator.Dep<WlDisplay>();
89 if (dmabuf == nullptr) {
90 WMLOGFE("dmabuf is nullptr");
91 return nullptr;
92 }
93
94 auto param = zwp_linux_dmabuf_v1_create_params(dmabuf);
95 if (param == nullptr) {
96 auto err = display->GetError();
97 WMLOGFE("zwp_linux_dmabuf_v1_create_params failed with %{public}s", strerror(err));
98 return nullptr;
99 }
100
101 uint64_t modifier = 0;
102 zwp_linux_buffer_params_v1_add(param, handle->fd, 0, 0,
103 handle->stride, modifier >> MODIFY_OFFSET, modifier & 0xffffffff);
104
105 SendBufferHandle(param, handle);
106
107 if (display->GetError() != 0) {
108 auto err = display->GetError();
109 WMLOGFE("zwp_linux_buffer_params_v1_add failed with %{public}s", strerror(err));
110 WMLOGFE("args: fd(%{public}d), w(%{public}d)", handle->fd, handle->width);
111 zwp_linux_buffer_params_v1_destroy(param);
112 return nullptr;
113 }
114
115 const struct zwp_linux_buffer_params_v1_listener listener = { Success, Failure };
116 if (zwp_linux_buffer_params_v1_add_listener(param, &listener, nullptr) == -1) {
117 WMLOGFE("zwp_linux_buffer_params_v1_add_listener failed");
118 zwp_linux_buffer_params_v1_destroy(param);
119 return nullptr;
120 }
121 return param;
122 }
123
124 namespace {
PixelFormatToDrmFormat(int32_t pixelFormat,uint32_t & drmFormat)125 bool PixelFormatToDrmFormat(int32_t pixelFormat, uint32_t &drmFormat)
126 {
127 constexpr struct {
128 int32_t pixelFormat;
129 uint32_t drmFormat;
130 } formatTable[] = {
131 {PIXEL_FMT_RGB_565, DRM_FORMAT_RGB565},
132 {PIXEL_FMT_RGBX_4444, DRM_FORMAT_RGBX4444},
133 {PIXEL_FMT_RGBA_4444, DRM_FORMAT_RGBA4444},
134 {PIXEL_FMT_RGBX_5551, DRM_FORMAT_RGBX5551},
135 {PIXEL_FMT_RGBA_5551, DRM_FORMAT_RGBA5551},
136 {PIXEL_FMT_RGBX_8888, DRM_FORMAT_RGBX8888},
137 {PIXEL_FMT_RGBA_8888, DRM_FORMAT_RGBA8888},
138 {PIXEL_FMT_RGB_888, DRM_FORMAT_RGB888},
139 {PIXEL_FMT_BGR_565, DRM_FORMAT_BGR565},
140 {PIXEL_FMT_BGRX_4444, DRM_FORMAT_BGRX4444},
141 {PIXEL_FMT_BGRA_4444, DRM_FORMAT_BGRA4444},
142 {PIXEL_FMT_BGRX_5551, DRM_FORMAT_BGRX5551},
143 {PIXEL_FMT_BGRA_5551, DRM_FORMAT_BGRA5551},
144 {PIXEL_FMT_BGRX_8888, DRM_FORMAT_BGRX8888},
145 {PIXEL_FMT_BGRA_8888, DRM_FORMAT_BGRA8888},
146 {PIXEL_FMT_YUV_422_I, DRM_FORMAT_YUV422},
147 {PIXEL_FMT_YUYV_422_PKG, DRM_FORMAT_YUYV},
148 {PIXEL_FMT_UYVY_422_PKG, DRM_FORMAT_UYVY},
149 {PIXEL_FMT_YVYU_422_PKG, DRM_FORMAT_YVYU},
150 {PIXEL_FMT_VYUY_422_PKG, DRM_FORMAT_VYUY},
151 {PIXEL_FMT_YCBCR_420_SP, DRM_FORMAT_NV12},
152 {PIXEL_FMT_YCRCB_420_SP, DRM_FORMAT_NV21},
153 {PIXEL_FMT_YCBCR_420_P, DRM_FORMAT_YUV420},
154 };
155
156 for (const auto &fmt : formatTable) {
157 if (fmt.pixelFormat == pixelFormat) {
158 drmFormat = fmt.drmFormat;
159 return true;
160 }
161 }
162 return false;
163 }
164 } // namespace
165
SendBufferHandle(zwp_linux_buffer_params_v1 * param,BufferHandle * handle)166 void WlDMABufferFactory::SendBufferHandle(zwp_linux_buffer_params_v1 *param, BufferHandle *handle)
167 {
168 auto display = delegator.Dep<WlDisplay>();
169 wl_array reservefds;
170 wl_array reserveints;
171
172 WMLOGFI("BufferHandle->fd = %{public}d", handle->fd);
173 WMLOGFI("BufferHandle->width = %{public}d", handle->width);
174 WMLOGFI("BufferHandle->stride = %{public}d", handle->stride);
175 WMLOGFI("BufferHandle->height = %{public}d", handle->height);
176 WMLOGFI("BufferHandle->size = %{public}d", handle->size);
177 WMLOGFI("BufferHandle->format = %{public}d", handle->format);
178 WMLOGFI("BufferHandle->usage = %{public}" PRIu64 ", %{public}u, %{public}u",
179 handle->usage, (uint32_t)(handle->usage >> BITS_OFFSET_32), (uint32_t)(handle->usage & 0xFFFFFFFF));
180 WMLOGFI("BufferHandle->phyAddr = %{public}" PRIu64 ", %{public}u, %{public}u",
181 handle->phyAddr, (uint32_t)(handle->phyAddr >> BITS_OFFSET_32), (uint32_t)(handle->phyAddr & 0xFFFFFFFF));
182 WMLOGFI("BufferHandle->key = %{public}d", handle->key);
183
184 WMLOGFI("BufferHandle->reserveFds = %{public}u", handle->reserveFds);
185 WMLOGFI("BufferHandle->reserveInts = %{public}u", handle->reserveInts);
186
187 wl_array_init(&reservefds);
188 for (int i = 0; i < handle->reserveFds; i++) {
189 uint32_t *p = (uint32_t *)wl_array_add(&reservefds, sizeof(uint32_t));
190 if (p != nullptr) {
191 *p = handle->reserve[i];
192 }
193 }
194
195 wl_array_init(&reserveints);
196 for (int i = 0; i < handle->reserveInts; i++) {
197 uint32_t *p = (uint32_t *)wl_array_add(&reserveints, sizeof(uint32_t));
198 if (p != nullptr) {
199 *p = handle->reserve[i + handle->reserveFds];
200 }
201 }
202
203 zwp_linux_buffer_params_v1_add_buffer_handle(param,
204 handle->fd, handle->width, handle->stride, handle->height,
205 handle->size, handle->format, handle->usage >> BITS_OFFSET_32, handle->usage & 0xFFFFFFFF,
206 handle->phyAddr >> BITS_OFFSET_32, handle->phyAddr & 0xFFFFFFFF, handle->key,
207 &reservefds, &reserveints);
208 }
209
Create(BufferHandle * handle)210 sptr<WlBuffer> WlDMABufferFactory::Create(BufferHandle *handle)
211 {
212 auto display = delegator.Dep<WlDisplay>();
213 uint32_t drmFormat;
214
215 if (handle == nullptr) {
216 WMLOGFE("handle == nullptr");
217 return nullptr;
218 }
219
220 if (PixelFormatToDrmFormat(handle->format, drmFormat) == false) {
221 WMLOGFE("PixelFormatToDrmFormat failed");
222 return nullptr;
223 }
224
225 auto param = CreateParam(handle);
226 if (param == nullptr) {
227 return nullptr;
228 }
229
230 // add death listener before send, and remove before erase(promise destroy)
231 g_bufferPromises[param] = new Promise<struct wl_buffer *>();
232 auto dl = display->AddDispatchDeathListener([&]() { g_bufferPromises[param]->Resolve(nullptr); });
233
234 constexpr uint32_t flags = 0;
235 zwp_linux_buffer_params_v1_create(param, handle->width, handle->height, drmFormat, flags);
236 display->Flush(); // send request
237
238 auto buffer = g_bufferPromises[param]->Await();
239 display->RemoveDispatchDeathListener(dl);
240 g_bufferPromises.erase(param);
241 if (display->GetError() != 0) {
242 WMLOGFE("zwp_linux_buffer_params_v1_create failed with %{public}d", display->GetError());
243 WMLOGFE("args: (%{public}dx%{public}d), format(0x%{public}x), flags(0x%{public}x)",
244 handle->width, handle->height, drmFormat, flags);
245 zwp_linux_buffer_params_v1_destroy(param);
246 return nullptr;
247 }
248
249 zwp_linux_buffer_params_v1_destroy(param);
250 display->Sync();
251 if (display->GetError() != 0) {
252 WMLOGFW("zwp_linux_buffer_params_v1_destroy failed with %{public}d", display->GetError());
253 }
254
255 if (buffer == nullptr) {
256 WMLOGFE("buffer is nullptr");
257 return nullptr;
258 }
259
260 sptr<WlBuffer> ret = new WlBuffer(buffer);
261 if (ret == nullptr) {
262 WMLOGFE("new WlBuffer failed");
263 return nullptr;
264 }
265 return ret;
266 }
267 } // namespace OHOS
268