Source code

Revision control

Other Tools

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