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