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