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