• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "hwc-bufferinfo-libdrm"
18 
19 #include "BufferInfoLibdrm.h"
20 
21 #include <cutils/properties.h>
22 #include <gralloc_handle.h>
23 #include <hardware/gralloc.h>
24 #include <log/log.h>
25 #include <xf86drm.h>
26 #include <xf86drmMode.h>
27 
28 namespace android {
29 
30 LEGACY_BUFFER_INFO_GETTER(BufferInfoLibdrm);
31 
32 enum chroma_order {
33   YCbCr,
34   YCrCb,
35 };
36 
37 struct droid_yuv_format {
38   /* Lookup keys */
39   int native;                     /* HAL_PIXEL_FORMAT_ */
40   enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */
41   int chroma_step; /* Distance in bytes between subsequent chroma pixels. */
42 
43   /* Result */
44   int fourcc; /* DRM_FORMAT_ */
45 };
46 
47 /* The following table is used to look up a DRI image FourCC based
48  * on native format and information contained in android_ycbcr struct. */
49 static const struct droid_yuv_format droid_yuv_formats[] = {
50     /* Native format, YCrCb, Chroma step, DRI image FourCC */
51     {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 2, DRM_FORMAT_NV12},
52     {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, DRM_FORMAT_YUV420},
53     {HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, DRM_FORMAT_YVU420},
54     {HAL_PIXEL_FORMAT_YV12, YCrCb, 1, DRM_FORMAT_YVU420},
55     /* HACK: See droid_create_image_from_prime_fds() and
56      * https://issuetracker.google.com/32077885. */
57     {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, DRM_FORMAT_NV12},
58     {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, DRM_FORMAT_YUV420},
59     {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_YVU420},
60     {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_AYUV},
61     {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_XYUV8888},
62 };
63 
64 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
65 
get_fourcc_yuv(int native,enum chroma_order chroma_order,int chroma_step)66 static int get_fourcc_yuv(int native, enum chroma_order chroma_order,
67                           int chroma_step) {
68   for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
69     if (droid_yuv_formats[i].native == native &&
70         droid_yuv_formats[i].chroma_order == chroma_order &&
71         droid_yuv_formats[i].chroma_step == chroma_step)
72       return droid_yuv_formats[i].fourcc;
73 
74   return -1;
75 }
76 
is_yuv(int native)77 static bool is_yuv(int native) {
78   for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
79     if (droid_yuv_formats[i].native == native)
80       return true;
81 
82   return false;
83 }
84 
GetYuvPlaneInfo(int num_fds,buffer_handle_t handle,hwc_drm_bo_t * bo)85 bool BufferInfoLibdrm::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle,
86                                        hwc_drm_bo_t *bo) {
87   struct android_ycbcr ycbcr;
88   enum chroma_order chroma_order;
89   int ret;
90 
91   if (!gralloc_->lock_ycbcr) {
92     static std::once_flag once;
93     std::call_once(once,
94                    []() { ALOGW("Gralloc does not support lock_ycbcr()"); });
95     return false;
96   }
97 
98   memset(&ycbcr, 0, sizeof(ycbcr));
99   ret = gralloc_->lock_ycbcr(gralloc_, handle, 0, 0, 0, 0, 0, &ycbcr);
100   if (ret) {
101     ALOGW("gralloc->lock_ycbcr failed: %d", ret);
102     return false;
103   }
104   gralloc_->unlock(gralloc_, handle);
105 
106   /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags
107    * it will return the .y/.cb/.cr pointers based on a NULL pointer,
108    * so they can be interpreted as offsets. */
109   bo->offsets[0] = (size_t)ycbcr.y;
110   /* We assume here that all the planes are located in one DMA-buf. */
111   if ((size_t)ycbcr.cr < (size_t)ycbcr.cb) {
112     chroma_order = YCrCb;
113     bo->offsets[1] = (size_t)ycbcr.cr;
114     bo->offsets[2] = (size_t)ycbcr.cb;
115   } else {
116     chroma_order = YCbCr;
117     bo->offsets[1] = (size_t)ycbcr.cb;
118     bo->offsets[2] = (size_t)ycbcr.cr;
119   }
120 
121   /* .ystride is the line length (in bytes) of the Y plane,
122    * .cstride is the line length (in bytes) of any of the remaining
123    * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully
124    * planar formats. */
125   bo->pitches[0] = ycbcr.ystride;
126   bo->pitches[1] = bo->pitches[2] = ycbcr.cstride;
127 
128   /* .chroma_step is the byte distance between the same chroma channel
129    * values of subsequent pixels, assumed to be the same for Cb and Cr. */
130   bo->format = get_fourcc_yuv(bo->hal_format, chroma_order, ycbcr.chroma_step);
131   if (bo->format == -1) {
132     ALOGW(
133         "unsupported YUV format, native = %x, chroma_order = %s, chroma_step = "
134         "%d",
135         bo->hal_format, chroma_order == YCbCr ? "YCbCr" : "YCrCb",
136         (int)ycbcr.chroma_step);
137     return false;
138   }
139 
140   /*
141    * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
142    * the single-fd case cannot happen.  So handle eithe single
143    * fd or fd-per-plane case:
144    */
145   if (num_fds == 1) {
146     bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0];
147   } else {
148     int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
149     if (num_fds != expected_planes)
150       return false;
151   }
152 
153   return true;
154 }
155 
ConvertBoInfo(buffer_handle_t handle,hwc_drm_bo_t * bo)156 int BufferInfoLibdrm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
157   gralloc_handle_t *gr_handle = gralloc_handle(handle);
158   if (!gr_handle)
159     return -EINVAL;
160 
161   bo->width = gr_handle->width;
162   bo->height = gr_handle->height;
163   bo->hal_format = gr_handle->format;
164 
165 #if GRALLOC_HANDLE_VERSION < 4
166   static std::once_flag once;
167   std::call_once(once, []() {
168     ALOGE(
169         "libdrm < v2.4.97 has broken gralloc_handle structure. Please update.");
170   });
171 #endif
172 #if GRALLOC_HANDLE_VERSION == 4
173   bo->modifiers[0] = gr_handle->modifier;
174   bo->with_modifiers = gr_handle->modifier != DRM_FORMAT_MOD_NONE &&
175                        gr_handle->modifier != DRM_FORMAT_MOD_INVALID;
176 #endif
177 
178   bo->usage = gr_handle->usage;
179   bo->prime_fds[0] = gr_handle->prime_fd;
180 
181   if (is_yuv(gr_handle->format)) {
182     if (!GetYuvPlaneInfo(handle->numFds, handle, bo))
183       return -EINVAL;
184   } else {
185     bo->pitches[0] = gr_handle->stride;
186     bo->offsets[0] = 0;
187     bo->format = ConvertHalFormatToDrm(gr_handle->format);
188     if (bo->format == DRM_FORMAT_INVALID)
189       return -EINVAL;
190   }
191 
192   return 0;
193 }
194 
195 }  // namespace android
196