1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "ColorBufferGl.h"
17
18 #include <GLES2/gl2ext.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 #include "BorrowedImageGl.h"
23 #include "DebugGl.h"
24 #include "OpenGLESDispatch/DispatchTables.h"
25 #include "OpenGLESDispatch/EGLDispatch.h"
26 #include "RenderThreadInfoGl.h"
27 #include "TextureDraw.h"
28 #include "TextureResize.h"
29 #include "gl/YUVConverter.h"
30 #include "glestranslator/include/GLcommon/GLutils.h"
31 #include "host-common/GfxstreamFatalError.h"
32 #include "host-common/opengl/misc.h"
33
34 #define DEBUG_CB_FBO 0
35
36 using android::base::ManagedDescriptor;
37 using emugl::ABORT_REASON_OTHER;
38 using emugl::FatalError;
39
40 namespace gfxstream {
41 namespace gl {
42 namespace {
43
44 // Lazily create and bind a framebuffer object to the current host context.
45 // |fbo| is the address of the framebuffer object name.
46 // |tex| is the name of a texture that is attached to the framebuffer object
47 // on creation only. I.e. all rendering operations will target it.
48 // returns true in case of success, false on failure.
bindFbo(GLuint * fbo,GLuint tex,bool ensureTextureAttached)49 bool bindFbo(GLuint* fbo, GLuint tex, bool ensureTextureAttached) {
50 if (*fbo) {
51 // fbo already exist - just bind
52 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
53 if (ensureTextureAttached) {
54 s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES,
55 GL_TEXTURE_2D, tex, 0);
56 }
57 return true;
58 }
59
60 s_gles2.glGenFramebuffers(1, fbo);
61 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
62 s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES,
63 GL_TEXTURE_2D, tex, 0);
64
65 #if DEBUG_CB_FBO
66 GLenum status = s_gles2.glCheckFramebufferStatus(GL_FRAMEBUFFER);
67 if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
68 ERR("ColorBufferGl::bindFbo: FBO not complete: %#x\n", status);
69 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
70 s_gles2.glDeleteFramebuffers(1, fbo);
71 *fbo = 0;
72 return false;
73 }
74 #endif
75
76 return true;
77 }
78
unbindFbo()79 void unbindFbo() {
80 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
81 }
82
83 }
84
sGetUnsizedColorBufferFormat(GLenum format)85 static GLenum sGetUnsizedColorBufferFormat(GLenum format) {
86 switch (format) {
87 case GL_R8:
88 return GL_RED;
89 case GL_RG8:
90 return GL_RG;
91 case GL_RGB8:
92 case GL_RGB565:
93 case GL_RGB16F:
94 return GL_RGB;
95 case GL_RGBA8:
96 case GL_RGB5_A1_OES:
97 case GL_RGBA4_OES:
98 case GL_UNSIGNED_INT_10_10_10_2_OES:
99 case GL_RGB10_A2:
100 case GL_RGBA16F:
101 return GL_RGBA;
102 case GL_BGRA8_EXT:
103 case GL_BGR10_A2_ANGLEX:
104 return GL_BGRA_EXT;
105 default: // already unsized
106 return format;
107 }
108 }
109
sGetFormatParameters(GLint * internalFormat,GLenum * texFormat,GLenum * pixelType,int * bytesPerPixel,GLint * sizedInternalFormat,bool * isBlob)110 static bool sGetFormatParameters(GLint* internalFormat,
111 GLenum* texFormat,
112 GLenum* pixelType,
113 int* bytesPerPixel,
114 GLint* sizedInternalFormat,
115 bool* isBlob) {
116 if (!internalFormat) {
117 fprintf(stderr, "%s: error: internal format not provided\n", __func__);
118 return false;
119 }
120
121 *isBlob = false;
122
123 switch (*internalFormat) {
124 case GL_RGB:
125 case GL_RGB8:
126 *texFormat = GL_RGB;
127 *pixelType = GL_UNSIGNED_BYTE;
128 *bytesPerPixel = 3;
129 *sizedInternalFormat = GL_RGB8;
130 return true;
131 case GL_RGB565_OES:
132 *texFormat = GL_RGB;
133 *pixelType = GL_UNSIGNED_SHORT_5_6_5;
134 *bytesPerPixel = 2;
135 *sizedInternalFormat = GL_RGB565;
136 return true;
137 case GL_RGBA:
138 case GL_RGBA8:
139 case GL_RGB5_A1_OES:
140 case GL_RGBA4_OES:
141 *texFormat = GL_RGBA;
142 *pixelType = GL_UNSIGNED_BYTE;
143 *bytesPerPixel = 4;
144 *sizedInternalFormat = GL_RGBA8;
145 return true;
146 case GL_UNSIGNED_INT_10_10_10_2_OES:
147 *texFormat = GL_RGBA;
148 *pixelType = GL_UNSIGNED_SHORT;
149 *bytesPerPixel = 4;
150 *sizedInternalFormat = GL_UNSIGNED_INT_10_10_10_2_OES;
151 return true;
152 case GL_RGB10_A2:
153 *texFormat = GL_RGBA;
154 *pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
155 *bytesPerPixel = 4;
156 *sizedInternalFormat = GL_RGB10_A2;
157 return true;
158 case GL_RGB16F:
159 *texFormat = GL_RGB;
160 *pixelType = GL_HALF_FLOAT;
161 *bytesPerPixel = 6;
162 *sizedInternalFormat = GL_RGB16F;
163 return true;
164 case GL_RGBA16F:
165 *texFormat = GL_RGBA;
166 *pixelType = GL_HALF_FLOAT;
167 *bytesPerPixel = 8;
168 *sizedInternalFormat = GL_RGBA16F;
169 return true;
170 case GL_LUMINANCE:
171 *texFormat = GL_LUMINANCE;
172 *pixelType = GL_UNSIGNED_BYTE;
173 *bytesPerPixel = 1;
174 *sizedInternalFormat = GL_R8;
175 *isBlob = true;
176 return true;
177 case GL_BGRA_EXT:
178 *texFormat = GL_BGRA_EXT;
179 *pixelType = GL_UNSIGNED_BYTE;
180 *bytesPerPixel = 4;
181 *sizedInternalFormat = GL_BGRA8_EXT;
182 return true;
183 case GL_BGR10_A2_ANGLEX:
184 *texFormat = GL_RGBA;
185 *pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
186 *bytesPerPixel = 4;
187 *internalFormat = GL_RGB10_A2_EXT;
188 // GL_BGR10_A2_ANGLEX is actually not a valid GL format. We should
189 // replace it with a normal GL internal format instead.
190 *sizedInternalFormat = GL_BGR10_A2_ANGLEX;
191 return true;
192 case GL_R8:
193 case GL_RED:
194 *texFormat = GL_RED;
195 *pixelType = GL_UNSIGNED_BYTE;
196 *bytesPerPixel = 1;
197 *sizedInternalFormat = GL_R8;
198 return true;
199 case GL_RG8:
200 case GL_RG:
201 *texFormat = GL_RG;
202 *pixelType = GL_UNSIGNED_BYTE;
203 *bytesPerPixel = 2;
204 *sizedInternalFormat = GL_RG8;
205 return true;
206 default:
207 fprintf(stderr, "%s: Unknown format 0x%x\n", __func__,
208 *internalFormat);
209 return false;
210 }
211 }
212
213 // static
create(EGLDisplay p_display,int p_width,int p_height,GLint p_internalFormat,FrameworkFormat p_frameworkFormat,HandleType hndl,ContextHelper * helper,TextureDraw * textureDraw,bool fastBlitSupported,const gfxstream::host::FeatureSet & features)214 std::unique_ptr<ColorBufferGl> ColorBufferGl::create(EGLDisplay p_display, int p_width,
215 int p_height, GLint p_internalFormat,
216 FrameworkFormat p_frameworkFormat,
217 HandleType hndl, ContextHelper* helper,
218 TextureDraw* textureDraw,
219 bool fastBlitSupported,
220 const gfxstream::host::FeatureSet& features) {
221 GLenum texFormat = 0;
222 GLenum pixelType = GL_UNSIGNED_BYTE;
223 int bytesPerPixel = 4;
224 GLint p_sizedInternalFormat = GL_RGBA8;
225 bool isBlob = false;;
226
227 if (!sGetFormatParameters(&p_internalFormat, &texFormat, &pixelType,
228 &bytesPerPixel, &p_sizedInternalFormat,
229 &isBlob)) {
230 ERR("ColorBufferGl::create invalid format 0x%x", p_internalFormat);
231 return nullptr;
232 }
233 const unsigned long bufsize = ((unsigned long)bytesPerPixel) * p_width
234 * p_height;
235
236 // This constructor is private, so std::make_unique can't be used.
237 std::unique_ptr<ColorBufferGl> cb{
238 new ColorBufferGl(p_display, hndl, p_width, p_height, helper, textureDraw)};
239 cb->m_internalFormat = p_internalFormat;
240 cb->m_sizedInternalFormat = p_sizedInternalFormat;
241 cb->m_format = texFormat;
242 cb->m_type = pixelType;
243 cb->m_frameworkFormat = p_frameworkFormat;
244 cb->m_yuv420888ToNv21 = features.Yuv420888ToNv21.enabled;
245 cb->m_fastBlitSupported = fastBlitSupported;
246 cb->m_numBytes = (size_t)bufsize;
247
248 RecursiveScopedContextBind context(helper);
249 if (!context.isOk()) {
250 return nullptr;
251 }
252
253 GL_SCOPED_DEBUG_GROUP("ColorBufferGl::create(handle:%d)", hndl);
254
255 GLint prevUnpackAlignment;
256 s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlignment);
257 s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
258
259 s_gles2.glGenTextures(1, &cb->m_tex);
260 s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_tex);
261
262 s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, p_internalFormat, p_width, p_height,
263 0, texFormat, pixelType, nullptr);
264
265 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
266 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
267 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
268 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
269 // Swizzle B/R channel for BGR10_A2 images.
270 if (p_sizedInternalFormat == GL_BGR10_A2_ANGLEX) {
271 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
272 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
273 cb->m_BRSwizzle = true;
274 }
275
276 //
277 // create another texture for that colorbuffer for blit
278 //
279 s_gles2.glGenTextures(1, &cb->m_blitTex);
280 s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex);
281 s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, p_internalFormat, p_width, p_height,
282 0, texFormat, pixelType, NULL);
283
284 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
285 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
286 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
287 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
288 // Swizzle B/R channel for BGR10_A2 images.
289 if (p_sizedInternalFormat == GL_BGR10_A2_ANGLEX) {
290 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
291 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
292 cb->m_BRSwizzle = true;
293 }
294
295 cb->m_eglImage = s_egl.eglCreateImageKHR(
296 p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
297 (EGLClientBuffer)SafePointerFromUInt(cb->m_tex), NULL);
298
299 cb->m_blitEGLImage = s_egl.eglCreateImageKHR(
300 p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
301 (EGLClientBuffer)SafePointerFromUInt(cb->m_blitTex), NULL);
302
303 cb->m_resizer = new TextureResize(p_width, p_height);
304
305 switch (cb->m_frameworkFormat) {
306 case FRAMEWORK_FORMAT_GL_COMPATIBLE:
307 break;
308 default: // Any YUV format
309 cb->m_yuv_converter.reset(
310 new YUVConverter(p_width, p_height, cb->m_frameworkFormat, cb->m_yuv420888ToNv21));
311 break;
312 }
313
314 // desktop GL only: use GL_UNSIGNED_INT_8_8_8_8_REV for faster readback.
315 if (emugl::getRenderer() == SELECTED_RENDERER_HOST) {
316 #define GL_UNSIGNED_INT_8_8_8_8 0x8035
317 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
318 cb->m_asyncReadbackType = GL_UNSIGNED_INT_8_8_8_8_REV;
319 }
320
321 s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlignment);
322
323 s_gles2.glFinish();
324 return cb;
325 }
326
ColorBufferGl(EGLDisplay display,HandleType hndl,GLuint width,GLuint height,ContextHelper * helper,TextureDraw * textureDraw)327 ColorBufferGl::ColorBufferGl(EGLDisplay display, HandleType hndl, GLuint width, GLuint height,
328 ContextHelper* helper, TextureDraw* textureDraw)
329 : m_width(width),
330 m_height(height),
331 m_display(display),
332 m_helper(helper),
333 m_textureDraw(textureDraw),
334 mHndl(hndl) {}
335
~ColorBufferGl()336 ColorBufferGl::~ColorBufferGl() {
337 RecursiveScopedContextBind context(m_helper);
338
339 // b/284523053
340 // Swiftshader logspam on exit. But it doesn't happen with SwANGLE.
341 if (!context.isOk()) {
342 GL_LOG("Failed to bind context when releasing color buffers\n");
343 return;
344 }
345
346 if (m_blitEGLImage) {
347 s_egl.eglDestroyImageKHR(m_display, m_blitEGLImage);
348 }
349 if (m_eglImage) {
350 s_egl.eglDestroyImageKHR(m_display, m_eglImage);
351 }
352
353 if (m_fbo) {
354 s_gles2.glDeleteFramebuffers(1, &m_fbo);
355 }
356
357 if (m_yuv_conversion_fbo) {
358 s_gles2.glDeleteFramebuffers(1, &m_yuv_conversion_fbo);
359 }
360
361 if (m_scaleRotationFbo) {
362 s_gles2.glDeleteFramebuffers(1, &m_scaleRotationFbo);
363 }
364
365 m_yuv_converter.reset();
366
367 GLuint tex[2] = {m_tex, m_blitTex};
368 s_gles2.glDeleteTextures(2, tex);
369
370 if (m_memoryObject) {
371 s_gles2.glDeleteMemoryObjectsEXT(1, &m_memoryObject);
372 }
373
374 delete m_resizer;
375 }
376
convertRgbaToRgbPixels(void * dst,const void * src,uint32_t w,uint32_t h)377 static void convertRgbaToRgbPixels(void* dst, const void* src, uint32_t w, uint32_t h) {
378 const size_t pixelCount = w * h;
379 const uint32_t* srcPixels = reinterpret_cast<const uint32_t*>(src);
380 uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dst);
381 for (size_t i = 0; i < pixelCount; ++i) {
382 const uint32_t pixel = *(srcPixels++);
383 *(dstBytes++) = (pixel & 0xff);
384 *(dstBytes++) = ((pixel >> 8) & 0xff);
385 *(dstBytes++) = ((pixel >> 16) & 0xff);
386 }
387 }
388
readPixels(int x,int y,int width,int height,GLenum p_format,GLenum p_type,void * pixels)389 bool ColorBufferGl::readPixels(int x, int y, int width, int height, GLenum p_format, GLenum p_type,
390 void* pixels) {
391 RecursiveScopedContextBind context(m_helper);
392 if (!context.isOk()) {
393 return false;
394 }
395
396 GL_SCOPED_DEBUG_GROUP("ColorBufferGl::readPixels(handle:%d fbo:%d tex:%d)", mHndl, m_fbo,
397 m_tex);
398
399 p_format = sGetUnsizedColorBufferFormat(p_format);
400
401 waitSync();
402
403 if (bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
404 m_needFboReattach = false;
405 GLint prevAlignment = 0;
406 s_gles2.glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);
407 s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, 1);
408 if ((p_format == GL_RGB || p_format == GL_RGB8) && p_type == GL_UNSIGNED_BYTE) {
409 // GL_RGB reads fail with SwiftShader.
410 uint8_t* tmpPixels = new uint8_t[width * height * 4];
411 s_gles2.glReadPixels(x, y, width, height, GL_RGBA, p_type, tmpPixels);
412 convertRgbaToRgbPixels(pixels, tmpPixels, width, height);
413 } else {
414 s_gles2.glReadPixels(x, y, width, height, p_format, p_type, pixels);
415 }
416 s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);
417 unbindFbo();
418 return true;
419 }
420
421 return false;
422 }
423
readPixelsScaled(int width,int height,GLenum p_format,GLenum p_type,int rotation,Rect rect,void * pixels)424 bool ColorBufferGl::readPixelsScaled(int width, int height, GLenum p_format, GLenum p_type,
425 int rotation, Rect rect, void* pixels) {
426 RecursiveScopedContextBind context(m_helper);
427 if (!context.isOk()) {
428 return false;
429 }
430 bool useSnipping = rect.size.w != 0 && rect.size.h != 0;
431 // Boundary check
432 if (useSnipping &&
433 (rect.pos.x < 0 || rect.pos.y < 0 || rect.pos.x + rect.size.w > width ||
434 rect.pos.y + rect.size.h > height)) {
435 ERR("readPixelsScaled failed. Out-of-bound rectangle: (%d, %d) [%d x %d]"
436 " with screen [%d x %d]",
437 rect.pos.x, rect.pos.y, rect.size.w, rect.size.h);
438 return false;
439 }
440 p_format = sGetUnsizedColorBufferFormat(p_format);
441
442 waitSync();
443 GLuint tex = m_resizer->update(m_tex, width, height, rotation);
444 if (bindFbo(&m_scaleRotationFbo, tex, m_needFboReattach)) {
445 m_needFboReattach = false;
446 GLint prevAlignment = 0;
447 s_gles2.glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);
448 s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, 1);
449 // SwANGLE does not suppot glReadPixels with 3 channels.
450 // In fact, the spec only require RGBA8888 format support. Supports for
451 // other formats are optional.
452 bool needConvert4To3Channel =
453 p_format == GL_RGB && p_type == GL_UNSIGNED_BYTE &&
454 (emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT ||
455 emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT);
456 std::vector<uint8_t> tmpPixels;
457 void* readPixelsDst = pixels;
458 if (needConvert4To3Channel) {
459 tmpPixels.resize(width * height * 4);
460 p_format = GL_RGBA;
461 readPixelsDst = tmpPixels.data();
462 }
463 if (useSnipping) {
464 s_gles2.glReadPixels(rect.pos.x, rect.pos.y, rect.size.w,
465 rect.size.h, p_format, p_type, readPixelsDst);
466 width = rect.size.w;
467 height = rect.size.h;
468 } else {
469 s_gles2.glReadPixels(0, 0, width, height, p_format, p_type,
470 readPixelsDst);
471 }
472 if (needConvert4To3Channel) {
473 uint8_t* src = tmpPixels.data();
474 uint8_t* dst = static_cast<uint8_t*>(pixels);
475 for (int h = 0; h < height; h++) {
476 for (int w = 0; w < width; w++) {
477 memcpy(dst, src, 3);
478 dst += 3;
479 src += 4;
480 }
481 }
482 }
483 s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);
484 unbindFbo();
485 return true;
486 }
487
488 return false;
489 }
490
readPixelsYUVCached(int x,int y,int width,int height,void * pixels,uint32_t pixels_size)491 bool ColorBufferGl::readPixelsYUVCached(int x, int y, int width, int height, void* pixels,
492 uint32_t pixels_size) {
493 RecursiveScopedContextBind context(m_helper);
494 if (!context.isOk()) {
495 return false;
496 }
497
498 waitSync();
499
500 #if DEBUG_CB_FBO
501 fprintf(stderr, "%s %d request width %d height %d\n", __func__, __LINE__,
502 width, height);
503 memset(pixels, 0x00, pixels_size);
504 assert(m_yuv_converter.get());
505 #endif
506
507 m_yuv_converter->readPixels((uint8_t*)pixels, pixels_size);
508
509 return true;
510 }
511
reformat(GLint internalformat,GLenum type)512 void ColorBufferGl::reformat(GLint internalformat, GLenum type) {
513 GLenum texFormat = internalformat;
514 GLenum pixelType = GL_UNSIGNED_BYTE;
515 GLint sizedInternalFormat = GL_RGBA8;
516 int bpp = 4;
517 bool isBlob = false;
518 if (!sGetFormatParameters(&internalformat, &texFormat, &pixelType, &bpp,
519 &sizedInternalFormat, &isBlob)) {
520 fprintf(stderr, "%s: WARNING: reformat failed. internal format: 0x%x\n",
521 __func__, internalformat);
522 }
523
524 // BUG: 143607546
525 //
526 // During reformatting, sGetFormatParameters can be too
527 // opinionated and override the guest's intended choice for the
528 // pixel type. If the guest wanted GL_UNSIGNED_SHORT_5_6_5 as
529 // the pixel type, and the incoming internal format is not
530 // explicitly sized, sGetFormatParameters will pick a default of
531 // GL_UNSIGNED BYTE, which goes against guest expectations.
532 //
533 // This happens only on older API levels where gralloc.cpp in
534 // goldfish-opengl communicated HAL_PIXEL_FORMAT_RGB_565 as GL
535 // format GL_RGB, pixel type GL_UNSIGNED_SHORT_5_6_5. Newer
536 // system images communicate HAL_PIXEL_FORMAT_RGB_565 as GL
537 // format GL_RGB565, which allows sGetFormatParameters to work
538 // correctly.
539 if (pixelType != type) {
540 pixelType = type;
541 }
542
543 s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
544 s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_width, m_height,
545 0, texFormat, pixelType, nullptr);
546
547 s_gles2.glBindTexture(GL_TEXTURE_2D, m_blitTex);
548 s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_width, m_height,
549 0, texFormat, pixelType, nullptr);
550
551 // EGL images need to be recreated because the EGL_KHR_image_base spec
552 // states that respecifying an image (i.e. glTexImage2D) will generally
553 // result in orphaning of the EGL image.
554 s_egl.eglDestroyImageKHR(m_display, m_eglImage);
555 m_eglImage = s_egl.eglCreateImageKHR(
556 m_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
557 (EGLClientBuffer)SafePointerFromUInt(m_tex), NULL);
558
559 s_egl.eglDestroyImageKHR(m_display, m_blitEGLImage);
560 m_blitEGLImage = s_egl.eglCreateImageKHR(
561 m_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
562 (EGLClientBuffer)SafePointerFromUInt(m_blitTex), NULL);
563
564 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
565
566 m_internalFormat = internalformat;
567 m_format = texFormat;
568 m_type = pixelType;
569 m_sizedInternalFormat = sizedInternalFormat;
570
571 m_numBytes = bpp * m_width * m_height;
572 }
573
swapYUVTextures(FrameworkFormat type,uint32_t * textures,void * metadata)574 void ColorBufferGl::swapYUVTextures(FrameworkFormat type, uint32_t* textures, void* metadata) {
575 if (type == FrameworkFormat::FRAMEWORK_FORMAT_NV12) {
576 m_yuv_converter->swapTextures(type, textures, metadata);
577 } else {
578 fprintf(stderr,
579 "%s: ERROR: format other than NV12 is not supported: 0x%x\n",
580 __func__, type);
581 }
582 }
583
subUpdate(int x,int y,int width,int height,GLenum p_format,GLenum p_type,const void * pixels,void * metadata)584 bool ColorBufferGl::subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type,
585 const void* pixels, void* metadata) {
586 return subUpdateFromFrameworkFormat(x, y, width, height, m_frameworkFormat, p_format, p_type,
587 pixels, metadata);
588 }
589
subUpdateFromFrameworkFormat(int x,int y,int width,int height,FrameworkFormat fwkFormat,GLenum p_format,GLenum p_type,const void * pixels,void * metadata)590 bool ColorBufferGl::subUpdateFromFrameworkFormat(int x, int y, int width, int height,
591 FrameworkFormat fwkFormat, GLenum p_format,
592 GLenum p_type, const void* pixels,
593 void* metadata) {
594 const GLenum p_unsizedFormat = sGetUnsizedColorBufferFormat(p_format);
595 RecursiveScopedContextBind context(m_helper);
596 if (!context.isOk()) {
597 return false;
598 }
599
600 GL_SCOPED_DEBUG_GROUP("ColorBufferGl::subUpdate(handle:%d fbo:%d tex:%d)", mHndl, m_fbo, m_tex);
601
602 if (m_needFormatCheck) {
603 if (p_type != m_type || p_format != m_format) {
604 reformat((GLint)p_format, p_type);
605 }
606 m_needFormatCheck = false;
607 }
608
609 if (m_frameworkFormat != FRAMEWORK_FORMAT_GL_COMPATIBLE || fwkFormat != m_frameworkFormat) {
610 assert(m_yuv_converter.get());
611
612 // This FBO will convert the YUV frame to RGB
613 // and render it to |m_tex|.
614 bindFbo(&m_yuv_conversion_fbo, m_tex, m_needFboReattach);
615 m_yuv_converter->drawConvertFromFormat(fwkFormat, x, y, width, height, (char*)pixels,
616 metadata);
617 unbindFbo();
618
619 // |m_tex| still needs to be bound afterwards
620 s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
621
622 } else {
623 s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
624 s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
625
626 s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, p_unsizedFormat,
627 p_type, pixels);
628 }
629
630 if (m_fastBlitSupported) {
631 s_gles2.glFlush();
632 m_sync = (GLsync)s_egl.eglSetImageFenceANDROID(m_display, m_eglImage);
633 }
634
635 return true;
636 }
637
replaceContents(const void * newContents,size_t numBytes)638 bool ColorBufferGl::replaceContents(const void* newContents, size_t numBytes) {
639 return subUpdate(0, 0, m_width, m_height, m_format, m_type, newContents);
640 }
641
readContents(size_t * numBytes,void * pixels)642 bool ColorBufferGl::readContents(size_t* numBytes, void* pixels) {
643 if (m_yuv_converter) {
644 // common code path for vk & gles
645 *numBytes = m_yuv_converter->getDataSize();
646 if (!pixels) {
647 return true;
648 }
649 return readPixelsYUVCached(0, 0, 0, 0, pixels, *numBytes);
650 } else {
651 *numBytes = m_numBytes;
652 if (!pixels) {
653 return true;
654 }
655 return readPixels(0, 0, m_width, m_height, m_format, m_type, pixels);
656 }
657 }
658
blitFromCurrentReadBuffer()659 bool ColorBufferGl::blitFromCurrentReadBuffer() {
660 RenderThreadInfoGl* const tInfo = RenderThreadInfoGl::get();
661 if (!tInfo) {
662 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
663 << "Render thread GL not available.";
664 }
665
666 if (!tInfo->currContext.get()) {
667 // no Current context
668 return false;
669 }
670
671 if (m_fastBlitSupported) {
672 s_egl.eglBlitFromCurrentReadBufferANDROID(m_display, m_eglImage);
673 m_sync = (GLsync)s_egl.eglSetImageFenceANDROID(m_display, m_eglImage);
674 } else {
675 // Copy the content of the current read surface into m_blitEGLImage.
676 // This is done by creating a temporary texture, bind it to the EGLImage
677 // then call glCopyTexSubImage2D().
678 GLuint tmpTex;
679 GLint currTexBind;
680 if (tInfo->currContext->clientVersion() > GLESApi_CM) {
681 s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
682 s_gles2.glGenTextures(1, &tmpTex);
683 s_gles2.glBindTexture(GL_TEXTURE_2D, tmpTex);
684 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
685
686 const bool isGles3 = tInfo->currContext->clientVersion() > GLESApi_2;
687
688 GLint prev_read_fbo = 0;
689 if (isGles3) {
690 // Make sure that we unbind any existing GL_READ_FRAMEBUFFER
691 // before calling glCopyTexSubImage2D, otherwise we may blit
692 // from the guest's current read framebuffer instead of the EGL
693 // read buffer.
694 s_gles2.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &prev_read_fbo);
695 if (prev_read_fbo != 0) {
696 s_gles2.glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
697 }
698 } else {
699 // On GLES 2, there are not separate read/draw framebuffers,
700 // only GL_FRAMEBUFFER. Per the EGL 1.4 spec section 3.9.3,
701 // the draw surface must be bound to the calling thread's
702 // current context, so GL_FRAMEBUFFER should be 0. However, the
703 // error case is not strongly defined and generating a new error
704 // may break existing apps.
705 //
706 // Instead of the obviously wrong behavior of posting whatever
707 // GL_FRAMEBUFFER is currently bound to, fix up the
708 // GL_FRAMEBUFFER if it is non-zero.
709 s_gles2.glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_read_fbo);
710 if (prev_read_fbo != 0) {
711 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
712 }
713 }
714
715 // If the read buffer is multisampled, we need to resolve.
716 GLint samples;
717 s_gles2.glGetIntegerv(GL_SAMPLE_BUFFERS, &samples);
718 if (isGles3 && samples > 0) {
719 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
720
721 GLuint resolve_fbo;
722 GLint prev_draw_fbo;
723 s_gles2.glGenFramebuffers(1, &resolve_fbo);
724 s_gles2.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prev_draw_fbo);
725
726 s_gles2.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
727 s_gles2.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
728 GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
729 tmpTex, 0);
730 s_gles2.glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width,
731 m_height, GL_COLOR_BUFFER_BIT,
732 GL_NEAREST);
733 s_gles2.glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
734 (GLuint)prev_draw_fbo);
735
736 s_gles2.glDeleteFramebuffers(1, &resolve_fbo);
737 s_gles2.glBindTexture(GL_TEXTURE_2D, tmpTex);
738 } else {
739 // If the buffer is not multisampled, perform a normal texture copy.
740 s_gles2.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width,
741 m_height);
742 }
743
744 if (prev_read_fbo != 0) {
745 if (isGles3) {
746 s_gles2.glBindFramebuffer(GL_READ_FRAMEBUFFER,
747 (GLuint)prev_read_fbo);
748 } else {
749 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER,
750 (GLuint)prev_read_fbo);
751 }
752 }
753
754 s_gles2.glDeleteTextures(1, &tmpTex);
755 s_gles2.glBindTexture(GL_TEXTURE_2D, currTexBind);
756
757 // clear GL errors, because its possible that the fbo format does not
758 // match
759 // the format of the read buffer, in the case of OpenGL ES 3.1 and
760 // integer
761 // RGBA formats.
762 s_gles2.glGetError();
763 // This is currently for dEQP purposes only; if we actually want these
764 // integer FBO formats to actually serve to display something for human
765 // consumption,
766 // we need to change the egl image to be of the same format,
767 // or we get some really psychedelic patterns.
768 } else {
769 // Like in the GLES 2 path above, correct the case where
770 // GL_FRAMEBUFFER_OES is not bound to zero so that we don't blit
771 // from arbitrary framebuffers.
772 // Use GLES 2 because it internally has the same value as the GLES 1
773 // API and it doesn't require GL_OES_framebuffer_object.
774 GLint prev_fbo = 0;
775 s_gles2.glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
776 if (prev_fbo != 0) {
777 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
778 }
779
780 s_gles1.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
781 s_gles1.glGenTextures(1, &tmpTex);
782 s_gles1.glBindTexture(GL_TEXTURE_2D, tmpTex);
783 s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
784 s_gles1.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width,
785 m_height);
786 s_gles1.glDeleteTextures(1, &tmpTex);
787 s_gles1.glBindTexture(GL_TEXTURE_2D, currTexBind);
788
789 if (prev_fbo != 0) {
790 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)prev_fbo);
791 }
792 }
793
794 RecursiveScopedContextBind context(m_helper);
795 if (!context.isOk()) {
796 return false;
797 }
798
799 if (!bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
800 return false;
801 }
802
803 // Save current viewport and match it to the current colorbuffer size.
804 GLint vport[4] = {
805 0,
806 };
807 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
808 s_gles2.glViewport(0, 0, m_width, m_height);
809
810 // render m_blitTex
811 m_textureDraw->draw(m_blitTex, 0., 0, 0);
812
813 // Restore previous viewport.
814 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
815 unbindFbo();
816 }
817
818 return true;
819 }
820
bindToTexture()821 bool ColorBufferGl::bindToTexture() {
822 if (!m_eglImage) {
823 return false;
824 }
825
826 RenderThreadInfoGl* const tInfo = RenderThreadInfoGl::get();
827 if (!tInfo) {
828 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
829 << "Render thread GL not available.";
830 }
831
832 if (!tInfo->currContext.get()) {
833 return false;
834 }
835
836 if (tInfo->currContext->clientVersion() > GLESApi_CM) {
837 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
838 } else {
839 s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
840 }
841 return true;
842 }
843
bindToTexture2()844 bool ColorBufferGl::bindToTexture2() {
845 if (!m_eglImage) {
846 return false;
847 }
848
849 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
850 return true;
851 }
852
bindToRenderbuffer()853 bool ColorBufferGl::bindToRenderbuffer() {
854 if (!m_eglImage) {
855 return false;
856 }
857
858 RenderThreadInfoGl* const tInfo = RenderThreadInfoGl::get();
859 if (!tInfo) {
860 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
861 << "Render thread GL not available.";
862 }
863
864 if (!tInfo->currContext.get()) {
865 return false;
866 }
867
868 if (tInfo->currContext->clientVersion() > GLESApi_CM) {
869 s_gles2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES,
870 m_eglImage);
871 } else {
872 s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES,
873 m_eglImage);
874 }
875 return true;
876 }
877
getViewportScaledTexture()878 GLuint ColorBufferGl::getViewportScaledTexture() { return m_resizer->update(m_tex); }
879
setSync(bool debug)880 void ColorBufferGl::setSync(bool debug) {
881 m_sync = (GLsync)s_egl.eglSetImageFenceANDROID(m_display, m_eglImage);
882 if (debug) fprintf(stderr, "%s: %u to %p\n", __func__, getHndl(), m_sync);
883 }
884
waitSync(bool debug)885 void ColorBufferGl::waitSync(bool debug) {
886 if (debug) fprintf(stderr, "%s: %u sync %p\n", __func__, getHndl(), m_sync);
887 if (m_sync) {
888 s_egl.eglWaitImageFenceANDROID(m_display, m_sync);
889 }
890 }
891
post(GLuint tex,float rotation,float dx,float dy)892 bool ColorBufferGl::post(GLuint tex, float rotation, float dx, float dy) {
893 // NOTE: Do not call m_helper->setupContext() here!
894 waitSync();
895 return m_textureDraw->draw(tex, rotation, dx, dy);
896 }
897
postViewportScaledWithOverlay(float rotation,float dx,float dy)898 bool ColorBufferGl::postViewportScaledWithOverlay(float rotation, float dx, float dy) {
899 // NOTE: Do not call m_helper->setupContext() here!
900 waitSync();
901 return m_textureDraw->drawWithOverlay(getViewportScaledTexture(), rotation, dx, dy);
902 }
903
readback(unsigned char * img,bool readbackBgra)904 void ColorBufferGl::readback(unsigned char* img, bool readbackBgra) {
905 RecursiveScopedContextBind context(m_helper);
906 if (!context.isOk()) {
907 return;
908 }
909
910 waitSync();
911
912 if (bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
913 m_needFboReattach = false;
914 // Flip the readback format if RED/BLUE components are swizzled.
915 bool shouldReadbackBgra = m_BRSwizzle ? !readbackBgra : readbackBgra;
916 GLenum format = shouldReadbackBgra ? GL_BGRA_EXT : GL_RGBA;
917
918 s_gles2.glReadPixels(0, 0, m_width, m_height, format, GL_UNSIGNED_BYTE, img);
919 unbindFbo();
920 }
921 }
922
readbackAsync(GLuint buffer,bool readbackBgra)923 void ColorBufferGl::readbackAsync(GLuint buffer, bool readbackBgra) {
924 RecursiveScopedContextBind context(m_helper);
925 if (!context.isOk()) {
926 return;
927 }
928
929 waitSync();
930
931 if (bindFbo(&m_fbo, m_tex, m_needFboReattach)) {
932 m_needFboReattach = false;
933 s_gles2.glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
934 bool shouldReadbackBgra = m_BRSwizzle ? !readbackBgra : readbackBgra;
935 GLenum format = shouldReadbackBgra ? GL_BGRA_EXT : GL_RGBA;
936 s_gles2.glReadPixels(0, 0, m_width, m_height, format, m_asyncReadbackType, 0);
937 s_gles2.glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
938 unbindFbo();
939 }
940 }
941
getHndl() const942 HandleType ColorBufferGl::getHndl() const { return mHndl; }
943
onSave(android::base::Stream * stream)944 void ColorBufferGl::onSave(android::base::Stream* stream) {
945 stream->putBe32(getHndl());
946 stream->putBe32(static_cast<uint32_t>(m_width));
947 stream->putBe32(static_cast<uint32_t>(m_height));
948 stream->putBe32(static_cast<uint32_t>(m_internalFormat));
949 stream->putBe32(static_cast<uint32_t>(m_frameworkFormat));
950 // for debug
951 assert(m_eglImage && m_blitEGLImage);
952 stream->putBe32(reinterpret_cast<uintptr_t>(m_eglImage));
953 stream->putBe32(reinterpret_cast<uintptr_t>(m_blitEGLImage));
954 stream->putBe32(m_needFormatCheck);
955 }
956
onLoad(android::base::Stream * stream,EGLDisplay p_display,ContextHelper * helper,TextureDraw * textureDraw,bool fastBlitSupported,const gfxstream::host::FeatureSet & features)957 std::unique_ptr<ColorBufferGl> ColorBufferGl::onLoad(android::base::Stream* stream,
958 EGLDisplay p_display, ContextHelper* helper,
959 TextureDraw* textureDraw,
960 bool fastBlitSupported,
961 const gfxstream::host::FeatureSet& features) {
962 HandleType hndl = static_cast<HandleType>(stream->getBe32());
963 GLuint width = static_cast<GLuint>(stream->getBe32());
964 GLuint height = static_cast<GLuint>(stream->getBe32());
965 GLenum internalFormat = static_cast<GLenum>(stream->getBe32());
966 FrameworkFormat frameworkFormat =
967 static_cast<FrameworkFormat>(stream->getBe32());
968 EGLImageKHR eglImage = reinterpret_cast<EGLImageKHR>(stream->getBe32());
969 EGLImageKHR blitEGLImage = reinterpret_cast<EGLImageKHR>(stream->getBe32());
970 uint32_t needFormatCheck = stream->getBe32();
971
972 if (!eglImage) {
973 return create(p_display, width, height, internalFormat, frameworkFormat,
974 hndl, helper, textureDraw, fastBlitSupported, features);
975 }
976 std::unique_ptr<ColorBufferGl> cb(
977 new ColorBufferGl(p_display, hndl, width, height, helper, textureDraw));
978 cb->m_eglImage = eglImage;
979 cb->m_blitEGLImage = blitEGLImage;
980 assert(eglImage && blitEGLImage);
981 cb->m_internalFormat = internalFormat;
982 cb->m_frameworkFormat = frameworkFormat;
983 cb->m_fastBlitSupported = fastBlitSupported;
984 cb->m_needFormatCheck = needFormatCheck;
985
986 GLenum texFormat;
987 GLenum pixelType;
988 int bytesPerPixel = 1;
989 GLint sizedInternalFormat;
990 bool isBlob;
991 sGetFormatParameters(&cb->m_internalFormat, &texFormat, &pixelType, &bytesPerPixel,
992 &sizedInternalFormat, &isBlob);
993 cb->m_type = pixelType;
994 cb->m_format = texFormat;
995 cb->m_sizedInternalFormat = sizedInternalFormat;
996 // TODO: set m_BRSwizzle properly
997 cb->m_numBytes = ((unsigned long)bytesPerPixel) * width * height;
998 return cb;
999 }
1000
restore()1001 void ColorBufferGl::restore() {
1002 RecursiveScopedContextBind context(m_helper);
1003 s_gles2.glGenTextures(1, &m_tex);
1004 s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
1005 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
1006
1007 s_gles2.glGenTextures(1, &m_blitTex);
1008 s_gles2.glBindTexture(GL_TEXTURE_2D, m_blitTex);
1009 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
1010
1011 m_resizer = new TextureResize(m_width, m_height);
1012 switch (m_frameworkFormat) {
1013 case FRAMEWORK_FORMAT_GL_COMPATIBLE:
1014 break;
1015 default: // any YUV format
1016 m_yuv_converter.reset(
1017 new YUVConverter(m_width, m_height, m_frameworkFormat, m_yuv420888ToNv21));
1018 break;
1019 }
1020 }
1021
getTexture()1022 GLuint ColorBufferGl::getTexture() { return m_tex; }
1023
postLayer(const ComposeLayer & l,int frameWidth,int frameHeight)1024 void ColorBufferGl::postLayer(const ComposeLayer& l, int frameWidth, int frameHeight) {
1025 waitSync();
1026 m_textureDraw->drawLayer(l, frameWidth, frameHeight, m_width, m_height,
1027 getViewportScaledTexture());
1028 }
1029
importMemory(ManagedDescriptor externalDescriptor,uint64_t size,bool dedicated,bool linearTiling)1030 bool ColorBufferGl::importMemory(ManagedDescriptor externalDescriptor, uint64_t size,
1031 bool dedicated, bool linearTiling) {
1032 RecursiveScopedContextBind context(m_helper);
1033 s_gles2.glCreateMemoryObjectsEXT(1, &m_memoryObject);
1034 if (dedicated) {
1035 static const GLint DEDICATED_FLAG = GL_TRUE;
1036 s_gles2.glMemoryObjectParameterivEXT(m_memoryObject,
1037 GL_DEDICATED_MEMORY_OBJECT_EXT,
1038 &DEDICATED_FLAG);
1039 }
1040 std::optional<ManagedDescriptor::DescriptorType> maybeRawDescriptor = externalDescriptor.get();
1041 if (!maybeRawDescriptor.has_value()) {
1042 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Uninitialized external descriptor.";
1043 }
1044 ManagedDescriptor::DescriptorType rawDescriptor = *maybeRawDescriptor;
1045
1046 #ifdef _WIN32
1047 s_gles2.glImportMemoryWin32HandleEXT(m_memoryObject, size, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT,
1048 rawDescriptor);
1049 #else
1050 s_gles2.glImportMemoryFdEXT(m_memoryObject, size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, rawDescriptor);
1051 #endif
1052 GLenum error = s_gles2.glGetError();
1053 if (error == GL_NO_ERROR) {
1054 #ifdef _WIN32
1055 // Let the external descriptor close when going out of scope. From the
1056 // EXT_external_objects_win32 spec: importing a Windows handle does not transfer ownership
1057 // of the handle to the GL implementation. For handle types defined as NT handles, the
1058 // application must release the handle using an appropriate system call when it is no longer
1059 // needed.
1060 #else
1061 // Inform ManagedDescriptor not to close the fd, since the owner of the fd is transferred to
1062 // the GL driver. From the EXT_external_objects_fd spec: a successful import operation
1063 // transfers ownership of <fd> to the GL implementation, and performing any operation on
1064 // <fd> in the application after an import results in undefined behavior.
1065 externalDescriptor.release();
1066 #endif
1067 } else {
1068 ERR("Failed to import external memory object with error: %d", static_cast<int>(error));
1069 return false;
1070 }
1071
1072 GLuint glTiling = linearTiling ? GL_LINEAR_TILING_EXT : GL_OPTIMAL_TILING_EXT;
1073
1074 std::vector<uint8_t> prevContents;
1075
1076 size_t bytes;
1077 readContents(&bytes, nullptr);
1078 prevContents.resize(bytes, 0);
1079 readContents(&bytes, prevContents.data());
1080
1081 s_gles2.glDeleteTextures(1, &m_tex);
1082 s_gles2.glDeleteFramebuffers(1, &m_fbo);
1083 m_fbo = 0;
1084 s_gles2.glDeleteFramebuffers(1, &m_scaleRotationFbo);
1085 m_scaleRotationFbo = 0;
1086 s_gles2.glDeleteFramebuffers(1, &m_yuv_conversion_fbo);
1087 m_yuv_conversion_fbo = 0;
1088 s_egl.eglDestroyImageKHR(m_display, m_eglImage);
1089
1090 s_gles2.glGenTextures(1, &m_tex);
1091 s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
1092
1093 // HOST needed because we do not expose this to guest
1094 s_gles2.glTexParameteriHOST(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, glTiling);
1095
1096 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1097 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1098 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1099 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1100
1101 if (m_sizedInternalFormat == GL_BGRA8_EXT ||
1102 m_sizedInternalFormat == GL_BGR10_A2_ANGLEX) {
1103 GLint internalFormat = m_sizedInternalFormat == GL_BGRA8_EXT
1104 ? GL_RGBA8
1105 : GL_RGB10_A2_EXT;
1106 s_gles2.glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, internalFormat, m_width,
1107 m_height, m_memoryObject, 0);
1108 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
1109 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
1110 m_BRSwizzle = true;
1111 } else {
1112 s_gles2.glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_sizedInternalFormat, m_width, m_height, m_memoryObject, 0);
1113 m_BRSwizzle = false;
1114 }
1115
1116 m_eglImage = s_egl.eglCreateImageKHR(
1117 m_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
1118 (EGLClientBuffer)SafePointerFromUInt(m_tex), NULL);
1119
1120 replaceContents(prevContents.data(), m_numBytes);
1121
1122 return true;
1123 }
1124
importEglNativePixmap(void * pixmap,bool preserveContent)1125 bool ColorBufferGl::importEglNativePixmap(void* pixmap, bool preserveContent) {
1126 EGLImageKHR image = s_egl.eglCreateImageKHR(m_display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, pixmap, nullptr);
1127
1128 if (image == EGL_NO_IMAGE_KHR) {
1129 fprintf(stderr, "%s: error: failed to import pixmap\n", __func__);
1130 return false;
1131 }
1132
1133 // Assume pixmap is compatible with ColorBufferGl's current dimensions and internal format.
1134 EGLBoolean setInfoRes = s_egl.eglSetImageInfoANDROID(m_display, image, m_width, m_height, m_internalFormat);
1135
1136 if (EGL_TRUE != setInfoRes) {
1137 fprintf(stderr, "%s: error: failed to set image info\n", __func__);
1138 s_egl.eglDestroyImageKHR(m_display, image);
1139 return false;
1140 }
1141
1142 rebindEglImage(image, preserveContent);
1143 return true;
1144 }
1145
importEglImage(void * nativeEglImage,bool preserveContent)1146 bool ColorBufferGl::importEglImage(void* nativeEglImage, bool preserveContent) {
1147 EGLImageKHR image = s_egl.eglImportImageANDROID(m_display, (EGLImage)nativeEglImage);
1148
1149 if (image == EGL_NO_IMAGE_KHR) return false;
1150
1151 // Assume nativeEglImage is compatible with ColorBufferGl's current dimensions and internal
1152 // format.
1153 EGLBoolean setInfoRes = s_egl.eglSetImageInfoANDROID(m_display, image, m_width, m_height, m_internalFormat);
1154
1155 if (EGL_TRUE != setInfoRes) {
1156 s_egl.eglDestroyImageKHR(m_display, image);
1157 return false;
1158 }
1159
1160 rebindEglImage(image, preserveContent);
1161 return true;
1162 }
1163
getContents()1164 std::vector<uint8_t> ColorBufferGl::getContents() {
1165 // Assume there is a current context.
1166 size_t bytes;
1167 readContents(&bytes, nullptr);
1168 std::vector<uint8_t> contents(bytes);
1169 readContents(&bytes, contents.data());
1170 return contents;
1171 }
1172
clearStorage()1173 void ColorBufferGl::clearStorage() {
1174 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)NULL);
1175 s_egl.eglDestroyImageKHR(m_display, m_eglImage);
1176 m_eglImage = (EGLImageKHR)0;
1177 }
1178
restoreEglImage(EGLImageKHR image)1179 void ColorBufferGl::restoreEglImage(EGLImageKHR image) {
1180 s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
1181
1182 m_eglImage = image;
1183 s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)m_eglImage);
1184 }
1185
rebindEglImage(EGLImageKHR image,bool preserveContent)1186 void ColorBufferGl::rebindEglImage(EGLImageKHR image, bool preserveContent) {
1187 RecursiveScopedContextBind context(m_helper);
1188
1189 std::vector<uint8_t> contents;
1190 if (preserveContent) {
1191 contents = getContents();
1192 }
1193 clearStorage();
1194 restoreEglImage(image);
1195
1196 if (preserveContent) {
1197 replaceContents(contents.data(), m_numBytes);
1198 }
1199 }
1200
getBorrowedImageInfo()1201 std::unique_ptr<BorrowedImageInfo> ColorBufferGl::getBorrowedImageInfo() {
1202 auto info = std::make_unique<BorrowedImageInfoGl>();
1203 info->id = mHndl;
1204 info->width = m_width;
1205 info->height = m_height;
1206 info->texture = m_tex;
1207 info->onCommandsIssued = [this]() { setSync(); };
1208 return info;
1209 }
1210
1211 } // namespace gl
1212 } // namespace gfxstream
1213