1 // Copyright 2024 The Android Open Source Project
2 //
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 #include "GrallocEmulated.h"
16 
17 #include <cutils/log.h>
18 
19 #include <optional>
20 
21 #include "drm_fourcc.h"
22 
23 namespace gfxstream {
24 namespace {
25 
26 static constexpr int numFds = 0;
27 static constexpr int numInts = 1;
28 
29 #define DRM_FORMAT_R8_BLOB fourcc_code('9', '9', '9', '9')
30 
GlFormatToDrmFormat(uint32_t glFormat)31 std::optional<uint32_t> GlFormatToDrmFormat(uint32_t glFormat) {
32     switch (glFormat) {
33         case kGlRGB:
34             return DRM_FORMAT_BGR888;
35         case kGlRGB565:
36             return DRM_FORMAT_BGR565;
37         case kGlRGBA:
38             return DRM_FORMAT_ABGR8888;
39     }
40     return std::nullopt;
41 }
42 
AhbToDrmFormat(uint32_t ahbFormat)43 std::optional<uint32_t> AhbToDrmFormat(uint32_t ahbFormat) {
44     switch (ahbFormat) {
45         case GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM:
46             return DRM_FORMAT_ABGR8888;
47         case GFXSTREAM_AHB_FORMAT_R8G8B8X8_UNORM:
48             return DRM_FORMAT_XBGR8888;
49         case GFXSTREAM_AHB_FORMAT_R8G8B8_UNORM:
50             return DRM_FORMAT_BGR888;
51         /*
52         * Confusingly, AHARDWAREBUFFER_FORMAT_RGB_565 is defined as:
53         *
54         * "16-bit packed format that has 5-bit R, 6-bit G, and 5-bit B components, in that
55         *  order, from the  most-sigfinicant bits to the least-significant bits."
56         *
57         * so the order of the components is intentionally not flipped between the pixel
58         * format and the DRM format.
59         */
60         case GFXSTREAM_AHB_FORMAT_R5G6B5_UNORM:
61             return DRM_FORMAT_RGB565;
62         case GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM:
63             return DRM_FORMAT_ARGB8888;
64         case GFXSTREAM_AHB_FORMAT_BLOB:
65             return DRM_FORMAT_R8_BLOB;
66         case GFXSTREAM_AHB_FORMAT_R8_UNORM:
67             return DRM_FORMAT_R8;
68         case GFXSTREAM_AHB_FORMAT_YV12:
69             return DRM_FORMAT_YVU420;
70         case GFXSTREAM_AHB_FORMAT_R16G16B16A16_FLOAT:
71             return DRM_FORMAT_ABGR16161616F;
72         case GFXSTREAM_AHB_FORMAT_R10G10B10A2_UNORM:
73             return DRM_FORMAT_ABGR2101010;
74     }
75     return std::nullopt;
76 }
77 
DrmToAhbFormat(uint32_t drmFormat)78 std::optional<uint32_t> DrmToAhbFormat(uint32_t drmFormat) {
79     switch (drmFormat) {
80         case DRM_FORMAT_ABGR8888:
81             return GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM;
82         case DRM_FORMAT_XBGR8888:
83             return GFXSTREAM_AHB_FORMAT_R8G8B8X8_UNORM;
84         case DRM_FORMAT_ARGB8888:
85             return GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM;
86         case DRM_FORMAT_BGR888:
87             return GFXSTREAM_AHB_FORMAT_R8G8B8_UNORM;
88         case DRM_FORMAT_RGB565:
89             return GFXSTREAM_AHB_FORMAT_R5G6B5_UNORM;
90         case DRM_FORMAT_R8_BLOB:
91             return GFXSTREAM_AHB_FORMAT_BLOB;
92         case DRM_FORMAT_R8:
93             return GFXSTREAM_AHB_FORMAT_R8_UNORM;
94         case DRM_FORMAT_YVU420:
95             return GFXSTREAM_AHB_FORMAT_YV12;
96         case DRM_FORMAT_ABGR16161616F:
97             return GFXSTREAM_AHB_FORMAT_R16G16B16A16_FLOAT;
98         case DRM_FORMAT_ABGR2101010:
99             return GFXSTREAM_AHB_FORMAT_R10G10B10A2_UNORM;
100     }
101     return std::nullopt;
102 }
103 
DrmToBpp(uint32_t drmFormat)104 std::optional<uint32_t> DrmToBpp(uint32_t drmFormat) {
105     switch (drmFormat) {
106         case DRM_FORMAT_ABGR8888:
107         case DRM_FORMAT_ARGB8888:
108         case DRM_FORMAT_XBGR8888:
109             return 4;
110         case DRM_FORMAT_BGR888:
111             return 3;
112         case DRM_FORMAT_RGB565:
113             return 2;
114         case DRM_FORMAT_R8_BLOB:
115         case DRM_FORMAT_R8:
116             return 1;
117     }
118     return std::nullopt;
119 }
120 
DrmToVirglFormat(uint32_t drmFormat)121 std::optional<uint32_t> DrmToVirglFormat(uint32_t drmFormat) {
122     switch (drmFormat) {
123         case DRM_FORMAT_ABGR8888:
124             return VIRGL_FORMAT_R8G8B8A8_UNORM;
125         case DRM_FORMAT_ARGB8888:
126             return VIRGL_FORMAT_B8G8R8A8_UNORM;
127         case DRM_FORMAT_BGR888:
128             return VIRGL_FORMAT_R8G8B8_UNORM;
129         case DRM_FORMAT_BGR565:
130             return VIRGL_FORMAT_B5G6R5_UNORM;
131         case DRM_FORMAT_R8:
132         case DRM_FORMAT_R8_BLOB:
133             return VIRGL_FORMAT_R8_UNORM;
134     }
135     return std::nullopt;
136 }
137 
138 }  // namespace
139 
EmulatedAHardwareBuffer(uint32_t width,uint32_t height,uint32_t drmFormat,VirtGpuResourcePtr resource)140 EmulatedAHardwareBuffer::EmulatedAHardwareBuffer(uint32_t width, uint32_t height,
141                                                  uint32_t drmFormat, VirtGpuResourcePtr resource)
142     : mRefCount(1), mWidth(width), mHeight(height), mDrmFormat(drmFormat), mResource(resource) {}
143 
~EmulatedAHardwareBuffer()144 EmulatedAHardwareBuffer::~EmulatedAHardwareBuffer() {}
145 
getResourceId() const146 uint32_t EmulatedAHardwareBuffer::getResourceId() const { return mResource->getResourceHandle(); }
147 
getWidth() const148 uint32_t EmulatedAHardwareBuffer::getWidth() const { return mWidth; }
149 
getHeight() const150 uint32_t EmulatedAHardwareBuffer::getHeight() const { return mHeight; }
151 
getAndroidFormat() const152 int EmulatedAHardwareBuffer::getAndroidFormat() const {
153     auto ahbFormat = DrmToAhbFormat(mDrmFormat);
154     if (!ahbFormat) {
155         ALOGE("Unhandled DRM format:%u", mDrmFormat);
156         return -1;
157     }
158     return *ahbFormat;
159 }
160 
getDrmFormat() const161 uint32_t EmulatedAHardwareBuffer::getDrmFormat() const { return mDrmFormat; }
162 
asAHardwareBuffer()163 AHardwareBuffer* EmulatedAHardwareBuffer::asAHardwareBuffer() {
164     return reinterpret_cast<AHardwareBuffer*>(this);
165 }
166 
asBufferHandle()167 buffer_handle_t EmulatedAHardwareBuffer::asBufferHandle() {
168     return reinterpret_cast<buffer_handle_t>(this);
169 }
170 
asEglClientBuffer()171 EGLClientBuffer EmulatedAHardwareBuffer::asEglClientBuffer() {
172     return reinterpret_cast<EGLClientBuffer>(this);
173 }
174 
acquire()175 void EmulatedAHardwareBuffer::acquire() { ++mRefCount; }
176 
release()177 void EmulatedAHardwareBuffer::release() {
178     --mRefCount;
179     if (mRefCount == 0) {
180         delete this;
181     }
182 }
183 
lock(uint8_t ** ptr)184 int EmulatedAHardwareBuffer::lock(uint8_t** ptr) {
185     if (!mMapped) {
186         mMapped = mResource->createMapping();
187         if (!mMapped) {
188             ALOGE("Failed to lock EmulatedAHardwareBuffer: failed to create mapping.");
189             return -1;
190         }
191 
192         mResource->transferFromHost(0, 0, mWidth, mHeight);
193         mResource->wait();
194     }
195 
196     *ptr = (*mMapped)->asRawPtr();
197     return 0;
198 }
199 
unlock()200 int EmulatedAHardwareBuffer::unlock() {
201     if (!mMapped) {
202         ALOGE("Failed to unlock EmulatedAHardwareBuffer: never locked?");
203         return -1;
204     }
205     mResource->transferToHost(0, 0, mWidth, mHeight);
206     mResource->wait();
207     mMapped.reset();
208     return 0;
209 }
210 
EmulatedGralloc()211 EmulatedGralloc::EmulatedGralloc() {}
212 
createColorBuffer(void *,int width,int height,uint32_t glFormat)213 uint32_t EmulatedGralloc::createColorBuffer(void*, int width, int height, uint32_t glFormat) {
214     auto drmFormat = GlFormatToDrmFormat(glFormat);
215     if (!drmFormat) {
216         ALOGE("Unhandled format");
217     }
218 
219     auto ahb = allocate(width, height, *drmFormat);
220 
221     EmulatedAHardwareBuffer* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
222 
223     mOwned.emplace_back(rahb);
224 
225     return rahb->getResourceId();
226 }
227 
allocate(uint32_t width,uint32_t height,uint32_t ahbFormat,uint64_t usage,AHardwareBuffer ** outputAhb)228 int EmulatedGralloc::allocate(uint32_t width, uint32_t height, uint32_t ahbFormat, uint64_t usage,
229                               AHardwareBuffer** outputAhb) {
230     (void)usage;
231 
232     auto drmFormat = AhbToDrmFormat(ahbFormat);
233     if (!drmFormat) {
234         ALOGE("Unhandled AHB format:%u", ahbFormat);
235         return -1;
236     }
237 
238     *outputAhb = allocate(width, height, *drmFormat);
239     if (*outputAhb == nullptr) {
240         return -1;
241     }
242 
243     return 0;
244 }
245 
allocate(uint32_t width,uint32_t height,uint32_t drmFormat)246 AHardwareBuffer* EmulatedGralloc::allocate(uint32_t width, uint32_t height, uint32_t drmFormat) {
247     ALOGE("Allocating AHB w:%u, h:%u, format %u", width, height, drmFormat);
248 
249     auto device = VirtGpuDevice::getInstance();
250     if (!device) {
251         ALOGE("Failed to allocate: no virtio gpu device.");
252         return nullptr;
253     }
254 
255     auto virglFormat = DrmToVirglFormat(drmFormat);
256     if (!virglFormat) {
257         ALOGE("Failed to allocate: Unhandled DRM format:%u to Virgl format conversion.", drmFormat);
258         return nullptr;
259     }
260 
261     auto bpp = DrmToBpp(drmFormat);
262     if (!virglFormat) {
263         ALOGE("Failed to allocate: Unhandled DRM format:%u to bpp conversion.", drmFormat);
264         return nullptr;
265     }
266 
267     const uint32_t bind =
268         (drmFormat == DRM_FORMAT_R8_BLOB) ? VIRGL_BIND_LINEAR : VIRGL_BIND_RENDER_TARGET;
269     const uint32_t stride = width * (*bpp);
270 
271     auto resource =
272         device->createResource(width, height, stride, *virglFormat, PIPE_TEXTURE_2D, bind);
273     if (!resource) {
274         ALOGE("Failed to allocate: failed to create virtio resource.");
275         return nullptr;
276     }
277 
278     resource->wait();
279 
280     return reinterpret_cast<AHardwareBuffer*>(
281         new EmulatedAHardwareBuffer(width, height, drmFormat, std::move(resource)));
282 }
283 
acquire(AHardwareBuffer * ahb)284 void EmulatedGralloc::acquire(AHardwareBuffer* ahb) {
285     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
286     rahb->acquire();
287 }
288 
release(AHardwareBuffer * ahb)289 void EmulatedGralloc::release(AHardwareBuffer* ahb) {
290     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
291     rahb->release();
292 }
293 
lock(AHardwareBuffer * ahb,uint8_t ** ptr)294 int EmulatedGralloc::lock(AHardwareBuffer* ahb, uint8_t** ptr) {
295     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
296     return rahb->lock(ptr);
297 }
298 
unlock(AHardwareBuffer * ahb)299 int EmulatedGralloc::unlock(AHardwareBuffer* ahb) {
300     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
301     return rahb->unlock();
302 }
303 
getHostHandle(const native_handle_t * handle)304 uint32_t EmulatedGralloc::getHostHandle(const native_handle_t* handle) {
305     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
306     return ahb->getResourceId();
307 }
308 
getHostHandle(const AHardwareBuffer * handle)309 uint32_t EmulatedGralloc::getHostHandle(const AHardwareBuffer* handle) {
310     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
311     return ahb->getResourceId();
312 }
313 
getNativeHandle(const AHardwareBuffer * ahb)314 const native_handle_t* EmulatedGralloc::getNativeHandle(const AHardwareBuffer* ahb) {
315     return reinterpret_cast<const native_handle_t*>(ahb);
316 }
317 
getFormat(const native_handle_t * handle)318 int EmulatedGralloc::getFormat(const native_handle_t* handle) {
319     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
320     return ahb->getAndroidFormat();
321 }
322 
getFormat(const AHardwareBuffer * handle)323 int EmulatedGralloc::getFormat(const AHardwareBuffer* handle) {
324     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
325     return ahb->getAndroidFormat();
326 }
327 
getFormatDrmFourcc(const AHardwareBuffer * handle)328 uint32_t EmulatedGralloc::getFormatDrmFourcc(const AHardwareBuffer* handle) {
329     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
330     return ahb->getDrmFormat();
331 }
332 
getWidth(const AHardwareBuffer * handle)333 uint32_t EmulatedGralloc::getWidth(const AHardwareBuffer* handle) {
334     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
335     return ahb->getWidth();
336 }
337 
getHeight(const AHardwareBuffer * handle)338 uint32_t EmulatedGralloc::getHeight(const AHardwareBuffer* handle) {
339     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
340     return ahb->getHeight();
341 }
342 
getAllocatedSize(const native_handle_t *)343 size_t EmulatedGralloc::getAllocatedSize(const native_handle_t*) {
344     ALOGE("Unimplemented.");
345     return 0;
346 }
347 
getAllocatedSize(const AHardwareBuffer *)348 size_t EmulatedGralloc::getAllocatedSize(const AHardwareBuffer*) {
349     ALOGE("Unimplemented.");
350     return 0;
351 }
352 
getId(const AHardwareBuffer * ahb,uint64_t * id)353 int EmulatedGralloc::getId(const AHardwareBuffer* ahb, uint64_t* id) {
354     const auto* rahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(ahb);
355     *id = rahb->getResourceId();
356     return 0;
357 }
358 
createPlatformGralloc(int)359 Gralloc* createPlatformGralloc(int /*deviceFd*/) {
360     return new EmulatedGralloc();
361 }
362 
363 }  // namespace gfxstream
364