Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/gl/GLBlitHelper.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "gfxUtils.h"
8
#include "GLBlitHelper.h"
9
#include "GLContext.h"
10
#include "GLScreenBuffer.h"
11
#include "ScopedGLHelpers.h"
12
#include "mozilla/Preferences.h"
13
#include "ImageContainer.h"
14
#include "HeapCopyOfStackArray.h"
15
#include "mozilla/ArrayUtils.h"
16
#include "mozilla/gfx/Logging.h"
17
#include "mozilla/gfx/Matrix.h"
18
#include "mozilla/UniquePtr.h"
19
#include "GPUVideoImage.h"
20
21
#ifdef MOZ_WIDGET_ANDROID
22
#include "GeneratedJNIWrappers.h"
23
#include "AndroidSurfaceTexture.h"
24
#include "GLImages.h"
25
#include "GLLibraryEGL.h"
26
#endif
27
28
#ifdef XP_MACOSX
29
#include "MacIOSurfaceImage.h"
30
#include "GLContextCGL.h"
31
#endif
32
33
using mozilla::layers::PlanarYCbCrImage;
34
using mozilla::layers::PlanarYCbCrData;
35
36
namespace mozilla {
37
namespace gl {
38
39
// --
40
41
const char* const kFragHeader_Tex2D = "\
42
    #define SAMPLER sampler2D                                                \n\
43
    #if __VERSION__ >= 130                                                   \n\
44
        #define TEXTURE texture                                              \n\
45
    #else                                                                    \n\
46
        #define TEXTURE texture2D                                            \n\
47
    #endif                                                                   \n\
48
";
49
const char* const kFragHeader_Tex2DRect = "\
50
    #define SAMPLER sampler2DRect                                            \n\
51
    #if __VERSION__ >= 130                                                   \n\
52
        #define TEXTURE texture                                              \n\
53
    #else                                                                    \n\
54
        #define TEXTURE texture2DRect                                        \n\
55
    #endif                                                                   \n\
56
";
57
const char* const kFragHeader_TexExt = "\
58
    #extension GL_OES_EGL_image_external : require                           \n\
59
    #if __VERSION__ >= 130                                                   \n\
60
        #define TEXTURE texture                                              \n\
61
    #else                                                                    \n\
62
        #define TEXTURE texture2D                                            \n\
63
    #endif                                                                   \n\
64
    #define SAMPLER samplerExternalOES                                       \n\
65
";
66
67
const char* const kFragBody_RGBA = "\
68
    VARYING vec2 vTexCoord0;                                                 \n\
69
    uniform SAMPLER uTex0;                                                   \n\
70
                                                                             \n\
71
    void main(void)                                                          \n\
72
    {                                                                        \n\
73
        FRAG_COLOR = TEXTURE(uTex0, vTexCoord0);                             \n\
74
    }                                                                        \n\
75
";
76
const char* const kFragBody_CrYCb = "\
77
    VARYING vec2 vTexCoord0;                                                 \n\
78
    uniform SAMPLER uTex0;                                                   \n\
79
    uniform MAT4X3 uColorMatrix;                                             \n\
80
                                                                             \n\
81
    void main(void)                                                          \n\
82
    {                                                                        \n\
83
        vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr,                      \n\
84
                        1.0);                                                \n\
85
        FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0);                    \n\
86
    }                                                                        \n\
87
";
88
const char* const kFragBody_NV12 = "\
89
    VARYING vec2 vTexCoord0;                                                 \n\
90
    VARYING vec2 vTexCoord1;                                                 \n\
91
    uniform SAMPLER uTex0;                                                   \n\
92
    uniform SAMPLER uTex1;                                                   \n\
93
    uniform MAT4X3 uColorMatrix;                                             \n\
94
                                                                             \n\
95
    void main(void)                                                          \n\
96
    {                                                                        \n\
97
        vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x,                        \n\
98
                        TEXTURE(uTex1, vTexCoord1).xy,                       \n\
99
                        1.0);                                                \n\
100
        FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0);                    \n\
101
    }                                                                        \n\
102
";
103
const char* const kFragBody_PlanarYUV = "\
104
    VARYING vec2 vTexCoord0;                                                 \n\
105
    VARYING vec2 vTexCoord1;                                                 \n\
106
    uniform SAMPLER uTex0;                                                   \n\
107
    uniform SAMPLER uTex1;                                                   \n\
108
    uniform SAMPLER uTex2;                                                   \n\
109
    uniform MAT4X3 uColorMatrix;                                             \n\
110
                                                                             \n\
111
    void main(void)                                                          \n\
112
    {                                                                        \n\
113
        vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x,                        \n\
114
                        TEXTURE(uTex1, vTexCoord1).x,                        \n\
115
                        TEXTURE(uTex2, vTexCoord1).x,                        \n\
116
                        1.0);                                                \n\
117
        FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0);                    \n\
118
    }                                                                        \n\
119
";
120
121
// --
122
123
template<uint8_t N>
124
/*static*/ Mat<N>
125
Mat<N>::Zero()
126
0
{
127
0
    Mat<N> ret;
128
0
    for (auto& x : ret.m) {
129
0
        x = 0.0f;
130
0
    }
131
0
    return ret;
132
0
}
133
134
template<uint8_t N>
135
/*static*/ Mat<N>
136
Mat<N>::I()
137
0
{
138
0
    auto ret = Mat<N>::Zero();
139
0
    for (uint8_t i = 0; i < N; i++) {
140
0
        ret.at(i,i) = 1.0f;
141
0
    }
142
0
    return ret;
143
0
}
144
145
template<uint8_t N>
146
Mat<N>
147
Mat<N>::operator*(const Mat<N>& r) const
148
{
149
    Mat<N> ret;
150
    for (uint8_t x = 0; x < N; x++) {
151
        for (uint8_t y = 0; y < N; y++) {
152
            float sum = 0.0f;
153
            for (uint8_t i = 0; i < N; i++) {
154
                sum += at(i,y) * r.at(x,i);
155
            }
156
            ret.at(x,y) = sum;
157
        }
158
    }
159
    return ret;
160
}
161
162
Mat3
163
SubRectMat3(const float x, const float y, const float w, const float h)
164
0
{
165
0
    auto ret = Mat3::Zero();
166
0
    ret.at(0,0) = w;
167
0
    ret.at(1,1) = h;
168
0
    ret.at(2,0) = x;
169
0
    ret.at(2,1) = y;
170
0
    ret.at(2,2) = 1.0f;
171
0
    return ret;
172
0
}
173
174
Mat3
175
SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size)
176
0
{
177
0
    return SubRectMat3(float(subrect.X()) / size.width,
178
0
                       float(subrect.Y()) / size.height,
179
0
                       float(subrect.Width()) / size.width,
180
0
                       float(subrect.Height()) / size.height);
181
0
}
182
183
Mat3
184
SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
185
            const gfx::IntSize& divisors)
186
0
{
187
0
    const float x = float(bigSubrect.X()) / divisors.width;
188
0
    const float y = float(bigSubrect.Y()) / divisors.height;
189
0
    const float w = float(bigSubrect.Width()) / divisors.width;
190
0
    const float h = float(bigSubrect.Height()) / divisors.height;
191
0
    return SubRectMat3(x / smallSize.width,
192
0
                       y / smallSize.height,
193
0
                       w / smallSize.width,
194
0
                       h / smallSize.height);
195
0
}
196
197
// --
198
199
ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, const uint8_t texCount,
200
                                       const GLenum texTarget)
201
    : mGL(*gl)
202
    , mTexCount(texCount)
203
    , mTexTarget(texTarget)
204
    , mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE))
205
0
{
206
0
    GLenum texBinding;
207
0
    switch (mTexTarget) {
208
0
    case LOCAL_GL_TEXTURE_2D:
209
0
        texBinding = LOCAL_GL_TEXTURE_BINDING_2D;
210
0
        break;
211
0
    case LOCAL_GL_TEXTURE_RECTANGLE:
212
0
        texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE;
213
0
        break;
214
0
    case LOCAL_GL_TEXTURE_EXTERNAL:
215
0
        texBinding = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
216
0
        break;
217
0
    default:
218
0
        gfxCriticalError() << "Unhandled texTarget: " << texTarget;
219
0
    }
220
0
221
0
    for (uint8_t i = 0; i < mTexCount; i++) {
222
0
        mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
223
0
        if (mGL.IsSupported(GLFeature::sampler_objects)) {
224
0
            mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING);
225
0
            mGL.fBindSampler(i, 0);
226
0
        }
227
0
        mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding);
228
0
    }
229
0
}
230
231
ScopedSaveMultiTex::~ScopedSaveMultiTex()
232
0
{
233
0
    for (uint8_t i = 0; i < mTexCount; i++) {
234
0
        mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
235
0
        if (mGL.IsSupported(GLFeature::sampler_objects)) {
236
0
            mGL.fBindSampler(i, mOldTexSampler[i]);
237
0
        }
238
0
        mGL.fBindTexture(mTexTarget, mOldTex[i]);
239
0
    }
240
0
    mGL.fActiveTexture(mOldTexUnit);
241
0
}
242
243
// --
244
245
class ScopedBindArrayBuffer final
246
{
247
    GLContext& mGL;
248
    const GLuint mOldVBO;
249
250
public:
251
    ScopedBindArrayBuffer(GLContext* const gl, const GLuint vbo)
252
        : mGL(*gl)
253
        , mOldVBO(mGL.GetIntAs<GLuint>(LOCAL_GL_ARRAY_BUFFER_BINDING))
254
0
    {
255
0
        mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
256
0
    }
257
258
    ~ScopedBindArrayBuffer()
259
0
    {
260
0
        mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mOldVBO);
261
0
    }
262
};
263
264
// --
265
266
class ScopedShader final
267
{
268
    GLContext& mGL;
269
    const GLuint mName;
270
271
public:
272
    ScopedShader(GLContext* const gl, const GLenum shaderType)
273
        : mGL(*gl)
274
        , mName(mGL.fCreateShader(shaderType))
275
0
    { }
276
277
    ~ScopedShader()
278
0
    {
279
0
        mGL.fDeleteShader(mName);
280
0
    }
281
282
0
    operator GLuint() const { return mName; }
283
};
284
285
// --
286
287
class SaveRestoreCurrentProgram final
288
{
289
    GLContext& mGL;
290
    const GLuint mOld;
291
292
public:
293
    explicit SaveRestoreCurrentProgram(GLContext* const gl)
294
        : mGL(*gl)
295
        , mOld(mGL.GetIntAs<GLuint>(LOCAL_GL_CURRENT_PROGRAM))
296
0
    { }
297
298
    ~SaveRestoreCurrentProgram()
299
0
    {
300
0
        mGL.fUseProgram(mOld);
301
0
    }
302
};
303
304
// --
305
306
class ScopedDrawBlitState final
307
{
308
    GLContext& mGL;
309
310
    const bool blend;
311
    const bool cullFace;
312
    const bool depthTest;
313
    const bool dither;
314
    const bool polyOffsFill;
315
    const bool sampleAToC;
316
    const bool sampleCover;
317
    const bool scissor;
318
    const bool stencil;
319
    Maybe<bool> rasterizerDiscard;
320
321
    realGLboolean colorMask[4];
322
    GLint viewport[4];
323
324
public:
325
    ScopedDrawBlitState(GLContext* const gl, const gfx::IntSize& destSize)
326
        : mGL(*gl)
327
        , blend       (mGL.PushEnabled(LOCAL_GL_BLEND,                    false))
328
        , cullFace    (mGL.PushEnabled(LOCAL_GL_CULL_FACE,                false))
329
        , depthTest   (mGL.PushEnabled(LOCAL_GL_DEPTH_TEST,               false))
330
        , dither      (mGL.PushEnabled(LOCAL_GL_DITHER,                   true))
331
        , polyOffsFill(mGL.PushEnabled(LOCAL_GL_POLYGON_OFFSET_FILL,      false))
332
        , sampleAToC  (mGL.PushEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false))
333
        , sampleCover (mGL.PushEnabled(LOCAL_GL_SAMPLE_COVERAGE,          false))
334
        , scissor     (mGL.PushEnabled(LOCAL_GL_SCISSOR_TEST,             false))
335
        , stencil     (mGL.PushEnabled(LOCAL_GL_STENCIL_TEST,             false))
336
0
    {
337
0
        if (mGL.IsSupported(GLFeature::transform_feedback2)) {
338
0
            // Technically transform_feedback2 requires transform_feedback, which actually
339
0
            // adds RASTERIZER_DISCARD.
340
0
            rasterizerDiscard = Some(mGL.PushEnabled(LOCAL_GL_RASTERIZER_DISCARD, false));
341
0
        }
342
0
343
0
        mGL.fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
344
0
        mGL.fColorMask(true, true, true, true);
345
0
346
0
        mGL.fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
347
0
        MOZ_ASSERT(destSize.width && destSize.height);
348
0
        mGL.fViewport(0, 0, destSize.width, destSize.height);
349
0
    }
350
351
    ~ScopedDrawBlitState()
352
0
    {
353
0
        mGL.SetEnabled(LOCAL_GL_BLEND,                    blend       );
354
0
        mGL.SetEnabled(LOCAL_GL_CULL_FACE,                cullFace    );
355
0
        mGL.SetEnabled(LOCAL_GL_DEPTH_TEST,               depthTest   );
356
0
        mGL.SetEnabled(LOCAL_GL_DITHER,                   dither      );
357
0
        mGL.SetEnabled(LOCAL_GL_POLYGON_OFFSET_FILL,      polyOffsFill);
358
0
        mGL.SetEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, sampleAToC  );
359
0
        mGL.SetEnabled(LOCAL_GL_SAMPLE_COVERAGE,          sampleCover );
360
0
        mGL.SetEnabled(LOCAL_GL_SCISSOR_TEST,             scissor     );
361
0
        mGL.SetEnabled(LOCAL_GL_STENCIL_TEST,             stencil     );
362
0
        if (rasterizerDiscard) {
363
0
            mGL.SetEnabled(LOCAL_GL_RASTERIZER_DISCARD, rasterizerDiscard.value());
364
0
        }
365
0
366
0
        mGL.fColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
367
0
        mGL.fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
368
0
    }
369
};
370
371
// --
372
373
DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog)
374
    : mParent(*parent)
375
    , mProg(prog)
376
    , mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix"))
377
    , mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0"))
378
    , mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1"))
379
    , mLoc_uColorMatrix(mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix"))
380
0
{
381
0
    MOZ_ASSERT(mLoc_uDestMatrix != -1);
382
0
    MOZ_ASSERT(mLoc_uTexMatrix0 != -1);
383
0
    if (mLoc_uColorMatrix != -1) {
384
0
        MOZ_ASSERT(mLoc_uTexMatrix1 != -1);
385
0
386
0
        const auto& gl = mParent.mGL;
387
0
        int32_t numActiveUniforms = 0;
388
0
        gl->fGetProgramiv(mProg, LOCAL_GL_ACTIVE_UNIFORMS, &numActiveUniforms);
389
0
390
0
        const size_t kMaxNameSize = 32;
391
0
        char name[kMaxNameSize] = {0};
392
0
        GLint size = 0;
393
0
        GLenum type = 0;
394
0
        for (int32_t i = 0; i < numActiveUniforms; i++) {
395
0
            gl->fGetActiveUniform(mProg, i, kMaxNameSize, nullptr, &size, &type, name);
396
0
            if (strcmp("uColorMatrix", name) == 0) {
397
0
                mType_uColorMatrix = type;
398
0
                break;
399
0
            }
400
0
        }
401
0
        MOZ_ASSERT(mType_uColorMatrix);
402
0
    }
403
0
}
404
405
DrawBlitProg::~DrawBlitProg()
406
0
{
407
0
    const auto& gl = mParent.mGL;
408
0
    if (!gl->MakeCurrent())
409
0
        return;
410
0
411
0
    gl->fDeleteProgram(mProg);
412
0
}
413
414
void
415
DrawBlitProg::Draw(const BaseArgs& args, const YUVArgs* const argsYUV) const
416
0
{
417
0
    const auto& gl = mParent.mGL;
418
0
419
0
    const SaveRestoreCurrentProgram oldProg(gl);
420
0
    gl->fUseProgram(mProg);
421
0
422
0
    // --
423
0
424
0
    Mat3 destMatrix;
425
0
    if (args.destRect) {
426
0
        const auto& destRect = args.destRect.value();
427
0
        destMatrix = SubRectMat3(destRect.X() / args.destSize.width,
428
0
                                 destRect.Y() / args.destSize.height,
429
0
                                 destRect.Width() / args.destSize.width,
430
0
                                 destRect.Height() / args.destSize.height);
431
0
    } else {
432
0
        destMatrix = Mat3::I();
433
0
    }
434
0
435
0
    if (args.yFlip) {
436
0
        // Apply the y-flip matrix before the destMatrix.
437
0
        // That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect.
438
0
        destMatrix.at(2,1) += destMatrix.at(1,1);
439
0
        destMatrix.at(1,1) *= -1.0f;
440
0
    }
441
0
442
0
    gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m);
443
0
    gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.m);
444
0
445
0
    MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1));
446
0
    if (argsYUV) {
447
0
        gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m);
448
0
449
0
        const auto& colorMatrix = gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
450
0
        float mat4x3[4*3];
451
0
        switch (mType_uColorMatrix) {
452
0
        case LOCAL_GL_FLOAT_MAT4:
453
0
            gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
454
0
            break;
455
0
        case LOCAL_GL_FLOAT_MAT4x3:
456
0
            for (int x = 0; x < 4; x++) {
457
0
                for (int y = 0; y < 3; y++) {
458
0
                    mat4x3[3*x+y] = colorMatrix[4*x+y];
459
0
                }
460
0
            }
461
0
            gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3);
462
0
            break;
463
0
        default:
464
0
            gfxCriticalError() << "Bad mType_uColorMatrix: "
465
0
                               << gfx::hexa(mType_uColorMatrix);
466
0
        }
467
0
    }
468
0
469
0
    // --
470
0
471
0
    const ScopedDrawBlitState drawState(gl, args.destSize);
472
0
473
0
    GLuint oldVAO;
474
0
    GLint vaa0Enabled;
475
0
    GLint vaa0Size;
476
0
    GLenum vaa0Type;
477
0
    GLint vaa0Normalized;
478
0
    GLsizei vaa0Stride;
479
0
    GLvoid* vaa0Pointer;
480
0
    if (mParent.mQuadVAO) {
481
0
        oldVAO = gl->GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING);
482
0
        gl->fBindVertexArray(mParent.mQuadVAO);
483
0
    } else {
484
0
        gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vaa0Enabled);
485
0
        gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &vaa0Size);
486
0
        gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint*)&vaa0Type);
487
0
        gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vaa0Normalized);
488
0
        gl->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, (GLint*)&vaa0Stride);
489
0
        gl->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &vaa0Pointer);
490
0
491
0
        gl->fEnableVertexAttribArray(0);
492
0
        const ScopedBindArrayBuffer bindVBO(gl, mParent.mQuadVBO);
493
0
        gl->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, false, 0, 0);
494
0
    }
495
0
496
0
    gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
497
0
498
0
    if (mParent.mQuadVAO) {
499
0
        gl->fBindVertexArray(oldVAO);
500
0
    } else {
501
0
        if (vaa0Enabled) {
502
0
            gl->fEnableVertexAttribArray(0);
503
0
        } else {
504
0
            gl->fDisableVertexAttribArray(0);
505
0
        }
506
0
        gl->fVertexAttribPointer(0, vaa0Size, vaa0Type, bool(vaa0Normalized), vaa0Stride,
507
0
                                 vaa0Pointer);
508
0
    }
509
0
}
510
511
// --
512
513
GLBlitHelper::GLBlitHelper(GLContext* const gl)
514
    : mGL(gl)
515
    , mDrawBlitProg_VertShader(mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER))
516
    //, mYuvUploads_YSize(0, 0)
517
    //, mYuvUploads_UVSize(0, 0)
518
0
{
519
0
    mGL->fGenBuffers(1, &mQuadVBO);
520
0
    {
521
0
        const ScopedBindArrayBuffer bindVBO(mGL, mQuadVBO);
522
0
523
0
        const float quadData[] = {
524
0
            0, 0,
525
0
            1, 0,
526
0
            0, 1,
527
0
            1, 1
528
0
        };
529
0
        const HeapCopyOfStackArray<float> heapQuadData(quadData);
530
0
        mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, heapQuadData.ByteLength(),
531
0
                         heapQuadData.Data(), LOCAL_GL_STATIC_DRAW);
532
0
533
0
        if (mGL->IsSupported(GLFeature::vertex_array_object)) {
534
0
            const auto prev = mGL->GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING);
535
0
536
0
            mGL->fGenVertexArrays(1, &mQuadVAO);
537
0
            mGL->fBindVertexArray(mQuadVAO);
538
0
            mGL->fEnableVertexAttribArray(0);
539
0
            mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, false, 0, 0);
540
0
541
0
            mGL->fBindVertexArray(prev);
542
0
        }
543
0
    }
544
0
545
0
    // --
546
0
547
0
    const auto glslVersion = mGL->ShadingLanguageVersion();
548
0
549
0
    // Always use 100 on ES because some devices have OES_EGL_image_external but not
550
0
    // OES_EGL_image_external_essl3. We could just use 100 in that particular case, but
551
0
    // this is a lot easier and is not harmful to other usages.
552
0
    if (mGL->IsGLES()) {
553
0
        mDrawBlitProg_VersionLine = nsCString("#version 100\n");
554
0
    } else if (glslVersion >= 130) {
555
0
        mDrawBlitProg_VersionLine = nsPrintfCString("#version %u\n", glslVersion);
556
0
    }
557
0
558
0
    const char kVertSource[] = "\
559
0
        #if __VERSION__ >= 130                                               \n\
560
0
            #define ATTRIBUTE in                                             \n\
561
0
            #define VARYING out                                              \n\
562
0
        #else                                                                \n\
563
0
            #define ATTRIBUTE attribute                                      \n\
564
0
            #define VARYING varying                                          \n\
565
0
        #endif                                                               \n\
566
0
                                                                             \n\
567
0
        ATTRIBUTE vec2 aVert; // [0.0-1.0]                                   \n\
568
0
                                                                             \n\
569
0
        uniform mat3 uDestMatrix;                                            \n\
570
0
        uniform mat3 uTexMatrix0;                                            \n\
571
0
        uniform mat3 uTexMatrix1;                                            \n\
572
0
                                                                             \n\
573
0
        VARYING vec2 vTexCoord0;                                             \n\
574
0
        VARYING vec2 vTexCoord1;                                             \n\
575
0
                                                                             \n\
576
0
        void main(void)                                                      \n\
577
0
        {                                                                    \n\
578
0
            vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy;              \n\
579
0
            gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0);               \n\
580
0
                                                                             \n\
581
0
            vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy;                \n\
582
0
            vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy;                \n\
583
0
        }                                                                    \n\
584
0
    ";
585
0
    const char* const parts[] = {
586
0
        mDrawBlitProg_VersionLine.get(),
587
0
        kVertSource
588
0
    };
589
0
    mGL->fShaderSource(mDrawBlitProg_VertShader, ArrayLength(parts), parts, nullptr);
590
0
    mGL->fCompileShader(mDrawBlitProg_VertShader);
591
0
}
592
593
GLBlitHelper::~GLBlitHelper()
594
0
{
595
0
    for (const auto& pair : mDrawBlitProgs) {
596
0
        const auto& ptr = pair.second;
597
0
        delete ptr;
598
0
    }
599
0
    mDrawBlitProgs.clear();
600
0
601
0
    if (!mGL->MakeCurrent())
602
0
        return;
603
0
604
0
    mGL->fDeleteShader(mDrawBlitProg_VertShader);
605
0
    mGL->fDeleteBuffers(1, &mQuadVBO);
606
0
607
0
    if (mQuadVAO) {
608
0
        mGL->fDeleteVertexArrays(1, &mQuadVAO);
609
0
    }
610
0
}
611
612
// --
613
614
const DrawBlitProg*
615
GLBlitHelper::GetDrawBlitProg(const DrawBlitProg::Key& key) const
616
0
{
617
0
    const auto& res = mDrawBlitProgs.insert({key, nullptr});
618
0
    auto& pair = *(res.first);
619
0
    const auto& didInsert = res.second;
620
0
    if (didInsert) {
621
0
        pair.second = CreateDrawBlitProg(pair.first);
622
0
    }
623
0
    return pair.second;
624
0
}
625
626
const DrawBlitProg*
627
GLBlitHelper::CreateDrawBlitProg(const DrawBlitProg::Key& key) const
628
0
{
629
0
    const char kFragHeader_Global[] = "\
630
0
        #ifdef GL_ES                                                         \n\
631
0
            #ifdef GL_FRAGMENT_PRECISION_HIGH                                \n\
632
0
                precision highp float;                                       \n\
633
0
            #else                                                            \n\
634
0
                precision mediump float;                                     \n\
635
0
            #endif                                                           \n\
636
0
        #endif                                                               \n\
637
0
                                                                             \n\
638
0
        #if __VERSION__ >= 130                                               \n\
639
0
            #define VARYING in                                               \n\
640
0
            #define FRAG_COLOR oFragColor                                    \n\
641
0
            out vec4 FRAG_COLOR;                                             \n\
642
0
        #else                                                                \n\
643
0
            #define VARYING varying                                          \n\
644
0
            #define FRAG_COLOR gl_FragColor                                  \n\
645
0
        #endif                                                               \n\
646
0
                                                                             \n\
647
0
        #if __VERSION__ >= 120                                               \n\
648
0
            #define MAT4X3 mat4x3                                            \n\
649
0
        #else                                                                \n\
650
0
            #define MAT4X3 mat4                                              \n\
651
0
        #endif                                                               \n\
652
0
    ";
653
0
654
0
    const ScopedShader fs(mGL, LOCAL_GL_FRAGMENT_SHADER);
655
0
    const char* const parts[] = {
656
0
        mDrawBlitProg_VersionLine.get(),
657
0
        key.fragHeader,
658
0
        kFragHeader_Global,
659
0
        key.fragBody
660
0
    };
661
0
    mGL->fShaderSource(fs, ArrayLength(parts), parts, nullptr);
662
0
    mGL->fCompileShader(fs);
663
0
664
0
    const auto prog = mGL->fCreateProgram();
665
0
    mGL->fAttachShader(prog, mDrawBlitProg_VertShader);
666
0
    mGL->fAttachShader(prog, fs);
667
0
668
0
    mGL->fBindAttribLocation(prog, 0, "aPosition");
669
0
    mGL->fLinkProgram(prog);
670
0
671
0
    GLenum status = 0;
672
0
    mGL->fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, (GLint*)&status);
673
0
    if (status == LOCAL_GL_TRUE) {
674
0
        const SaveRestoreCurrentProgram oldProg(mGL);
675
0
        mGL->fUseProgram(prog);
676
0
        const char* samplerNames[] = {
677
0
            "uTex0",
678
0
            "uTex1",
679
0
            "uTex2"
680
0
        };
681
0
        for (int i = 0; i < 3; i++) {
682
0
            const auto loc = mGL->fGetUniformLocation(prog, samplerNames[i]);
683
0
            if (loc == -1)
684
0
                break;
685
0
            mGL->fUniform1i(loc, i);
686
0
        }
687
0
688
0
        return new DrawBlitProg(this, prog);
689
0
    }
690
0
691
0
    GLuint progLogLen = 0;
692
0
    mGL->fGetProgramiv(prog, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&progLogLen);
693
0
    const UniquePtr<char[]> progLog(new char[progLogLen+1]);
694
0
    mGL->fGetProgramInfoLog(prog, progLogLen, nullptr, progLog.get());
695
0
    progLog[progLogLen] = 0;
696
0
697
0
    const auto& vs = mDrawBlitProg_VertShader;
698
0
    GLuint vsLogLen = 0;
699
0
    mGL->fGetShaderiv(vs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&vsLogLen);
700
0
    const UniquePtr<char[]> vsLog(new char[vsLogLen+1]);
701
0
    mGL->fGetShaderInfoLog(vs, vsLogLen, nullptr, vsLog.get());
702
0
    vsLog[vsLogLen] = 0;
703
0
704
0
    GLuint fsLogLen = 0;
705
0
    mGL->fGetShaderiv(fs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&fsLogLen);
706
0
    const UniquePtr<char[]> fsLog(new char[fsLogLen+1]);
707
0
    mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get());
708
0
    fsLog[fsLogLen] = 0;
709
0
710
0
    gfxCriticalError() << "DrawBlitProg link failed:\n"
711
0
                       << "progLog: " << progLog.get() << "\n"
712
0
                       << "vsLog: " << vsLog.get() << "\n"
713
0
                       << "fsLog: " << fsLog.get() << "\n";
714
0
    return nullptr;
715
0
}
716
717
// -----------------------------------------------------------------------------
718
719
bool
720
GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage,
721
                                     const gfx::IntSize& destSize,
722
                                     const OriginPos destOrigin)
723
0
{
724
0
    switch (srcImage->GetFormat()) {
725
0
    case ImageFormat::PLANAR_YCBCR:
726
0
        return BlitImage(static_cast<PlanarYCbCrImage*>(srcImage), destSize, destOrigin);
727
0
728
#ifdef MOZ_WIDGET_ANDROID
729
    case ImageFormat::SURFACE_TEXTURE:
730
        return BlitImage(static_cast<layers::SurfaceTextureImage*>(srcImage), destSize,
731
                         destOrigin);
732
#endif
733
#ifdef XP_MACOSX
734
    case ImageFormat::MAC_IOSURFACE:
735
        return BlitImage(srcImage->AsMacIOSurfaceImage(), destSize, destOrigin);
736
#endif
737
#ifdef XP_WIN
738
    case ImageFormat::GPU_VIDEO:
739
        return BlitImage(static_cast<layers::GPUVideoImage*>(srcImage), destSize,
740
                         destOrigin);
741
    case ImageFormat::D3D11_YCBCR_IMAGE:
742
        return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize, destOrigin);
743
    case ImageFormat::D3D9_RGB32_TEXTURE:
744
        return false; // todo
745
#endif
746
0
    default:
747
0
        gfxCriticalError() << "Unhandled srcImage->GetFormat(): "
748
0
                           << uint32_t(srcImage->GetFormat());
749
0
        return false;
750
0
    }
751
0
}
752
753
// -------------------------------------
754
755
#ifdef MOZ_WIDGET_ANDROID
756
bool
757
GLBlitHelper::BlitImage(layers::SurfaceTextureImage* srcImage, const gfx::IntSize& destSize,
758
                        const OriginPos destOrigin) const
759
{
760
    AndroidSurfaceTextureHandle handle = srcImage->GetHandle();
761
    const auto& surfaceTexture = java::GeckoSurfaceTexture::Lookup(handle);
762
763
    if (!surfaceTexture) {
764
        return false;
765
    }
766
767
    const ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
768
769
    if (!surfaceTexture->IsAttachedToGLContext((int64_t)mGL)) {
770
        GLuint tex;
771
        mGL->MakeCurrent();
772
        mGL->fGenTextures(1, &tex);
773
774
        if (NS_FAILED(surfaceTexture->AttachToGLContext((int64_t)mGL, tex))) {
775
            mGL->fDeleteTextures(1, &tex);
776
            return false;
777
        }
778
    }
779
780
    const ScopedBindTexture savedTex(mGL, surfaceTexture->GetTexName(), LOCAL_GL_TEXTURE_EXTERNAL);
781
    surfaceTexture->UpdateTexImage();
782
783
    gfx::Matrix4x4 transform4;
784
    AndroidSurfaceTexture::GetTransformMatrix(java::sdk::SurfaceTexture::Ref::From(surfaceTexture),
785
                                              &transform4);
786
    Mat3 transform3;
787
    transform3.at(0,0) = transform4._11;
788
    transform3.at(0,1) = transform4._12;
789
    transform3.at(0,2) = transform4._14;
790
    transform3.at(1,0) = transform4._21;
791
    transform3.at(1,1) = transform4._22;
792
    transform3.at(1,2) = transform4._24;
793
    transform3.at(2,0) = transform4._41;
794
    transform3.at(2,1) = transform4._42;
795
    transform3.at(2,2) = transform4._44;
796
797
    // We don't do w-divison, so if these aren't what we expect, we're probably doing
798
    // something wrong.
799
    MOZ_ASSERT(transform3.at(0,2) == 0);
800
    MOZ_ASSERT(transform3.at(1,2) == 0);
801
    MOZ_ASSERT(transform3.at(2,2) == 1);
802
803
    const auto& srcOrigin = srcImage->GetOriginPos();
804
805
    // I honestly have no idea why this logic is flipped, but changing the
806
    // source origin would mean we'd have to flip it in the compositor
807
    // which makes just as little sense as this.
808
    const bool yFlip = (srcOrigin == destOrigin);
809
810
    const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_RGBA});
811
    MOZ_RELEASE_ASSERT(prog);
812
813
    // There is no padding on these images, so we can use the GetTransformMatrix directly.
814
    const DrawBlitProg::BaseArgs baseArgs = { transform3, yFlip, destSize, Nothing() };
815
    prog->Draw(baseArgs, nullptr);
816
817
    if (surfaceTexture->IsSingleBuffer()) {
818
        surfaceTexture->ReleaseTexImage();
819
    }
820
821
    return true;
822
}
823
#endif
824
825
// -------------------------------------
826
827
bool
828
GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
829
              gfx::IntSize* const out_divisors)
830
0
{
831
0
    const gfx::IntSize divisors((ySize.width  == uvSize.width ) ? 1 : 2,
832
0
                                (ySize.height == uvSize.height) ? 1 : 2);
833
0
    if (uvSize.width  * divisors.width != ySize.width ||
834
0
        uvSize.height * divisors.height != ySize.height)
835
0
    {
836
0
        return false;
837
0
    }
838
0
    *out_divisors = divisors;
839
0
    return true;
840
0
}
841
842
bool
843
GLBlitHelper::BlitImage(layers::PlanarYCbCrImage* const yuvImage,
844
                        const gfx::IntSize& destSize, const OriginPos destOrigin)
845
0
{
846
0
    const auto& prog = GetDrawBlitProg({kFragHeader_Tex2D, kFragBody_PlanarYUV});
847
0
    MOZ_RELEASE_ASSERT(prog);
848
0
849
0
    if (!mYuvUploads[0]) {
850
0
        mGL->fGenTextures(3, mYuvUploads);
851
0
        const ScopedBindTexture bindTex(mGL, mYuvUploads[0]);
852
0
        mGL->TexParams_SetClampNoMips();
853
0
        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]);
854
0
        mGL->TexParams_SetClampNoMips();
855
0
        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]);
856
0
        mGL->TexParams_SetClampNoMips();
857
0
    }
858
0
859
0
    // --
860
0
861
0
    const PlanarYCbCrData* const yuvData = yuvImage->GetData();
862
0
863
0
    if (yuvData->mYSkip || yuvData->mCbSkip || yuvData->mCrSkip ||
864
0
        yuvData->mYSize.width < 0 || yuvData->mYSize.height < 0 ||
865
0
        yuvData->mCbCrSize.width < 0 || yuvData->mCbCrSize.height < 0 ||
866
0
        yuvData->mYStride < 0 || yuvData->mCbCrStride < 0)
867
0
    {
868
0
        gfxCriticalError() << "Unusual PlanarYCbCrData: "
869
0
                           << yuvData->mYSkip << ","
870
0
                           << yuvData->mCbSkip << ","
871
0
                           << yuvData->mCrSkip << ", "
872
0
                           << yuvData->mYSize.width << ","
873
0
                           << yuvData->mYSize.height << ", "
874
0
                           << yuvData->mCbCrSize.width << ","
875
0
                           << yuvData->mCbCrSize.height << ", "
876
0
                           << yuvData->mYStride << ","
877
0
                           << yuvData->mCbCrStride;
878
0
        return false;
879
0
    }
880
0
881
0
    gfx::IntSize divisors;
882
0
    if (!GuessDivisors(yuvData->mYSize, yuvData->mCbCrSize, &divisors)) {
883
0
        gfxCriticalError() << "GuessDivisors failed:"
884
0
                           << yuvData->mYSize.width << ","
885
0
                           << yuvData->mYSize.height << ", "
886
0
                           << yuvData->mCbCrSize.width << ","
887
0
                           << yuvData->mCbCrSize.height;
888
0
        return false;
889
0
    }
890
0
891
0
    // --
892
0
893
0
    // RED textures aren't valid in GLES2, and ALPHA textures are not valid in desktop GL Core Profiles.
894
0
    // So use R8 textures on GL3.0+ and GLES3.0+, but LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
895
0
    GLenum internalFormat;
896
0
    GLenum unpackFormat;
897
0
    if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
898
0
        mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300))
899
0
    {
900
0
        internalFormat = LOCAL_GL_R8;
901
0
        unpackFormat = LOCAL_GL_RED;
902
0
    } else {
903
0
        internalFormat = LOCAL_GL_LUMINANCE;
904
0
        unpackFormat = LOCAL_GL_LUMINANCE;
905
0
    }
906
0
907
0
    // --
908
0
909
0
    const ScopedSaveMultiTex saveTex(mGL, 3, LOCAL_GL_TEXTURE_2D);
910
0
    const ResetUnpackState reset(mGL);
911
0
    const gfx::IntSize yTexSize(yuvData->mYStride, yuvData->mYSize.height);
912
0
    const gfx::IntSize uvTexSize(yuvData->mCbCrStride, yuvData->mCbCrSize.height);
913
0
914
0
    if (yTexSize != mYuvUploads_YSize ||
915
0
        uvTexSize != mYuvUploads_UVSize)
916
0
    {
917
0
        mYuvUploads_YSize = yTexSize;
918
0
        mYuvUploads_UVSize = uvTexSize;
919
0
920
0
        mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
921
0
        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]);
922
0
        mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat,
923
0
                         yTexSize.width, yTexSize.height, 0,
924
0
                         unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
925
0
        for (int i = 1; i < 3; i++) {
926
0
            mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
927
0
            mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[i]);
928
0
            mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat,
929
0
                             uvTexSize.width, uvTexSize.height, 0,
930
0
                             unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
931
0
        }
932
0
    }
933
0
934
0
    // --
935
0
936
0
    mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
937
0
    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]);
938
0
    mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
939
0
                        yTexSize.width, yTexSize.height,
940
0
                        unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mYChannel);
941
0
    mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
942
0
    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]);
943
0
    mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
944
0
                        uvTexSize.width, uvTexSize.height,
945
0
                        unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mCbChannel);
946
0
    mGL->fActiveTexture(LOCAL_GL_TEXTURE2);
947
0
    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]);
948
0
    mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
949
0
                        uvTexSize.width, uvTexSize.height,
950
0
                        unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mCrChannel);
951
0
952
0
    // --
953
0
954
0
    const auto& clipRect = yuvData->GetPictureRect();
955
0
    const auto srcOrigin = OriginPos::BottomLeft;
956
0
    const bool yFlip = (destOrigin != srcOrigin);
957
0
958
0
    const DrawBlitProg::BaseArgs baseArgs = {
959
0
        SubRectMat3(clipRect, yTexSize),
960
0
        yFlip, destSize, Nothing()
961
0
    };
962
0
    const DrawBlitProg::YUVArgs yuvArgs = {
963
0
        SubRectMat3(clipRect, uvTexSize, divisors),
964
0
        yuvData->mYUVColorSpace
965
0
    };
966
0
    prog->Draw(baseArgs, &yuvArgs);
967
0
    return true;
968
0
}
969
970
// -------------------------------------
971
972
#ifdef XP_MACOSX
973
bool
974
GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* const srcImage,
975
                        const gfx::IntSize& destSize, const OriginPos destOrigin) const
976
{
977
    MacIOSurface* const iosurf = srcImage->GetSurface();
978
    if (mGL->GetContextType() != GLContextType::CGL) {
979
        MOZ_ASSERT(false);
980
        return false;
981
    }
982
    const auto glCGL = static_cast<GLContextCGL*>(mGL);
983
    const auto cglContext = glCGL->GetCGLContext();
984
985
    const auto& srcOrigin = OriginPos::BottomLeft;
986
987
    DrawBlitProg::BaseArgs baseArgs;
988
    baseArgs.yFlip = (destOrigin != srcOrigin);
989
    baseArgs.destSize = destSize;
990
991
    DrawBlitProg::YUVArgs yuvArgs;
992
    yuvArgs.colorSpace = YUVColorSpace::BT601;
993
994
    const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
995
996
    auto planes = iosurf->GetPlaneCount();
997
    if (!planes) {
998
        planes = 1; // Bad API. No cookie.
999
    }
1000
1001
    const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE;
1002
    const char* const fragHeader = kFragHeader_Tex2DRect;
1003
1004
    const ScopedSaveMultiTex saveTex(mGL, planes, texTarget);
1005
    const ScopedTexture tex0(mGL);
1006
    const ScopedTexture tex1(mGL);
1007
    const ScopedTexture tex2(mGL);
1008
    const GLuint texs[3] = {
1009
        tex0,
1010
        tex1,
1011
        tex2
1012
    };
1013
1014
    const auto pixelFormat = iosurf->GetPixelFormat();
1015
    const auto formatChars = (const char*)&pixelFormat;
1016
    const char formatStr[] = {
1017
        formatChars[3],
1018
        formatChars[2],
1019
        formatChars[1],
1020
        formatChars[0],
1021
        0
1022
    };
1023
    if (mGL->ShouldSpew()) {
1024
        printf_stderr("iosurf format: %s (0x%08x)\n", formatStr, uint32_t(pixelFormat));
1025
    }
1026
1027
    const char* fragBody;
1028
    GLenum internalFormats[3] = {0, 0, 0};
1029
    GLenum unpackFormats[3] = {0, 0, 0};
1030
    GLenum unpackTypes[3] = { LOCAL_GL_UNSIGNED_BYTE,
1031
                              LOCAL_GL_UNSIGNED_BYTE,
1032
                              LOCAL_GL_UNSIGNED_BYTE };
1033
    switch (planes) {
1034
    case 1:
1035
        fragBody = kFragBody_RGBA;
1036
        internalFormats[0] = LOCAL_GL_RGBA;
1037
        unpackFormats[0] = LOCAL_GL_RGBA;
1038
        break;
1039
    case 2:
1040
        fragBody = kFragBody_NV12;
1041
        if (mGL->Version() >= 300) {
1042
            internalFormats[0] = LOCAL_GL_R8;
1043
            unpackFormats[0] = LOCAL_GL_RED;
1044
            internalFormats[1] = LOCAL_GL_RG8;
1045
            unpackFormats[1] = LOCAL_GL_RG;
1046
        } else {
1047
            internalFormats[0] = LOCAL_GL_LUMINANCE;
1048
            unpackFormats[0] = LOCAL_GL_LUMINANCE;
1049
            internalFormats[1] = LOCAL_GL_LUMINANCE_ALPHA;
1050
            unpackFormats[1] = LOCAL_GL_LUMINANCE_ALPHA;
1051
        }
1052
        pYuvArgs = &yuvArgs;
1053
        break;
1054
    case 3:
1055
        fragBody = kFragBody_PlanarYUV;
1056
        if (mGL->Version() >= 300) {
1057
            internalFormats[0] = LOCAL_GL_R8;
1058
            unpackFormats[0] = LOCAL_GL_RED;
1059
        } else {
1060
            internalFormats[0] = LOCAL_GL_LUMINANCE;
1061
            unpackFormats[0] = LOCAL_GL_LUMINANCE;
1062
        }
1063
        internalFormats[1] = internalFormats[0];
1064
        internalFormats[2] = internalFormats[0];
1065
        unpackFormats[1] = unpackFormats[0];
1066
        unpackFormats[2] = unpackFormats[0];
1067
        pYuvArgs = &yuvArgs;
1068
        break;
1069
    default:
1070
        gfxCriticalError() << "Unexpected plane count: " << planes;
1071
        return false;
1072
    }
1073
1074
    if (pixelFormat == '2vuy') {
1075
        fragBody = kFragBody_CrYCb;
1076
        // APPLE_rgb_422 adds RGB_RAW_422_APPLE for `internalFormat`, but only RGB seems
1077
        // to work?
1078
        internalFormats[0] = LOCAL_GL_RGB;
1079
        unpackFormats[0] = LOCAL_GL_RGB_422_APPLE;
1080
        unpackTypes[0] = LOCAL_GL_UNSIGNED_SHORT_8_8_APPLE;
1081
        pYuvArgs = &yuvArgs;
1082
    }
1083
1084
    for (uint32_t p = 0; p < planes; p++) {
1085
        mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + p);
1086
        mGL->fBindTexture(texTarget, texs[p]);
1087
        mGL->TexParams_SetClampNoMips(texTarget);
1088
1089
        const auto width = iosurf->GetDevicePixelWidth(p);
1090
        const auto height = iosurf->GetDevicePixelHeight(p);
1091
        auto err = iosurf->CGLTexImageIOSurface2D(cglContext, texTarget,
1092
                                                  internalFormats[p], width, height,
1093
                                                  unpackFormats[p], unpackTypes[p], p);
1094
        if (err) {
1095
            const nsPrintfCString errStr("CGLTexImageIOSurface2D(context, target, 0x%04x,"
1096
                                         " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
1097
                                         internalFormats[p], uint32_t(width),
1098
                                         uint32_t(height), unpackFormats[p],
1099
                                         unpackTypes[p], p, err);
1100
            gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr << ")";
1101
            return false;
1102
        }
1103
1104
        if (p == 0) {
1105
            baseArgs.texMatrix0 = SubRectMat3(0, 0, width, height);
1106
            yuvArgs.texMatrix1 = SubRectMat3(0, 0, width / 2.0, height / 2.0);
1107
        }
1108
    }
1109
1110
    const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
1111
    if (!prog)
1112
        return false;
1113
1114
    prog->Draw(baseArgs, pYuvArgs);
1115
    return true;
1116
}
1117
#endif
1118
1119
// -----------------------------------------------------------------------------
1120
1121
void
1122
GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
1123
                                           const gfx::IntSize& srcSize,
1124
                                           const gfx::IntSize& destSize,
1125
                                           const GLenum srcTarget) const
1126
0
{
1127
0
    const char* fragHeader;
1128
0
    Mat3 texMatrix0;
1129
0
    switch (srcTarget) {
1130
0
    case LOCAL_GL_TEXTURE_2D:
1131
0
        fragHeader = kFragHeader_Tex2D;
1132
0
        texMatrix0 = Mat3::I();
1133
0
        break;
1134
0
    case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
1135
0
        fragHeader = kFragHeader_Tex2DRect;
1136
0
        texMatrix0 = SubRectMat3(0, 0, srcSize.width, srcSize.height);
1137
0
        break;
1138
0
    default:
1139
0
        gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
1140
0
        return;
1141
0
    }
1142
0
    const auto& prog = GetDrawBlitProg({ fragHeader, kFragBody_RGBA});
1143
0
    MOZ_ASSERT(prog);
1144
0
1145
0
    const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget);
1146
0
    mGL->fBindTexture(srcTarget, srcTex);
1147
0
1148
0
    const bool yFlip = false;
1149
0
    const DrawBlitProg::BaseArgs baseArgs = { texMatrix0, yFlip, destSize, Nothing() };
1150
0
    prog->Draw(baseArgs);
1151
0
}
1152
1153
// -----------------------------------------------------------------------------
1154
1155
void
1156
GLBlitHelper::BlitFramebuffer(const gfx::IntSize& srcSize,
1157
                              const gfx::IntSize& destSize,
1158
                              GLuint filter) const
1159
0
{
1160
0
    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
1161
0
1162
0
    const ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
1163
0
    mGL->fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
1164
0
                          0, 0, destSize.width, destSize.height,
1165
0
                          LOCAL_GL_COLOR_BUFFER_BIT,
1166
0
                          filter);
1167
0
}
1168
1169
// --
1170
1171
void
1172
GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB, const GLuint destFB,
1173
                                           const gfx::IntSize& srcSize,
1174
                                           const gfx::IntSize& destSize,
1175
                                           GLuint filter) const
1176
0
{
1177
0
    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
1178
0
    MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
1179
0
    MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
1180
0
1181
0
    const ScopedBindFramebuffer boundFB(mGL);
1182
0
    mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB);
1183
0
    mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB);
1184
0
1185
0
    BlitFramebuffer(srcSize, destSize, filter);
1186
0
}
1187
1188
void
1189
GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
1190
                                       const gfx::IntSize& destSize,
1191
                                       GLenum srcTarget) const
1192
0
{
1193
0
    MOZ_ASSERT(mGL->fIsTexture(srcTex));
1194
0
1195
0
    if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
1196
0
        const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
1197
0
        const ScopedBindFramebuffer bindFB(mGL);
1198
0
        mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcWrapper.FB());
1199
0
        BlitFramebuffer(srcSize, destSize);
1200
0
        return;
1201
0
    }
1202
0
1203
0
    DrawBlitTextureToFramebuffer(srcTex, srcSize, destSize, srcTarget);
1204
0
}
1205
1206
void
1207
GLBlitHelper::BlitFramebufferToTexture(GLuint destTex,
1208
                                       const gfx::IntSize& srcSize,
1209
                                       const gfx::IntSize& destSize,
1210
                                       GLenum destTarget) const
1211
0
{
1212
0
    MOZ_ASSERT(mGL->fIsTexture(destTex));
1213
0
1214
0
    if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
1215
0
        const ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
1216
0
        const ScopedBindFramebuffer bindFB(mGL);
1217
0
        mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destWrapper.FB());
1218
0
        BlitFramebuffer(srcSize, destSize);
1219
0
        return;
1220
0
    }
1221
0
1222
0
    ScopedBindTexture autoTex(mGL, destTex, destTarget);
1223
0
    ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
1224
0
    mGL->fCopyTexSubImage2D(destTarget, 0,
1225
0
                            0, 0,
1226
0
                            0, 0,
1227
0
                            srcSize.width, srcSize.height);
1228
0
}
1229
1230
void
1231
GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
1232
                                   const gfx::IntSize& srcSize,
1233
                                   const gfx::IntSize& destSize,
1234
                                   GLenum srcTarget, GLenum destTarget) const
1235
0
{
1236
0
    MOZ_ASSERT(mGL->fIsTexture(srcTex));
1237
0
    MOZ_ASSERT(mGL->fIsTexture(destTex));
1238
0
1239
0
    // Start down the CopyTexSubImage path, not the DrawBlit path.
1240
0
    const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
1241
0
    const ScopedBindFramebuffer bindFB(mGL, srcWrapper.FB());
1242
0
    BlitFramebufferToTexture(destTex, srcSize, destSize, destTarget);
1243
0
}
1244
1245
} // namespace gl
1246
} // namespace mozilla