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