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