1*0a9764feSAndroid Build Coastguard Worker /*
2*0a9764feSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*0a9764feSAndroid Build Coastguard Worker *
4*0a9764feSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*0a9764feSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*0a9764feSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*0a9764feSAndroid Build Coastguard Worker *
8*0a9764feSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*0a9764feSAndroid Build Coastguard Worker *
10*0a9764feSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*0a9764feSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*0a9764feSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0a9764feSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*0a9764feSAndroid Build Coastguard Worker * limitations under the License.
15*0a9764feSAndroid Build Coastguard Worker */
16*0a9764feSAndroid Build Coastguard Worker
17*0a9764feSAndroid Build Coastguard Worker #define LOG_TAG "drmhwc"
18*0a9764feSAndroid Build Coastguard Worker
19*0a9764feSAndroid Build Coastguard Worker #include "BufferInfoLibdrm.h"
20*0a9764feSAndroid Build Coastguard Worker
21*0a9764feSAndroid Build Coastguard Worker #include <gralloc_handle.h>
22*0a9764feSAndroid Build Coastguard Worker #include <hardware/gralloc.h>
23*0a9764feSAndroid Build Coastguard Worker #include <xf86drm.h>
24*0a9764feSAndroid Build Coastguard Worker #include <xf86drmMode.h>
25*0a9764feSAndroid Build Coastguard Worker
26*0a9764feSAndroid Build Coastguard Worker #include <mutex>
27*0a9764feSAndroid Build Coastguard Worker
28*0a9764feSAndroid Build Coastguard Worker #include "utils/log.h"
29*0a9764feSAndroid Build Coastguard Worker #include "utils/properties.h"
30*0a9764feSAndroid Build Coastguard Worker
31*0a9764feSAndroid Build Coastguard Worker namespace android {
32*0a9764feSAndroid Build Coastguard Worker
33*0a9764feSAndroid Build Coastguard Worker LEGACY_BUFFER_INFO_GETTER(BufferInfoLibdrm);
34*0a9764feSAndroid Build Coastguard Worker
35*0a9764feSAndroid Build Coastguard Worker enum chroma_order {
36*0a9764feSAndroid Build Coastguard Worker kYCbCr,
37*0a9764feSAndroid Build Coastguard Worker kYCrCb,
38*0a9764feSAndroid Build Coastguard Worker };
39*0a9764feSAndroid Build Coastguard Worker
40*0a9764feSAndroid Build Coastguard Worker struct DroidYuvFormat {
41*0a9764feSAndroid Build Coastguard Worker /* Lookup keys */
42*0a9764feSAndroid Build Coastguard Worker uint32_t native; /* HAL_PIXEL_FORMAT_ */
43*0a9764feSAndroid Build Coastguard Worker enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */
44*0a9764feSAndroid Build Coastguard Worker size_t chroma_step; /* Distance in bytes between subsequent chroma pixels. */
45*0a9764feSAndroid Build Coastguard Worker
46*0a9764feSAndroid Build Coastguard Worker /* Result */
47*0a9764feSAndroid Build Coastguard Worker int fourcc; /* DRM_FORMAT_ */
48*0a9764feSAndroid Build Coastguard Worker };
49*0a9764feSAndroid Build Coastguard Worker
50*0a9764feSAndroid Build Coastguard Worker #ifndef DRM_FORMAT_XYUV8888
51*0a9764feSAndroid Build Coastguard Worker #define DRM_FORMAT_XYUV8888 \
52*0a9764feSAndroid Build Coastguard Worker fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
53*0a9764feSAndroid Build Coastguard Worker #endif
54*0a9764feSAndroid Build Coastguard Worker
55*0a9764feSAndroid Build Coastguard Worker /* The following table is used to look up a DRI image FourCC based
56*0a9764feSAndroid Build Coastguard Worker * on native format and information contained in android_ycbcr struct. */
57*0a9764feSAndroid Build Coastguard Worker static const struct DroidYuvFormat kDroidYuvFormats[] = {
58*0a9764feSAndroid Build Coastguard Worker /* Native format, YCrCb, Chroma step, DRI image FourCC */
59*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_YCbCr_420_888, kYCbCr, 2, DRM_FORMAT_NV12},
60*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_YCbCr_420_888, kYCbCr, 1, DRM_FORMAT_YUV420},
61*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_YCbCr_420_888, kYCrCb, 1, DRM_FORMAT_YVU420},
62*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_YV12, kYCrCb, 1, DRM_FORMAT_YVU420},
63*0a9764feSAndroid Build Coastguard Worker /* HACK: See droid_create_image_from_prime_fds() and
64*0a9764feSAndroid Build Coastguard Worker * https://issuetracker.google.com/32077885. */
65*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCbCr, 2, DRM_FORMAT_NV12},
66*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCbCr, 1, DRM_FORMAT_YUV420},
67*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCrCb, 1, DRM_FORMAT_YVU420},
68*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCrCb, 1, DRM_FORMAT_AYUV},
69*0a9764feSAndroid Build Coastguard Worker {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCrCb, 1, DRM_FORMAT_XYUV8888},
70*0a9764feSAndroid Build Coastguard Worker };
71*0a9764feSAndroid Build Coastguard Worker
72*0a9764feSAndroid Build Coastguard Worker #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
73*0a9764feSAndroid Build Coastguard Worker
get_fourcc_yuv(uint32_t native,enum chroma_order chroma_order,size_t chroma_step)74*0a9764feSAndroid Build Coastguard Worker static uint32_t get_fourcc_yuv(uint32_t native, enum chroma_order chroma_order,
75*0a9764feSAndroid Build Coastguard Worker size_t chroma_step) {
76*0a9764feSAndroid Build Coastguard Worker for (auto droid_yuv_format : kDroidYuvFormats)
77*0a9764feSAndroid Build Coastguard Worker if (droid_yuv_format.native == native &&
78*0a9764feSAndroid Build Coastguard Worker droid_yuv_format.chroma_order == chroma_order &&
79*0a9764feSAndroid Build Coastguard Worker droid_yuv_format.chroma_step == chroma_step)
80*0a9764feSAndroid Build Coastguard Worker return droid_yuv_format.fourcc;
81*0a9764feSAndroid Build Coastguard Worker
82*0a9764feSAndroid Build Coastguard Worker return UINT32_MAX;
83*0a9764feSAndroid Build Coastguard Worker }
84*0a9764feSAndroid Build Coastguard Worker
is_yuv(uint32_t native)85*0a9764feSAndroid Build Coastguard Worker static bool is_yuv(uint32_t native) {
86*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(readability-use-anyofallof)
87*0a9764feSAndroid Build Coastguard Worker for (auto droid_yuv_format : kDroidYuvFormats)
88*0a9764feSAndroid Build Coastguard Worker if (droid_yuv_format.native == native)
89*0a9764feSAndroid Build Coastguard Worker return true;
90*0a9764feSAndroid Build Coastguard Worker
91*0a9764feSAndroid Build Coastguard Worker return false;
92*0a9764feSAndroid Build Coastguard Worker }
93*0a9764feSAndroid Build Coastguard Worker
GetYuvPlaneInfo(uint32_t hal_format,int num_fds,buffer_handle_t handle,BufferInfo * bo)94*0a9764feSAndroid Build Coastguard Worker bool BufferInfoLibdrm::GetYuvPlaneInfo(uint32_t hal_format, int num_fds,
95*0a9764feSAndroid Build Coastguard Worker buffer_handle_t handle, BufferInfo *bo) {
96*0a9764feSAndroid Build Coastguard Worker struct android_ycbcr ycbcr {};
97*0a9764feSAndroid Build Coastguard Worker enum chroma_order chroma_order {};
98*0a9764feSAndroid Build Coastguard Worker int ret = 0;
99*0a9764feSAndroid Build Coastguard Worker
100*0a9764feSAndroid Build Coastguard Worker if (!gralloc_->lock_ycbcr) {
101*0a9764feSAndroid Build Coastguard Worker static std::once_flag once;
102*0a9764feSAndroid Build Coastguard Worker std::call_once(once,
103*0a9764feSAndroid Build Coastguard Worker []() { ALOGW("Gralloc does not support lock_ycbcr()"); });
104*0a9764feSAndroid Build Coastguard Worker return false;
105*0a9764feSAndroid Build Coastguard Worker }
106*0a9764feSAndroid Build Coastguard Worker
107*0a9764feSAndroid Build Coastguard Worker memset(&ycbcr, 0, sizeof(ycbcr));
108*0a9764feSAndroid Build Coastguard Worker ret = gralloc_->lock_ycbcr(gralloc_, handle, 0, 0, 0, 0, 0, &ycbcr);
109*0a9764feSAndroid Build Coastguard Worker if (ret) {
110*0a9764feSAndroid Build Coastguard Worker ALOGW("gralloc->lock_ycbcr failed: %d", ret);
111*0a9764feSAndroid Build Coastguard Worker return false;
112*0a9764feSAndroid Build Coastguard Worker }
113*0a9764feSAndroid Build Coastguard Worker gralloc_->unlock(gralloc_, handle);
114*0a9764feSAndroid Build Coastguard Worker
115*0a9764feSAndroid Build Coastguard Worker /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags
116*0a9764feSAndroid Build Coastguard Worker * it will return the .y/.cb/.cr pointers based on a NULL pointer,
117*0a9764feSAndroid Build Coastguard Worker * so they can be interpreted as offsets. */
118*0a9764feSAndroid Build Coastguard Worker bo->offsets[0] = (size_t)ycbcr.y;
119*0a9764feSAndroid Build Coastguard Worker /* We assume here that all the planes are located in one DMA-buf. */
120*0a9764feSAndroid Build Coastguard Worker if ((size_t)ycbcr.cr < (size_t)ycbcr.cb) {
121*0a9764feSAndroid Build Coastguard Worker chroma_order = kYCrCb;
122*0a9764feSAndroid Build Coastguard Worker bo->offsets[1] = (size_t)ycbcr.cr;
123*0a9764feSAndroid Build Coastguard Worker bo->offsets[2] = (size_t)ycbcr.cb;
124*0a9764feSAndroid Build Coastguard Worker } else {
125*0a9764feSAndroid Build Coastguard Worker chroma_order = kYCbCr;
126*0a9764feSAndroid Build Coastguard Worker bo->offsets[1] = (size_t)ycbcr.cb;
127*0a9764feSAndroid Build Coastguard Worker bo->offsets[2] = (size_t)ycbcr.cr;
128*0a9764feSAndroid Build Coastguard Worker }
129*0a9764feSAndroid Build Coastguard Worker
130*0a9764feSAndroid Build Coastguard Worker /* .ystride is the line length (in bytes) of the Y plane,
131*0a9764feSAndroid Build Coastguard Worker * .cstride is the line length (in bytes) of any of the remaining
132*0a9764feSAndroid Build Coastguard Worker * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully
133*0a9764feSAndroid Build Coastguard Worker * planar formats. */
134*0a9764feSAndroid Build Coastguard Worker bo->pitches[0] = ycbcr.ystride;
135*0a9764feSAndroid Build Coastguard Worker bo->pitches[1] = bo->pitches[2] = ycbcr.cstride;
136*0a9764feSAndroid Build Coastguard Worker
137*0a9764feSAndroid Build Coastguard Worker /* .chroma_step is the byte distance between the same chroma channel
138*0a9764feSAndroid Build Coastguard Worker * values of subsequent pixels, assumed to be the same for Cb and Cr. */
139*0a9764feSAndroid Build Coastguard Worker bo->format = get_fourcc_yuv(hal_format, chroma_order, ycbcr.chroma_step);
140*0a9764feSAndroid Build Coastguard Worker if (bo->format == UINT32_MAX) {
141*0a9764feSAndroid Build Coastguard Worker ALOGW(
142*0a9764feSAndroid Build Coastguard Worker "unsupported YUV format, native = %x, chroma_order = %s, chroma_step = "
143*0a9764feSAndroid Build Coastguard Worker "%d",
144*0a9764feSAndroid Build Coastguard Worker hal_format, chroma_order == kYCbCr ? "YCbCr" : "YCrCb",
145*0a9764feSAndroid Build Coastguard Worker (int)ycbcr.chroma_step);
146*0a9764feSAndroid Build Coastguard Worker return false;
147*0a9764feSAndroid Build Coastguard Worker }
148*0a9764feSAndroid Build Coastguard Worker
149*0a9764feSAndroid Build Coastguard Worker /*
150*0a9764feSAndroid Build Coastguard Worker * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
151*0a9764feSAndroid Build Coastguard Worker * the single-fd case cannot happen. So handle eithe single
152*0a9764feSAndroid Build Coastguard Worker * fd or fd-per-plane case:
153*0a9764feSAndroid Build Coastguard Worker */
154*0a9764feSAndroid Build Coastguard Worker if (num_fds == 1) {
155*0a9764feSAndroid Build Coastguard Worker bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0];
156*0a9764feSAndroid Build Coastguard Worker } else {
157*0a9764feSAndroid Build Coastguard Worker const int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
158*0a9764feSAndroid Build Coastguard Worker if (num_fds != expected_planes)
159*0a9764feSAndroid Build Coastguard Worker return false;
160*0a9764feSAndroid Build Coastguard Worker }
161*0a9764feSAndroid Build Coastguard Worker
162*0a9764feSAndroid Build Coastguard Worker return true;
163*0a9764feSAndroid Build Coastguard Worker }
164*0a9764feSAndroid Build Coastguard Worker
GetBoInfo(buffer_handle_t handle)165*0a9764feSAndroid Build Coastguard Worker auto BufferInfoLibdrm::GetBoInfo(buffer_handle_t handle)
166*0a9764feSAndroid Build Coastguard Worker -> std::optional<BufferInfo> {
167*0a9764feSAndroid Build Coastguard Worker gralloc_handle_t *gr_handle = gralloc_handle(handle);
168*0a9764feSAndroid Build Coastguard Worker if (!gr_handle)
169*0a9764feSAndroid Build Coastguard Worker return {};
170*0a9764feSAndroid Build Coastguard Worker
171*0a9764feSAndroid Build Coastguard Worker BufferInfo bi{};
172*0a9764feSAndroid Build Coastguard Worker
173*0a9764feSAndroid Build Coastguard Worker bi.width = gr_handle->width;
174*0a9764feSAndroid Build Coastguard Worker bi.height = gr_handle->height;
175*0a9764feSAndroid Build Coastguard Worker
176*0a9764feSAndroid Build Coastguard Worker #if GRALLOC_HANDLE_VERSION < 4
177*0a9764feSAndroid Build Coastguard Worker static std::once_flag once;
178*0a9764feSAndroid Build Coastguard Worker std::call_once(once, []() {
179*0a9764feSAndroid Build Coastguard Worker ALOGE(
180*0a9764feSAndroid Build Coastguard Worker "libdrm < v2.4.97 has broken gralloc_handle structure. Please update.");
181*0a9764feSAndroid Build Coastguard Worker });
182*0a9764feSAndroid Build Coastguard Worker #endif
183*0a9764feSAndroid Build Coastguard Worker #if GRALLOC_HANDLE_VERSION == 4
184*0a9764feSAndroid Build Coastguard Worker bi.modifiers[0] = gr_handle->modifier;
185*0a9764feSAndroid Build Coastguard Worker #endif
186*0a9764feSAndroid Build Coastguard Worker
187*0a9764feSAndroid Build Coastguard Worker bi.prime_fds[0] = gr_handle->prime_fd;
188*0a9764feSAndroid Build Coastguard Worker
189*0a9764feSAndroid Build Coastguard Worker if (is_yuv(gr_handle->format)) {
190*0a9764feSAndroid Build Coastguard Worker if (!GetYuvPlaneInfo(gr_handle->format, handle->numFds, handle, &bi))
191*0a9764feSAndroid Build Coastguard Worker return {};
192*0a9764feSAndroid Build Coastguard Worker } else {
193*0a9764feSAndroid Build Coastguard Worker bi.pitches[0] = gr_handle->stride;
194*0a9764feSAndroid Build Coastguard Worker bi.offsets[0] = 0;
195*0a9764feSAndroid Build Coastguard Worker
196*0a9764feSAndroid Build Coastguard Worker /* FOSS graphic components (gbm_gralloc, mesa3d) are translating
197*0a9764feSAndroid Build Coastguard Worker * HAL_PIXEL_FORMAT_RGB_565 to DRM_FORMAT_RGB565 without swapping
198*0a9764feSAndroid Build Coastguard Worker * the R and B components. Same must be done here. */
199*0a9764feSAndroid Build Coastguard Worker switch (gr_handle->format) {
200*0a9764feSAndroid Build Coastguard Worker case HAL_PIXEL_FORMAT_RGB_565:
201*0a9764feSAndroid Build Coastguard Worker bi.format = DRM_FORMAT_RGB565;
202*0a9764feSAndroid Build Coastguard Worker break;
203*0a9764feSAndroid Build Coastguard Worker default:
204*0a9764feSAndroid Build Coastguard Worker bi.format = ConvertHalFormatToDrm(gr_handle->format);
205*0a9764feSAndroid Build Coastguard Worker }
206*0a9764feSAndroid Build Coastguard Worker
207*0a9764feSAndroid Build Coastguard Worker if (bi.format == DRM_FORMAT_INVALID)
208*0a9764feSAndroid Build Coastguard Worker return {};
209*0a9764feSAndroid Build Coastguard Worker }
210*0a9764feSAndroid Build Coastguard Worker
211*0a9764feSAndroid Build Coastguard Worker return bi;
212*0a9764feSAndroid Build Coastguard Worker }
213*0a9764feSAndroid Build Coastguard Worker
214*0a9764feSAndroid Build Coastguard Worker constexpr char gbm_gralloc_module_name[] = "GBM Memory Allocator";
215*0a9764feSAndroid Build Coastguard Worker constexpr char drm_gralloc_module_name[] = "DRM Memory Allocator";
216*0a9764feSAndroid Build Coastguard Worker
ValidateGralloc()217*0a9764feSAndroid Build Coastguard Worker int BufferInfoLibdrm::ValidateGralloc() {
218*0a9764feSAndroid Build Coastguard Worker if (strcmp(gralloc_->common.name, drm_gralloc_module_name) != 0 &&
219*0a9764feSAndroid Build Coastguard Worker strcmp(gralloc_->common.name, gbm_gralloc_module_name) != 0) {
220*0a9764feSAndroid Build Coastguard Worker ALOGE(
221*0a9764feSAndroid Build Coastguard Worker "Gralloc name isn't valid: Expected: \"%s\" or \"%s\", Actual: \"%s\"",
222*0a9764feSAndroid Build Coastguard Worker gbm_gralloc_module_name, drm_gralloc_module_name,
223*0a9764feSAndroid Build Coastguard Worker gralloc_->common.name);
224*0a9764feSAndroid Build Coastguard Worker return -EINVAL;
225*0a9764feSAndroid Build Coastguard Worker }
226*0a9764feSAndroid Build Coastguard Worker
227*0a9764feSAndroid Build Coastguard Worker return 0;
228*0a9764feSAndroid Build Coastguard Worker }
229*0a9764feSAndroid Build Coastguard Worker
230*0a9764feSAndroid Build Coastguard Worker } // namespace android
231