• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2016 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 
17 #include "YUVConverter.h"
18 
19 #include <assert.h>
20 #include <stdio.h>
21 #include <string>
22 
23 #include "OpenGLESDispatch/DispatchTables.h"
24 #include "host-common/feature_control.h"
25 #include "host-common/opengl/misc.h"
26 
27 namespace gfxstream {
28 namespace gl {
29 
30 #define FATAL(fmt,...) do { \
31     fprintf(stderr, "%s: FATAL: " fmt "\n", __func__, ##__VA_ARGS__); \
32     assert(false); \
33 } while(0)
34 
35 #define YUV_CONVERTER_DEBUG 0
36 
37 #if YUV_CONVERTER_DEBUG
38 #define YUV_DEBUG_LOG(fmt, ...)                                                        \
39     fprintf(stderr, "yuv-converter: %s %s:%d " fmt "\n", __FILE__, __func__, __LINE__, \
40             ##__VA_ARGS__);
41 #else
42 #define YUV_DEBUG_LOG(fmt, ...)
43 #endif
44 
isInterleaved(FrameworkFormat format,bool yuv420888ToNv21)45 bool isInterleaved(FrameworkFormat format, bool yuv420888ToNv21) {
46     switch (format) {
47     case FRAMEWORK_FORMAT_NV12:
48     case FRAMEWORK_FORMAT_P010:
49         return true;
50     case FRAMEWORK_FORMAT_YUV_420_888:
51         return yuv420888ToNv21;
52     case FRAMEWORK_FORMAT_YV12:
53         return false;
54     default:
55         FATAL("Invalid for format:%d", format);
56         return false;
57     }
58 }
59 
60 enum class YUVInterleaveDirection {
61     VU = 0,
62     UV = 1,
63 };
64 
getInterleaveDirection(FrameworkFormat format,bool yuv420888ToNv21)65 YUVInterleaveDirection getInterleaveDirection(FrameworkFormat format, bool yuv420888ToNv21) {
66     if (!isInterleaved(format, yuv420888ToNv21)) {
67         FATAL("Format:%d not interleaved", format);
68     }
69 
70     switch (format) {
71     case FRAMEWORK_FORMAT_NV12:
72     case FRAMEWORK_FORMAT_P010:
73         return YUVInterleaveDirection::UV;
74     case FRAMEWORK_FORMAT_YUV_420_888:
75         if (yuv420888ToNv21) {
76             return YUVInterleaveDirection::VU;
77         }
78         FATAL("Format:%d not interleaved", format);
79         return YUVInterleaveDirection::UV;
80     case FRAMEWORK_FORMAT_YV12:
81     default:
82         FATAL("Format:%d not interleaved", format);
83         return YUVInterleaveDirection::UV;
84     }
85 }
86 
getGlTextureFormat(FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane)87 GLint getGlTextureFormat(FrameworkFormat format, bool yuv420888ToNv21, YUVPlane plane) {
88     switch (format) {
89     case FRAMEWORK_FORMAT_YV12:
90         switch (plane) {
91         case YUVPlane::Y:
92         case YUVPlane::U:
93         case YUVPlane::V:
94             return GL_R8;
95         case YUVPlane::UV:
96             FATAL("Invalid plane for format:%d", format);
97             return 0;
98         }
99     case FRAMEWORK_FORMAT_YUV_420_888:
100         if (yuv420888ToNv21) {
101             switch (plane) {
102             case YUVPlane::Y:
103                 return GL_R8;
104             case YUVPlane::UV:
105                 return GL_RG8;
106             case YUVPlane::U:
107             case YUVPlane::V:
108                 FATAL("Invalid plane for format:%d", format);
109                 return 0;
110             }
111         } else {
112             switch (plane) {
113             case YUVPlane::Y:
114             case YUVPlane::U:
115             case YUVPlane::V:
116                 return GL_R8;
117             case YUVPlane::UV:
118                 FATAL("Invalid plane for format:%d", format);
119                 return 0;
120             }
121         }
122     case FRAMEWORK_FORMAT_NV12:
123         switch (plane) {
124         case YUVPlane::Y:
125             return GL_R8;
126         case YUVPlane::UV:
127             return GL_RG8;
128         case YUVPlane::U:
129         case YUVPlane::V:
130             FATAL("Invalid plane for format:%d", format);
131             return 0;
132         }
133     case FRAMEWORK_FORMAT_P010:
134         switch (plane) {
135         case YUVPlane::Y:
136             return GL_R16UI;
137         case YUVPlane::UV:
138             return GL_RG16UI;
139         case YUVPlane::U:
140         case YUVPlane::V:
141             FATAL("Invalid plane for format:%d", format);
142             return 0;
143         }
144     default:
145         FATAL("Invalid format:%d", format);
146         return 0;
147     }
148 }
149 
getGlPixelFormat(FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane)150 GLenum getGlPixelFormat(FrameworkFormat format, bool yuv420888ToNv21, YUVPlane plane) {
151     switch (format) {
152     case FRAMEWORK_FORMAT_YV12:
153         switch (plane) {
154         case YUVPlane::Y:
155         case YUVPlane::U:
156         case YUVPlane::V:
157             return GL_RED;
158         case YUVPlane::UV:
159             FATAL("Invalid plane for format:%d", format);
160             return 0;
161         }
162     case FRAMEWORK_FORMAT_YUV_420_888:
163         if (yuv420888ToNv21) {
164             switch (plane) {
165             case YUVPlane::Y:
166                 return GL_RED;
167             case YUVPlane::UV:
168                 return GL_RG;
169             case YUVPlane::U:
170             case YUVPlane::V:
171                 FATAL("Invalid plane for format:%d", format);
172                 return 0;
173             }
174         } else {
175             switch (plane) {
176             case YUVPlane::Y:
177             case YUVPlane::U:
178             case YUVPlane::V:
179                 return GL_RED;
180             case YUVPlane::UV:
181                 FATAL("Invalid plane for format:%d", format);
182                 return 0;
183             }
184         }
185     case FRAMEWORK_FORMAT_NV12:
186         switch (plane) {
187         case YUVPlane::Y:
188             return GL_RED;
189         case YUVPlane::UV:
190             return GL_RG;
191         case YUVPlane::U:
192         case YUVPlane::V:
193             FATAL("Invalid plane for format:%d", format);
194             return 0;
195         }
196     case FRAMEWORK_FORMAT_P010:
197         switch (plane) {
198         case YUVPlane::Y:
199             return GL_RED_INTEGER;
200         case YUVPlane::UV:
201             return GL_RG_INTEGER;
202         case YUVPlane::U:
203         case YUVPlane::V:
204             FATAL("Invalid plane for format:%d", format);
205             return 0;
206         }
207     default:
208         FATAL("Invalid format:%d", format);
209         return 0;
210     }
211 }
212 
getGlPixelType(FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane)213 GLsizei getGlPixelType(FrameworkFormat format, bool yuv420888ToNv21, YUVPlane plane) {
214     switch (format) {
215     case FRAMEWORK_FORMAT_YV12:
216         switch (plane) {
217         case YUVPlane::Y:
218         case YUVPlane::U:
219         case YUVPlane::V:
220             return GL_UNSIGNED_BYTE;
221         case YUVPlane::UV:
222             FATAL("Invalid plane for format:%d", format);
223             return 0;
224         }
225     case FRAMEWORK_FORMAT_YUV_420_888:
226         if (yuv420888ToNv21) {
227             switch (plane) {
228             case YUVPlane::Y:
229             case YUVPlane::UV:
230                 return GL_UNSIGNED_BYTE;
231             case YUVPlane::U:
232             case YUVPlane::V:
233                 FATAL("Invalid plane for format:%d", format);
234                 return 0;
235             }
236         } else {
237             switch (plane) {
238             case YUVPlane::Y:
239             case YUVPlane::U:
240             case YUVPlane::V:
241                 return GL_UNSIGNED_BYTE;
242             case YUVPlane::UV:
243                 FATAL("Invalid plane for format:%d", format);
244                 return 0;
245             }
246         }
247     case FRAMEWORK_FORMAT_NV12:
248         switch (plane) {
249         case YUVPlane::Y:
250         case YUVPlane::UV:
251             return GL_UNSIGNED_BYTE;
252         case YUVPlane::U:
253         case YUVPlane::V:
254             FATAL("Invalid plane for format:%d", format);
255             return 0;
256         }
257     case FRAMEWORK_FORMAT_P010:
258         switch (plane) {
259         case YUVPlane::Y:
260         case YUVPlane::UV:
261             return GL_UNSIGNED_SHORT;
262         case YUVPlane::U:
263         case YUVPlane::V:
264             FATAL("Invalid plane for format:%d", format);
265             return 0;
266         }
267     default:
268         FATAL("Invalid format:%d", format);
269         return 0;
270     }
271 }
272 
273 // NV12 and YUV420 are all packed
NV12ToYUV420PlanarInPlaceConvert(int nWidth,int nHeight,uint8_t * pFrame,uint8_t * pQuad)274 static void NV12ToYUV420PlanarInPlaceConvert(int nWidth,
275                                              int nHeight,
276                                              uint8_t* pFrame,
277                                              uint8_t* pQuad) {
278     std::vector<uint8_t> tmp;
279     if (pQuad == nullptr) {
280         tmp.resize(nWidth * nHeight / 4);
281         pQuad = tmp.data();
282     }
283     int nPitch = nWidth;
284     uint8_t *puv = pFrame + nPitch * nHeight, *pu = puv,
285             *pv = puv + nPitch * nHeight / 4;
286     for (int y = 0; y < nHeight / 2; y++) {
287         for (int x = 0; x < nWidth / 2; x++) {
288             pu[y * nPitch / 2 + x] = puv[y * nPitch + x * 2];
289             pQuad[y * nWidth / 2 + x] = puv[y * nPitch + x * 2 + 1];
290         }
291     }
292     memcpy(pv, pQuad, nWidth * nHeight / 4);
293 }
294 
alignToPower2(uint32_t val,uint32_t align)295 inline uint32_t alignToPower2(uint32_t val, uint32_t align) {
296     return (val + (align - 1)) & ~(align - 1);
297 }
298 
299 // getYUVOffsets(), given a YUV-formatted buffer that is arranged
300 // according to the spec
301 // https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV
302 // In particular, Android YUV widths are aligned to 16 pixels.
303 // Inputs:
304 // |yv12|: the YUV-formatted buffer
305 // Outputs:
306 // |yOffsetBytes|: offset into |yv12| of the start of the Y component
307 // |uOffsetBytes|: offset into |yv12| of the start of the U component
308 // |vOffsetBytes|: offset into |yv12| of the start of the V component
getYUVOffsets(int width,int height,FrameworkFormat format,bool yuv420888ToNv21,uint32_t * yWidth,uint32_t * yHeight,uint32_t * yOffsetBytes,uint32_t * yStridePixels,uint32_t * yStrideBytes,uint32_t * uWidth,uint32_t * uHeight,uint32_t * uOffsetBytes,uint32_t * uStridePixels,uint32_t * uStrideBytes,uint32_t * vWidth,uint32_t * vHeight,uint32_t * vOffsetBytes,uint32_t * vStridePixels,uint32_t * vStrideBytes)309 static void getYUVOffsets(int width,
310                           int height,
311                           FrameworkFormat format,
312                           bool yuv420888ToNv21,
313                           uint32_t* yWidth,
314                           uint32_t* yHeight,
315                           uint32_t* yOffsetBytes,
316                           uint32_t* yStridePixels,
317                           uint32_t* yStrideBytes,
318                           uint32_t* uWidth,
319                           uint32_t* uHeight,
320                           uint32_t* uOffsetBytes,
321                           uint32_t* uStridePixels,
322                           uint32_t* uStrideBytes,
323                           uint32_t* vWidth,
324                           uint32_t* vHeight,
325                           uint32_t* vOffsetBytes,
326                           uint32_t* vStridePixels,
327                           uint32_t* vStrideBytes) {
328     switch (format) {
329         case FRAMEWORK_FORMAT_YV12: {
330             *yWidth = width;
331             *yHeight = height;
332             *yOffsetBytes = 0;
333             // Luma stride is 32 bytes aligned in minigbm, 16 in goldfish
334             // gralloc.
335             *yStridePixels = alignToPower2(width, emugl::getGrallocImplementation() == MINIGBM
336                     ? 32 : 16);
337             *yStrideBytes = *yStridePixels;
338 
339             // Chroma stride is 16 bytes aligned.
340             *vWidth = width / 2;
341             *vHeight = height / 2;
342             *vOffsetBytes = (*yStrideBytes) * (*yHeight);
343             *vStridePixels = alignToPower2((*yStridePixels) / 2, 16);
344             *vStrideBytes = (*vStridePixels);
345 
346             *uWidth = width / 2;
347             *uHeight = height / 2;
348             *uOffsetBytes = (*vOffsetBytes) + ((*vStrideBytes) * (*vHeight));
349             *uStridePixels = alignToPower2((*yStridePixels) / 2, 16);
350             *uStrideBytes = *uStridePixels;
351             break;
352         }
353         case FRAMEWORK_FORMAT_YUV_420_888: {
354             if (yuv420888ToNv21) {
355                 *yWidth = width;
356                 *yHeight = height;
357                 *yOffsetBytes = 0;
358                 *yStridePixels = width;
359                 *yStrideBytes = *yStridePixels;
360 
361                 *vWidth = width / 2;
362                 *vHeight = height / 2;
363                 *vOffsetBytes = (*yStrideBytes) * (*yHeight);
364                 *vStridePixels = (*yStridePixels) / 2;
365                 *vStrideBytes = (*vStridePixels);
366 
367                 *uWidth = width / 2;
368                 *uHeight = height / 2;
369                 *uOffsetBytes = (*vOffsetBytes) + 1;
370                 *uStridePixels = (*yStridePixels) / 2;
371                 *uStrideBytes = *uStridePixels;
372             } else {
373                 *yWidth = width;
374                 *yHeight = height;
375                 *yOffsetBytes = 0;
376                 *yStridePixels = width;
377                 *yStrideBytes = *yStridePixels;
378 
379                 *uWidth = width / 2;
380                 *uHeight = height / 2;
381                 *uOffsetBytes = (*yStrideBytes) * (*yHeight);
382                 *uStridePixels = (*yStridePixels) / 2;
383                 *uStrideBytes = *uStridePixels;
384 
385                 *vWidth = width / 2;
386                 *vHeight = height / 2;
387                 *vOffsetBytes = (*uOffsetBytes) + ((*uStrideBytes) * (*uHeight));
388                 *vStridePixels = (*yStridePixels) / 2;
389                 *vStrideBytes = (*vStridePixels);
390             }
391             break;
392         }
393         case FRAMEWORK_FORMAT_NV12: {
394             *yWidth = width;
395             *yHeight = height;
396             *yOffsetBytes = 0;
397             *yStridePixels = width;
398             *yStrideBytes = *yStridePixels;
399 
400             *uWidth = width / 2;
401             *uHeight = height / 2;
402             *uOffsetBytes = (*yStrideBytes) * (*yHeight);
403             *uStridePixels = (*yStridePixels) / 2;
404             *uStrideBytes = *uStridePixels;
405 
406             *vWidth = width / 2;
407             *vHeight = height / 2;
408             *vOffsetBytes = (*uOffsetBytes) + 1;
409             *vStridePixels = (*yStridePixels) / 2;
410             *vStrideBytes = (*vStridePixels);
411             break;
412         }
413         case FRAMEWORK_FORMAT_P010: {
414             *yWidth = width;
415             *yHeight = height;
416             *yOffsetBytes = 0;
417             *yStridePixels = width;
418             *yStrideBytes = (*yStridePixels) * /*bytes per pixel=*/2;
419 
420             *uWidth = width / 2;
421             *uHeight = height / 2;
422             *uOffsetBytes = (*yStrideBytes) * (*yHeight);
423             *uStridePixels = (*uWidth);
424             *uStrideBytes = *uStridePixels  * /*bytes per pixel=*/2;
425 
426             *vWidth = width / 2;
427             *vHeight = height / 2;
428             *vOffsetBytes = (*uOffsetBytes) + 2;
429             *vStridePixels = (*vWidth);
430             *vStrideBytes = (*vStridePixels)  * /*bytes per pixel=*/2;
431             break;
432         }
433         case FRAMEWORK_FORMAT_GL_COMPATIBLE: {
434             FATAL("Input not a YUV format! (FRAMEWORK_FORMAT_GL_COMPATIBLE)");
435             break;
436         }
437         default: {
438             FATAL("Unknown format: 0x%x", format);
439             break;
440         }
441     }
442 }
443 
444 // Allocates an OpenGL texture that is large enough for a single plane of
445 // a YUV buffer of the given format and returns the texture name in the
446 // `outTextureName` argument.
createYUVGLTex(GLenum textureUnit,GLsizei width,GLsizei height,FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane,GLuint * outTextureName)447 void YUVConverter::createYUVGLTex(GLenum textureUnit,
448                                   GLsizei width,
449                                   GLsizei height,
450                                   FrameworkFormat format,
451                                   bool yuv420888ToNv21,
452                                   YUVPlane plane,
453                                   GLuint* outTextureName) {
454     YUV_DEBUG_LOG("w:%d h:%d format:%d plane:%d", width, height, format, plane);
455 
456     s_gles2.glActiveTexture(textureUnit);
457     s_gles2.glGenTextures(1, outTextureName);
458     s_gles2.glBindTexture(GL_TEXTURE_2D, *outTextureName);
459     s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
460     s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
461     GLint unprevAlignment = 0;
462     s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &unprevAlignment);
463     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
464     const GLint textureFormat = getGlTextureFormat(format, yuv420888ToNv21, plane);
465     const GLenum pixelFormat = getGlPixelFormat(format, yuv420888ToNv21, plane);
466     const GLenum pixelType = getGlPixelType(format, yuv420888ToNv21, plane);
467     s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, width, height, 0, pixelFormat, pixelType, NULL);
468     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, unprevAlignment);
469     s_gles2.glActiveTexture(GL_TEXTURE0);
470 }
471 
readYUVTex(GLuint tex,FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane,void * pixels,uint32_t pixelsStride)472 static void readYUVTex(GLuint tex, FrameworkFormat format, bool yuv420888ToNv21,
473                        YUVPlane plane, void* pixels, uint32_t pixelsStride) {
474     YUV_DEBUG_LOG("format%d plane:%d pixels:%p", format, plane, pixels);
475 
476     GLuint prevTexture = 0;
477     s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&prevTexture);
478     s_gles2.glBindTexture(GL_TEXTURE_2D, tex);
479     GLint prevAlignment = 0;
480     s_gles2.glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);
481     s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, 1);
482     GLint prevStride = 0;
483     s_gles2.glGetIntegerv(GL_PACK_ROW_LENGTH, &prevStride);
484     s_gles2.glPixelStorei(GL_PACK_ROW_LENGTH, pixelsStride);
485 
486     const GLenum pixelFormat = getGlPixelFormat(format, yuv420888ToNv21, plane);
487     const GLenum pixelType = getGlPixelType(format, yuv420888ToNv21,plane);
488     if (s_gles2.glGetTexImage) {
489         s_gles2.glGetTexImage(GL_TEXTURE_2D, 0, pixelFormat, pixelType, pixels);
490     } else {
491         YUV_DEBUG_LOG("empty glGetTexImage");
492     }
493 
494     s_gles2.glPixelStorei(GL_PACK_ROW_LENGTH, prevStride);
495     s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);
496     s_gles2.glBindTexture(GL_TEXTURE_2D, prevTexture);
497 }
498 
499 // Updates a given YUV buffer's plane texture at the coordinates
500 // (x, y, width, height), with the raw YUV data in |pixels|.  We
501 // cannot view the result properly until after conversion; this is
502 // to be used only as input to the conversion shader.
subUpdateYUVGLTex(GLenum texture_unit,GLuint tex,int x,int y,int width,int height,FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane,const void * pixels)503 static void subUpdateYUVGLTex(GLenum texture_unit,
504                               GLuint tex,
505                               int x,
506                               int y,
507                               int width,
508                               int height,
509                               FrameworkFormat format,
510                               bool yuv420888ToNv21,
511                               YUVPlane plane,
512                               const void* pixels) {
513     YUV_DEBUG_LOG("x:%d y:%d w:%d h:%d format:%d plane:%d", x, y, width, height, format, plane);
514 
515     const GLenum pixelFormat = getGlPixelFormat(format, yuv420888ToNv21, plane);
516     const GLenum pixelType = getGlPixelType(format, yuv420888ToNv21, plane);
517 
518     s_gles2.glActiveTexture(texture_unit);
519     s_gles2.glBindTexture(GL_TEXTURE_2D, tex);
520     GLint unprevAlignment = 0;
521     s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &unprevAlignment);
522     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
523     s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, pixelFormat, pixelType, pixels);
524     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, unprevAlignment);
525     s_gles2.glActiveTexture(GL_TEXTURE0);
526 }
527 
checkAndUpdateColorAspectsChanged(void * metadata)528 bool YUVConverter::checkAndUpdateColorAspectsChanged(void* metadata) {
529     bool needToUpdateConversionShader = false;
530     if (metadata) {
531         uint64_t type = *(uint64_t*)(metadata);
532         uint8_t* pmetadata = (uint8_t*)(metadata);
533         if (type == 1) {
534             uint64_t primaries = *(uint64_t*)(pmetadata + 8);
535             uint64_t range = *(uint64_t*)(pmetadata + 16);
536             uint64_t transfer = *(uint64_t*)(pmetadata + 24);
537             if (primaries != mColorPrimaries || range != mColorRange ||
538                 transfer != mColorTransfer) {
539                 mColorPrimaries = primaries;
540                 mColorRange = range;
541                 mColorTransfer = transfer;
542                 needToUpdateConversionShader = true;
543             }
544         }
545     }
546 
547     return needToUpdateConversionShader;
548 }
549 
createYUVGLShader()550 void YUVConverter::createYUVGLShader() {
551     YUV_DEBUG_LOG("format:%d", mFormat);
552 
553     // P010 needs uint samplers.
554     if (mFormat == FRAMEWORK_FORMAT_P010 && !mHasGlsl3Support) {
555         return;
556     }
557 
558     static const char kVertShader[] = R"(
559 precision highp float;
560 attribute mediump vec4 aPosition;
561 attribute highp vec2 aTexCoord;
562 varying highp vec2 vTexCoord;
563 void main(void) {
564   gl_Position = aPosition;
565   vTexCoord = aTexCoord;
566 }
567     )";
568 
569     static const char kFragShaderVersion3[] = R"(#version 300 es)";
570 
571     static const char kFragShaderBegin[] = R"(
572 precision highp float;
573 
574 varying highp vec2 vTexCoord;
575 
576 uniform highp float uYWidthCutoff;
577 uniform highp float uUVWidthCutoff;
578     )";
579     static const char kFragShaderBeginVersion3[] = R"(
580 precision highp float;
581 
582 layout (location = 0) out vec4 FragColor;
583 in highp vec2 vTexCoord;
584 
585 uniform highp float uYWidthCutoff;
586 uniform highp float uUVWidthCutoff;
587     )";
588 
589     static const char kSamplerUniforms[] = R"(
590 uniform sampler2D uSamplerY;
591 uniform sampler2D uSamplerU;
592 uniform sampler2D uSamplerV;
593     )";
594     static const char kSamplerUniformsUint[] = R"(
595 uniform highp usampler2D uSamplerY;
596 uniform highp usampler2D uSamplerU;
597 uniform highp usampler2D uSamplerV;
598     )";
599 
600     static const char kFragShaderMainBegin[] = R"(
601 void main(void) {
602     highp vec2 yTexCoords = vTexCoord;
603     highp vec2 uvTexCoords = vTexCoord;
604 
605     // For textures with extra padding for alignment (e.g. YV12 pads to 16),
606     // scale the coordinates to only sample from the non-padded area.
607     yTexCoords.x *= uYWidthCutoff;
608     uvTexCoords.x *= uUVWidthCutoff;
609 
610     highp vec3 yuv;
611 )";
612 
613     static const char kSampleY[] = R"(
614     yuv[0] = texture2D(uSamplerY, yTexCoords).r;
615     )";
616     static const char kSampleUV[] = R"(
617     yuv[1] = texture2D(uSamplerU, uvTexCoords).r;
618     yuv[2] = texture2D(uSamplerV, uvTexCoords).r;
619     )";
620     static const char kSampleInterleavedUV[] = R"(
621     // Note: uSamplerU and vSamplerV refer to the same texture.
622     yuv[1] = texture2D(uSamplerU, uvTexCoords).r;
623     yuv[2] = texture2D(uSamplerV, uvTexCoords).g;
624     )";
625     static const char kSampleInterleavedVU[] = R"(
626     // Note: uSamplerU and vSamplerV refer to the same texture.
627     yuv[1] = texture2D(uSamplerU, uvTexCoords).g;
628     yuv[2] = texture2D(uSamplerV, uvTexCoords).r;
629     )";
630 
631     static const char kSampleP010[] = R"(
632         uint yRaw = texture(uSamplerY, yTexCoords).r;
633         uint uRaw = texture(uSamplerU, uvTexCoords).r;
634         uint vRaw = texture(uSamplerV, uvTexCoords).g;
635 
636         // P010 values are stored in the upper 10-bits of 16-bit unsigned shorts.
637         yuv[0] = float(yRaw >> 6) / 1023.0;
638         yuv[1] = float(uRaw >> 6) / 1023.0;
639         yuv[2] = float(vRaw >> 6) / 1023.0;
640     )";
641 
642     // default
643     // limited range (2) 601 (4) sRGB transfer (3)
644     static const char kFragShaderMain_2_4_3[] = R"(
645     yuv[0] = yuv[0] - 0.0625;
646     yuv[1] = (yuv[1] - 0.5);
647     yuv[2] = (yuv[2] - 0.5);
648 
649     highp float yscale = 1.1643835616438356;
650     highp vec3 rgb = mat3(            yscale,               yscale,            yscale,
651                                            0, -0.39176229009491365, 2.017232142857143,
652                           1.5960267857142856,  -0.8129676472377708,                 0) * yuv;
653 
654     )";
655 
656     // full range (1) 601 (4) sRGB transfer (3)
657     static const char kFragShaderMain_1_4_3[] = R"(
658     yuv[0] = yuv[0];
659     yuv[1] = (yuv[1] - 0.5);
660     yuv[2] = (yuv[2] - 0.5);
661 
662     highp float yscale = 1.0;
663     highp vec3 rgb = mat3(            yscale,               yscale,            yscale,
664                                            0, -0.344136* yscale, 1.772* yscale,
665                           yscale*1.402,  -0.714136* yscale,                 0) * yuv;
666 
667     )";
668 
669     // limited range (2) 709 (1) sRGB transfer (3)
670     static const char kFragShaderMain_2_1_3[] = R"(
671     highp float xscale = 219.0/ 224.0;
672     yuv[0] = yuv[0] - 0.0625;
673     yuv[1] = xscale* (yuv[1] - 0.5);
674     yuv[2] = xscale* (yuv[2] - 0.5);
675 
676     highp float yscale = 255.0/219.0;
677     highp vec3 rgb = mat3(            yscale,               yscale,            yscale,
678                                            0, -0.1873* yscale, 1.8556* yscale,
679                           yscale*1.5748,  -0.4681* yscale,                 0) * yuv;
680 
681     )";
682 
683     static const char kFragShaderMainEnd[] = R"(
684     gl_FragColor = vec4(rgb, 1.0);
685 }
686     )";
687 
688     static const char kFragShaderMainEndVersion3[] = R"(
689     FragColor = vec4(rgb, 1.0);
690 }
691     )";
692     std::string vertShaderSource(kVertShader);
693     std::string fragShaderSource;
694 
695     if (mFormat == FRAMEWORK_FORMAT_P010) {
696         fragShaderSource += kFragShaderVersion3;
697         fragShaderSource += kFragShaderBeginVersion3;
698     } else {
699         fragShaderSource += kFragShaderBegin;
700     }
701 
702     if (mFormat == FRAMEWORK_FORMAT_P010) {
703         fragShaderSource += kSamplerUniformsUint;
704     } else {
705         fragShaderSource += kSamplerUniforms;
706     }
707 
708     fragShaderSource += kFragShaderMainBegin;
709 
710     switch (mFormat) {
711     case FRAMEWORK_FORMAT_NV12:
712     case FRAMEWORK_FORMAT_YUV_420_888:
713     case FRAMEWORK_FORMAT_YV12:
714         fragShaderSource += kSampleY;
715         if (isInterleaved(mFormat, mYuv420888ToNv21)) {
716             if (getInterleaveDirection(mFormat, mYuv420888ToNv21) == YUVInterleaveDirection::UV) {
717                 fragShaderSource += kSampleInterleavedUV;
718             } else {
719                 fragShaderSource += kSampleInterleavedVU;
720             }
721         } else {
722             fragShaderSource += kSampleUV;
723         }
724         break;
725     case FRAMEWORK_FORMAT_P010:
726         fragShaderSource += kSampleP010;
727         break;
728     default:
729         FATAL("%s: invalid format:%d", __FUNCTION__, mFormat);
730         return;
731     }
732 
733     if (mColorRange == 1 && mColorPrimaries == 4) {
734         fragShaderSource += kFragShaderMain_1_4_3;
735     } else if (mColorRange == 2 && mColorPrimaries == 1) {
736         fragShaderSource += kFragShaderMain_2_1_3;
737     } else {
738         fragShaderSource += kFragShaderMain_2_4_3;
739     }
740 
741     if (mFormat == FRAMEWORK_FORMAT_P010) {
742         fragShaderSource += kFragShaderMainEndVersion3;
743     } else {
744         fragShaderSource += kFragShaderMainEnd;
745     }
746 
747     YUV_DEBUG_LOG("format:%d vert-source:%s frag-source:%s", mFormat, vertShaderSource.c_str(), fragShaderSource.c_str());
748 
749     const GLchar* const vertShaderSourceChars = vertShaderSource.c_str();
750     const GLchar* const fragShaderSourceChars = fragShaderSource.c_str();
751     const GLint vertShaderSourceLen = vertShaderSource.length();
752     const GLint fragShaderSourceLen = fragShaderSource.length();
753 
754     GLuint vertShader = s_gles2.glCreateShader(GL_VERTEX_SHADER);
755     GLuint fragShader = s_gles2.glCreateShader(GL_FRAGMENT_SHADER);
756     s_gles2.glShaderSource(vertShader, 1, &vertShaderSourceChars, &vertShaderSourceLen);
757     s_gles2.glShaderSource(fragShader, 1, &fragShaderSourceChars, &fragShaderSourceLen);
758     s_gles2.glCompileShader(vertShader);
759     s_gles2.glCompileShader(fragShader);
760 
761     for (GLuint shader : {vertShader, fragShader}) {
762         GLint status = GL_FALSE;
763         s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
764         if (status == GL_FALSE) {
765             GLchar error[1024];
766             s_gles2.glGetShaderInfoLog(shader, sizeof(error), nullptr, &error[0]);
767             FATAL("Failed to compile YUV conversion shader: %s", error);
768             s_gles2.glDeleteShader(shader);
769             return;
770         }
771     }
772 
773     mProgram = s_gles2.glCreateProgram();
774     s_gles2.glAttachShader(mProgram, vertShader);
775     s_gles2.glAttachShader(mProgram, fragShader);
776     s_gles2.glLinkProgram(mProgram);
777 
778     GLint status = GL_FALSE;
779     s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
780     if (status == GL_FALSE) {
781         GLchar error[1024];
782         s_gles2.glGetProgramInfoLog(mProgram, sizeof(error), 0, &error[0]);
783         FATAL("Failed to link YUV conversion program: %s", error);
784         s_gles2.glDeleteProgram(mProgram);
785         mProgram = 0;
786         return;
787     }
788 
789     mUniformLocYWidthCutoff = s_gles2.glGetUniformLocation(mProgram, "uYWidthCutoff");
790     mUniformLocUVWidthCutoff = s_gles2.glGetUniformLocation(mProgram, "uUVWidthCutoff");
791     mUniformLocSamplerY = s_gles2.glGetUniformLocation(mProgram, "uSamplerY");
792     mUniformLocSamplerU = s_gles2.glGetUniformLocation(mProgram, "uSamplerU");
793     mUniformLocSamplerV = s_gles2.glGetUniformLocation(mProgram, "uSamplerV");
794     mAttributeLocPos = s_gles2.glGetAttribLocation(mProgram, "aPosition");
795     mAttributeLocTexCoord = s_gles2.glGetAttribLocation(mProgram, "aTexCoord");
796 
797     s_gles2.glDeleteShader(vertShader);
798     s_gles2.glDeleteShader(fragShader);
799 }
800 
createYUVGLFullscreenQuad()801 void YUVConverter::createYUVGLFullscreenQuad() {
802     s_gles2.glGenBuffers(1, &mQuadVertexBuffer);
803     s_gles2.glGenBuffers(1, &mQuadIndexBuffer);
804 
805     static const float kVertices[] = {
806         +1, -1, +0, +1, +0,
807         +1, +1, +0, +1, +1,
808         -1, +1, +0, +0, +1,
809         -1, -1, +0, +0, +0,
810     };
811 
812     static const GLubyte kIndices[] = { 0, 1, 2, 2, 3, 0 };
813 
814     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
815     s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
816     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer);
817     s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndices), kIndices, GL_STATIC_DRAW);
818 }
819 
doYUVConversionDraw(GLuint program,GLint uniformLocYWidthCutoff,GLint uniformLocUVWidthCutoff,GLint uniformLocYSampler,GLint uniformLocUSampler,GLint uniformLocVSampler,GLint attributeLocTexCoord,GLint attributeLocPos,GLuint quadVertexBuffer,GLuint quadIndexBuffer,float uYWidthCutoff,float uUVWidthCutoff)820 static void doYUVConversionDraw(GLuint program,
821                                 GLint uniformLocYWidthCutoff,
822                                 GLint uniformLocUVWidthCutoff,
823                                 GLint uniformLocYSampler,
824                                 GLint uniformLocUSampler,
825                                 GLint uniformLocVSampler,
826                                 GLint attributeLocTexCoord,
827                                 GLint attributeLocPos,
828                                 GLuint quadVertexBuffer,
829                                 GLuint quadIndexBuffer,
830                                 float uYWidthCutoff,
831                                 float uUVWidthCutoff) {
832     const GLsizei kVertexAttribStride = 5 * sizeof(GL_FLOAT);
833     const GLvoid* kVertexAttribPosOffset = (GLvoid*)0;
834     const GLvoid* kVertexAttribCoordOffset = (GLvoid*)(3 * sizeof(GL_FLOAT));
835 
836     s_gles2.glUseProgram(program);
837 
838     s_gles2.glUniform1f(uniformLocYWidthCutoff, uYWidthCutoff);
839     s_gles2.glUniform1f(uniformLocUVWidthCutoff, uUVWidthCutoff);
840 
841     s_gles2.glUniform1i(uniformLocYSampler, 0);
842     s_gles2.glUniform1i(uniformLocUSampler, 1);
843     s_gles2.glUniform1i(uniformLocVSampler, 2);
844 
845     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, quadVertexBuffer);
846     s_gles2.glEnableVertexAttribArray(attributeLocPos);
847     s_gles2.glEnableVertexAttribArray(attributeLocTexCoord);
848 
849     s_gles2.glVertexAttribPointer(attributeLocPos, 3, GL_FLOAT, false,
850                                   kVertexAttribStride,
851                                   kVertexAttribPosOffset);
852     s_gles2.glVertexAttribPointer(attributeLocTexCoord, 2, GL_FLOAT, false,
853                                   kVertexAttribStride,
854                                   kVertexAttribCoordOffset);
855 
856     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadIndexBuffer);
857     s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
858 
859     s_gles2.glDisableVertexAttribArray(attributeLocPos);
860     s_gles2.glDisableVertexAttribArray(attributeLocTexCoord);
861 }
862 
863 // initialize(): allocate GPU memory for YUV components,
864 // and create shaders and vertex data.
YUVConverter(int width,int height,FrameworkFormat format,bool yuv420888ToNv21)865 YUVConverter::YUVConverter(int width, int height, FrameworkFormat format, bool yuv420888ToNv21)
866     : mWidth(width),
867       mHeight(height),
868       mFormat(format),
869       mColorBufferFormat(format),
870       mYuv420888ToNv21(yuv420888ToNv21) {}
871 
init(int width,int height,FrameworkFormat format)872 void YUVConverter::init(int width, int height, FrameworkFormat format) {
873     YUV_DEBUG_LOG("w:%d h:%d format:%d", width, height, format);
874 
875     uint32_t yWidth, yHeight = 0, yOffsetBytes, yStridePixels = 0, yStrideBytes;
876     uint32_t uWidth, uHeight = 0, uOffsetBytes, uStridePixels = 0, uStrideBytes;
877     uint32_t vWidth, vHeight = 0, vOffsetBytes, vStridePixels = 0, vStrideBytes;
878     getYUVOffsets(width, height, mFormat, mYuv420888ToNv21,
879                   &yWidth, &yHeight, &yOffsetBytes, &yStridePixels, &yStrideBytes,
880                   &uWidth, &uHeight, &uOffsetBytes, &uStridePixels, &uStrideBytes,
881                   &vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
882     mWidth = width;
883     mHeight = height;
884     if (!mTextureY) {
885         createYUVGLTex(GL_TEXTURE0, yStridePixels, yHeight, mFormat, mYuv420888ToNv21, YUVPlane::Y, &mTextureY);
886     }
887     if (isInterleaved(mFormat, mYuv420888ToNv21)) {
888         if (!mTextureU) {
889             createYUVGLTex(GL_TEXTURE1, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::UV, &mTextureU);
890             mTextureV = mTextureU;
891         }
892     } else {
893         if (!mTextureU) {
894             createYUVGLTex(GL_TEXTURE1, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::U, &mTextureU);
895         }
896         if (!mTextureV) {
897             createYUVGLTex(GL_TEXTURE2, vStridePixels, vHeight, mFormat, mYuv420888ToNv21, YUVPlane::V, &mTextureV);
898         }
899     }
900 
901     int glesMajor;
902     int glesMinor;
903     emugl::getGlesVersion(&glesMajor, &glesMinor);
904     mHasGlsl3Support = glesMajor >= 3;
905     YUV_DEBUG_LOG("YUVConverter has GLSL ES 3 support:%s (major:%d minor:%d", (mHasGlsl3Support ? "yes" : "no"), glesMajor, glesMinor);
906 
907     createYUVGLShader();
908     createYUVGLFullscreenQuad();
909 }
910 
saveGLState()911 void YUVConverter::saveGLState() {
912     s_gles2.glGetFloatv(GL_VIEWPORT, mCurrViewport);
913     s_gles2.glGetIntegerv(GL_ACTIVE_TEXTURE, &mCurrTexUnit);
914     s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &mCurrTexBind);
915     s_gles2.glGetIntegerv(GL_CURRENT_PROGRAM, &mCurrProgram);
916     s_gles2.glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &mCurrVbo);
917     s_gles2.glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &mCurrIbo);
918 }
919 
restoreGLState()920 void YUVConverter::restoreGLState() {
921     s_gles2.glViewport(mCurrViewport[0], mCurrViewport[1],
922                        mCurrViewport[2], mCurrViewport[3]);
923     s_gles2.glActiveTexture(mCurrTexUnit);
924     s_gles2.glUseProgram(mCurrProgram);
925     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mCurrVbo);
926     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mCurrIbo);
927 }
928 
getDataSize()929 uint32_t YUVConverter::getDataSize() {
930     uint32_t align = (mFormat == FRAMEWORK_FORMAT_YV12) ? 16 : 1;
931     uint32_t yStrideBytes = (mWidth + (align - 1)) & ~(align - 1);
932     uint32_t uvStride = (yStrideBytes / 2 + (align - 1)) & ~(align - 1);
933     uint32_t uvHeight = mHeight / 2;
934     uint32_t dataSize = yStrideBytes * mHeight + 2 * (uvHeight * uvStride);
935     YUV_DEBUG_LOG("w:%d h:%d format:%d has data size:%d", mWidth, mHeight, mFormat, dataSize);
936     return dataSize;
937 }
938 
readPixels(uint8_t * pixels,uint32_t pixels_size)939 void YUVConverter::readPixels(uint8_t* pixels, uint32_t pixels_size) {
940     YUV_DEBUG_LOG("w:%d h:%d format:%d pixels:%p pixels-size:%d", mWidth, mHeight, mFormat, pixels, pixels_size);
941 
942     uint32_t yWidth, yHeight, yOffsetBytes, yStridePixels, yStrideBytes;
943     uint32_t uWidth, uHeight, uOffsetBytes, uStridePixels, uStrideBytes;
944     uint32_t vWidth, vHeight, vOffsetBytes, vStridePixels, vStrideBytes;
945     getYUVOffsets(mWidth, mHeight, mFormat, mYuv420888ToNv21,
946                   &yWidth, &yHeight, &yOffsetBytes, &yStridePixels, &yStrideBytes,
947                   &uWidth, &uHeight, &uOffsetBytes, &uStridePixels, &uStrideBytes,
948                   &vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
949 
950     if (isInterleaved(mFormat, mYuv420888ToNv21)) {
951         readYUVTex(mTextureV, mFormat, mYuv420888ToNv21, YUVPlane::UV, pixels + std::min(uOffsetBytes, vOffsetBytes),
952                    uStridePixels);
953     } else {
954         readYUVTex(mTextureU, mFormat, mYuv420888ToNv21, YUVPlane::U, pixels + uOffsetBytes, uStridePixels);
955         readYUVTex(mTextureV, mFormat, mYuv420888ToNv21, YUVPlane::V, pixels + vOffsetBytes, vStridePixels);
956     }
957 
958     if (mFormat == FRAMEWORK_FORMAT_NV12 && mColorBufferFormat == FRAMEWORK_FORMAT_YUV_420_888) {
959         NV12ToYUV420PlanarInPlaceConvert(mWidth, mHeight, pixels, pixels);
960     }
961 
962     // Read the Y plane last because so that we can use it as a scratch space.
963     readYUVTex(mTextureY, mFormat, mYuv420888ToNv21, YUVPlane::Y, pixels + yOffsetBytes, yStridePixels);
964 }
965 
swapTextures(FrameworkFormat format,GLuint * textures,void * metadata)966 void YUVConverter::swapTextures(FrameworkFormat format, GLuint* textures, void* metadata) {
967     if (isInterleaved(format, mYuv420888ToNv21)) {
968         std::swap(textures[0], mTextureY);
969         std::swap(textures[1], mTextureU);
970         mTextureV = mTextureU;
971     } else {
972         std::swap(textures[0], mTextureY);
973         std::swap(textures[1], mTextureU);
974         std::swap(textures[2], mTextureV);
975     }
976 
977     mFormat = format;
978 
979     const bool needToUpdateConversionShader = checkAndUpdateColorAspectsChanged(metadata);
980     if (needToUpdateConversionShader) {
981         saveGLState();
982         reset();
983         init(mWidth, mHeight, mFormat);
984     }
985 
986     mTexturesSwapped = true;
987 }
988 
989 // drawConvert: per-frame updates.
990 // Update YUV textures, then draw the fullscreen
991 // quad set up above, which results in a framebuffer
992 // with the RGB colors.
drawConvert(int x,int y,int width,int height,const char * pixels)993 void YUVConverter::drawConvert(int x, int y, int width, int height, const char* pixels) {
994     drawConvertFromFormat(mFormat, x, y, width, height, pixels);
995 }
996 
drawConvertFromFormat(FrameworkFormat format,int x,int y,int width,int height,const char * pixels,void * metadata)997 void YUVConverter::drawConvertFromFormat(FrameworkFormat format, int x, int y, int width,
998                                          int height, const char* pixels, void* metadata) {
999     saveGLState();
1000     const bool needToUpdateConversionShader = checkAndUpdateColorAspectsChanged(metadata);
1001 
1002     if (pixels && (width != mWidth || height != mHeight)) {
1003         reset();
1004     }
1005 
1006     bool uploadFormatChanged = !mTexturesSwapped && pixels && (format != mFormat);
1007     bool initNeeded = (mProgram == 0) || uploadFormatChanged || needToUpdateConversionShader;
1008 
1009     if (initNeeded) {
1010         if (uploadFormatChanged) {
1011             mFormat = format;
1012             // TODO: missing cherry-picks, put it back
1013             // b/264928117
1014             //mCbFormat = format;
1015             reset();
1016         }
1017         init(width, height, mFormat);
1018     }
1019 
1020     if (mFormat == FRAMEWORK_FORMAT_P010 && !mHasGlsl3Support) {
1021         // TODO: perhaps fallback to just software conversion.
1022         return;
1023     }
1024 
1025     uint32_t yWidth = 0, yHeight = 0, yOffsetBytes, yStridePixels = 0, yStrideBytes;
1026     uint32_t uWidth = 0, uHeight = 0, uOffsetBytes, uStridePixels = 0, uStrideBytes;
1027     uint32_t vWidth = 0, vHeight = 0, vOffsetBytes, vStridePixels = 0, vStrideBytes;
1028     getYUVOffsets(width, height, mFormat, mYuv420888ToNv21,
1029                   &yWidth, &yHeight, &yOffsetBytes, &yStridePixels, &yStrideBytes,
1030                   &uWidth, &uHeight, &uOffsetBytes, &uStridePixels, &uStrideBytes,
1031                   &vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
1032 
1033     YUV_DEBUG_LOG("Updating YUV textures for drawConvert() "
1034                   "x:%d y:%d width:%d height:%d "
1035                   "yWidth:%d yHeight:%d yOffsetBytes:%d yStridePixels:%d yStrideBytes:%d "
1036                   "uWidth:%d uHeight:%d uOffsetBytes:%d uStridePixels:%d uStrideBytes:%d "
1037                   "vWidth:%d vHeight:%d vOffsetBytes:%d vStridePixels:%d vStrideBytes:%d ",
1038                   x, y, width, height,
1039                   yWidth, yHeight, yOffsetBytes, yStridePixels, yStrideBytes,
1040                   uWidth, uHeight, uOffsetBytes, uStridePixels, uStrideBytes,
1041                   vWidth, vHeight, vOffsetBytes, vStridePixels, vStrideBytes);
1042 
1043     s_gles2.glViewport(x, y, width, height);
1044 
1045     updateCutoffs(static_cast<float>(yWidth),
1046                   static_cast<float>(yStridePixels),
1047                   static_cast<float>(uWidth),
1048                   static_cast<float>(uStridePixels));
1049 
1050     if (pixels) {
1051         subUpdateYUVGLTex(GL_TEXTURE0, mTextureY, x, y, yStridePixels, yHeight, mFormat, mYuv420888ToNv21, YUVPlane::Y, pixels + yOffsetBytes);
1052         if (isInterleaved(mFormat, mYuv420888ToNv21)) {
1053             subUpdateYUVGLTex(GL_TEXTURE1, mTextureU, x, y, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::UV, pixels + std::min(uOffsetBytes, vOffsetBytes));
1054         } else {
1055             subUpdateYUVGLTex(GL_TEXTURE1, mTextureU, x, y, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::U, pixels + uOffsetBytes);
1056             subUpdateYUVGLTex(GL_TEXTURE2, mTextureV, x, y, vStridePixels, vHeight, mFormat, mYuv420888ToNv21, YUVPlane::V, pixels + vOffsetBytes);
1057         }
1058     } else {
1059         // special case: draw from texture, only support NV12 for now
1060         // as cuvid's native format is NV12.
1061         // TODO: add more formats if there are such needs in the future.
1062         assert(mFormat == FRAMEWORK_FORMAT_NV12);
1063     }
1064 
1065     s_gles2.glActiveTexture(GL_TEXTURE0);
1066     s_gles2.glBindTexture(GL_TEXTURE_2D, mTextureY);
1067     s_gles2.glActiveTexture(GL_TEXTURE1);
1068     s_gles2.glBindTexture(GL_TEXTURE_2D, mTextureU);
1069     s_gles2.glActiveTexture(GL_TEXTURE2);
1070     s_gles2.glBindTexture(GL_TEXTURE_2D, mTextureV);
1071 
1072     doYUVConversionDraw(mProgram,
1073                         mUniformLocYWidthCutoff,
1074                         mUniformLocUVWidthCutoff,
1075                         mUniformLocSamplerY,
1076                         mUniformLocSamplerU,
1077                         mUniformLocSamplerV,
1078                         mAttributeLocTexCoord,
1079                         mAttributeLocPos,
1080                         mQuadVertexBuffer,
1081                         mQuadIndexBuffer,
1082                         mYWidthCutoff,
1083                         mUVWidthCutoff);
1084 
1085     restoreGLState();
1086 }
1087 
updateCutoffs(float yWidth,float yStridePixels,float uvWidth,float uvStridePixels)1088 void YUVConverter::updateCutoffs(float yWidth, float yStridePixels,
1089                                  float uvWidth, float uvStridePixels) {
1090     switch (mFormat) {
1091     case FRAMEWORK_FORMAT_YV12:
1092         mYWidthCutoff = yWidth / yStridePixels;
1093         mUVWidthCutoff = uvWidth / uvStridePixels;
1094         break;
1095     case FRAMEWORK_FORMAT_NV12:
1096     case FRAMEWORK_FORMAT_P010:
1097     case FRAMEWORK_FORMAT_YUV_420_888:
1098         mYWidthCutoff = 1.0f;
1099         mUVWidthCutoff = 1.0f;
1100         break;
1101     case FRAMEWORK_FORMAT_GL_COMPATIBLE:
1102         FATAL("Input not a YUV format!");
1103     }
1104 }
1105 
reset()1106 void YUVConverter::reset() {
1107     if (mQuadIndexBuffer) s_gles2.glDeleteBuffers(1, &mQuadIndexBuffer);
1108     if (mQuadVertexBuffer) s_gles2.glDeleteBuffers(1, &mQuadVertexBuffer);
1109     if (mProgram) s_gles2.glDeleteProgram(mProgram);
1110     if (mTextureY) s_gles2.glDeleteTextures(1, &mTextureY);
1111     if (isInterleaved(mFormat, mYuv420888ToNv21)) {
1112         if (mTextureU) s_gles2.glDeleteTextures(1, &mTextureU);
1113     } else {
1114         if (mTextureU) s_gles2.glDeleteTextures(1, &mTextureU);
1115         if (mTextureV) s_gles2.glDeleteTextures(1, &mTextureV);
1116     }
1117     mQuadIndexBuffer = 0;
1118     mQuadVertexBuffer = 0;
1119     mProgram = 0;
1120     mTextureY = 0;
1121     mTextureU = 0;
1122     mTextureV = 0;
1123 }
1124 
~YUVConverter()1125 YUVConverter::~YUVConverter() {
1126     reset();
1127 }
1128 
1129 }  // namespace gl
1130 }  // namespace gfxstream
1131