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/. */
7 #include "GLBlitHelper.h"
10 #include "GLScreenBuffer.h"
11 #include "GPUVideoImage.h"
12 #include "HeapCopyOfStackArray.h"
13 #include "ImageContainer.h"
14 #include "ScopedGLHelpers.h"
16 #include "mozilla/ArrayUtils.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/UniquePtr.h"
19 #include "mozilla/gfx/Logging.h"
20 #include "mozilla/gfx/Matrix.h"
21 #include "mozilla/layers/ImageDataSerializer.h"
22 #include "mozilla/layers/LayersSurfaces.h"
24 #ifdef MOZ_WIDGET_ANDROID
25 # include "AndroidSurfaceTexture.h"
26 # include "GLLibraryEGL.h"
30 # include "GLContextCGL.h"
31 # include "MacIOSurfaceImage.h"
35 # include "mozilla/layers/D3D11ShareHandleImage.h"
36 # include "mozilla/layers/D3D11TextureIMFSampleImage.h"
37 # include "mozilla/layers/D3D11YCbCrImage.h"
41 # include "mozilla/layers/DMABUFSurfaceImage.h"
42 # include "mozilla/widget/DMABufSurface.h"
45 using mozilla::layers::PlanarYCbCrData
;
46 using mozilla::layers::PlanarYCbCrImage
;
53 const char* const kFragHeader_Tex2D
=
55 #define SAMPLER sampler2D \n\
56 #if __VERSION__ >= 130 \n\
57 #define TEXTURE texture \n\
59 #define TEXTURE texture2D \n\
62 const char* const kFragHeader_Tex2DRect
=
64 #define SAMPLER sampler2DRect \n\
65 #if __VERSION__ >= 130 \n\
66 #define TEXTURE texture \n\
68 #define TEXTURE texture2DRect \n\
71 const char* const kFragHeader_TexExt
=
73 #extension GL_OES_EGL_image_external : require \n\
74 #if __VERSION__ >= 130 \n\
75 #define TEXTURE texture \n\
77 #define TEXTURE texture2D \n\
79 #define SAMPLER samplerExternalOES \n\
82 const char* const kFragBody_RGBA
=
84 VARYING vec2 vTexCoord0; \n\
85 uniform SAMPLER uTex0; \n\
89 FRAG_COLOR = TEXTURE(uTex0, vTexCoord0); \n\
92 const char* const kFragBody_BGRA
=
94 VARYING vec2 vTexCoord0; \n\
95 uniform SAMPLER uTex0; \n\
99 FRAG_COLOR = TEXTURE(uTex0, vTexCoord0).bgra; \n\
102 const char* const kFragBody_CrYCb
=
104 VARYING vec2 vTexCoord0; \n\
105 uniform SAMPLER uTex0; \n\
106 uniform MAT4X3 uColorMatrix; \n\
110 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr, \n\
112 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
115 const char* const kFragBody_NV12
=
117 VARYING vec2 vTexCoord0; \n\
118 VARYING vec2 vTexCoord1; \n\
119 uniform SAMPLER uTex0; \n\
120 uniform SAMPLER uTex1; \n\
121 uniform MAT4X3 uColorMatrix; \n\
125 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
126 TEXTURE(uTex1, vTexCoord1).xy, \n\
128 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
131 const char* const kFragBody_PlanarYUV
=
133 VARYING vec2 vTexCoord0; \n\
134 VARYING vec2 vTexCoord1; \n\
135 uniform SAMPLER uTex0; \n\
136 uniform SAMPLER uTex1; \n\
137 uniform SAMPLER uTex2; \n\
138 uniform MAT4X3 uColorMatrix; \n\
142 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
143 TEXTURE(uTex1, vTexCoord1).x, \n\
144 TEXTURE(uTex2, vTexCoord1).x, \n\
146 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
153 /*static*/ Mat
<N
> Mat
<N
>::Zero() {
155 for (auto& x
: ret
.m
) {
162 /*static*/ Mat
<N
> Mat
<N
>::I() {
163 auto ret
= Mat
<N
>::Zero();
164 for (uint8_t i
= 0; i
< N
; i
++) {
171 Mat
<N
> Mat
<N
>::operator*(const Mat
<N
>& r
) const {
173 for (uint8_t x
= 0; x
< N
; x
++) {
174 for (uint8_t y
= 0; y
< N
; y
++) {
176 for (uint8_t i
= 0; i
< N
; i
++) {
177 sum
+= at(i
, y
) * r
.at(x
, i
);
185 Mat3
SubRectMat3(const float x
, const float y
, const float w
, const float h
) {
186 auto ret
= Mat3::Zero();
195 Mat3
SubRectMat3(const gfx::IntRect
& subrect
, const gfx::IntSize
& size
) {
196 return SubRectMat3(float(subrect
.X()) / size
.width
,
197 float(subrect
.Y()) / size
.height
,
198 float(subrect
.Width()) / size
.width
,
199 float(subrect
.Height()) / size
.height
);
202 Mat3
SubRectMat3(const gfx::IntRect
& bigSubrect
, const gfx::IntSize
& smallSize
,
203 const gfx::IntSize
& divisors
) {
204 const float x
= float(bigSubrect
.X()) / divisors
.width
;
205 const float y
= float(bigSubrect
.Y()) / divisors
.height
;
206 const float w
= float(bigSubrect
.Width()) / divisors
.width
;
207 const float h
= float(bigSubrect
.Height()) / divisors
.height
;
208 return SubRectMat3(x
/ smallSize
.width
, y
/ smallSize
.height
,
209 w
/ smallSize
.width
, h
/ smallSize
.height
);
214 ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext
* const gl
,
215 const uint8_t texCount
,
216 const GLenum texTarget
)
219 mTexTarget(texTarget
),
220 mOldTexUnit(mGL
.GetIntAs
<GLenum
>(LOCAL_GL_ACTIVE_TEXTURE
)) {
222 switch (mTexTarget
) {
223 case LOCAL_GL_TEXTURE_2D
:
224 texBinding
= LOCAL_GL_TEXTURE_BINDING_2D
;
226 case LOCAL_GL_TEXTURE_RECTANGLE
:
227 texBinding
= LOCAL_GL_TEXTURE_BINDING_RECTANGLE
;
229 case LOCAL_GL_TEXTURE_EXTERNAL
:
230 texBinding
= LOCAL_GL_TEXTURE_BINDING_EXTERNAL
;
233 gfxCriticalError() << "Unhandled texTarget: " << texTarget
;
236 for (uint8_t i
= 0; i
< mTexCount
; i
++) {
237 mGL
.fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
238 if (mGL
.IsSupported(GLFeature::sampler_objects
)) {
239 mOldTexSampler
[i
] = mGL
.GetIntAs
<GLuint
>(LOCAL_GL_SAMPLER_BINDING
);
240 mGL
.fBindSampler(i
, 0);
242 mOldTex
[i
] = mGL
.GetIntAs
<GLuint
>(texBinding
);
246 ScopedSaveMultiTex::~ScopedSaveMultiTex() {
247 for (uint8_t i
= 0; i
< mTexCount
; i
++) {
248 mGL
.fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
249 if (mGL
.IsSupported(GLFeature::sampler_objects
)) {
250 mGL
.fBindSampler(i
, mOldTexSampler
[i
]);
252 mGL
.fBindTexture(mTexTarget
, mOldTex
[i
]);
254 mGL
.fActiveTexture(mOldTexUnit
);
259 class ScopedBindArrayBuffer final
{
262 const GLuint mOldVBO
;
264 ScopedBindArrayBuffer(GLContext
* const gl
, const GLuint vbo
)
265 : mGL(*gl
), mOldVBO(mGL
.GetIntAs
<GLuint
>(LOCAL_GL_ARRAY_BUFFER_BINDING
)) {
266 mGL
.fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, vbo
);
269 ~ScopedBindArrayBuffer() { mGL
.fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mOldVBO
); }
274 class ScopedShader final
{
279 ScopedShader(GLContext
* const gl
, const GLenum shaderType
)
280 : mGL(*gl
), mName(mGL
.fCreateShader(shaderType
)) {}
282 ~ScopedShader() { mGL
.fDeleteShader(mName
); }
284 operator GLuint() const { return mName
; }
289 class SaveRestoreCurrentProgram final
{
294 explicit SaveRestoreCurrentProgram(GLContext
* const gl
)
295 : mGL(*gl
), mOld(mGL
.GetIntAs
<GLuint
>(LOCAL_GL_CURRENT_PROGRAM
)) {}
297 ~SaveRestoreCurrentProgram() { mGL
.fUseProgram(mOld
); }
302 class ScopedDrawBlitState final
{
307 const bool depthTest
;
309 const bool polyOffsFill
;
310 const bool sampleAToC
;
311 const bool sampleCover
;
314 Maybe
<bool> rasterizerDiscard
;
316 realGLboolean colorMask
[4];
320 ScopedDrawBlitState(GLContext
* const gl
, const gfx::IntSize
& destSize
)
322 blend(mGL
.PushEnabled(LOCAL_GL_BLEND
, false)),
323 cullFace(mGL
.PushEnabled(LOCAL_GL_CULL_FACE
, false)),
324 depthTest(mGL
.PushEnabled(LOCAL_GL_DEPTH_TEST
, false)),
325 dither(mGL
.PushEnabled(LOCAL_GL_DITHER
, true)),
326 polyOffsFill(mGL
.PushEnabled(LOCAL_GL_POLYGON_OFFSET_FILL
, false)),
327 sampleAToC(mGL
.PushEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
, false)),
328 sampleCover(mGL
.PushEnabled(LOCAL_GL_SAMPLE_COVERAGE
, false)),
329 scissor(mGL
.PushEnabled(LOCAL_GL_SCISSOR_TEST
, false)),
330 stencil(mGL
.PushEnabled(LOCAL_GL_STENCIL_TEST
, false)) {
331 if (mGL
.IsSupported(GLFeature::transform_feedback2
)) {
332 // Technically transform_feedback2 requires transform_feedback, which
333 // actually adds RASTERIZER_DISCARD.
335 Some(mGL
.PushEnabled(LOCAL_GL_RASTERIZER_DISCARD
, false));
338 mGL
.fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK
, colorMask
);
339 if (mGL
.IsSupported(GLFeature::draw_buffers_indexed
)) {
340 mGL
.fColorMaski(0, true, true, true, true);
342 mGL
.fColorMask(true, true, true, true);
345 mGL
.fGetIntegerv(LOCAL_GL_VIEWPORT
, viewport
);
346 MOZ_ASSERT(destSize
.width
&& destSize
.height
);
347 mGL
.fViewport(0, 0, destSize
.width
, destSize
.height
);
350 ~ScopedDrawBlitState() {
351 mGL
.SetEnabled(LOCAL_GL_BLEND
, blend
);
352 mGL
.SetEnabled(LOCAL_GL_CULL_FACE
, cullFace
);
353 mGL
.SetEnabled(LOCAL_GL_DEPTH_TEST
, depthTest
);
354 mGL
.SetEnabled(LOCAL_GL_DITHER
, dither
);
355 mGL
.SetEnabled(LOCAL_GL_POLYGON_OFFSET_FILL
, polyOffsFill
);
356 mGL
.SetEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
, sampleAToC
);
357 mGL
.SetEnabled(LOCAL_GL_SAMPLE_COVERAGE
, sampleCover
);
358 mGL
.SetEnabled(LOCAL_GL_SCISSOR_TEST
, scissor
);
359 mGL
.SetEnabled(LOCAL_GL_STENCIL_TEST
, stencil
);
360 if (rasterizerDiscard
) {
361 mGL
.SetEnabled(LOCAL_GL_RASTERIZER_DISCARD
, rasterizerDiscard
.value());
364 if (mGL
.IsSupported(GLFeature::draw_buffers_indexed
)) {
365 mGL
.fColorMaski(0, colorMask
[0], colorMask
[1], colorMask
[2],
368 mGL
.fColorMask(colorMask
[0], colorMask
[1], colorMask
[2], colorMask
[3]);
370 mGL
.fViewport(viewport
[0], viewport
[1], viewport
[2], viewport
[3]);
376 DrawBlitProg::DrawBlitProg(const GLBlitHelper
* const parent
, const GLuint prog
)
379 mLoc_uDestMatrix(mParent
.mGL
->fGetUniformLocation(mProg
, "uDestMatrix")),
380 mLoc_uTexMatrix0(mParent
.mGL
->fGetUniformLocation(mProg
, "uTexMatrix0")),
381 mLoc_uTexMatrix1(mParent
.mGL
->fGetUniformLocation(mProg
, "uTexMatrix1")),
383 mParent
.mGL
->fGetUniformLocation(mProg
, "uColorMatrix")) {
384 const auto& gl
= mParent
.mGL
;
385 MOZ_GL_ASSERT(gl
, mLoc_uDestMatrix
!= -1);
386 MOZ_GL_ASSERT(gl
, mLoc_uTexMatrix0
!= -1);
387 if (mLoc_uColorMatrix
!= -1) {
388 MOZ_GL_ASSERT(gl
, mLoc_uTexMatrix1
!= -1);
390 int32_t numActiveUniforms
= 0;
391 gl
->fGetProgramiv(mProg
, LOCAL_GL_ACTIVE_UNIFORMS
, &numActiveUniforms
);
393 const size_t kMaxNameSize
= 32;
394 char name
[kMaxNameSize
] = {0};
397 for (int32_t i
= 0; i
< numActiveUniforms
; i
++) {
398 gl
->fGetActiveUniform(mProg
, i
, kMaxNameSize
, nullptr, &size
, &type
,
400 if (strcmp("uColorMatrix", name
) == 0) {
401 mType_uColorMatrix
= type
;
405 MOZ_GL_ASSERT(gl
, mType_uColorMatrix
);
409 DrawBlitProg::~DrawBlitProg() {
410 const auto& gl
= mParent
.mGL
;
411 if (!gl
->MakeCurrent()) return;
413 gl
->fDeleteProgram(mProg
);
416 void DrawBlitProg::Draw(const BaseArgs
& args
,
417 const YUVArgs
* const argsYUV
) const {
418 const auto& gl
= mParent
.mGL
;
420 const SaveRestoreCurrentProgram
oldProg(gl
);
421 gl
->fUseProgram(mProg
);
427 const auto& destRect
= args
.destRect
.value();
428 destMatrix
= SubRectMat3(destRect
.X() / args
.destSize
.width
,
429 destRect
.Y() / args
.destSize
.height
,
430 destRect
.Width() / args
.destSize
.width
,
431 destRect
.Height() / args
.destSize
.height
);
433 destMatrix
= Mat3::I();
437 // Apply the y-flip matrix before the destMatrix.
438 // That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect.
439 destMatrix
.at(2, 1) += destMatrix
.at(1, 1);
440 destMatrix
.at(1, 1) *= -1.0f
;
443 gl
->fUniformMatrix3fv(mLoc_uDestMatrix
, 1, false, destMatrix
.m
);
444 gl
->fUniformMatrix3fv(mLoc_uTexMatrix0
, 1, false, args
.texMatrix0
.m
);
446 MOZ_ASSERT(bool(argsYUV
) == (mLoc_uColorMatrix
!= -1));
448 gl
->fUniformMatrix3fv(mLoc_uTexMatrix1
, 1, false, argsYUV
->texMatrix1
.m
);
450 const auto& colorMatrix
=
451 gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV
->colorSpace
);
453 switch (mType_uColorMatrix
) {
454 case LOCAL_GL_FLOAT_MAT4
:
455 gl
->fUniformMatrix4fv(mLoc_uColorMatrix
, 1, false, colorMatrix
);
457 case LOCAL_GL_FLOAT_MAT4x3
:
458 for (int x
= 0; x
< 4; x
++) {
459 for (int y
= 0; y
< 3; y
++) {
460 mat4x3
[3 * x
+ y
] = colorMatrix
[4 * x
+ y
];
463 gl
->fUniformMatrix4x3fv(mLoc_uColorMatrix
, 1, false, mat4x3
);
466 gfxCriticalError() << "Bad mType_uColorMatrix: "
467 << gfx::hexa(mType_uColorMatrix
);
473 const ScopedDrawBlitState
drawState(gl
, args
.destSize
);
479 GLint vaa0Normalized
;
483 if (mParent
.mQuadVAO
) {
484 oldVAO
= gl
->GetIntAs
<GLuint
>(LOCAL_GL_VERTEX_ARRAY_BINDING
);
485 gl
->fBindVertexArray(mParent
.mQuadVAO
);
488 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED
, &vaa0Enabled
);
489 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE
, &vaa0Size
);
490 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE
, (GLint
*)&vaa0Type
);
491 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
, &vaa0Normalized
);
492 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE
, (GLint
*)&vaa0Stride
);
493 gl
->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER
, &vaa0Pointer
);
496 gl
->fEnableVertexAttribArray(0);
497 const ScopedBindArrayBuffer
bindVBO(gl
, mParent
.mQuadVBO
);
498 vaa0Buffer
= bindVBO
.mOldVBO
;
499 gl
->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT
, false, 0, 0);
502 gl
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
504 if (mParent
.mQuadVAO
) {
505 gl
->fBindVertexArray(oldVAO
);
508 gl
->fEnableVertexAttribArray(0);
510 gl
->fDisableVertexAttribArray(0);
512 // The current VERTEX_ARRAY_BINDING is not necessarily the same as the
513 // buffer set for vaa0Buffer.
514 const ScopedBindArrayBuffer
bindVBO(gl
, vaa0Buffer
);
515 gl
->fVertexAttribPointer(0, vaa0Size
, vaa0Type
, bool(vaa0Normalized
),
516 vaa0Stride
, vaa0Pointer
);
522 GLBlitHelper::GLBlitHelper(GLContext
* const gl
)
524 mDrawBlitProg_VertShader(mGL
->fCreateShader(LOCAL_GL_VERTEX_SHADER
))
525 //, mYuvUploads_YSize(0, 0)
526 //, mYuvUploads_UVSize(0, 0)
528 mGL
->fGenBuffers(1, &mQuadVBO
);
530 const ScopedBindArrayBuffer
bindVBO(mGL
, mQuadVBO
);
532 const float quadData
[] = {0, 0, 1, 0, 0, 1, 1, 1};
533 const HeapCopyOfStackArray
<float> heapQuadData(quadData
);
534 mGL
->fBufferData(LOCAL_GL_ARRAY_BUFFER
, heapQuadData
.ByteLength(),
535 heapQuadData
.Data(), LOCAL_GL_STATIC_DRAW
);
537 if (mGL
->IsSupported(GLFeature::vertex_array_object
)) {
538 const auto prev
= mGL
->GetIntAs
<GLuint
>(LOCAL_GL_VERTEX_ARRAY_BINDING
);
540 mGL
->fGenVertexArrays(1, &mQuadVAO
);
541 mGL
->fBindVertexArray(mQuadVAO
);
542 mGL
->fEnableVertexAttribArray(0);
543 mGL
->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT
, false, 0, 0);
545 mGL
->fBindVertexArray(prev
);
551 const auto glslVersion
= mGL
->ShadingLanguageVersion();
553 // Always use 100 on ES because some devices have OES_EGL_image_external but
554 // not OES_EGL_image_external_essl3. We could just use 100 in that particular
555 // case, but this is a lot easier and is not harmful to other usages.
557 mDrawBlitProg_VersionLine
= nsCString("#version 100\n");
558 } else if (glslVersion
>= 130) {
559 mDrawBlitProg_VersionLine
= nsPrintfCString("#version %u\n", glslVersion
);
562 const char kVertSource
[] =
564 #if __VERSION__ >= 130 \n\
565 #define ATTRIBUTE in \n\
566 #define VARYING out \n\
568 #define ATTRIBUTE attribute \n\
569 #define VARYING varying \n\
572 ATTRIBUTE vec2 aVert; // [0.0-1.0] \n\
574 uniform mat3 uDestMatrix; \n\
575 uniform mat3 uTexMatrix0; \n\
576 uniform mat3 uTexMatrix1; \n\
578 VARYING vec2 vTexCoord0; \n\
579 VARYING vec2 vTexCoord1; \n\
583 vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy; \n\
584 gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0); \n\
586 vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy; \n\
587 vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy; \n\
590 const char* const parts
[] = {mDrawBlitProg_VersionLine
.get(), kVertSource
};
591 mGL
->fShaderSource(mDrawBlitProg_VertShader
, ArrayLength(parts
), parts
,
593 mGL
->fCompileShader(mDrawBlitProg_VertShader
);
596 GLBlitHelper::~GLBlitHelper() {
597 for (const auto& pair
: mDrawBlitProgs
) {
598 const auto& ptr
= pair
.second
;
601 mDrawBlitProgs
.clear();
603 if (!mGL
->MakeCurrent()) return;
605 mGL
->fDeleteShader(mDrawBlitProg_VertShader
);
606 mGL
->fDeleteBuffers(1, &mQuadVBO
);
609 mGL
->fDeleteVertexArrays(1, &mQuadVAO
);
615 const DrawBlitProg
* GLBlitHelper::GetDrawBlitProg(
616 const DrawBlitProg::Key
& key
) const {
617 const auto& res
= mDrawBlitProgs
.insert({key
, nullptr});
618 auto& pair
= *(res
.first
);
619 const auto& didInsert
= res
.second
;
621 pair
.second
= CreateDrawBlitProg(pair
.first
);
626 const DrawBlitProg
* GLBlitHelper::CreateDrawBlitProg(
627 const DrawBlitProg::Key
& key
) const {
628 const char kFragHeader_Global
[] =
631 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
632 precision highp float; \n\
634 precision mediump float; \n\
638 #if __VERSION__ >= 130 \n\
639 #define VARYING in \n\
640 #define FRAG_COLOR oFragColor \n\
641 out vec4 FRAG_COLOR; \n\
643 #define VARYING varying \n\
644 #define FRAG_COLOR gl_FragColor \n\
647 #if __VERSION__ >= 120 \n\
648 #define MAT4X3 mat4x3 \n\
650 #define MAT4X3 mat4 \n\
654 const ScopedShader
fs(mGL
, LOCAL_GL_FRAGMENT_SHADER
);
655 const char* const parts
[] = {mDrawBlitProg_VersionLine
.get(), key
.fragHeader
,
656 kFragHeader_Global
, key
.fragBody
};
657 mGL
->fShaderSource(fs
, ArrayLength(parts
), parts
, nullptr);
658 mGL
->fCompileShader(fs
);
660 const auto prog
= mGL
->fCreateProgram();
661 mGL
->fAttachShader(prog
, mDrawBlitProg_VertShader
);
662 mGL
->fAttachShader(prog
, fs
);
664 mGL
->fBindAttribLocation(prog
, 0, "aPosition");
665 mGL
->fLinkProgram(prog
);
668 mGL
->fGetProgramiv(prog
, LOCAL_GL_LINK_STATUS
, (GLint
*)&status
);
669 if (status
== LOCAL_GL_TRUE
|| !mGL
->CheckContextLost()) {
670 const SaveRestoreCurrentProgram
oldProg(mGL
);
671 mGL
->fUseProgram(prog
);
672 const char* samplerNames
[] = {"uTex0", "uTex1", "uTex2"};
673 for (int i
= 0; i
< 3; i
++) {
674 const auto loc
= mGL
->fGetUniformLocation(prog
, samplerNames
[i
]);
675 if (loc
== -1) break;
676 mGL
->fUniform1i(loc
, i
);
679 return new DrawBlitProg(this, prog
);
682 GLuint progLogLen
= 0;
683 mGL
->fGetProgramiv(prog
, LOCAL_GL_INFO_LOG_LENGTH
, (GLint
*)&progLogLen
);
684 const UniquePtr
<char[]> progLog(new char[progLogLen
+ 1]);
685 mGL
->fGetProgramInfoLog(prog
, progLogLen
, nullptr, progLog
.get());
686 progLog
[progLogLen
] = 0;
688 const auto& vs
= mDrawBlitProg_VertShader
;
690 mGL
->fGetShaderiv(vs
, LOCAL_GL_INFO_LOG_LENGTH
, (GLint
*)&vsLogLen
);
691 const UniquePtr
<char[]> vsLog(new char[vsLogLen
+ 1]);
692 mGL
->fGetShaderInfoLog(vs
, vsLogLen
, nullptr, vsLog
.get());
696 mGL
->fGetShaderiv(fs
, LOCAL_GL_INFO_LOG_LENGTH
, (GLint
*)&fsLogLen
);
697 const UniquePtr
<char[]> fsLog(new char[fsLogLen
+ 1]);
698 mGL
->fGetShaderInfoLog(fs
, fsLogLen
, nullptr, fsLog
.get());
701 gfxCriticalError() << "DrawBlitProg link failed:\n"
702 << "progLog: " << progLog
.get() << "\n"
703 << "vsLog: " << vsLog
.get() << "\n"
704 << "fsLog: " << fsLog
.get() << "\n";
708 // -----------------------------------------------------------------------------
711 static RefPtr
<MacIOSurface
> LookupSurface(
712 const layers::SurfaceDescriptorMacIOSurface
& sd
) {
713 return MacIOSurface::LookupSurface(sd
.surfaceId(), !sd
.isOpaque(),
718 bool GLBlitHelper::BlitSdToFramebuffer(const layers::SurfaceDescriptor
& asd
,
719 const gfx::IntSize
& destSize
,
720 const OriginPos destOrigin
) {
721 const auto sdType
= asd
.type();
723 case layers::SurfaceDescriptor::TSurfaceDescriptorBuffer
: {
724 const auto& sd
= asd
.get_SurfaceDescriptorBuffer();
725 const auto yuvData
= PlanarYCbCrData::From(sd
);
727 gfxCriticalNote
<< "[GLBlitHelper::BlitSdToFramebuffer] "
728 "PlanarYCbCrData::From failed";
731 return BlitPlanarYCbCr(*yuvData
, destSize
, destOrigin
);
734 case layers::SurfaceDescriptor::TSurfaceDescriptorD3D10
: {
735 const auto& sd
= asd
.get_SurfaceDescriptorD3D10();
736 return BlitDescriptor(sd
, destSize
, destOrigin
);
738 case layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr
: {
739 const auto& sd
= asd
.get_SurfaceDescriptorDXGIYCbCr();
740 return BlitDescriptor(sd
, destSize
, destOrigin
);
744 case layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface
: {
745 const auto& sd
= asd
.get_SurfaceDescriptorMacIOSurface();
746 const auto surf
= LookupSurface(sd
);
748 NS_WARNING("LookupSurface(MacIOSurface) failed");
749 // Sometimes that frame for our handle gone already. That's life, for
753 return BlitImage(surf
, destSize
, destOrigin
);
756 #ifdef MOZ_WIDGET_ANDROID
757 case layers::SurfaceDescriptor::TSurfaceTextureDescriptor
: {
758 const auto& sd
= asd
.get_SurfaceTextureDescriptor();
759 auto surfaceTexture
= java::GeckoSurfaceTexture::Lookup(sd
.handle());
760 return Blit(surfaceTexture
, destSize
, destOrigin
);
768 bool GLBlitHelper::BlitImageToFramebuffer(layers::Image
* const srcImage
,
769 const gfx::IntSize
& destSize
,
770 const OriginPos destOrigin
) {
771 switch (srcImage
->GetFormat()) {
772 case ImageFormat::PLANAR_YCBCR
: {
773 const auto srcImage2
= static_cast<PlanarYCbCrImage
*>(srcImage
);
774 const auto data
= srcImage2
->GetData();
775 return BlitPlanarYCbCr(*data
, destSize
, destOrigin
);
778 case ImageFormat::SURFACE_TEXTURE
: {
779 #ifdef MOZ_WIDGET_ANDROID
780 auto* image
= srcImage
->AsSurfaceTextureImage();
782 auto surfaceTexture
=
783 java::GeckoSurfaceTexture::Lookup(image
->GetHandle());
784 return Blit(surfaceTexture
, destSize
, destOrigin
);
790 case ImageFormat::MAC_IOSURFACE
:
792 return BlitImage(srcImage
->AsMacIOSurfaceImage(), destSize
, destOrigin
);
798 case ImageFormat::GPU_VIDEO
:
799 return BlitImage(static_cast<layers::GPUVideoImage
*>(srcImage
), destSize
,
802 case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE
:
803 return BlitImage(static_cast<layers::D3D11ShareHandleImage
*>(srcImage
),
804 destSize
, destOrigin
);
805 case ImageFormat::D3D11_TEXTURE_IMF_SAMPLE
:
807 static_cast<layers::D3D11TextureIMFSampleImage
*>(srcImage
), destSize
,
809 case ImageFormat::D3D11_YCBCR_IMAGE
:
810 return BlitImage(static_cast<layers::D3D11YCbCrImage
*>(srcImage
),
811 destSize
, destOrigin
);
812 case ImageFormat::D3D9_RGB32_TEXTURE
:
813 return false; // todo
815 case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE
:
816 case ImageFormat::D3D11_TEXTURE_IMF_SAMPLE
:
817 case ImageFormat::D3D11_YCBCR_IMAGE
:
818 case ImageFormat::D3D9_RGB32_TEXTURE
:
822 case ImageFormat::DMABUF
:
824 return BlitImage(static_cast<layers::DMABUFSurfaceImage
*>(srcImage
),
825 destSize
, destOrigin
);
829 case ImageFormat::CAIRO_SURFACE
:
830 case ImageFormat::NV_IMAGE
:
831 case ImageFormat::OVERLAY_IMAGE
:
832 case ImageFormat::SHARED_RGB
:
833 case ImageFormat::TEXTURE_WRAPPER
:
834 return false; // todo
839 // -------------------------------------
841 #ifdef MOZ_WIDGET_ANDROID
842 bool GLBlitHelper::Blit(const java::GeckoSurfaceTexture::Ref
& surfaceTexture
,
843 const gfx::IntSize
& destSize
,
844 const OriginPos destOrigin
) const {
845 if (!surfaceTexture
) {
849 const ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
851 if (!surfaceTexture
->IsAttachedToGLContext((int64_t)mGL
)) {
854 mGL
->fGenTextures(1, &tex
);
856 if (NS_FAILED(surfaceTexture
->AttachToGLContext((int64_t)mGL
, tex
))) {
857 mGL
->fDeleteTextures(1, &tex
);
862 const ScopedBindTexture
savedTex(mGL
, surfaceTexture
->GetTexName(),
863 LOCAL_GL_TEXTURE_EXTERNAL
);
864 surfaceTexture
->UpdateTexImage();
865 const auto transform3
= Mat3::I();
866 const auto srcOrigin
= OriginPos::TopLeft
;
867 const bool yFlip
= (srcOrigin
!= destOrigin
);
868 const auto& prog
= GetDrawBlitProg({kFragHeader_TexExt
, kFragBody_RGBA
});
869 const DrawBlitProg::BaseArgs baseArgs
= {transform3
, yFlip
, destSize
,
871 prog
->Draw(baseArgs
, nullptr);
873 if (surfaceTexture
->IsSingleBuffer()) {
874 surfaceTexture
->ReleaseTexImage();
881 // -------------------------------------
883 bool GuessDivisors(const gfx::IntSize
& ySize
, const gfx::IntSize
& uvSize
,
884 gfx::IntSize
* const out_divisors
) {
885 const gfx::IntSize
divisors((ySize
.width
== uvSize
.width
) ? 1 : 2,
886 (ySize
.height
== uvSize
.height
) ? 1 : 2);
887 if (uvSize
.width
* divisors
.width
!= ySize
.width
||
888 uvSize
.height
* divisors
.height
!= ySize
.height
) {
891 *out_divisors
= divisors
;
895 bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData
& yuvData
,
896 const gfx::IntSize
& destSize
,
897 const OriginPos destOrigin
) {
898 const auto& prog
= GetDrawBlitProg({kFragHeader_Tex2D
, kFragBody_PlanarYUV
});
900 if (!mYuvUploads
[0]) {
901 mGL
->fGenTextures(3, mYuvUploads
);
902 const ScopedBindTexture
bindTex(mGL
, mYuvUploads
[0]);
903 mGL
->TexParams_SetClampNoMips();
904 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[1]);
905 mGL
->TexParams_SetClampNoMips();
906 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[2]);
907 mGL
->TexParams_SetClampNoMips();
912 auto ySize
= yuvData
.YDataSize();
913 auto cbcrSize
= yuvData
.CbCrDataSize();
914 if (yuvData
.mYSkip
|| yuvData
.mCbSkip
|| yuvData
.mCrSkip
|| ySize
.width
< 0 ||
915 ySize
.height
< 0 || cbcrSize
.width
< 0 || cbcrSize
.height
< 0 ||
916 yuvData
.mYStride
< 0 || yuvData
.mCbCrStride
< 0) {
917 gfxCriticalError() << "Unusual PlanarYCbCrData: " << yuvData
.mYSkip
<< ","
918 << yuvData
.mCbSkip
<< "," << yuvData
.mCrSkip
<< ", "
919 << ySize
.width
<< "," << ySize
.height
<< ", "
920 << cbcrSize
.width
<< "," << cbcrSize
.height
<< ", "
921 << yuvData
.mYStride
<< "," << yuvData
.mCbCrStride
;
925 gfx::IntSize divisors
;
926 switch (yuvData
.mChromaSubsampling
) {
927 case gfx::ChromaSubsampling::FULL
:
928 divisors
= gfx::IntSize(1, 1);
930 case gfx::ChromaSubsampling::HALF_WIDTH
:
931 divisors
= gfx::IntSize(2, 1);
933 case gfx::ChromaSubsampling::HALF_WIDTH_AND_HEIGHT
:
934 divisors
= gfx::IntSize(2, 2);
937 gfxCriticalError() << "Unknown chroma subsampling:"
938 << int(yuvData
.mChromaSubsampling
);
944 // RED textures aren't valid in GLES2, and ALPHA textures are not valid in
945 // desktop GL Core Profiles. So use R8 textures on GL3.0+ and GLES3.0+, but
946 // LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
947 GLenum internalFormat
;
949 if (mGL
->IsAtLeast(gl::ContextProfile::OpenGLCore
, 300) ||
950 mGL
->IsAtLeast(gl::ContextProfile::OpenGLES
, 300)) {
951 internalFormat
= LOCAL_GL_R8
;
952 unpackFormat
= LOCAL_GL_RED
;
954 internalFormat
= LOCAL_GL_LUMINANCE
;
955 unpackFormat
= LOCAL_GL_LUMINANCE
;
960 const ScopedSaveMultiTex
saveTex(mGL
, 3, LOCAL_GL_TEXTURE_2D
);
961 const ResetUnpackState
reset(mGL
);
962 const gfx::IntSize
yTexSize(yuvData
.mYStride
, yuvData
.YDataSize().height
);
963 const gfx::IntSize
uvTexSize(yuvData
.mCbCrStride
,
964 yuvData
.CbCrDataSize().height
);
966 if (yTexSize
!= mYuvUploads_YSize
|| uvTexSize
!= mYuvUploads_UVSize
) {
967 mYuvUploads_YSize
= yTexSize
;
968 mYuvUploads_UVSize
= uvTexSize
;
970 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
);
971 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[0]);
972 mGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
, 0, internalFormat
, yTexSize
.width
,
973 yTexSize
.height
, 0, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
975 for (int i
= 1; i
< 3; i
++) {
976 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
977 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[i
]);
978 mGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
, 0, internalFormat
, uvTexSize
.width
,
979 uvTexSize
.height
, 0, unpackFormat
,
980 LOCAL_GL_UNSIGNED_BYTE
, nullptr);
986 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
);
987 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[0]);
988 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
, 0, 0, 0, yTexSize
.width
,
989 yTexSize
.height
, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
991 mGL
->fActiveTexture(LOCAL_GL_TEXTURE1
);
992 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[1]);
993 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
, 0, 0, 0, uvTexSize
.width
,
994 uvTexSize
.height
, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
996 mGL
->fActiveTexture(LOCAL_GL_TEXTURE2
);
997 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[2]);
998 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
, 0, 0, 0, uvTexSize
.width
,
999 uvTexSize
.height
, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
1000 yuvData
.mCrChannel
);
1004 const auto& clipRect
= yuvData
.mPictureRect
;
1005 const auto srcOrigin
= OriginPos::BottomLeft
;
1006 const bool yFlip
= (destOrigin
!= srcOrigin
);
1008 const DrawBlitProg::BaseArgs baseArgs
= {SubRectMat3(clipRect
, yTexSize
),
1009 yFlip
, destSize
, Nothing()};
1010 const DrawBlitProg::YUVArgs yuvArgs
= {
1011 SubRectMat3(clipRect
, uvTexSize
, divisors
), yuvData
.mYUVColorSpace
};
1012 prog
->Draw(baseArgs
, &yuvArgs
);
1016 // -------------------------------------
1019 bool GLBlitHelper::BlitImage(layers::MacIOSurfaceImage
* const srcImage
,
1020 const gfx::IntSize
& destSize
,
1021 const OriginPos destOrigin
) const {
1022 return BlitImage(srcImage
->GetSurface(), destSize
, destOrigin
);
1025 static std::string
IntAsAscii(const int x
) {
1028 auto u
= static_cast<unsigned int>(x
);
1030 str
.insert(str
.begin(), u
& 0xff);
1033 str
.insert(str
.begin(), '\'');
1034 str
.push_back('\'');
1038 bool GLBlitHelper::BlitImage(MacIOSurface
* const iosurf
,
1039 const gfx::IntSize
& destSize
,
1040 const OriginPos destOrigin
) const {
1042 gfxCriticalError() << "Null MacIOSurface for GLBlitHelper::BlitImage";
1045 if (mGL
->GetContextType() != GLContextType::CGL
) {
1049 const auto glCGL
= static_cast<GLContextCGL
*>(mGL
);
1050 const auto cglContext
= glCGL
->GetCGLContext();
1052 const auto& srcOrigin
= OriginPos::BottomLeft
;
1054 DrawBlitProg::BaseArgs baseArgs
;
1055 baseArgs
.yFlip
= (destOrigin
!= srcOrigin
);
1056 baseArgs
.destSize
= destSize
;
1058 // TODO: The colorspace is known by the IOSurface, why override it?
1059 // See GetYUVColorSpace/GetFullRange()
1060 DrawBlitProg::YUVArgs yuvArgs
;
1061 yuvArgs
.colorSpace
= iosurf
->GetYUVColorSpace();
1063 const DrawBlitProg::YUVArgs
* pYuvArgs
= nullptr;
1065 auto planes
= iosurf
->GetPlaneCount();
1067 planes
= 1; // Bad API. No cookie.
1070 const GLenum texTarget
= LOCAL_GL_TEXTURE_RECTANGLE
;
1071 const char* const fragHeader
= kFragHeader_Tex2DRect
;
1073 const ScopedSaveMultiTex
saveTex(mGL
, planes
, texTarget
);
1074 const ScopedTexture
tex0(mGL
);
1075 const ScopedTexture
tex1(mGL
);
1076 const ScopedTexture
tex2(mGL
);
1077 const GLuint texs
[3] = {tex0
, tex1
, tex2
};
1079 const auto pixelFormat
= iosurf
->GetPixelFormat();
1080 if (mGL
->ShouldSpew()) {
1081 const auto formatStr
= IntAsAscii(pixelFormat
);
1082 printf_stderr("iosurf format: %s (0x%08x)\n", formatStr
.c_str(),
1086 const char* fragBody
;
1089 switch (pixelFormat
) {
1090 case kCVPixelFormatType_24RGB
:
1091 case kCVPixelFormatType_24BGR
:
1092 case kCVPixelFormatType_32ARGB
:
1093 case kCVPixelFormatType_32BGRA
:
1094 case kCVPixelFormatType_32ABGR
:
1095 case kCVPixelFormatType_32RGBA
:
1096 case kCVPixelFormatType_64ARGB
:
1097 case kCVPixelFormatType_48RGB
:
1098 fragBody
= kFragBody_RGBA
;
1100 case kCVPixelFormatType_422YpCbCr8
:
1101 case kCVPixelFormatType_422YpCbCr8_yuvs
:
1102 fragBody
= kFragBody_CrYCb
;
1103 pYuvArgs
= &yuvArgs
;
1107 if (pixelFormat
<= 0xff) {
1108 str
= std::to_string(pixelFormat
);
1110 str
= IntAsAscii(pixelFormat
);
1112 gfxCriticalError() << "Unhandled kCVPixelFormatType_*: " << str
;
1114 // Probably YUV though
1115 fragBody
= kFragBody_CrYCb
;
1116 pYuvArgs
= &yuvArgs
;
1121 fragBody
= kFragBody_NV12
;
1122 pYuvArgs
= &yuvArgs
;
1125 fragBody
= kFragBody_PlanarYUV
;
1126 pYuvArgs
= &yuvArgs
;
1129 gfxCriticalError() << "Unexpected plane count: " << planes
;
1133 for (uint32_t p
= 0; p
< planes
; p
++) {
1134 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ p
);
1135 mGL
->fBindTexture(texTarget
, texs
[p
]);
1136 mGL
->TexParams_SetClampNoMips(texTarget
);
1138 auto err
= iosurf
->CGLTexImageIOSurface2D(mGL
, cglContext
, p
);
1144 const auto width
= iosurf
->GetDevicePixelWidth(p
);
1145 const auto height
= iosurf
->GetDevicePixelHeight(p
);
1146 baseArgs
.texMatrix0
= SubRectMat3(0, 0, width
, height
);
1147 yuvArgs
.texMatrix1
= SubRectMat3(0, 0, width
/ 2.0, height
/ 2.0);
1151 const auto& prog
= GetDrawBlitProg({fragHeader
, fragBody
});
1152 prog
->Draw(baseArgs
, pYuvArgs
);
1157 // -----------------------------------------------------------------------------
1159 void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex
,
1160 const gfx::IntSize
& srcSize
,
1161 const gfx::IntSize
& destSize
,
1162 const GLenum srcTarget
,
1163 const bool srcIsBGRA
) const {
1164 const char* fragHeader
= nullptr;
1166 switch (srcTarget
) {
1167 case LOCAL_GL_TEXTURE_2D
:
1168 fragHeader
= kFragHeader_Tex2D
;
1169 texMatrix0
= Mat3::I();
1171 case LOCAL_GL_TEXTURE_RECTANGLE_ARB
:
1172 fragHeader
= kFragHeader_Tex2DRect
;
1173 texMatrix0
= SubRectMat3(0, 0, srcSize
.width
, srcSize
.height
);
1176 gfxCriticalError() << "Unexpected srcTarget: " << srcTarget
;
1179 const char* fragBody
= srcIsBGRA
? kFragBody_BGRA
: kFragBody_RGBA
;
1180 const auto& prog
= GetDrawBlitProg({fragHeader
, fragBody
});
1182 const ScopedSaveMultiTex
saveTex(mGL
, 1, srcTarget
);
1183 mGL
->fBindTexture(srcTarget
, srcTex
);
1185 const bool yFlip
= false;
1186 const DrawBlitProg::BaseArgs baseArgs
= {texMatrix0
, yFlip
, destSize
,
1188 prog
->Draw(baseArgs
);
1191 // -----------------------------------------------------------------------------
1193 void GLBlitHelper::BlitFramebuffer(const gfx::IntRect
& srcRect
,
1194 const gfx::IntRect
& destRect
,
1195 GLuint filter
) const {
1196 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
1198 const ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
1199 mGL
->fBlitFramebuffer(srcRect
.x
, srcRect
.y
, srcRect
.XMost(), srcRect
.YMost(),
1200 destRect
.x
, destRect
.y
, destRect
.XMost(),
1201 destRect
.YMost(), LOCAL_GL_COLOR_BUFFER_BIT
, filter
);
1206 void GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB
,
1207 const GLuint destFB
,
1208 const gfx::IntRect
& srcRect
,
1209 const gfx::IntRect
& destRect
,
1210 GLuint filter
) const {
1211 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
1212 MOZ_GL_ASSERT(mGL
, !srcFB
|| mGL
->fIsFramebuffer(srcFB
));
1213 MOZ_GL_ASSERT(mGL
, !destFB
|| mGL
->fIsFramebuffer(destFB
));
1215 const ScopedBindFramebuffer
boundFB(mGL
);
1216 mGL
->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER
, srcFB
);
1217 mGL
->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER
, destFB
);
1219 BlitFramebuffer(srcRect
, destRect
, filter
);
1222 void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex
,
1223 const gfx::IntSize
& srcSize
,
1224 const gfx::IntSize
& destSize
,
1225 GLenum srcTarget
) const {
1226 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(srcTex
));
1228 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
1229 const ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
1230 const ScopedBindFramebuffer
bindFB(mGL
);
1231 mGL
->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER
, srcWrapper
.FB());
1232 BlitFramebuffer(gfx::IntRect({}, srcSize
), gfx::IntRect({}, destSize
));
1236 DrawBlitTextureToFramebuffer(srcTex
, srcSize
, destSize
, srcTarget
);
1239 void GLBlitHelper::BlitFramebufferToTexture(GLuint destTex
,
1240 const gfx::IntSize
& srcSize
,
1241 const gfx::IntSize
& destSize
,
1242 GLenum destTarget
) const {
1243 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(destTex
));
1245 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
1246 const ScopedFramebufferForTexture
destWrapper(mGL
, destTex
, destTarget
);
1247 const ScopedBindFramebuffer
bindFB(mGL
);
1248 mGL
->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER
, destWrapper
.FB());
1249 BlitFramebuffer(gfx::IntRect({}, srcSize
), gfx::IntRect({}, destSize
));
1253 ScopedBindTexture
autoTex(mGL
, destTex
, destTarget
);
1254 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
1255 mGL
->fCopyTexSubImage2D(destTarget
, 0, 0, 0, 0, 0, srcSize
.width
,
1259 void GLBlitHelper::BlitTextureToTexture(GLuint srcTex
, GLuint destTex
,
1260 const gfx::IntSize
& srcSize
,
1261 const gfx::IntSize
& destSize
,
1263 GLenum destTarget
) const {
1264 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(srcTex
));
1265 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(destTex
));
1267 // Start down the CopyTexSubImage path, not the DrawBlit path.
1268 const ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
1269 const ScopedBindFramebuffer
bindFB(mGL
, srcWrapper
.FB());
1270 BlitFramebufferToTexture(destTex
, srcSize
, destSize
, destTarget
);
1273 // -------------------------------------
1275 bool GLBlitHelper::BlitImage(layers::GPUVideoImage
* const srcImage
,
1276 const gfx::IntSize
& destSize
,
1277 const OriginPos destOrigin
) const {
1278 const auto& data
= srcImage
->GetData();
1279 if (!data
) return false;
1281 const auto& desc
= data
->SD();
1285 layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder
);
1286 const auto& subdescUnion
=
1287 desc
.get_SurfaceDescriptorRemoteDecoder().subdesc();
1288 switch (subdescUnion
.type()) {
1289 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDMABuf
: {
1294 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorD3D10
: {
1295 const auto& subdesc
= subdescUnion
.get_SurfaceDescriptorD3D10();
1296 return BlitDescriptor(subdesc
, destSize
, destOrigin
);
1298 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDXGIYCbCr
: {
1299 const auto& subdesc
= subdescUnion
.get_SurfaceDescriptorDXGIYCbCr();
1300 return BlitDescriptor(subdesc
, destSize
, destOrigin
);
1304 case layers::RemoteDecoderVideoSubDescriptor::
1305 TSurfaceDescriptorMacIOSurface
: {
1306 const auto& subdesc
= subdescUnion
.get_SurfaceDescriptorMacIOSurface();
1307 RefPtr
<MacIOSurface
> surface
= MacIOSurface::LookupSurface(
1308 subdesc
.surfaceId(), !subdesc
.isOpaque(), subdesc
.yUVColorSpace());
1309 MOZ_ASSERT(surface
);
1313 return BlitImage(surface
, destSize
, destOrigin
);
1316 case layers::RemoteDecoderVideoSubDescriptor::Tnull_t
:
1317 // This GPUVideoImage isn't directly readable outside the GPU process.
1321 gfxCriticalError() << "Unhandled subdesc type: "
1322 << uint32_t(subdescUnion
.type());
1327 // -------------------------------------
1329 bool GLBlitHelper::BlitImage(layers::DMABUFSurfaceImage
* srcImage
,
1330 const gfx::IntSize
& destSize
,
1331 OriginPos destOrigin
) const {
1332 DMABufSurface
* surface
= srcImage
->GetSurface();
1334 gfxCriticalError() << "Null DMABUFSurface for GLBlitHelper::BlitImage";
1338 const auto& srcOrigin
= OriginPos::BottomLeft
;
1340 DrawBlitProg::BaseArgs baseArgs
;
1341 baseArgs
.yFlip
= (destOrigin
!= srcOrigin
);
1342 baseArgs
.destSize
= destSize
;
1344 // TODO: The colorspace is known by the DMABUFSurface, why override it?
1345 // See GetYUVColorSpace/GetFullRange()
1346 DrawBlitProg::YUVArgs yuvArgs
;
1347 yuvArgs
.colorSpace
= surface
->GetYUVColorSpace();
1349 const DrawBlitProg::YUVArgs
* pYuvArgs
= nullptr;
1351 const auto planes
= surface
->GetTextureCount();
1352 const GLenum texTarget
= LOCAL_GL_TEXTURE_2D
;
1354 const ScopedSaveMultiTex
saveTex(mGL
, planes
, texTarget
);
1355 const auto pixelFormat
= surface
->GetSurfaceType();
1357 const char* fragBody
;
1358 switch (pixelFormat
) {
1359 case DMABufSurface::SURFACE_RGBA
:
1360 fragBody
= kFragBody_RGBA
;
1362 case DMABufSurface::SURFACE_NV12
:
1363 fragBody
= kFragBody_NV12
;
1364 pYuvArgs
= &yuvArgs
;
1366 case DMABufSurface::SURFACE_YUV420
:
1367 fragBody
= kFragBody_PlanarYUV
;
1368 pYuvArgs
= &yuvArgs
;
1371 gfxCriticalError() << "Unexpected pixel format: " << pixelFormat
;
1375 for (const auto p
: IntegerRange(planes
)) {
1376 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ p
);
1377 mGL
->fBindTexture(texTarget
, surface
->GetTexture(p
));
1378 mGL
->TexParams_SetClampNoMips(texTarget
);
1381 // We support only NV12/YUV420 formats only with 1/2 texture scale.
1382 // We don't set cliprect as DMABus textures are created without padding.
1383 baseArgs
.texMatrix0
= SubRectMat3(0, 0, 1, 1);
1384 yuvArgs
.texMatrix1
= SubRectMat3(0, 0, 1, 1);
1386 const auto& prog
= GetDrawBlitProg({kFragHeader_Tex2D
, fragBody
});
1387 prog
->Draw(baseArgs
, pYuvArgs
);
1394 } // namespace mozilla