• 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 #if __ANDROID_API__ >= 30
18 
19 #define LOG_TAG "drmhwc"
20 
21 #include "BufferInfoMapperMetadata.h"
22 
23 #include <drm/drm_fourcc.h>
24 #include <ui/GraphicBufferMapper.h>
25 #include <xf86drm.h>
26 #include <xf86drmMode.h>
27 
28 #include <cinttypes>
29 
30 #include "utils/log.h"
31 
32 namespace android {
33 
34 namespace {
35 
GetAlignedDimensions(const ui::PlaneLayout & layout)36 std::optional<std::pair<uint32_t, uint32_t>> GetAlignedDimensions(
37     const ui::PlaneLayout &layout) {
38   if (layout.sampleIncrementInBits == 0 || layout.strideInBytes == 0) {
39     ALOGW("Invalid plane layout");
40     return std::nullopt;
41   }
42 
43   constexpr uint32_t kBitsPerByte = 8;
44   return std::pair{layout.strideInBytes * kBitsPerByte /
45                        layout.sampleIncrementInBits,
46                    layout.totalSizeInBytes / layout.strideInBytes};
47 }
48 
49 }  // namespace
50 
CreateInstance()51 BufferInfoGetter *BufferInfoMapperMetadata::CreateInstance() {
52   if (GraphicBufferMapper::getInstance().getMapperVersion() <
53       GraphicBufferMapper::GRALLOC_4)
54     return nullptr;
55 
56   return new BufferInfoMapperMetadata();
57 }
58 
59 /* The implementation below makes assumptions on the order and number of file
60  * descriptors that Gralloc places in the native_handle_t and as such it very
61  * likely needs to be adapted to match the particular Gralloc implementation
62  * used in the system. For this reason it is been declared as a weak symbol,
63  * so that it can be overridden.
64  */
65 int __attribute__((weak))
GetFds(buffer_handle_t handle,BufferInfo * bo)66 BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, BufferInfo *bo) {
67   int fd_index = 0;
68 
69   if (handle->numFds <= 0) {
70     ALOGE("Handle has no fds");
71     return android::BAD_VALUE;
72   }
73 
74   for (int i = 0; i < kBufferMaxPlanes; i++) {
75     /* If no size, we're out of usable planes */
76     if (bo->sizes[i] <= 0) {
77       if (i == 0) {
78         ALOGE("Bad handle metadata");
79         return android::BAD_VALUE;
80       }
81       break;
82     }
83 
84     /*
85      * If the offset is zero, its multi-buffer
86      * so move to the next fd
87      */
88     if (i != 0 && bo->offsets[i] == 0) {
89       fd_index++;
90       if (fd_index >= handle->numFds) {
91         ALOGE("Handle has no more fds");
92         return android::BAD_VALUE;
93       }
94     }
95 
96     bo->prime_fds[i] = handle->data[fd_index];
97     if (bo->prime_fds[i] <= 0) {
98       ALOGE("Invalid prime fd");
99       return android::BAD_VALUE;
100     }
101   }
102 
103   return 0;
104 }
105 
GetBoInfo(buffer_handle_t handle)106 auto BufferInfoMapperMetadata::GetBoInfo(buffer_handle_t handle)
107     -> std::optional<BufferInfo> {
108   GraphicBufferMapper &mapper = GraphicBufferMapper::getInstance();
109   if (handle == nullptr)
110     return {};
111 
112   BufferInfo bi{};
113 
114   int err = mapper.getPixelFormatFourCC(handle, &bi.format);
115   if (err != 0) {
116     ALOGE("Failed to get FourCC format err=%d", err);
117     return {};
118   }
119 
120   err = mapper.getPixelFormatModifier(handle, &bi.modifiers[0]);
121   if (err != 0) {
122     ALOGE("Failed to get DRM Modifier err=%d", err);
123     return {};
124   }
125 
126   uint64_t width = 0;
127   err = mapper.getWidth(handle, &width);
128   if (err != 0) {
129     ALOGE("Failed to get Width err=%d", err);
130     return {};
131   }
132   bi.width = static_cast<uint32_t>(width);
133 
134   uint64_t height = 0;
135   err = mapper.getHeight(handle, &height);
136   if (err != 0) {
137     ALOGE("Failed to get Height err=%d", err);
138     return {};
139   }
140   bi.height = static_cast<uint32_t>(height);
141 
142   std::vector<ui::PlaneLayout> layouts;
143   err = mapper.getPlaneLayouts(handle, &layouts);
144   if (err != 0) {
145     ALOGE("Failed to get Plane Layouts err=%d", err);
146     return {};
147   }
148 
149   for (uint32_t i = 0; i < layouts.size(); i++) {
150     bi.modifiers[i] = bi.modifiers[0];
151     bi.pitches[i] = layouts[i].strideInBytes;
152     bi.offsets[i] = layouts[i].offsetInBytes;
153     bi.sizes[i] = layouts[i].totalSizeInBytes;
154   }
155 
156   uint64_t usage = 0;
157   err = mapper.getUsage(handle, &usage);
158   if (err != 0) {
159     ALOGE("Failed to get Usage err=%d", err);
160     return {};
161   }
162 
163   if ((usage & GRALLOC_USAGE_CURSOR) != 0) {
164     if (layouts.size() > 1) {
165       ALOGW("Multiplanar format buffer alignment not supported");
166     } else {
167       auto aligned = GetAlignedDimensions(layouts[0]);
168       if (aligned.has_value()) {
169         bi.width = aligned->first;
170         bi.height = aligned->second;
171       }
172     }
173   }
174 
175   err = GetFds(handle, &bi);
176   if (err != 0) {
177     ALOGE("Failed to get fds (err=%d)", err);
178     return {};
179   }
180 
181   return bi;
182 }
183 
184 }  // namespace android
185 
186 #endif
187