• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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