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