xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/android/GrallocEmulated.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2024 Google LLC
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "GrallocEmulated.h"
7 
8 #include <optional>
9 #include <unordered_map>
10 
11 #include "drm_fourcc.h"
12 #include "util/log.h"
13 
14 namespace gfxstream {
15 namespace {
16 
17 static constexpr int numFds = 0;
18 static constexpr int numInts = 1;
19 
20 #define DRM_FORMAT_R8_BLOB fourcc_code('9', '9', '9', '9')
21 
22 template <typename T, typename N>
DivideRoundUp(T n,N divisor)23 T DivideRoundUp(T n, N divisor) {
24     const T div = static_cast<T>(divisor);
25     const T q = n / div;
26     return n % div == 0 ? q : q + 1;
27 }
28 
29 template <typename T, typename N>
Align(T number,N n)30 T Align(T number, N n) {
31     return DivideRoundUp(number, n) * n;
32 }
33 
GlFormatToDrmFormat(uint32_t glFormat)34 std::optional<uint32_t> GlFormatToDrmFormat(uint32_t glFormat) {
35     switch (glFormat) {
36         case kGlRGB:
37             return DRM_FORMAT_BGR888;
38         case kGlRGB565:
39             return DRM_FORMAT_BGR565;
40         case kGlRGBA:
41             return DRM_FORMAT_ABGR8888;
42     }
43     return std::nullopt;
44 }
45 
AhbToDrmFormat(uint32_t ahbFormat)46 std::optional<uint32_t> AhbToDrmFormat(uint32_t ahbFormat) {
47     switch (ahbFormat) {
48         case GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM:
49             return DRM_FORMAT_ABGR8888;
50         case GFXSTREAM_AHB_FORMAT_R8G8B8X8_UNORM:
51             return DRM_FORMAT_XBGR8888;
52         case GFXSTREAM_AHB_FORMAT_R8G8B8_UNORM:
53             return DRM_FORMAT_BGR888;
54         /*
55         * Confusingly, AHARDWAREBUFFER_FORMAT_RGB_565 is defined as:
56         *
57         * "16-bit packed format that has 5-bit R, 6-bit G, and 5-bit B components, in that
58         *  order, from the  most-sigfinicant bits to the least-significant bits."
59         *
60         * so the order of the components is intentionally not flipped between the pixel
61         * format and the DRM format.
62         */
63         case GFXSTREAM_AHB_FORMAT_R5G6B5_UNORM:
64             return DRM_FORMAT_RGB565;
65         case GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM:
66             return DRM_FORMAT_ARGB8888;
67         case GFXSTREAM_AHB_FORMAT_BLOB:
68             return DRM_FORMAT_R8_BLOB;
69         case GFXSTREAM_AHB_FORMAT_R8_UNORM:
70             return DRM_FORMAT_R8;
71         case GFXSTREAM_AHB_FORMAT_YV12:
72             return DRM_FORMAT_YVU420;
73         case GFXSTREAM_AHB_FORMAT_R16G16B16A16_FLOAT:
74             return DRM_FORMAT_ABGR16161616F;
75         case GFXSTREAM_AHB_FORMAT_R10G10B10A2_UNORM:
76             return DRM_FORMAT_ABGR2101010;
77         case GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420:
78             return DRM_FORMAT_NV12;
79     }
80     return std::nullopt;
81 }
82 
83 struct DrmFormatPlaneInfo {
84     uint32_t horizontalSubsampling;
85     uint32_t verticalSubsampling;
86     uint32_t bytesPerPixel;
87 };
88 struct DrmFormatInfo {
89     uint32_t androidFormat;
90     uint32_t virglFormat;
91     bool isYuv;
92     uint32_t horizontalAlignmentPixels;
93     uint32_t verticalAlignmentPixels;
94     std::vector<DrmFormatPlaneInfo> planes;
95 };
GetDrmFormatInfoMap()96 const std::unordered_map<uint32_t, DrmFormatInfo>& GetDrmFormatInfoMap() {
97     static const auto* kFormatInfoMap = new std::unordered_map<uint32_t, DrmFormatInfo>({
98         {DRM_FORMAT_ABGR8888,
99          {
100              .androidFormat = GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM,
101              .virglFormat = VIRGL_FORMAT_R8G8B8A8_UNORM,
102              .isYuv = false,
103              .horizontalAlignmentPixels = 1,
104              .verticalAlignmentPixels = 1,
105              .planes =
106                  {
107                      {
108                          .horizontalSubsampling = 1,
109                          .verticalSubsampling = 1,
110                          .bytesPerPixel = 4,
111                      },
112                  },
113          }},
114         {DRM_FORMAT_ARGB8888,
115          {
116              .androidFormat = GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM,
117              .virglFormat = VIRGL_FORMAT_B8G8R8A8_UNORM,
118              .isYuv = false,
119              .horizontalAlignmentPixels = 1,
120              .verticalAlignmentPixels = 1,
121              .planes =
122                  {
123                      {
124                          .horizontalSubsampling = 1,
125                          .verticalSubsampling = 1,
126                          .bytesPerPixel = 4,
127                      },
128                  },
129          }},
130         {DRM_FORMAT_BGR888,
131          {
132              .androidFormat = GFXSTREAM_AHB_FORMAT_R8G8B8_UNORM,
133              .virglFormat = VIRGL_FORMAT_R8G8B8_UNORM,
134              .isYuv = false,
135              .horizontalAlignmentPixels = 1,
136              .verticalAlignmentPixels = 1,
137              .planes =
138                  {
139                      {
140                          .horizontalSubsampling = 1,
141                          .verticalSubsampling = 1,
142                          .bytesPerPixel = 3,
143                      },
144                  },
145          }},
146         {DRM_FORMAT_BGR565,
147          {
148              .androidFormat = GFXSTREAM_AHB_FORMAT_R5G6B5_UNORM,
149              .virglFormat = VIRGL_FORMAT_B5G6R5_UNORM,
150              .isYuv = false,
151              .horizontalAlignmentPixels = 1,
152              .verticalAlignmentPixels = 1,
153              .planes =
154                  {
155                      {
156                          .horizontalSubsampling = 1,
157                          .verticalSubsampling = 1,
158                          .bytesPerPixel = 2,
159                      },
160                  },
161          }},
162         {DRM_FORMAT_R8,
163          {
164              .androidFormat = GFXSTREAM_AHB_FORMAT_R8_UNORM,
165              .virglFormat = VIRGL_FORMAT_R8_UNORM,
166              .isYuv = false,
167              .horizontalAlignmentPixels = 1,
168              .verticalAlignmentPixels = 1,
169              .planes =
170                  {
171                      {
172                          .horizontalSubsampling = 1,
173                          .verticalSubsampling = 1,
174                          .bytesPerPixel = 1,
175                      },
176                  },
177          }},
178         {DRM_FORMAT_R8_BLOB,
179          {
180              .androidFormat = GFXSTREAM_AHB_FORMAT_BLOB,
181              .virglFormat = VIRGL_FORMAT_R8_UNORM,
182              .isYuv = false,
183              .horizontalAlignmentPixels = 1,
184              .verticalAlignmentPixels = 1,
185              .planes =
186                  {
187                      {
188                          .horizontalSubsampling = 1,
189                          .verticalSubsampling = 1,
190                          .bytesPerPixel = 1,
191                      },
192                  },
193          }},
194         {DRM_FORMAT_ABGR16161616F,
195          {
196              .androidFormat = GFXSTREAM_AHB_FORMAT_R16G16B16A16_FLOAT,
197              .virglFormat = VIRGL_FORMAT_R16G16B16A16_FLOAT,
198              .isYuv = false,
199              .horizontalAlignmentPixels = 1,
200              .verticalAlignmentPixels = 1,
201              .planes =
202                  {
203                      {
204                          .horizontalSubsampling = 1,
205                          .verticalSubsampling = 1,
206                          .bytesPerPixel = 8,
207                      },
208                  },
209          }},
210         {DRM_FORMAT_ABGR2101010,
211          {
212              .androidFormat = GFXSTREAM_AHB_FORMAT_R10G10B10A2_UNORM,
213              .virglFormat = VIRGL_FORMAT_R10G10B10A2_UNORM,
214              .isYuv = false,
215              .horizontalAlignmentPixels = 1,
216              .verticalAlignmentPixels = 1,
217              .planes =
218                  {
219                      {
220                          .horizontalSubsampling = 1,
221                          .verticalSubsampling = 1,
222                          .bytesPerPixel = 4,
223                      },
224                  },
225          }},
226         {DRM_FORMAT_NV12,
227          {
228              .androidFormat = GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420,
229              .virglFormat = VIRGL_FORMAT_NV12,
230              .isYuv = true,
231              .horizontalAlignmentPixels = 2,
232              .verticalAlignmentPixels = 1,
233              .planes =
234                  {
235                      {
236                          .horizontalSubsampling = 1,
237                          .verticalSubsampling = 1,
238                          .bytesPerPixel = 1,
239                      },
240                      {
241                          .horizontalSubsampling = 2,
242                          .verticalSubsampling = 2,
243                          .bytesPerPixel = 2,
244                      },
245                  },
246          }},
247         {DRM_FORMAT_YVU420,
248          {
249              .androidFormat = GFXSTREAM_AHB_FORMAT_YV12,
250              .virglFormat = VIRGL_FORMAT_YV12,
251              .isYuv = true,
252              .horizontalAlignmentPixels = 32,
253              .verticalAlignmentPixels = 1,
254              .planes =
255                  {
256                      {
257                          .horizontalSubsampling = 1,
258                          .verticalSubsampling = 1,
259                          .bytesPerPixel = 1,
260                      },
261                      {
262                          .horizontalSubsampling = 2,
263                          .verticalSubsampling = 2,
264                          .bytesPerPixel = 1,
265                      },
266                      {
267                          .horizontalSubsampling = 2,
268                          .verticalSubsampling = 2,
269                          .bytesPerPixel = 1,
270                      },
271                  },
272          }},
273     });
274     return *kFormatInfoMap;
275 }
276 
277 }  // namespace
278 
EmulatedAHardwareBuffer(uint32_t width,uint32_t height,uint32_t drmFormat,VirtGpuResourcePtr resource)279 EmulatedAHardwareBuffer::EmulatedAHardwareBuffer(uint32_t width, uint32_t height,
280                                                  uint32_t drmFormat, VirtGpuResourcePtr resource)
281     : mRefCount(1), mWidth(width), mHeight(height), mDrmFormat(drmFormat), mResource(resource) {}
282 
~EmulatedAHardwareBuffer()283 EmulatedAHardwareBuffer::~EmulatedAHardwareBuffer() {}
284 
getResourceId() const285 uint32_t EmulatedAHardwareBuffer::getResourceId() const { return mResource->getResourceHandle(); }
286 
getWidth() const287 uint32_t EmulatedAHardwareBuffer::getWidth() const { return mWidth; }
288 
getHeight() const289 uint32_t EmulatedAHardwareBuffer::getHeight() const { return mHeight; }
290 
getAndroidFormat() const291 int EmulatedAHardwareBuffer::getAndroidFormat() const {
292     const auto& formatInfosMap = GetDrmFormatInfoMap();
293     auto formatInfoIt = formatInfosMap.find(mDrmFormat);
294     if (formatInfoIt == formatInfosMap.end()) {
295         mesa_loge("Unhandled DRM format:%u", mDrmFormat);
296         return -1;
297     }
298     const auto& formatInfo = formatInfoIt->second;
299     return formatInfo.androidFormat;
300 }
301 
getDrmFormat() const302 uint32_t EmulatedAHardwareBuffer::getDrmFormat() const { return mDrmFormat; }
303 
asAHardwareBuffer()304 AHardwareBuffer* EmulatedAHardwareBuffer::asAHardwareBuffer() {
305     return reinterpret_cast<AHardwareBuffer*>(this);
306 }
307 
asBufferHandle()308 buffer_handle_t EmulatedAHardwareBuffer::asBufferHandle() {
309     return reinterpret_cast<buffer_handle_t>(this);
310 }
311 
asEglClientBuffer()312 EGLClientBuffer EmulatedAHardwareBuffer::asEglClientBuffer() {
313     return reinterpret_cast<EGLClientBuffer>(this);
314 }
315 
acquire()316 void EmulatedAHardwareBuffer::acquire() { ++mRefCount; }
317 
release()318 void EmulatedAHardwareBuffer::release() {
319     --mRefCount;
320     if (mRefCount == 0) {
321         delete this;
322     }
323 }
324 
lock(uint8_t ** ptr)325 int EmulatedAHardwareBuffer::lock(uint8_t** ptr) {
326     if (!mMapped) {
327         mMapped = mResource->createMapping();
328         if (!mMapped) {
329             mesa_loge("Failed to lock EmulatedAHardwareBuffer: failed to create mapping.");
330             return -1;
331         }
332 
333         mResource->transferFromHost(0, 0, mWidth, mHeight);
334         mResource->wait();
335     }
336 
337     *ptr = (*mMapped)->asRawPtr();
338     return 0;
339 }
340 
lockPlanes(std::vector<Gralloc::LockedPlane> * ahbPlanes)341 int EmulatedAHardwareBuffer::lockPlanes(std::vector<Gralloc::LockedPlane>* ahbPlanes) {
342     uint8_t* data = 0;
343     int ret = lock(&data);
344     if (ret) {
345         return ret;
346     }
347 
348     const auto& formatInfosMap = GetDrmFormatInfoMap();
349     auto formatInfoIt = formatInfosMap.find(mDrmFormat);
350     if (formatInfoIt == formatInfosMap.end()) {
351         mesa_loge("Failed to lock: failed to find format info for drm format:%u", mDrmFormat);
352         return -1;
353     }
354     const auto& formatInfo = formatInfoIt->second;
355 
356     const uint32_t alignedWidth = Align(mWidth, formatInfo.horizontalAlignmentPixels);
357     const uint32_t alignedHeight = Align(mHeight, formatInfo.verticalAlignmentPixels);
358     uint32_t cumulativeSize = 0;
359     for (const DrmFormatPlaneInfo& planeInfo : formatInfo.planes) {
360         const uint32_t planeWidth = DivideRoundUp(alignedWidth, planeInfo.horizontalSubsampling);
361         const uint32_t planeHeight = DivideRoundUp(alignedHeight, planeInfo.verticalSubsampling);
362         const uint32_t planeBpp = planeInfo.bytesPerPixel;
363         const uint32_t planeStrideBytes = planeWidth * planeBpp;
364         const uint32_t planeSizeBytes = planeHeight * planeStrideBytes;
365         ahbPlanes->emplace_back(Gralloc::LockedPlane{
366             .data = data + cumulativeSize,
367             .pixelStrideBytes = planeBpp,
368             .rowStrideBytes = planeStrideBytes,
369         });
370         cumulativeSize += planeSizeBytes;
371     }
372 
373     if (mDrmFormat == DRM_FORMAT_NV12) {
374         const auto& uPlane = (*ahbPlanes)[1];
375         auto vPlane = uPlane;
376         vPlane.data += 1;
377 
378         ahbPlanes->push_back(vPlane);
379     } else if (mDrmFormat == DRM_FORMAT_YVU420) {
380         // Note: lockPlanes() always returns Y, then U, then V but YV12 is Y, then V, then U.
381         auto& plane1 = (*ahbPlanes)[1];
382         auto& plane2 = (*ahbPlanes)[2];
383         std::swap(plane1, plane2);
384     }
385 
386     return 0;
387 }
388 
unlock()389 int EmulatedAHardwareBuffer::unlock() {
390     if (!mMapped) {
391         mesa_loge("Failed to unlock EmulatedAHardwareBuffer: never locked?");
392         return -1;
393     }
394     mResource->transferToHost(0, 0, mWidth, mHeight);
395     mResource->wait();
396     mMapped.reset();
397     return 0;
398 }
399 
EmulatedGralloc(int32_t descriptor)400 EmulatedGralloc::EmulatedGralloc(int32_t descriptor) {
401     mDevice.reset(createPlatformVirtGpuDevice(kCapsetNone, descriptor));
402 }
403 
~EmulatedGralloc()404 EmulatedGralloc::~EmulatedGralloc() { mOwned.clear(); }
405 
getGrallocType()406 GrallocType EmulatedGralloc::getGrallocType() { return GRALLOC_TYPE_EMULATED; }
407 
createColorBuffer(int width,int height,uint32_t glFormat)408 uint32_t EmulatedGralloc::createColorBuffer(int width, int height, uint32_t glFormat) {
409     auto drmFormat = GlFormatToDrmFormat(glFormat);
410     if (!drmFormat) {
411         mesa_loge("Unhandled format");
412         return -1;
413     }
414 
415     auto ahb = allocate(width, height, *drmFormat);
416     if (ahb == nullptr) {
417         return -1;
418     }
419 
420     EmulatedAHardwareBuffer* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
421 
422     mOwned.emplace_back(rahb);
423 
424     return rahb->getResourceId();
425 }
426 
allocate(uint32_t width,uint32_t height,uint32_t ahbFormat,uint64_t usage,AHardwareBuffer ** outputAhb)427 int EmulatedGralloc::allocate(uint32_t width, uint32_t height, uint32_t ahbFormat, uint64_t usage,
428                               AHardwareBuffer** outputAhb) {
429     (void)usage;
430 
431     auto drmFormat = AhbToDrmFormat(ahbFormat);
432     if (!drmFormat) {
433         mesa_loge("Unhandled AHB format:%u", ahbFormat);
434         return -1;
435     }
436 
437     *outputAhb = allocate(width, height, *drmFormat);
438     if (*outputAhb == nullptr) {
439         return -1;
440     }
441 
442     return 0;
443 }
444 
allocate(uint32_t width,uint32_t height,uint32_t drmFormat)445 AHardwareBuffer* EmulatedGralloc::allocate(uint32_t width, uint32_t height, uint32_t drmFormat) {
446     mesa_loge("Allocating AHB w:%u, h:%u, format %u", width, height, drmFormat);
447 
448     const auto& formatInfosMap = GetDrmFormatInfoMap();
449     auto formatInfoIt = formatInfosMap.find(drmFormat);
450     if (formatInfoIt == formatInfosMap.end()) {
451         mesa_loge("Failed to allocate: failed to find format info for drm format:%u", drmFormat);
452         return nullptr;
453     }
454     const auto& formatInfo = formatInfoIt->second;
455 
456     const uint32_t alignedWidth = Align(width, formatInfo.horizontalAlignmentPixels);
457     const uint32_t alignedHeight = Align(height, formatInfo.verticalAlignmentPixels);
458     uint32_t stride = 0;
459     uint32_t size = 0;
460     for (uint32_t i = 0; i < formatInfo.planes.size(); i++) {
461         const DrmFormatPlaneInfo& planeInfo = formatInfo.planes[i];
462         const uint32_t planeWidth = DivideRoundUp(alignedWidth, planeInfo.horizontalSubsampling);
463         const uint32_t planeHeight = DivideRoundUp(alignedHeight, planeInfo.verticalSubsampling);
464         const uint32_t planeBpp = planeInfo.bytesPerPixel;
465         const uint32_t planeStrideBytes = planeWidth * planeBpp;
466         const uint32_t planeSizeBytes = planeHeight * planeStrideBytes;
467         size += planeSizeBytes;
468         if (i == 0) stride = planeStrideBytes;
469     }
470 
471     const uint32_t bind = (drmFormat == DRM_FORMAT_R8_BLOB || drmFormat == DRM_FORMAT_NV12 ||
472                            drmFormat == DRM_FORMAT_YVU420)
473                               ? VIRGL_BIND_LINEAR
474                               : VIRGL_BIND_RENDER_TARGET;
475 
476     auto resource = mDevice->createResource(width, height, stride, size, formatInfo.virglFormat,
477                                             PIPE_TEXTURE_2D, bind);
478     if (!resource) {
479         mesa_loge("Failed to allocate: failed to create virtio resource.");
480         return nullptr;
481     }
482 
483     resource->wait();
484 
485     return reinterpret_cast<AHardwareBuffer*>(
486         new EmulatedAHardwareBuffer(width, height, drmFormat, std::move(resource)));
487 }
488 
acquire(AHardwareBuffer * ahb)489 void EmulatedGralloc::acquire(AHardwareBuffer* ahb) {
490     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
491     rahb->acquire();
492 }
493 
release(AHardwareBuffer * ahb)494 void EmulatedGralloc::release(AHardwareBuffer* ahb) {
495     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
496     rahb->release();
497 }
498 
lock(AHardwareBuffer * ahb,uint8_t ** ptr)499 int EmulatedGralloc::lock(AHardwareBuffer* ahb, uint8_t** ptr) {
500     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
501     return rahb->lock(ptr);
502 }
503 
lockPlanes(AHardwareBuffer * ahb,std::vector<LockedPlane> * ahbPlanes)504 int EmulatedGralloc::lockPlanes(AHardwareBuffer* ahb, std::vector<LockedPlane>* ahbPlanes) {
505     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
506     return rahb->lockPlanes(ahbPlanes);
507 }
508 
unlock(AHardwareBuffer * ahb)509 int EmulatedGralloc::unlock(AHardwareBuffer* ahb) {
510     auto* rahb = reinterpret_cast<EmulatedAHardwareBuffer*>(ahb);
511     return rahb->unlock();
512 }
513 
getHostHandle(const native_handle_t * handle)514 uint32_t EmulatedGralloc::getHostHandle(const native_handle_t* handle) {
515     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
516     return ahb->getResourceId();
517 }
518 
getHostHandle(const AHardwareBuffer * handle)519 uint32_t EmulatedGralloc::getHostHandle(const AHardwareBuffer* handle) {
520     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
521     return ahb->getResourceId();
522 }
523 
getNativeHandle(const AHardwareBuffer * ahb)524 const native_handle_t* EmulatedGralloc::getNativeHandle(const AHardwareBuffer* ahb) {
525     return reinterpret_cast<const native_handle_t*>(ahb);
526 }
527 
getFormat(const native_handle_t * handle)528 int EmulatedGralloc::getFormat(const native_handle_t* handle) {
529     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
530     return ahb->getAndroidFormat();
531 }
532 
getFormat(const AHardwareBuffer * handle)533 int EmulatedGralloc::getFormat(const AHardwareBuffer* handle) {
534     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
535     return ahb->getAndroidFormat();
536 }
537 
getFormatDrmFourcc(const AHardwareBuffer * handle)538 uint32_t EmulatedGralloc::getFormatDrmFourcc(const AHardwareBuffer* handle) {
539     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
540     return ahb->getDrmFormat();
541 }
542 
getWidth(const AHardwareBuffer * handle)543 uint32_t EmulatedGralloc::getWidth(const AHardwareBuffer* handle) {
544     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
545     return ahb->getWidth();
546 }
547 
getHeight(const AHardwareBuffer * handle)548 uint32_t EmulatedGralloc::getHeight(const AHardwareBuffer* handle) {
549     const auto* ahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(handle);
550     return ahb->getHeight();
551 }
552 
getAllocatedSize(const native_handle_t *)553 size_t EmulatedGralloc::getAllocatedSize(const native_handle_t*) {
554     mesa_loge("Unimplemented.");
555     return 0;
556 }
557 
getAllocatedSize(const AHardwareBuffer *)558 size_t EmulatedGralloc::getAllocatedSize(const AHardwareBuffer*) {
559     mesa_loge("Unimplemented.");
560     return 0;
561 }
562 
getId(const AHardwareBuffer * ahb,uint64_t * id)563 int EmulatedGralloc::getId(const AHardwareBuffer* ahb, uint64_t* id) {
564     const auto* rahb = reinterpret_cast<const EmulatedAHardwareBuffer*>(ahb);
565     *id = rahb->getResourceId();
566     return 0;
567 }
568 
createPlatformGralloc(int32_t descriptor)569 Gralloc* createPlatformGralloc(int32_t descriptor) { return new EmulatedGralloc(descriptor); }
570 
571 }  // namespace gfxstream
572