• 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         }
436         default: {
437             FATAL("Unknown format: 0x%x", format);
438         }
439     }
440 }
441 
442 // Allocates an OpenGL texture that is large enough for a single plane of
443 // a YUV buffer of the given format and returns the texture name in the
444 // `outTextureName` argument.
createYUVGLTex(GLenum textureUnit,GLsizei width,GLsizei height,FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane,GLuint * outTextureName)445 void YUVConverter::createYUVGLTex(GLenum textureUnit,
446                                   GLsizei width,
447                                   GLsizei height,
448                                   FrameworkFormat format,
449                                   bool yuv420888ToNv21,
450                                   YUVPlane plane,
451                                   GLuint* outTextureName) {
452     YUV_DEBUG_LOG("w:%d h:%d format:%d plane:%d", width, height, format, plane);
453 
454     s_gles2.glActiveTexture(textureUnit);
455     s_gles2.glGenTextures(1, outTextureName);
456     s_gles2.glBindTexture(GL_TEXTURE_2D, *outTextureName);
457     s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
458     s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
459     GLint unprevAlignment = 0;
460     s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &unprevAlignment);
461     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
462     const GLint textureFormat = getGlTextureFormat(format, yuv420888ToNv21, plane);
463     const GLenum pixelFormat = getGlPixelFormat(format, yuv420888ToNv21, plane);
464     const GLenum pixelType = getGlPixelType(format, yuv420888ToNv21, plane);
465     s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, width, height, 0, pixelFormat, pixelType, NULL);
466     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, unprevAlignment);
467     s_gles2.glActiveTexture(GL_TEXTURE0);
468 }
469 
readYUVTex(GLuint tex,FrameworkFormat format,bool yuv420888ToNv21,YUVPlane plane,void * pixels,uint32_t pixelsStride)470 static void readYUVTex(GLuint tex, FrameworkFormat format, bool yuv420888ToNv21,
471                        YUVPlane plane, void* pixels, uint32_t pixelsStride) {
472     YUV_DEBUG_LOG("format%d plane:%d pixels:%p", format, plane, pixels);
473 
474     GLuint prevTexture = 0;
475     s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&prevTexture);
476     s_gles2.glBindTexture(GL_TEXTURE_2D, tex);
477     GLint prevAlignment = 0;
478     s_gles2.glGetIntegerv(GL_PACK_ALIGNMENT, &prevAlignment);
479     s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, 1);
480     GLint prevStride = 0;
481     s_gles2.glGetIntegerv(GL_PACK_ROW_LENGTH, &prevStride);
482     s_gles2.glPixelStorei(GL_PACK_ROW_LENGTH, pixelsStride);
483 
484     const GLenum pixelFormat = getGlPixelFormat(format, yuv420888ToNv21, plane);
485     const GLenum pixelType = getGlPixelType(format, yuv420888ToNv21,plane);
486     if (s_gles2.glGetTexImage) {
487         s_gles2.glGetTexImage(GL_TEXTURE_2D, 0, pixelFormat, pixelType, pixels);
488     } else {
489         YUV_DEBUG_LOG("empty glGetTexImage");
490     }
491 
492     s_gles2.glPixelStorei(GL_PACK_ROW_LENGTH, prevStride);
493     s_gles2.glPixelStorei(GL_PACK_ALIGNMENT, prevAlignment);
494     s_gles2.glBindTexture(GL_TEXTURE_2D, prevTexture);
495 }
496 
497 // Updates a given YUV buffer's plane texture at the coordinates
498 // (x, y, width, height), with the raw YUV data in |pixels|.  We
499 // cannot view the result properly until after conversion; this is
500 // 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)501 static void subUpdateYUVGLTex(GLenum texture_unit,
502                               GLuint tex,
503                               int x,
504                               int y,
505                               int width,
506                               int height,
507                               FrameworkFormat format,
508                               bool yuv420888ToNv21,
509                               YUVPlane plane,
510                               const void* pixels) {
511     YUV_DEBUG_LOG("x:%d y:%d w:%d h:%d format:%d plane:%d", x, y, width, height, format, plane);
512 
513     const GLenum pixelFormat = getGlPixelFormat(format, yuv420888ToNv21, plane);
514     const GLenum pixelType = getGlPixelType(format, yuv420888ToNv21, plane);
515 
516     s_gles2.glActiveTexture(texture_unit);
517     s_gles2.glBindTexture(GL_TEXTURE_2D, tex);
518     GLint unprevAlignment = 0;
519     s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &unprevAlignment);
520     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
521     s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, pixelFormat, pixelType, pixels);
522     s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, unprevAlignment);
523     s_gles2.glActiveTexture(GL_TEXTURE0);
524 }
525 
checkAndUpdateColorAspectsChanged(void * metadata)526 bool YUVConverter::checkAndUpdateColorAspectsChanged(void* metadata) {
527     bool needToUpdateConversionShader = false;
528     if (metadata) {
529         uint64_t type = *(uint64_t*)(metadata);
530         uint8_t* pmetadata = (uint8_t*)(metadata);
531         if (type == 1) {
532             uint64_t primaries = *(uint64_t*)(pmetadata + 8);
533             uint64_t range = *(uint64_t*)(pmetadata + 16);
534             uint64_t transfer = *(uint64_t*)(pmetadata + 24);
535             if (primaries != mColorPrimaries || range != mColorRange ||
536                 transfer != mColorTransfer) {
537                 mColorPrimaries = primaries;
538                 mColorRange = range;
539                 mColorTransfer = transfer;
540                 needToUpdateConversionShader = true;
541             }
542         }
543     }
544 
545     return needToUpdateConversionShader;
546 }
547 
createYUVGLShader()548 void YUVConverter::createYUVGLShader() {
549     YUV_DEBUG_LOG("format:%d", mFormat);
550 
551     // P010 needs uint samplers.
552     if (mFormat == FRAMEWORK_FORMAT_P010 && !mHasGlsl3Support) {
553         return;
554     }
555 
556     static const char kVertShader[] = R"(
557 precision highp float;
558 attribute mediump vec4 aPosition;
559 attribute highp vec2 aTexCoord;
560 varying highp vec2 vTexCoord;
561 void main(void) {
562   gl_Position = aPosition;
563   vTexCoord = aTexCoord;
564 }
565     )";
566 
567     static const char kFragShaderVersion3[] = R"(#version 300 es)";
568 
569     static const char kFragShaderBegin[] = R"(
570 precision highp float;
571 
572 varying highp vec2 vTexCoord;
573 
574 uniform highp float uYWidthCutoff;
575 uniform highp float uUVWidthCutoff;
576     )";
577     static const char kFragShaderBeginVersion3[] = R"(
578 precision highp float;
579 
580 layout (location = 0) out vec4 FragColor;
581 in highp vec2 vTexCoord;
582 
583 uniform highp float uYWidthCutoff;
584 uniform highp float uUVWidthCutoff;
585     )";
586 
587     static const char kSamplerUniforms[] = R"(
588 uniform sampler2D uSamplerY;
589 uniform sampler2D uSamplerU;
590 uniform sampler2D uSamplerV;
591     )";
592     static const char kSamplerUniformsUint[] = R"(
593 uniform highp usampler2D uSamplerY;
594 uniform highp usampler2D uSamplerU;
595 uniform highp usampler2D uSamplerV;
596     )";
597 
598     static const char kFragShaderMainBegin[] = R"(
599 void main(void) {
600     highp vec2 yTexCoords = vTexCoord;
601     highp vec2 uvTexCoords = vTexCoord;
602 
603     // For textures with extra padding for alignment (e.g. YV12 pads to 16),
604     // scale the coordinates to only sample from the non-padded area.
605     yTexCoords.x *= uYWidthCutoff;
606     uvTexCoords.x *= uUVWidthCutoff;
607 
608     highp vec3 yuv;
609 )";
610 
611     static const char kSampleY[] = R"(
612     yuv[0] = texture2D(uSamplerY, yTexCoords).r;
613     )";
614     static const char kSampleUV[] = R"(
615     yuv[1] = texture2D(uSamplerU, uvTexCoords).r;
616     yuv[2] = texture2D(uSamplerV, uvTexCoords).r;
617     )";
618     static const char kSampleInterleavedUV[] = R"(
619     // Note: uSamplerU and vSamplerV refer to the same texture.
620     yuv[1] = texture2D(uSamplerU, uvTexCoords).r;
621     yuv[2] = texture2D(uSamplerV, uvTexCoords).g;
622     )";
623     static const char kSampleInterleavedVU[] = R"(
624     // Note: uSamplerU and vSamplerV refer to the same texture.
625     yuv[1] = texture2D(uSamplerU, uvTexCoords).g;
626     yuv[2] = texture2D(uSamplerV, uvTexCoords).r;
627     )";
628 
629     static const char kSampleP010[] = R"(
630         uint yRaw = texture(uSamplerY, yTexCoords).r;
631         uint uRaw = texture(uSamplerU, uvTexCoords).r;
632         uint vRaw = texture(uSamplerV, uvTexCoords).g;
633 
634         // P010 values are stored in the upper 10-bits of 16-bit unsigned shorts.
635         yuv[0] = float(yRaw >> 6) / 1023.0;
636         yuv[1] = float(uRaw >> 6) / 1023.0;
637         yuv[2] = float(vRaw >> 6) / 1023.0;
638     )";
639 
640     // default
641     // limited range (2) 601 (4) sRGB transfer (3)
642     static const char kFragShaderMain_2_4_3[] = R"(
643     yuv[0] = yuv[0] - 0.0625;
644     yuv[1] = (yuv[1] - 0.5);
645     yuv[2] = (yuv[2] - 0.5);
646 
647     highp float yscale = 1.1643835616438356;
648     highp vec3 rgb = mat3(            yscale,               yscale,            yscale,
649                                            0, -0.39176229009491365, 2.017232142857143,
650                           1.5960267857142856,  -0.8129676472377708,                 0) * yuv;
651 
652     )";
653 
654     // full range (1) 601 (4) sRGB transfer (3)
655     static const char kFragShaderMain_1_4_3[] = R"(
656     yuv[0] = yuv[0];
657     yuv[1] = (yuv[1] - 0.5);
658     yuv[2] = (yuv[2] - 0.5);
659 
660     highp float yscale = 1.0;
661     highp vec3 rgb = mat3(            yscale,               yscale,            yscale,
662                                            0, -0.344136* yscale, 1.772* yscale,
663                           yscale*1.402,  -0.714136* yscale,                 0) * yuv;
664 
665     )";
666 
667     // limited range (2) 709 (1) sRGB transfer (3)
668     static const char kFragShaderMain_2_1_3[] = R"(
669     highp float xscale = 219.0/ 224.0;
670     yuv[0] = yuv[0] - 0.0625;
671     yuv[1] = xscale* (yuv[1] - 0.5);
672     yuv[2] = xscale* (yuv[2] - 0.5);
673 
674     highp float yscale = 255.0/219.0;
675     highp vec3 rgb = mat3(            yscale,               yscale,            yscale,
676                                            0, -0.1873* yscale, 1.8556* yscale,
677                           yscale*1.5748,  -0.4681* yscale,                 0) * yuv;
678 
679     )";
680 
681     static const char kFragShaderMainEnd[] = R"(
682     gl_FragColor = vec4(rgb, 1.0);
683 }
684     )";
685 
686     static const char kFragShaderMainEndVersion3[] = R"(
687     FragColor = vec4(rgb, 1.0);
688 }
689     )";
690     std::string vertShaderSource(kVertShader);
691     std::string fragShaderSource;
692 
693     if (mFormat == FRAMEWORK_FORMAT_P010) {
694         fragShaderSource += kFragShaderVersion3;
695         fragShaderSource += kFragShaderBeginVersion3;
696     } else {
697         fragShaderSource += kFragShaderBegin;
698     }
699 
700     if (mFormat == FRAMEWORK_FORMAT_P010) {
701         fragShaderSource += kSamplerUniformsUint;
702     } else {
703         fragShaderSource += kSamplerUniforms;
704     }
705 
706     fragShaderSource += kFragShaderMainBegin;
707 
708     switch (mFormat) {
709     case FRAMEWORK_FORMAT_NV12:
710     case FRAMEWORK_FORMAT_YUV_420_888:
711     case FRAMEWORK_FORMAT_YV12:
712         fragShaderSource += kSampleY;
713         if (isInterleaved(mFormat, mYuv420888ToNv21)) {
714             if (getInterleaveDirection(mFormat, mYuv420888ToNv21) == YUVInterleaveDirection::UV) {
715                 fragShaderSource += kSampleInterleavedUV;
716             } else {
717                 fragShaderSource += kSampleInterleavedVU;
718             }
719         } else {
720             fragShaderSource += kSampleUV;
721         }
722         break;
723     case FRAMEWORK_FORMAT_P010:
724         fragShaderSource += kSampleP010;
725         break;
726     default:
727         FATAL("%s: invalid format:%d", __FUNCTION__, mFormat);
728         return;
729     }
730 
731     if (mColorRange == 1 && mColorPrimaries == 4) {
732         fragShaderSource += kFragShaderMain_1_4_3;
733     } else if (mColorRange == 2 && mColorPrimaries == 1) {
734         fragShaderSource += kFragShaderMain_2_1_3;
735     } else {
736         fragShaderSource += kFragShaderMain_2_4_3;
737     }
738 
739     if (mFormat == FRAMEWORK_FORMAT_P010) {
740         fragShaderSource += kFragShaderMainEndVersion3;
741     } else {
742         fragShaderSource += kFragShaderMainEnd;
743     }
744 
745     YUV_DEBUG_LOG("format:%d vert-source:%s frag-source:%s", mFormat, vertShaderSource.c_str(), fragShaderSource.c_str());
746 
747     const GLchar* const vertShaderSourceChars = vertShaderSource.c_str();
748     const GLchar* const fragShaderSourceChars = fragShaderSource.c_str();
749     const GLint vertShaderSourceLen = vertShaderSource.length();
750     const GLint fragShaderSourceLen = fragShaderSource.length();
751 
752     GLuint vertShader = s_gles2.glCreateShader(GL_VERTEX_SHADER);
753     GLuint fragShader = s_gles2.glCreateShader(GL_FRAGMENT_SHADER);
754     s_gles2.glShaderSource(vertShader, 1, &vertShaderSourceChars, &vertShaderSourceLen);
755     s_gles2.glShaderSource(fragShader, 1, &fragShaderSourceChars, &fragShaderSourceLen);
756     s_gles2.glCompileShader(vertShader);
757     s_gles2.glCompileShader(fragShader);
758 
759     for (GLuint shader : {vertShader, fragShader}) {
760         GLint status = GL_FALSE;
761         s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
762         if (status == GL_FALSE) {
763             GLchar error[1024];
764             s_gles2.glGetShaderInfoLog(shader, sizeof(error), nullptr, &error[0]);
765             FATAL("Failed to compile YUV conversion shader: %s", error);
766             s_gles2.glDeleteShader(shader);
767             return;
768         }
769     }
770 
771     mProgram = s_gles2.glCreateProgram();
772     s_gles2.glAttachShader(mProgram, vertShader);
773     s_gles2.glAttachShader(mProgram, fragShader);
774     s_gles2.glLinkProgram(mProgram);
775 
776     GLint status = GL_FALSE;
777     s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
778     if (status == GL_FALSE) {
779         GLchar error[1024];
780         s_gles2.glGetProgramInfoLog(mProgram, sizeof(error), 0, &error[0]);
781         FATAL("Failed to link YUV conversion program: %s", error);
782         s_gles2.glDeleteProgram(mProgram);
783         mProgram = 0;
784         return;
785     }
786 
787     mUniformLocYWidthCutoff = s_gles2.glGetUniformLocation(mProgram, "uYWidthCutoff");
788     mUniformLocUVWidthCutoff = s_gles2.glGetUniformLocation(mProgram, "uUVWidthCutoff");
789     mUniformLocSamplerY = s_gles2.glGetUniformLocation(mProgram, "uSamplerY");
790     mUniformLocSamplerU = s_gles2.glGetUniformLocation(mProgram, "uSamplerU");
791     mUniformLocSamplerV = s_gles2.glGetUniformLocation(mProgram, "uSamplerV");
792     mAttributeLocPos = s_gles2.glGetAttribLocation(mProgram, "aPosition");
793     mAttributeLocTexCoord = s_gles2.glGetAttribLocation(mProgram, "aTexCoord");
794 
795     s_gles2.glDeleteShader(vertShader);
796     s_gles2.glDeleteShader(fragShader);
797 }
798 
createYUVGLFullscreenQuad()799 void YUVConverter::createYUVGLFullscreenQuad() {
800     s_gles2.glGenBuffers(1, &mQuadVertexBuffer);
801     s_gles2.glGenBuffers(1, &mQuadIndexBuffer);
802 
803     static const float kVertices[] = {
804         +1, -1, +0, +1, +0,
805         +1, +1, +0, +1, +1,
806         -1, +1, +0, +0, +1,
807         -1, -1, +0, +0, +0,
808     };
809 
810     static const GLubyte kIndices[] = { 0, 1, 2, 2, 3, 0 };
811 
812     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
813     s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
814     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer);
815     s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndices), kIndices, GL_STATIC_DRAW);
816 }
817 
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)818 static void doYUVConversionDraw(GLuint program,
819                                 GLint uniformLocYWidthCutoff,
820                                 GLint uniformLocUVWidthCutoff,
821                                 GLint uniformLocYSampler,
822                                 GLint uniformLocUSampler,
823                                 GLint uniformLocVSampler,
824                                 GLint attributeLocTexCoord,
825                                 GLint attributeLocPos,
826                                 GLuint quadVertexBuffer,
827                                 GLuint quadIndexBuffer,
828                                 float uYWidthCutoff,
829                                 float uUVWidthCutoff) {
830     const GLsizei kVertexAttribStride = 5 * sizeof(GL_FLOAT);
831     const GLvoid* kVertexAttribPosOffset = (GLvoid*)0;
832     const GLvoid* kVertexAttribCoordOffset = (GLvoid*)(3 * sizeof(GL_FLOAT));
833 
834     s_gles2.glUseProgram(program);
835 
836     s_gles2.glUniform1f(uniformLocYWidthCutoff, uYWidthCutoff);
837     s_gles2.glUniform1f(uniformLocUVWidthCutoff, uUVWidthCutoff);
838 
839     s_gles2.glUniform1i(uniformLocYSampler, 0);
840     s_gles2.glUniform1i(uniformLocUSampler, 1);
841     s_gles2.glUniform1i(uniformLocVSampler, 2);
842 
843     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, quadVertexBuffer);
844     s_gles2.glEnableVertexAttribArray(attributeLocPos);
845     s_gles2.glEnableVertexAttribArray(attributeLocTexCoord);
846 
847     s_gles2.glVertexAttribPointer(attributeLocPos, 3, GL_FLOAT, false,
848                                   kVertexAttribStride,
849                                   kVertexAttribPosOffset);
850     s_gles2.glVertexAttribPointer(attributeLocTexCoord, 2, GL_FLOAT, false,
851                                   kVertexAttribStride,
852                                   kVertexAttribCoordOffset);
853 
854     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadIndexBuffer);
855     s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
856 
857     s_gles2.glDisableVertexAttribArray(attributeLocPos);
858     s_gles2.glDisableVertexAttribArray(attributeLocTexCoord);
859 }
860 
861 // initialize(): allocate GPU memory for YUV components,
862 // and create shaders and vertex data.
YUVConverter(int width,int height,FrameworkFormat format,bool yuv420888ToNv21)863 YUVConverter::YUVConverter(int width, int height, FrameworkFormat format, bool yuv420888ToNv21)
864     : mWidth(width),
865       mHeight(height),
866       mFormat(format),
867       mColorBufferFormat(format),
868       mYuv420888ToNv21(yuv420888ToNv21) {}
869 
init(int width,int height,FrameworkFormat format)870 void YUVConverter::init(int width, int height, FrameworkFormat format) {
871     YUV_DEBUG_LOG("w:%d h:%d format:%d", width, height, format);
872 
873     uint32_t yWidth, yHeight = 0, yOffsetBytes, yStridePixels = 0, yStrideBytes;
874     uint32_t uWidth, uHeight = 0, uOffsetBytes, uStridePixels = 0, uStrideBytes;
875     uint32_t vWidth, vHeight = 0, vOffsetBytes, vStridePixels = 0, vStrideBytes;
876     getYUVOffsets(width, height, mFormat, mYuv420888ToNv21,
877                   &yWidth, &yHeight, &yOffsetBytes, &yStridePixels, &yStrideBytes,
878                   &uWidth, &uHeight, &uOffsetBytes, &uStridePixels, &uStrideBytes,
879                   &vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
880     mWidth = width;
881     mHeight = height;
882     if (!mTextureY) {
883         createYUVGLTex(GL_TEXTURE0, yStridePixels, yHeight, mFormat, mYuv420888ToNv21, YUVPlane::Y, &mTextureY);
884     }
885     if (isInterleaved(mFormat, mYuv420888ToNv21)) {
886         if (!mTextureU) {
887             createYUVGLTex(GL_TEXTURE1, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::UV, &mTextureU);
888             mTextureV = mTextureU;
889         }
890     } else {
891         if (!mTextureU) {
892             createYUVGLTex(GL_TEXTURE1, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::U, &mTextureU);
893         }
894         if (!mTextureV) {
895             createYUVGLTex(GL_TEXTURE2, vStridePixels, vHeight, mFormat, mYuv420888ToNv21, YUVPlane::V, &mTextureV);
896         }
897     }
898 
899     int glesMajor;
900     int glesMinor;
901     emugl::getGlesVersion(&glesMajor, &glesMinor);
902     mHasGlsl3Support = glesMajor >= 3;
903     YUV_DEBUG_LOG("YUVConverter has GLSL ES 3 support:%s (major:%d minor:%d", (mHasGlsl3Support ? "yes" : "no"), glesMajor, glesMinor);
904 
905     createYUVGLShader();
906     createYUVGLFullscreenQuad();
907 }
908 
saveGLState()909 void YUVConverter::saveGLState() {
910     s_gles2.glGetFloatv(GL_VIEWPORT, mCurrViewport);
911     s_gles2.glGetIntegerv(GL_ACTIVE_TEXTURE, &mCurrTexUnit);
912     s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &mCurrTexBind);
913     s_gles2.glGetIntegerv(GL_CURRENT_PROGRAM, &mCurrProgram);
914     s_gles2.glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &mCurrVbo);
915     s_gles2.glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &mCurrIbo);
916 }
917 
restoreGLState()918 void YUVConverter::restoreGLState() {
919     s_gles2.glViewport(mCurrViewport[0], mCurrViewport[1],
920                        mCurrViewport[2], mCurrViewport[3]);
921     s_gles2.glActiveTexture(mCurrTexUnit);
922     s_gles2.glUseProgram(mCurrProgram);
923     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mCurrVbo);
924     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mCurrIbo);
925 }
926 
getDataSize()927 uint32_t YUVConverter::getDataSize() {
928     uint32_t align = (mFormat == FRAMEWORK_FORMAT_YV12) ? 16 : 1;
929     uint32_t yStrideBytes = (mWidth + (align - 1)) & ~(align - 1);
930     uint32_t uvStride = (yStrideBytes / 2 + (align - 1)) & ~(align - 1);
931     uint32_t uvHeight = mHeight / 2;
932     uint32_t dataSize = yStrideBytes * mHeight + 2 * (uvHeight * uvStride);
933     YUV_DEBUG_LOG("w:%d h:%d format:%d has data size:%d", mWidth, mHeight, mFormat, dataSize);
934     return dataSize;
935 }
936 
readPixels(uint8_t * pixels,uint32_t pixels_size)937 void YUVConverter::readPixels(uint8_t* pixels, uint32_t pixels_size) {
938     YUV_DEBUG_LOG("w:%d h:%d format:%d pixels:%p pixels-size:%d", mWidth, mHeight, mFormat, pixels, pixels_size);
939 
940     uint32_t yWidth, yHeight, yOffsetBytes, yStridePixels, yStrideBytes;
941     uint32_t uWidth, uHeight, uOffsetBytes, uStridePixels, uStrideBytes;
942     uint32_t vWidth, vHeight, vOffsetBytes, vStridePixels, vStrideBytes;
943     getYUVOffsets(mWidth, mHeight, mFormat, mYuv420888ToNv21,
944                   &yWidth, &yHeight, &yOffsetBytes, &yStridePixels, &yStrideBytes,
945                   &uWidth, &uHeight, &uOffsetBytes, &uStridePixels, &uStrideBytes,
946                   &vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
947 
948     if (isInterleaved(mFormat, mYuv420888ToNv21)) {
949         readYUVTex(mTextureV, mFormat, mYuv420888ToNv21, YUVPlane::UV, pixels + std::min(uOffsetBytes, vOffsetBytes),
950                    uStridePixels);
951     } else {
952         readYUVTex(mTextureU, mFormat, mYuv420888ToNv21, YUVPlane::U, pixels + uOffsetBytes, uStridePixels);
953         readYUVTex(mTextureV, mFormat, mYuv420888ToNv21, YUVPlane::V, pixels + vOffsetBytes, vStridePixels);
954     }
955 
956     if (mFormat == FRAMEWORK_FORMAT_NV12 && mColorBufferFormat == FRAMEWORK_FORMAT_YUV_420_888) {
957         NV12ToYUV420PlanarInPlaceConvert(mWidth, mHeight, pixels, pixels);
958     }
959 
960     // Read the Y plane last because so that we can use it as a scratch space.
961     readYUVTex(mTextureY, mFormat, mYuv420888ToNv21, YUVPlane::Y, pixels + yOffsetBytes, yStridePixels);
962 }
963 
swapTextures(FrameworkFormat format,GLuint * textures,void * metadata)964 void YUVConverter::swapTextures(FrameworkFormat format, GLuint* textures, void* metadata) {
965     if (isInterleaved(format, mYuv420888ToNv21)) {
966         std::swap(textures[0], mTextureY);
967         std::swap(textures[1], mTextureU);
968         mTextureV = mTextureU;
969     } else {
970         std::swap(textures[0], mTextureY);
971         std::swap(textures[1], mTextureU);
972         std::swap(textures[2], mTextureV);
973     }
974 
975     mFormat = format;
976 
977     const bool needToUpdateConversionShader = checkAndUpdateColorAspectsChanged(metadata);
978     if (needToUpdateConversionShader) {
979         saveGLState();
980         reset();
981         init(mWidth, mHeight, mFormat);
982     }
983 
984     mTexturesSwapped = true;
985 }
986 
987 // drawConvert: per-frame updates.
988 // Update YUV textures, then draw the fullscreen
989 // quad set up above, which results in a framebuffer
990 // with the RGB colors.
drawConvert(int x,int y,int width,int height,const char * pixels)991 void YUVConverter::drawConvert(int x, int y, int width, int height, const char* pixels) {
992     drawConvertFromFormat(mFormat, x, y, width, height, pixels);
993 }
994 
drawConvertFromFormat(FrameworkFormat format,int x,int y,int width,int height,const char * pixels,void * metadata)995 void YUVConverter::drawConvertFromFormat(FrameworkFormat format, int x, int y, int width,
996                                          int height, const char* pixels, void* metadata) {
997     saveGLState();
998     const bool needToUpdateConversionShader = checkAndUpdateColorAspectsChanged(metadata);
999 
1000     if (pixels && (width != mWidth || height != mHeight)) {
1001         reset();
1002     }
1003 
1004     bool uploadFormatChanged = !mTexturesSwapped && pixels && (format != mFormat);
1005     bool initNeeded = (mProgram == 0) || uploadFormatChanged || needToUpdateConversionShader;
1006 
1007     if (initNeeded) {
1008         if (uploadFormatChanged) {
1009             mFormat = format;
1010             // TODO: missing cherry-picks, put it back
1011             // b/264928117
1012             //mCbFormat = format;
1013             reset();
1014         }
1015         init(width, height, mFormat);
1016     }
1017 
1018     if (mFormat == FRAMEWORK_FORMAT_P010 && !mHasGlsl3Support) {
1019         // TODO: perhaps fallback to just software conversion.
1020         return;
1021     }
1022 
1023     uint32_t yWidth = 0, yHeight = 0, yOffsetBytes, yStridePixels = 0, yStrideBytes;
1024     uint32_t uWidth = 0, uHeight = 0, uOffsetBytes, uStridePixels = 0, uStrideBytes;
1025     uint32_t vWidth = 0, vHeight = 0, vOffsetBytes, vStridePixels = 0, vStrideBytes;
1026     getYUVOffsets(width, height, mFormat, mYuv420888ToNv21,
1027                   &yWidth, &yHeight, &yOffsetBytes, &yStridePixels, &yStrideBytes,
1028                   &uWidth, &uHeight, &uOffsetBytes, &uStridePixels, &uStrideBytes,
1029                   &vWidth, &vHeight, &vOffsetBytes, &vStridePixels, &vStrideBytes);
1030 
1031     YUV_DEBUG_LOG("Updating YUV textures for drawConvert() "
1032                   "x:%d y:%d width:%d height:%d "
1033                   "yWidth:%d yHeight:%d yOffsetBytes:%d yStridePixels:%d yStrideBytes:%d "
1034                   "uWidth:%d uHeight:%d uOffsetBytes:%d uStridePixels:%d uStrideBytes:%d "
1035                   "vWidth:%d vHeight:%d vOffsetBytes:%d vStridePixels:%d vStrideBytes:%d ",
1036                   x, y, width, height,
1037                   yWidth, yHeight, yOffsetBytes, yStridePixels, yStrideBytes,
1038                   uWidth, uHeight, uOffsetBytes, uStridePixels, uStrideBytes,
1039                   vWidth, vHeight, vOffsetBytes, vStridePixels, vStrideBytes);
1040 
1041     s_gles2.glViewport(x, y, width, height);
1042 
1043     updateCutoffs(static_cast<float>(yWidth),
1044                   static_cast<float>(yStridePixels),
1045                   static_cast<float>(uWidth),
1046                   static_cast<float>(uStridePixels));
1047 
1048     if (pixels) {
1049         subUpdateYUVGLTex(GL_TEXTURE0, mTextureY, x, y, yStridePixels, yHeight, mFormat, mYuv420888ToNv21, YUVPlane::Y, pixels + yOffsetBytes);
1050         if (isInterleaved(mFormat, mYuv420888ToNv21)) {
1051             subUpdateYUVGLTex(GL_TEXTURE1, mTextureU, x, y, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::UV, pixels + std::min(uOffsetBytes, vOffsetBytes));
1052         } else {
1053             subUpdateYUVGLTex(GL_TEXTURE1, mTextureU, x, y, uStridePixels, uHeight, mFormat, mYuv420888ToNv21, YUVPlane::U, pixels + uOffsetBytes);
1054             subUpdateYUVGLTex(GL_TEXTURE2, mTextureV, x, y, vStridePixels, vHeight, mFormat, mYuv420888ToNv21, YUVPlane::V, pixels + vOffsetBytes);
1055         }
1056     } else {
1057         // special case: draw from texture, only support NV12 for now
1058         // as cuvid's native format is NV12.
1059         // TODO: add more formats if there are such needs in the future.
1060         assert(mFormat == FRAMEWORK_FORMAT_NV12);
1061     }
1062 
1063     s_gles2.glActiveTexture(GL_TEXTURE0);
1064     s_gles2.glBindTexture(GL_TEXTURE_2D, mTextureY);
1065     s_gles2.glActiveTexture(GL_TEXTURE1);
1066     s_gles2.glBindTexture(GL_TEXTURE_2D, mTextureU);
1067     s_gles2.glActiveTexture(GL_TEXTURE2);
1068     s_gles2.glBindTexture(GL_TEXTURE_2D, mTextureV);
1069 
1070     doYUVConversionDraw(mProgram,
1071                         mUniformLocYWidthCutoff,
1072                         mUniformLocUVWidthCutoff,
1073                         mUniformLocSamplerY,
1074                         mUniformLocSamplerU,
1075                         mUniformLocSamplerV,
1076                         mAttributeLocTexCoord,
1077                         mAttributeLocPos,
1078                         mQuadVertexBuffer,
1079                         mQuadIndexBuffer,
1080                         mYWidthCutoff,
1081                         mUVWidthCutoff);
1082 
1083     restoreGLState();
1084 }
1085 
updateCutoffs(float yWidth,float yStridePixels,float uvWidth,float uvStridePixels)1086 void YUVConverter::updateCutoffs(float yWidth, float yStridePixels,
1087                                  float uvWidth, float uvStridePixels) {
1088     switch (mFormat) {
1089     case FRAMEWORK_FORMAT_YV12:
1090         mYWidthCutoff = yWidth / yStridePixels;
1091         mUVWidthCutoff = uvWidth / uvStridePixels;
1092         break;
1093     case FRAMEWORK_FORMAT_NV12:
1094     case FRAMEWORK_FORMAT_P010:
1095     case FRAMEWORK_FORMAT_YUV_420_888:
1096         mYWidthCutoff = 1.0f;
1097         mUVWidthCutoff = 1.0f;
1098         break;
1099     case FRAMEWORK_FORMAT_GL_COMPATIBLE:
1100         FATAL("Input not a YUV format!");
1101     }
1102 }
1103 
reset()1104 void YUVConverter::reset() {
1105     if (mQuadIndexBuffer) s_gles2.glDeleteBuffers(1, &mQuadIndexBuffer);
1106     if (mQuadVertexBuffer) s_gles2.glDeleteBuffers(1, &mQuadVertexBuffer);
1107     if (mProgram) s_gles2.glDeleteProgram(mProgram);
1108     if (mTextureY) s_gles2.glDeleteTextures(1, &mTextureY);
1109     if (isInterleaved(mFormat, mYuv420888ToNv21)) {
1110         if (mTextureU) s_gles2.glDeleteTextures(1, &mTextureU);
1111     } else {
1112         if (mTextureU) s_gles2.glDeleteTextures(1, &mTextureU);
1113         if (mTextureV) s_gles2.glDeleteTextures(1, &mTextureV);
1114     }
1115     mQuadIndexBuffer = 0;
1116     mQuadVertexBuffer = 0;
1117     mProgram = 0;
1118     mTextureY = 0;
1119     mTextureU = 0;
1120     mTextureV = 0;
1121 }
1122 
~YUVConverter()1123 YUVConverter::~YUVConverter() {
1124     reset();
1125 }
1126 
1127 }  // namespace gl
1128 }  // namespace gfxstream
1129