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