1 // Copyright 2022 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 expresso or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "ColorBuffer.h"
16 
17 #if GFXSTREAM_ENABLE_HOST_GLES
18 #include "gl/EmulationGl.h"
19 #endif
20 
21 #include "host-common/GfxstreamFatalError.h"
22 #include "host-common/logging.h"
23 #include "vulkan/ColorBufferVk.h"
24 #include "vulkan/VkCommonOperations.h"
25 #include "FrameBuffer.h"
26 
27 using android::base::ManagedDescriptor;
28 using emugl::ABORT_REASON_OTHER;
29 using emugl::FatalError;
30 
31 namespace gfxstream {
32 namespace {
33 
34 // ColorBufferVk natively supports YUV images. However, ColorBufferGl
35 // needs to emulate YUV support by having an underlying RGBA texture
36 // and adding in additional YUV<->RGBA conversions when needed. The
37 // memory should not be shared between the VK YUV image and the GL RGBA
38 // texture.
shouldAttemptExternalMemorySharing(FrameworkFormat format)39 bool shouldAttemptExternalMemorySharing(FrameworkFormat format) {
40     return format == FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE;
41 }
42 
43 }  // namespace
44 
ColorBuffer(HandleType handle,uint32_t width,uint32_t height,GLenum format,FrameworkFormat frameworkFormat)45 ColorBuffer::ColorBuffer(HandleType handle, uint32_t width, uint32_t height, GLenum format,
46                          FrameworkFormat frameworkFormat)
47     : mHandle(handle),
48       mWidth(width),
49       mHeight(height),
50       mFormat(format),
51       mFrameworkFormat(frameworkFormat) {}
52 
53 /*static*/
create(gl::EmulationGl * emulationGl,vk::VkEmulation * emulationVk,uint32_t width,uint32_t height,GLenum format,FrameworkFormat frameworkFormat,HandleType handle,android::base::Stream * stream,bool linear)54 std::shared_ptr<ColorBuffer> ColorBuffer::create(gl::EmulationGl* emulationGl,
55                                                  vk::VkEmulation* emulationVk, uint32_t width,
56                                                  uint32_t height, GLenum format,
57                                                  FrameworkFormat frameworkFormat, HandleType handle,
58                                                  android::base::Stream* stream, bool linear) {
59     std::shared_ptr<ColorBuffer> colorBuffer(
60         new ColorBuffer(handle, width, height, format, frameworkFormat));
61 
62     if (stream) {
63         // When vk snapshot enabled, mNeedRestore will be touched and set to false immediately.
64         colorBuffer->mNeedRestore = true;
65     }
66 #if GFXSTREAM_ENABLE_HOST_GLES
67     if (emulationGl) {
68         if (stream) {
69             colorBuffer->mColorBufferGl = emulationGl->loadColorBuffer(stream);
70             assert(width == colorBuffer->mColorBufferGl->getWidth());
71             assert(height == colorBuffer->mColorBufferGl->getHeight());
72             assert(frameworkFormat == colorBuffer->mColorBufferGl->getFrameworkFormat());
73         } else {
74             colorBuffer->mColorBufferGl =
75                 emulationGl->createColorBuffer(width, height, format, frameworkFormat, handle);
76         }
77         if (!colorBuffer->mColorBufferGl) {
78             ERR("Failed to initialize ColorBufferGl.");
79             return nullptr;
80         }
81     }
82 #endif
83 
84     if (emulationVk && emulationVk->live) {
85         const bool vulkanOnly = colorBuffer->mColorBufferGl == nullptr;
86         uint32_t memoryProperty = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
87         if (vulkanOnly && linear) {
88             memoryProperty |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
89         }
90         colorBuffer->mColorBufferVk = vk::ColorBufferVk::create(
91             handle, width, height, format, frameworkFormat, vulkanOnly, memoryProperty, stream);
92         if (!colorBuffer->mColorBufferVk) {
93             if (emulationGl) {
94                 // Historically, ColorBufferVk setup was deferred until the first actual Vulkan
95                 // usage. This allowed ColorBufferVk setup failures to be unintentionally avoided.
96             } else {
97                 ERR("Failed to initialize ColorBufferVk.");
98                 return nullptr;
99             }
100         }
101     }
102 
103 #if GFXSTREAM_ENABLE_HOST_GLES
104     bool b271028352Workaround = emulationGl && strstr(emulationGl->getGlesRenderer().c_str(), "Intel");
105     bool vkSnapshotEnabled = emulationVk && emulationVk->features.VulkanSnapshots.enabled;
106 
107     if ((!stream || vkSnapshotEnabled) && colorBuffer->mColorBufferGl && colorBuffer->mColorBufferVk &&
108         !b271028352Workaround && shouldAttemptExternalMemorySharing(frameworkFormat)) {
109         colorBuffer->touch();
110         auto memoryExport = vk::exportColorBufferMemory(handle);
111         if (memoryExport) {
112             if (colorBuffer->mColorBufferGl->importMemory(
113                     std::move(memoryExport->descriptor), memoryExport->size,
114                     memoryExport->dedicatedAllocation, memoryExport->linearTiling)) {
115                 colorBuffer->mGlAndVkAreSharingExternalMemory = true;
116             } else {
117                 ERR("Failed to import memory to ColorBufferGl:%d", handle);
118             }
119         }
120     }
121 #endif
122 
123     return colorBuffer;
124 }
125 
126 /*static*/
onLoad(gl::EmulationGl * emulationGl,vk::VkEmulation * emulationVk,android::base::Stream * stream)127 std::shared_ptr<ColorBuffer> ColorBuffer::onLoad(gl::EmulationGl* emulationGl,
128                                                  vk::VkEmulation* emulationVk,
129                                                  android::base::Stream* stream) {
130     const auto handle = static_cast<HandleType>(stream->getBe32());
131     const auto width = static_cast<uint32_t>(stream->getBe32());
132     const auto height = static_cast<uint32_t>(stream->getBe32());
133     const auto format = static_cast<GLenum>(stream->getBe32());
134     const auto frameworkFormat = static_cast<FrameworkFormat>(stream->getBe32());
135 
136     std::shared_ptr<ColorBuffer> colorBuffer = ColorBuffer::create(
137         emulationGl, emulationVk, width, height, format, frameworkFormat, handle, stream);
138 
139     return colorBuffer;
140 }
141 
onSave(android::base::Stream * stream)142 void ColorBuffer::onSave(android::base::Stream* stream) {
143     stream->putBe32(getHndl());
144     stream->putBe32(mWidth);
145     stream->putBe32(mHeight);
146     stream->putBe32(static_cast<uint32_t>(mFormat));
147     stream->putBe32(static_cast<uint32_t>(mFrameworkFormat));
148 
149 #if GFXSTREAM_ENABLE_HOST_GLES
150     if (mColorBufferGl) {
151         mColorBufferGl->onSave(stream);
152     }
153 #endif
154     if (mColorBufferVk) {
155         mColorBufferVk->onSave(stream);
156     }
157 }
158 
restore()159 void ColorBuffer::restore() {
160 #if GFXSTREAM_ENABLE_HOST_GLES
161     if (mColorBufferGl) {
162         mColorBufferGl->restore();
163     }
164 #endif
165 }
166 
readToBytes(int x,int y,int width,int height,GLenum pixelsFormat,GLenum pixelsType,void * outPixels,uint64_t outPixelsSize)167 void ColorBuffer::readToBytes(int x, int y, int width, int height, GLenum pixelsFormat,
168                               GLenum pixelsType, void* outPixels, uint64_t outPixelsSize) {
169     touch();
170 
171 #if GFXSTREAM_ENABLE_HOST_GLES
172     if (mColorBufferGl) {
173         mColorBufferGl->readPixels(x, y, width, height, pixelsFormat, pixelsType, outPixels);
174         return;
175     }
176 #endif
177 
178     if (mColorBufferVk) {
179         mColorBufferVk->readToBytes(x, y, width, height, outPixels, outPixelsSize);
180         return;
181     }
182 
183     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
184 }
185 
readToBytesScaled(int pixelsWidth,int pixelsHeight,GLenum pixelsFormat,GLenum pixelsType,int pixelsRotation,Rect rect,void * outPixels)186 void ColorBuffer::readToBytesScaled(int pixelsWidth, int pixelsHeight, GLenum pixelsFormat,
187                                     GLenum pixelsType, int pixelsRotation, Rect rect,
188                                     void* outPixels) {
189     touch();
190 
191 #if GFXSTREAM_ENABLE_HOST_GLES
192     if (mColorBufferGl) {
193         mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsFormat, pixelsType,
194                                          pixelsRotation, rect, outPixels);
195         return;
196     }
197 #endif
198 
199     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented.";
200 }
201 
readYuvToBytes(int x,int y,int width,int height,void * outPixels,uint32_t outPixelsSize)202 void ColorBuffer::readYuvToBytes(int x, int y, int width, int height, void* outPixels,
203                                  uint32_t outPixelsSize) {
204     touch();
205 
206 #if GFXSTREAM_ENABLE_HOST_GLES
207     if (mColorBufferGl) {
208         mColorBufferGl->readPixelsYUVCached(x, y, width, height, outPixels, outPixelsSize);
209         return;
210     }
211 #endif
212 
213     if (mColorBufferVk) {
214         mColorBufferVk->readToBytes(x, y, width, height, outPixels, outPixelsSize);
215         return;
216     }
217 
218     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
219 }
220 
updateFromBytes(int x,int y,int width,int height,FrameworkFormat frameworkFormat,GLenum pixelsFormat,GLenum pixelsType,const void * pixels,void * metadata)221 bool ColorBuffer::updateFromBytes(int x, int y, int width, int height,
222                                   FrameworkFormat frameworkFormat, GLenum pixelsFormat,
223                                   GLenum pixelsType, const void* pixels, void* metadata) {
224     touch();
225 
226 #if GFXSTREAM_ENABLE_HOST_GLES
227     if (mColorBufferGl) {
228         mColorBufferGl->subUpdateFromFrameworkFormat(x, y, width, height, frameworkFormat,
229                                                      pixelsFormat, pixelsType, pixels, metadata);
230         flushFromGl();
231         return true;
232     }
233 #endif
234 
235     if (mColorBufferVk) {
236         bool success = mColorBufferVk->updateFromBytes(x, y, width, height, pixels);
237         if (!success) return success;
238         flushFromVk();
239         return true;
240     }
241 
242     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
243     return false;
244 }
245 
updateFromBytes(int x,int y,int width,int height,GLenum pixelsFormat,GLenum pixelsType,const void * pixels)246 bool ColorBuffer::updateFromBytes(int x, int y, int width, int height, GLenum pixelsFormat,
247                                   GLenum pixelsType, const void* pixels) {
248     touch();
249 
250 #if GFXSTREAM_ENABLE_HOST_GLES
251     if (mColorBufferGl) {
252         bool res = mColorBufferGl->subUpdate(x, y, width, height, pixelsFormat, pixelsType, pixels);
253         if (res) {
254             flushFromGl();
255         }
256         return res;
257     }
258 #endif
259 
260     if (mColorBufferVk) {
261         return mColorBufferVk->updateFromBytes(x, y, width, height, pixels);
262     }
263 
264     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No ColorBuffer impl?";
265     return false;
266 }
267 
updateGlFromBytes(const void * bytes,std::size_t bytesSize)268 bool ColorBuffer::updateGlFromBytes(const void* bytes, std::size_t bytesSize) {
269 #if GFXSTREAM_ENABLE_HOST_GLES
270     if (mColorBufferGl) {
271         touch();
272 
273         return mColorBufferGl->replaceContents(bytes, bytesSize);
274     }
275 #endif
276 
277     return true;
278 }
279 
borrowForComposition(UsedApi api,bool isTarget)280 std::unique_ptr<BorrowedImageInfo> ColorBuffer::borrowForComposition(UsedApi api, bool isTarget) {
281     switch (api) {
282         case UsedApi::kGl: {
283 #if GFXSTREAM_ENABLE_HOST_GLES
284             if (!mColorBufferGl) {
285                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
286             }
287             return mColorBufferGl->getBorrowedImageInfo();
288 #endif
289         }
290         case UsedApi::kVk: {
291             if (!mColorBufferVk) {
292                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
293             }
294             return vk::borrowColorBufferForComposition(getHndl(), isTarget);
295         }
296     }
297     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented";
298     return nullptr;
299 }
300 
borrowForDisplay(UsedApi api)301 std::unique_ptr<BorrowedImageInfo> ColorBuffer::borrowForDisplay(UsedApi api) {
302     switch (api) {
303         case UsedApi::kGl: {
304 #if GFXSTREAM_ENABLE_HOST_GLES
305             if (!mColorBufferGl) {
306                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
307             }
308             return mColorBufferGl->getBorrowedImageInfo();
309 #endif
310         }
311         case UsedApi::kVk: {
312             if (!mColorBufferVk) {
313                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
314             }
315             return vk::borrowColorBufferForDisplay(getHndl());
316         }
317     }
318     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented";
319     return nullptr;
320 }
321 
flushFromGl()322 bool ColorBuffer::flushFromGl() {
323     if (!(mColorBufferGl && mColorBufferVk)) {
324         return true;
325     }
326 
327     if (mGlAndVkAreSharingExternalMemory) {
328         return true;
329     }
330 
331     // ColorBufferGl is currently considered the "main" backing. If this changes,
332     // the "main"  should be updated from the current contents of the GL backing.
333     mGlTexDirty = true;
334     return true;
335 }
336 
flushFromVk()337 bool ColorBuffer::flushFromVk() {
338     if (!(mColorBufferGl && mColorBufferVk)) {
339         return true;
340     }
341 
342     if (mGlAndVkAreSharingExternalMemory) {
343         return true;
344     }
345     std::vector<uint8_t> contents;
346     if (!vk::readColorBufferToBytes(mHandle, &contents)) {
347         ERR("Failed to get VK contents for ColorBuffer:%d", mHandle);
348         return false;
349     }
350 
351     if (contents.empty()) {
352         return false;
353     }
354 
355 #if GFXSTREAM_ENABLE_HOST_GLES
356     if (!mColorBufferGl->replaceContents(contents.data(), contents.size())) {
357         ERR("Failed to set GL contents for ColorBuffer:%d", mHandle);
358         return false;
359     }
360 #endif
361     mGlTexDirty = false;
362     return true;
363 }
364 
flushFromVkBytes(const void * bytes,size_t bytesSize)365 bool ColorBuffer::flushFromVkBytes(const void* bytes, size_t bytesSize) {
366     if (!(mColorBufferGl && mColorBufferVk)) {
367         return true;
368     }
369 
370     if (mGlAndVkAreSharingExternalMemory) {
371         return true;
372     }
373 
374 #if GFXSTREAM_ENABLE_HOST_GLES
375     if (mColorBufferGl) {
376         if (!mColorBufferGl->replaceContents(bytes, bytesSize)) {
377             ERR("Failed to update ColorBuffer:%d GL backing from VK bytes.", mHandle);
378             return false;
379         }
380     }
381 #endif
382     mGlTexDirty = false;
383     return true;
384 }
385 
invalidateForGl()386 bool ColorBuffer::invalidateForGl() {
387     if (!(mColorBufferGl && mColorBufferVk)) {
388         return true;
389     }
390 
391     if (mGlAndVkAreSharingExternalMemory) {
392         return true;
393     }
394 
395     // ColorBufferGl is currently considered the "main" backing. If this changes,
396     // the GL backing should be updated from the "main" backing.
397     return true;
398 }
399 
invalidateForVk()400 bool ColorBuffer::invalidateForVk() {
401     if (!(mColorBufferGl && mColorBufferVk)) {
402         return true;
403     }
404 
405     if (mGlAndVkAreSharingExternalMemory) {
406         return true;
407     }
408 
409     if (!mGlTexDirty) {
410         return true;
411     }
412 
413 #if GFXSTREAM_ENABLE_HOST_GLES
414     std::size_t contentsSize = 0;
415     if (!mColorBufferGl->readContents(&contentsSize, nullptr)) {
416         ERR("Failed to get GL contents size for ColorBuffer:%d", mHandle);
417         return false;
418     }
419 
420     std::vector<uint8_t> contents(contentsSize, 0);
421 
422     if (!mColorBufferGl->readContents(&contentsSize, contents.data())) {
423         ERR("Failed to get GL contents for ColorBuffer:%d", mHandle);
424         return false;
425     }
426 
427     if (!mColorBufferVk->updateFromBytes(contents)) {
428         ERR("Failed to set VK contents for ColorBuffer:%d", mHandle);
429         return false;
430     }
431 #endif
432     mGlTexDirty = false;
433     return true;
434 }
435 
importNativeResource(void * nativeResource,uint32_t type,bool preserveContent)436 bool ColorBuffer::importNativeResource(void* nativeResource, uint32_t type, bool preserveContent) {
437     switch (type) {
438         case RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE: {
439             if (mColorBufferGl) {
440                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
441                     << "Native resource import type %s is invalid when GL emulation is active. "
442                     << "Use RESOURCE_TYPE_EGL_NATIVE_PIXMAP of RESOURCE_TYPE_EGL_IMAGE imports "
443                        "instead.";
444                 return false;
445             } else if (!mColorBufferVk) {
446                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
447                     << "Vulkan emulation must be available for RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE "
448                        "import.";
449                 return false;
450             }
451             return mColorBufferVk->importExtMemoryHandle(nativeResource, type, preserveContent);
452         }
453         default:
454             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
455                 << "Unrecognized type for ColorBuffer::importNativeResource.";
456             return false;
457     }
458 }
459 
waitSync()460 int ColorBuffer::waitSync() {
461     if (mColorBufferGl) {
462         return -1;
463     }
464 
465     if (!mColorBufferVk) {
466         return -1;
467     }
468 
469     return mColorBufferVk->waitSync();
470 }
471 
exportBlob()472 std::optional<BlobDescriptorInfo> ColorBuffer::exportBlob() {
473     if (!mColorBufferVk) {
474         return std::nullopt;
475     }
476 
477     return mColorBufferVk->exportBlob();
478 }
479 
480 #if GFXSTREAM_ENABLE_HOST_GLES
glOpBlitFromCurrentReadBuffer()481 bool ColorBuffer::glOpBlitFromCurrentReadBuffer() {
482     if (!mColorBufferGl) {
483         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
484     }
485 
486     touch();
487 
488     return mColorBufferGl->blitFromCurrentReadBuffer();
489 }
490 
glOpBindToTexture()491 bool ColorBuffer::glOpBindToTexture() {
492     if (!mColorBufferGl) {
493         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
494     }
495 
496     touch();
497 
498     return mColorBufferGl->bindToTexture();
499 }
500 
glOpBindToTexture2()501 bool ColorBuffer::glOpBindToTexture2() {
502     if (!mColorBufferGl) {
503         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
504     }
505 
506     return mColorBufferGl->bindToTexture2();
507 }
508 
glOpBindToRenderbuffer()509 bool ColorBuffer::glOpBindToRenderbuffer() {
510     if (!mColorBufferGl) {
511         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
512     }
513 
514     touch();
515 
516     return mColorBufferGl->bindToRenderbuffer();
517 }
518 
glOpGetTexture()519 GLuint ColorBuffer::glOpGetTexture() {
520     if (!mColorBufferGl) {
521         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
522     }
523 
524     touch();
525 
526     return mColorBufferGl->getTexture();
527 }
528 
glOpReadback(unsigned char * img,bool readbackBgra)529 void ColorBuffer::glOpReadback(unsigned char* img, bool readbackBgra) {
530     if (!mColorBufferGl) {
531         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
532     }
533 
534     touch();
535 
536     return mColorBufferGl->readback(img, readbackBgra);
537 }
538 
glOpReadbackAsync(GLuint buffer,bool readbackBgra)539 void ColorBuffer::glOpReadbackAsync(GLuint buffer, bool readbackBgra) {
540     if (!mColorBufferGl) {
541         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
542     }
543 
544     touch();
545 
546     mColorBufferGl->readbackAsync(buffer, readbackBgra);
547 }
548 
glOpImportEglImage(void * image,bool preserveContent)549 bool ColorBuffer::glOpImportEglImage(void* image, bool preserveContent) {
550     if (!mColorBufferGl) {
551         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
552     }
553 
554     return mColorBufferGl->importEglImage(image, preserveContent);
555 }
556 
glOpImportEglNativePixmap(void * pixmap,bool preserveContent)557 bool ColorBuffer::glOpImportEglNativePixmap(void* pixmap, bool preserveContent) {
558     if (!mColorBufferGl) {
559         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
560     }
561 
562     return mColorBufferGl->importEglNativePixmap(pixmap, preserveContent);
563 }
564 
glOpSwapYuvTexturesAndUpdate(GLenum format,GLenum type,FrameworkFormat frameworkFormat,GLuint * textures)565 void ColorBuffer::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type,
566                                                FrameworkFormat frameworkFormat, GLuint* textures) {
567     if (!mColorBufferGl) {
568         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
569     }
570 
571     mColorBufferGl->swapYUVTextures(frameworkFormat, textures);
572 
573     // This makes ColorBufferGl regenerate the RGBA texture using
574     // YUVConverter::drawConvert() with the updated YUV textures.
575     mColorBufferGl->subUpdate(0, 0, mWidth, mHeight, format, type, nullptr);
576 
577     flushFromGl();
578 }
579 
glOpReadContents(size_t * outNumBytes,void * outContents)580 bool ColorBuffer::glOpReadContents(size_t* outNumBytes, void* outContents) {
581     if (!mColorBufferGl) {
582         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
583     }
584 
585     return mColorBufferGl->readContents(outNumBytes, outContents);
586 }
587 
glOpIsFastBlitSupported() const588 bool ColorBuffer::glOpIsFastBlitSupported() const {
589     if (!mColorBufferGl) {
590         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
591     }
592 
593     return mColorBufferGl->isFastBlitSupported();
594 }
595 
glOpPostLayer(const ComposeLayer & l,int frameWidth,int frameHeight)596 void ColorBuffer::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight) {
597     if (!mColorBufferGl) {
598         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
599     }
600 
601     mColorBufferGl->postLayer(l, frameWidth, frameHeight);
602 }
603 
glOpPostViewportScaledWithOverlay(float rotation,float dx,float dy)604 void ColorBuffer::glOpPostViewportScaledWithOverlay(float rotation, float dx, float dy) {
605     if (!mColorBufferGl) {
606         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
607     }
608 
609     mColorBufferGl->postViewportScaledWithOverlay(rotation, dx, dy);
610 }
611 #endif
612 
613 }  // namespace gfxstream
614