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 "GLImages.h"
27 # include "GLLibraryEGL.h"
28 # include "mozilla/java/GeckoSurfaceTextureWrappers.h"
32 # include "GLContextCGL.h"
33 # include "MacIOSurfaceImage.h"
37 # include "mozilla/layers/D3D11ShareHandleImage.h"
38 # include "mozilla/layers/D3D11YCbCrImage.h"
42 # include "mozilla/layers/DMABUFSurfaceImage.h"
43 # include "mozilla/widget/DMABufSurface.h"
46 using mozilla::layers::PlanarYCbCrData
;
47 using mozilla::layers::PlanarYCbCrImage
;
54 const char* const kFragHeader_Tex2D
=
56 #define SAMPLER sampler2D \n\
57 #if __VERSION__ >= 130 \n\
58 #define TEXTURE texture \n\
60 #define TEXTURE texture2D \n\
63 const char* const kFragHeader_Tex2DRect
=
65 #define SAMPLER sampler2DRect \n\
66 #if __VERSION__ >= 130 \n\
67 #define TEXTURE texture \n\
69 #define TEXTURE texture2DRect \n\
72 const char* const kFragHeader_TexExt
=
74 #extension GL_OES_EGL_image_external : require \n\
75 #if __VERSION__ >= 130 \n\
76 #define TEXTURE texture \n\
78 #define TEXTURE texture2D \n\
80 #define SAMPLER samplerExternalOES \n\
83 const char* const kFragBody_RGBA
=
85 VARYING vec2 vTexCoord0; \n\
86 uniform SAMPLER uTex0; \n\
90 FRAG_COLOR = TEXTURE(uTex0, vTexCoord0); \n\
93 const char* const kFragBody_CrYCb
=
95 VARYING vec2 vTexCoord0; \n\
96 uniform SAMPLER uTex0; \n\
97 uniform MAT4X3 uColorMatrix; \n\
101 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr, \n\
103 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
106 const char* const kFragBody_NV12
=
108 VARYING vec2 vTexCoord0; \n\
109 VARYING vec2 vTexCoord1; \n\
110 uniform SAMPLER uTex0; \n\
111 uniform SAMPLER uTex1; \n\
112 uniform MAT4X3 uColorMatrix; \n\
116 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
117 TEXTURE(uTex1, vTexCoord1).xy, \n\
119 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
122 const char* const kFragBody_PlanarYUV
=
124 VARYING vec2 vTexCoord0; \n\
125 VARYING vec2 vTexCoord1; \n\
126 uniform SAMPLER uTex0; \n\
127 uniform SAMPLER uTex1; \n\
128 uniform SAMPLER uTex2; \n\
129 uniform MAT4X3 uColorMatrix; \n\
133 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
134 TEXTURE(uTex1, vTexCoord1).x, \n\
135 TEXTURE(uTex2, vTexCoord1).x, \n\
137 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
144 /*static*/ Mat
<N
> Mat
<N
>::Zero() {
146 for (auto& x
: ret
.m
) {
153 /*static*/ Mat
<N
> Mat
<N
>::I() {
154 auto ret
= Mat
<N
>::Zero();
155 for (uint8_t i
= 0; i
< N
; i
++) {
162 Mat
<N
> Mat
<N
>::operator*(const Mat
<N
>& r
) const {
164 for (uint8_t x
= 0; x
< N
; x
++) {
165 for (uint8_t y
= 0; y
< N
; y
++) {
167 for (uint8_t i
= 0; i
< N
; i
++) {
168 sum
+= at(i
, y
) * r
.at(x
, i
);
176 Mat3
SubRectMat3(const float x
, const float y
, const float w
, const float h
) {
177 auto ret
= Mat3::Zero();
186 Mat3
SubRectMat3(const gfx::IntRect
& subrect
, const gfx::IntSize
& size
) {
187 return SubRectMat3(float(subrect
.X()) / size
.width
,
188 float(subrect
.Y()) / size
.height
,
189 float(subrect
.Width()) / size
.width
,
190 float(subrect
.Height()) / size
.height
);
193 Mat3
SubRectMat3(const gfx::IntRect
& bigSubrect
, const gfx::IntSize
& smallSize
,
194 const gfx::IntSize
& divisors
) {
195 const float x
= float(bigSubrect
.X()) / divisors
.width
;
196 const float y
= float(bigSubrect
.Y()) / divisors
.height
;
197 const float w
= float(bigSubrect
.Width()) / divisors
.width
;
198 const float h
= float(bigSubrect
.Height()) / divisors
.height
;
199 return SubRectMat3(x
/ smallSize
.width
, y
/ smallSize
.height
,
200 w
/ smallSize
.width
, h
/ smallSize
.height
);
205 ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext
* const gl
,
206 const uint8_t texCount
,
207 const GLenum texTarget
)
210 mTexTarget(texTarget
),
211 mOldTexUnit(mGL
.GetIntAs
<GLenum
>(LOCAL_GL_ACTIVE_TEXTURE
)) {
213 switch (mTexTarget
) {
214 case LOCAL_GL_TEXTURE_2D
:
215 texBinding
= LOCAL_GL_TEXTURE_BINDING_2D
;
217 case LOCAL_GL_TEXTURE_RECTANGLE
:
218 texBinding
= LOCAL_GL_TEXTURE_BINDING_RECTANGLE
;
220 case LOCAL_GL_TEXTURE_EXTERNAL
:
221 texBinding
= LOCAL_GL_TEXTURE_BINDING_EXTERNAL
;
224 gfxCriticalError() << "Unhandled texTarget: " << texTarget
;
227 for (uint8_t i
= 0; i
< mTexCount
; i
++) {
228 mGL
.fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
229 if (mGL
.IsSupported(GLFeature::sampler_objects
)) {
230 mOldTexSampler
[i
] = mGL
.GetIntAs
<GLuint
>(LOCAL_GL_SAMPLER_BINDING
);
231 mGL
.fBindSampler(i
, 0);
233 mOldTex
[i
] = mGL
.GetIntAs
<GLuint
>(texBinding
);
237 ScopedSaveMultiTex::~ScopedSaveMultiTex() {
238 for (uint8_t i
= 0; i
< mTexCount
; i
++) {
239 mGL
.fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
240 if (mGL
.IsSupported(GLFeature::sampler_objects
)) {
241 mGL
.fBindSampler(i
, mOldTexSampler
[i
]);
243 mGL
.fBindTexture(mTexTarget
, mOldTex
[i
]);
245 mGL
.fActiveTexture(mOldTexUnit
);
250 class ScopedBindArrayBuffer final
{
252 const GLuint mOldVBO
;
255 ScopedBindArrayBuffer(GLContext
* const gl
, const GLuint vbo
)
256 : mGL(*gl
), mOldVBO(mGL
.GetIntAs
<GLuint
>(LOCAL_GL_ARRAY_BUFFER_BINDING
)) {
257 mGL
.fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, vbo
);
260 ~ScopedBindArrayBuffer() { mGL
.fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mOldVBO
); }
265 class ScopedShader final
{
270 ScopedShader(GLContext
* const gl
, const GLenum shaderType
)
271 : mGL(*gl
), mName(mGL
.fCreateShader(shaderType
)) {}
273 ~ScopedShader() { mGL
.fDeleteShader(mName
); }
275 operator GLuint() const { return mName
; }
280 class SaveRestoreCurrentProgram final
{
285 explicit SaveRestoreCurrentProgram(GLContext
* const gl
)
286 : mGL(*gl
), mOld(mGL
.GetIntAs
<GLuint
>(LOCAL_GL_CURRENT_PROGRAM
)) {}
288 ~SaveRestoreCurrentProgram() { mGL
.fUseProgram(mOld
); }
293 class ScopedDrawBlitState final
{
298 const bool depthTest
;
300 const bool polyOffsFill
;
301 const bool sampleAToC
;
302 const bool sampleCover
;
305 Maybe
<bool> rasterizerDiscard
;
307 realGLboolean colorMask
[4];
311 ScopedDrawBlitState(GLContext
* const gl
, const gfx::IntSize
& destSize
)
313 blend(mGL
.PushEnabled(LOCAL_GL_BLEND
, false)),
314 cullFace(mGL
.PushEnabled(LOCAL_GL_CULL_FACE
, false)),
315 depthTest(mGL
.PushEnabled(LOCAL_GL_DEPTH_TEST
, false)),
316 dither(mGL
.PushEnabled(LOCAL_GL_DITHER
, true)),
317 polyOffsFill(mGL
.PushEnabled(LOCAL_GL_POLYGON_OFFSET_FILL
, false)),
318 sampleAToC(mGL
.PushEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
, false)),
319 sampleCover(mGL
.PushEnabled(LOCAL_GL_SAMPLE_COVERAGE
, false)),
320 scissor(mGL
.PushEnabled(LOCAL_GL_SCISSOR_TEST
, false)),
321 stencil(mGL
.PushEnabled(LOCAL_GL_STENCIL_TEST
, false)) {
322 if (mGL
.IsSupported(GLFeature::transform_feedback2
)) {
323 // Technically transform_feedback2 requires transform_feedback, which
324 // actually adds RASTERIZER_DISCARD.
326 Some(mGL
.PushEnabled(LOCAL_GL_RASTERIZER_DISCARD
, false));
329 mGL
.fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK
, colorMask
);
330 mGL
.fColorMask(true, true, true, true);
332 mGL
.fGetIntegerv(LOCAL_GL_VIEWPORT
, viewport
);
333 MOZ_ASSERT(destSize
.width
&& destSize
.height
);
334 mGL
.fViewport(0, 0, destSize
.width
, destSize
.height
);
337 ~ScopedDrawBlitState() {
338 mGL
.SetEnabled(LOCAL_GL_BLEND
, blend
);
339 mGL
.SetEnabled(LOCAL_GL_CULL_FACE
, cullFace
);
340 mGL
.SetEnabled(LOCAL_GL_DEPTH_TEST
, depthTest
);
341 mGL
.SetEnabled(LOCAL_GL_DITHER
, dither
);
342 mGL
.SetEnabled(LOCAL_GL_POLYGON_OFFSET_FILL
, polyOffsFill
);
343 mGL
.SetEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
, sampleAToC
);
344 mGL
.SetEnabled(LOCAL_GL_SAMPLE_COVERAGE
, sampleCover
);
345 mGL
.SetEnabled(LOCAL_GL_SCISSOR_TEST
, scissor
);
346 mGL
.SetEnabled(LOCAL_GL_STENCIL_TEST
, stencil
);
347 if (rasterizerDiscard
) {
348 mGL
.SetEnabled(LOCAL_GL_RASTERIZER_DISCARD
, rasterizerDiscard
.value());
351 mGL
.fColorMask(colorMask
[0], colorMask
[1], colorMask
[2], colorMask
[3]);
352 mGL
.fViewport(viewport
[0], viewport
[1], viewport
[2], viewport
[3]);
358 DrawBlitProg::DrawBlitProg(const GLBlitHelper
* const parent
, const GLuint prog
)
361 mLoc_uDestMatrix(mParent
.mGL
->fGetUniformLocation(mProg
, "uDestMatrix")),
362 mLoc_uTexMatrix0(mParent
.mGL
->fGetUniformLocation(mProg
, "uTexMatrix0")),
363 mLoc_uTexMatrix1(mParent
.mGL
->fGetUniformLocation(mProg
, "uTexMatrix1")),
365 mParent
.mGL
->fGetUniformLocation(mProg
, "uColorMatrix")) {
366 const auto& gl
= mParent
.mGL
;
367 MOZ_GL_ASSERT(gl
, mLoc_uDestMatrix
!= -1);
368 MOZ_GL_ASSERT(gl
, mLoc_uTexMatrix0
!= -1);
369 if (mLoc_uColorMatrix
!= -1) {
370 MOZ_GL_ASSERT(gl
, mLoc_uTexMatrix1
!= -1);
372 int32_t numActiveUniforms
= 0;
373 gl
->fGetProgramiv(mProg
, LOCAL_GL_ACTIVE_UNIFORMS
, &numActiveUniforms
);
375 const size_t kMaxNameSize
= 32;
376 char name
[kMaxNameSize
] = {0};
379 for (int32_t i
= 0; i
< numActiveUniforms
; i
++) {
380 gl
->fGetActiveUniform(mProg
, i
, kMaxNameSize
, nullptr, &size
, &type
,
382 if (strcmp("uColorMatrix", name
) == 0) {
383 mType_uColorMatrix
= type
;
387 MOZ_GL_ASSERT(gl
, mType_uColorMatrix
);
391 DrawBlitProg::~DrawBlitProg() {
392 const auto& gl
= mParent
.mGL
;
393 if (!gl
->MakeCurrent()) return;
395 gl
->fDeleteProgram(mProg
);
398 void DrawBlitProg::Draw(const BaseArgs
& args
,
399 const YUVArgs
* const argsYUV
) const {
400 const auto& gl
= mParent
.mGL
;
402 const SaveRestoreCurrentProgram
oldProg(gl
);
403 gl
->fUseProgram(mProg
);
409 const auto& destRect
= args
.destRect
.value();
410 destMatrix
= SubRectMat3(destRect
.X() / args
.destSize
.width
,
411 destRect
.Y() / args
.destSize
.height
,
412 destRect
.Width() / args
.destSize
.width
,
413 destRect
.Height() / args
.destSize
.height
);
415 destMatrix
= Mat3::I();
419 // Apply the y-flip matrix before the destMatrix.
420 // That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect.
421 destMatrix
.at(2, 1) += destMatrix
.at(1, 1);
422 destMatrix
.at(1, 1) *= -1.0f
;
425 gl
->fUniformMatrix3fv(mLoc_uDestMatrix
, 1, false, destMatrix
.m
);
426 gl
->fUniformMatrix3fv(mLoc_uTexMatrix0
, 1, false, args
.texMatrix0
.m
);
428 MOZ_ASSERT(bool(argsYUV
) == (mLoc_uColorMatrix
!= -1));
430 gl
->fUniformMatrix3fv(mLoc_uTexMatrix1
, 1, false, argsYUV
->texMatrix1
.m
);
432 const auto& colorMatrix
=
433 gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV
->colorSpace
);
435 switch (mType_uColorMatrix
) {
436 case LOCAL_GL_FLOAT_MAT4
:
437 gl
->fUniformMatrix4fv(mLoc_uColorMatrix
, 1, false, colorMatrix
);
439 case LOCAL_GL_FLOAT_MAT4x3
:
440 for (int x
= 0; x
< 4; x
++) {
441 for (int y
= 0; y
< 3; y
++) {
442 mat4x3
[3 * x
+ y
] = colorMatrix
[4 * x
+ y
];
445 gl
->fUniformMatrix4x3fv(mLoc_uColorMatrix
, 1, false, mat4x3
);
448 gfxCriticalError() << "Bad mType_uColorMatrix: "
449 << gfx::hexa(mType_uColorMatrix
);
455 const ScopedDrawBlitState
drawState(gl
, args
.destSize
);
461 GLint vaa0Normalized
;
464 if (mParent
.mQuadVAO
) {
465 oldVAO
= gl
->GetIntAs
<GLuint
>(LOCAL_GL_VERTEX_ARRAY_BINDING
);
466 gl
->fBindVertexArray(mParent
.mQuadVAO
);
469 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED
, &vaa0Enabled
);
470 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE
, &vaa0Size
);
471 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE
, (GLint
*)&vaa0Type
);
472 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
, &vaa0Normalized
);
473 gl
->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE
, (GLint
*)&vaa0Stride
);
474 gl
->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER
, &vaa0Pointer
);
477 gl
->fEnableVertexAttribArray(0);
478 const ScopedBindArrayBuffer
bindVBO(gl
, mParent
.mQuadVBO
);
479 gl
->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT
, false, 0, 0);
482 gl
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
484 if (mParent
.mQuadVAO
) {
485 gl
->fBindVertexArray(oldVAO
);
488 gl
->fEnableVertexAttribArray(0);
490 gl
->fDisableVertexAttribArray(0);
492 gl
->fVertexAttribPointer(0, vaa0Size
, vaa0Type
, bool(vaa0Normalized
),
493 vaa0Stride
, vaa0Pointer
);
499 GLBlitHelper::GLBlitHelper(GLContext
* const gl
)
501 mDrawBlitProg_VertShader(mGL
->fCreateShader(LOCAL_GL_VERTEX_SHADER
))
502 //, mYuvUploads_YSize(0, 0)
503 //, mYuvUploads_UVSize(0, 0)
505 mGL
->fGenBuffers(1, &mQuadVBO
);
507 const ScopedBindArrayBuffer
bindVBO(mGL
, mQuadVBO
);
509 const float quadData
[] = {0, 0, 1, 0, 0, 1, 1, 1};
510 const HeapCopyOfStackArray
<float> heapQuadData(quadData
);
511 mGL
->fBufferData(LOCAL_GL_ARRAY_BUFFER
, heapQuadData
.ByteLength(),
512 heapQuadData
.Data(), LOCAL_GL_STATIC_DRAW
);
514 if (mGL
->IsSupported(GLFeature::vertex_array_object
)) {
515 const auto prev
= mGL
->GetIntAs
<GLuint
>(LOCAL_GL_VERTEX_ARRAY_BINDING
);
517 mGL
->fGenVertexArrays(1, &mQuadVAO
);
518 mGL
->fBindVertexArray(mQuadVAO
);
519 mGL
->fEnableVertexAttribArray(0);
520 mGL
->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT
, false, 0, 0);
522 mGL
->fBindVertexArray(prev
);
528 const auto glslVersion
= mGL
->ShadingLanguageVersion();
530 // Always use 100 on ES because some devices have OES_EGL_image_external but
531 // not OES_EGL_image_external_essl3. We could just use 100 in that particular
532 // case, but this is a lot easier and is not harmful to other usages.
534 mDrawBlitProg_VersionLine
= nsCString("#version 100\n");
535 } else if (glslVersion
>= 130) {
536 mDrawBlitProg_VersionLine
= nsPrintfCString("#version %u\n", glslVersion
);
539 const char kVertSource
[] =
541 #if __VERSION__ >= 130 \n\
542 #define ATTRIBUTE in \n\
543 #define VARYING out \n\
545 #define ATTRIBUTE attribute \n\
546 #define VARYING varying \n\
549 ATTRIBUTE vec2 aVert; // [0.0-1.0] \n\
551 uniform mat3 uDestMatrix; \n\
552 uniform mat3 uTexMatrix0; \n\
553 uniform mat3 uTexMatrix1; \n\
555 VARYING vec2 vTexCoord0; \n\
556 VARYING vec2 vTexCoord1; \n\
560 vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy; \n\
561 gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0); \n\
563 vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy; \n\
564 vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy; \n\
567 const char* const parts
[] = {mDrawBlitProg_VersionLine
.get(), kVertSource
};
568 mGL
->fShaderSource(mDrawBlitProg_VertShader
, ArrayLength(parts
), parts
,
570 mGL
->fCompileShader(mDrawBlitProg_VertShader
);
573 GLBlitHelper::~GLBlitHelper() {
574 for (const auto& pair
: mDrawBlitProgs
) {
575 const auto& ptr
= pair
.second
;
578 mDrawBlitProgs
.clear();
580 if (!mGL
->MakeCurrent()) return;
582 mGL
->fDeleteShader(mDrawBlitProg_VertShader
);
583 mGL
->fDeleteBuffers(1, &mQuadVBO
);
586 mGL
->fDeleteVertexArrays(1, &mQuadVAO
);
592 const DrawBlitProg
* GLBlitHelper::GetDrawBlitProg(
593 const DrawBlitProg::Key
& key
) const {
594 const auto& res
= mDrawBlitProgs
.insert({key
, nullptr});
595 auto& pair
= *(res
.first
);
596 const auto& didInsert
= res
.second
;
598 pair
.second
= CreateDrawBlitProg(pair
.first
);
603 const DrawBlitProg
* GLBlitHelper::CreateDrawBlitProg(
604 const DrawBlitProg::Key
& key
) const {
605 const char kFragHeader_Global
[] =
608 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
609 precision highp float; \n\
611 precision mediump float; \n\
615 #if __VERSION__ >= 130 \n\
616 #define VARYING in \n\
617 #define FRAG_COLOR oFragColor \n\
618 out vec4 FRAG_COLOR; \n\
620 #define VARYING varying \n\
621 #define FRAG_COLOR gl_FragColor \n\
624 #if __VERSION__ >= 120 \n\
625 #define MAT4X3 mat4x3 \n\
627 #define MAT4X3 mat4 \n\
631 const ScopedShader
fs(mGL
, LOCAL_GL_FRAGMENT_SHADER
);
632 const char* const parts
[] = {mDrawBlitProg_VersionLine
.get(), key
.fragHeader
,
633 kFragHeader_Global
, key
.fragBody
};
634 mGL
->fShaderSource(fs
, ArrayLength(parts
), parts
, nullptr);
635 mGL
->fCompileShader(fs
);
637 const auto prog
= mGL
->fCreateProgram();
638 mGL
->fAttachShader(prog
, mDrawBlitProg_VertShader
);
639 mGL
->fAttachShader(prog
, fs
);
641 mGL
->fBindAttribLocation(prog
, 0, "aPosition");
642 mGL
->fLinkProgram(prog
);
645 mGL
->fGetProgramiv(prog
, LOCAL_GL_LINK_STATUS
, (GLint
*)&status
);
646 if (status
== LOCAL_GL_TRUE
|| !mGL
->CheckContextLost()) {
647 const SaveRestoreCurrentProgram
oldProg(mGL
);
648 mGL
->fUseProgram(prog
);
649 const char* samplerNames
[] = {"uTex0", "uTex1", "uTex2"};
650 for (int i
= 0; i
< 3; i
++) {
651 const auto loc
= mGL
->fGetUniformLocation(prog
, samplerNames
[i
]);
652 if (loc
== -1) break;
653 mGL
->fUniform1i(loc
, i
);
656 return new DrawBlitProg(this, prog
);
659 GLuint progLogLen
= 0;
660 mGL
->fGetProgramiv(prog
, LOCAL_GL_INFO_LOG_LENGTH
, (GLint
*)&progLogLen
);
661 const UniquePtr
<char[]> progLog(new char[progLogLen
+ 1]);
662 mGL
->fGetProgramInfoLog(prog
, progLogLen
, nullptr, progLog
.get());
663 progLog
[progLogLen
] = 0;
665 const auto& vs
= mDrawBlitProg_VertShader
;
667 mGL
->fGetShaderiv(vs
, LOCAL_GL_INFO_LOG_LENGTH
, (GLint
*)&vsLogLen
);
668 const UniquePtr
<char[]> vsLog(new char[vsLogLen
+ 1]);
669 mGL
->fGetShaderInfoLog(vs
, vsLogLen
, nullptr, vsLog
.get());
673 mGL
->fGetShaderiv(fs
, LOCAL_GL_INFO_LOG_LENGTH
, (GLint
*)&fsLogLen
);
674 const UniquePtr
<char[]> fsLog(new char[fsLogLen
+ 1]);
675 mGL
->fGetShaderInfoLog(fs
, fsLogLen
, nullptr, fsLog
.get());
678 gfxCriticalError() << "DrawBlitProg link failed:\n"
679 << "progLog: " << progLog
.get() << "\n"
680 << "vsLog: " << vsLog
.get() << "\n"
681 << "fsLog: " << fsLog
.get() << "\n";
685 // -----------------------------------------------------------------------------
688 static RefPtr
<MacIOSurface
> LookupSurface(
689 const layers::SurfaceDescriptorMacIOSurface
& sd
) {
690 return MacIOSurface::LookupSurface(sd
.surfaceId(), !sd
.isOpaque(),
695 bool GLBlitHelper::BlitSdToFramebuffer(const layers::SurfaceDescriptor
& asd
,
696 const gfx::IntSize
& destSize
,
697 const OriginPos destOrigin
) {
698 const auto sdType
= asd
.type();
701 case layers::SurfaceDescriptor::TSurfaceDescriptorD3D10
: {
702 const auto& sd
= asd
.get_SurfaceDescriptorD3D10();
703 return BlitDescriptor(sd
, destSize
, destOrigin
);
705 case layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr
: {
706 const auto& sd
= asd
.get_SurfaceDescriptorDXGIYCbCr();
707 return BlitDescriptor(sd
, destSize
, destOrigin
);
711 case layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface
: {
712 const auto& sd
= asd
.get_SurfaceDescriptorMacIOSurface();
713 const auto surf
= LookupSurface(sd
);
715 NS_WARNING("LookupSurface(MacIOSurface) failed");
716 // Sometimes that frame for our handle gone already. That's life, for
720 return BlitImage(surf
, destSize
, destOrigin
);
728 bool GLBlitHelper::BlitImageToFramebuffer(layers::Image
* const srcImage
,
729 const gfx::IntSize
& destSize
,
730 const OriginPos destOrigin
) {
731 switch (srcImage
->GetFormat()) {
732 case ImageFormat::PLANAR_YCBCR
:
733 return BlitImage(static_cast<PlanarYCbCrImage
*>(srcImage
), destSize
,
736 case ImageFormat::SURFACE_TEXTURE
:
737 #ifdef MOZ_WIDGET_ANDROID
738 return BlitImage(static_cast<layers::SurfaceTextureImage
*>(srcImage
),
739 destSize
, destOrigin
);
745 case ImageFormat::MAC_IOSURFACE
:
747 return BlitImage(srcImage
->AsMacIOSurfaceImage(), destSize
, destOrigin
);
753 case ImageFormat::GPU_VIDEO
:
754 return BlitImage(static_cast<layers::GPUVideoImage
*>(srcImage
), destSize
,
757 case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE
:
758 return BlitImage(static_cast<layers::D3D11ShareHandleImage
*>(srcImage
),
759 destSize
, destOrigin
);
760 case ImageFormat::D3D11_YCBCR_IMAGE
:
761 return BlitImage(static_cast<layers::D3D11YCbCrImage
*>(srcImage
),
762 destSize
, destOrigin
);
763 case ImageFormat::D3D9_RGB32_TEXTURE
:
764 return false; // todo
766 case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE
:
767 case ImageFormat::D3D11_YCBCR_IMAGE
:
768 case ImageFormat::D3D9_RGB32_TEXTURE
:
772 case ImageFormat::DMABUF
:
774 return BlitImage(static_cast<layers::DMABUFSurfaceImage
*>(srcImage
),
775 destSize
, destOrigin
);
779 case ImageFormat::CAIRO_SURFACE
:
780 case ImageFormat::NV_IMAGE
:
781 case ImageFormat::OVERLAY_IMAGE
:
782 case ImageFormat::SHARED_RGB
:
783 case ImageFormat::TEXTURE_WRAPPER
:
784 return false; // todo
789 // -------------------------------------
791 #ifdef MOZ_WIDGET_ANDROID
792 bool GLBlitHelper::BlitImage(layers::SurfaceTextureImage
* srcImage
,
793 const gfx::IntSize
& destSize
,
794 const OriginPos destOrigin
) const {
795 AndroidSurfaceTextureHandle handle
= srcImage
->GetHandle();
796 const auto& surfaceTexture
= java::GeckoSurfaceTexture::Lookup(handle
);
798 if (!surfaceTexture
) {
802 const ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
804 if (!surfaceTexture
->IsAttachedToGLContext((int64_t)mGL
)) {
807 mGL
->fGenTextures(1, &tex
);
809 if (NS_FAILED(surfaceTexture
->AttachToGLContext((int64_t)mGL
, tex
))) {
810 mGL
->fDeleteTextures(1, &tex
);
815 const ScopedBindTexture
savedTex(mGL
, surfaceTexture
->GetTexName(),
816 LOCAL_GL_TEXTURE_EXTERNAL
);
817 surfaceTexture
->UpdateTexImage();
819 gfx::Matrix4x4 transform4
;
820 AndroidSurfaceTexture::GetTransformMatrix(
821 java::sdk::SurfaceTexture::Ref::From(surfaceTexture
), &transform4
);
823 transform3
.at(0, 0) = transform4
._11
;
824 transform3
.at(0, 1) = transform4
._12
;
825 transform3
.at(0, 2) = transform4
._14
;
826 transform3
.at(1, 0) = transform4
._21
;
827 transform3
.at(1, 1) = transform4
._22
;
828 transform3
.at(1, 2) = transform4
._24
;
829 transform3
.at(2, 0) = transform4
._41
;
830 transform3
.at(2, 1) = transform4
._42
;
831 transform3
.at(2, 2) = transform4
._44
;
833 // We don't do w-divison, so if these aren't what we expect, we're probably
834 // doing something wrong.
835 MOZ_ASSERT(transform3
.at(0, 2) == 0);
836 MOZ_ASSERT(transform3
.at(1, 2) == 0);
837 MOZ_ASSERT(transform3
.at(2, 2) == 1);
839 const auto& srcOrigin
= srcImage
->GetOriginPos();
841 // I honestly have no idea why this logic is flipped, but changing the
842 // source origin would mean we'd have to flip it in the compositor
843 // which makes just as little sense as this.
844 const bool yFlip
= (srcOrigin
== destOrigin
);
846 const auto& prog
= GetDrawBlitProg({kFragHeader_TexExt
, kFragBody_RGBA
});
848 // There is no padding on these images, so we can use the GetTransformMatrix
850 const DrawBlitProg::BaseArgs baseArgs
= {transform3
, yFlip
, destSize
,
852 prog
->Draw(baseArgs
, nullptr);
854 if (surfaceTexture
->IsSingleBuffer()) {
855 surfaceTexture
->ReleaseTexImage();
862 // -------------------------------------
864 bool GuessDivisors(const gfx::IntSize
& ySize
, const gfx::IntSize
& uvSize
,
865 gfx::IntSize
* const out_divisors
) {
866 const gfx::IntSize
divisors((ySize
.width
== uvSize
.width
) ? 1 : 2,
867 (ySize
.height
== uvSize
.height
) ? 1 : 2);
868 if (uvSize
.width
* divisors
.width
!= ySize
.width
||
869 uvSize
.height
* divisors
.height
!= ySize
.height
) {
872 *out_divisors
= divisors
;
876 bool GLBlitHelper::BlitImage(layers::PlanarYCbCrImage
* const yuvImage
,
877 const gfx::IntSize
& destSize
,
878 const OriginPos destOrigin
) {
879 const auto& prog
= GetDrawBlitProg({kFragHeader_Tex2D
, kFragBody_PlanarYUV
});
881 if (!mYuvUploads
[0]) {
882 mGL
->fGenTextures(3, mYuvUploads
);
883 const ScopedBindTexture
bindTex(mGL
, mYuvUploads
[0]);
884 mGL
->TexParams_SetClampNoMips();
885 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[1]);
886 mGL
->TexParams_SetClampNoMips();
887 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[2]);
888 mGL
->TexParams_SetClampNoMips();
893 const PlanarYCbCrData
* const yuvData
= yuvImage
->GetData();
895 if (yuvData
->mYSkip
|| yuvData
->mCbSkip
|| yuvData
->mCrSkip
||
896 yuvData
->mYSize
.width
< 0 || yuvData
->mYSize
.height
< 0 ||
897 yuvData
->mCbCrSize
.width
< 0 || yuvData
->mCbCrSize
.height
< 0 ||
898 yuvData
->mYStride
< 0 || yuvData
->mCbCrStride
< 0) {
899 gfxCriticalError() << "Unusual PlanarYCbCrData: " << yuvData
->mYSkip
<< ","
900 << yuvData
->mCbSkip
<< "," << yuvData
->mCrSkip
<< ", "
901 << yuvData
->mYSize
.width
<< "," << yuvData
->mYSize
.height
902 << ", " << yuvData
->mCbCrSize
.width
<< ","
903 << yuvData
->mCbCrSize
.height
<< ", " << yuvData
->mYStride
904 << "," << yuvData
->mCbCrStride
;
908 gfx::IntSize divisors
;
909 if (!GuessDivisors(yuvData
->mYSize
, yuvData
->mCbCrSize
, &divisors
)) {
910 gfxCriticalError() << "GuessDivisors failed:" << yuvData
->mYSize
.width
911 << "," << yuvData
->mYSize
.height
<< ", "
912 << yuvData
->mCbCrSize
.width
<< ","
913 << yuvData
->mCbCrSize
.height
;
919 // RED textures aren't valid in GLES2, and ALPHA textures are not valid in
920 // desktop GL Core Profiles. So use R8 textures on GL3.0+ and GLES3.0+, but
921 // LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
922 GLenum internalFormat
;
924 if (mGL
->IsAtLeast(gl::ContextProfile::OpenGLCore
, 300) ||
925 mGL
->IsAtLeast(gl::ContextProfile::OpenGLES
, 300)) {
926 internalFormat
= LOCAL_GL_R8
;
927 unpackFormat
= LOCAL_GL_RED
;
929 internalFormat
= LOCAL_GL_LUMINANCE
;
930 unpackFormat
= LOCAL_GL_LUMINANCE
;
935 const ScopedSaveMultiTex
saveTex(mGL
, 3, LOCAL_GL_TEXTURE_2D
);
936 const ResetUnpackState
reset(mGL
);
937 const gfx::IntSize
yTexSize(yuvData
->mYStride
, yuvData
->mYSize
.height
);
938 const gfx::IntSize
uvTexSize(yuvData
->mCbCrStride
, yuvData
->mCbCrSize
.height
);
940 if (yTexSize
!= mYuvUploads_YSize
|| uvTexSize
!= mYuvUploads_UVSize
) {
941 mYuvUploads_YSize
= yTexSize
;
942 mYuvUploads_UVSize
= uvTexSize
;
944 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
);
945 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[0]);
946 mGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
, 0, internalFormat
, yTexSize
.width
,
947 yTexSize
.height
, 0, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
949 for (int i
= 1; i
< 3; i
++) {
950 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
951 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[i
]);
952 mGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
, 0, internalFormat
, uvTexSize
.width
,
953 uvTexSize
.height
, 0, unpackFormat
,
954 LOCAL_GL_UNSIGNED_BYTE
, nullptr);
960 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
);
961 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[0]);
962 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
, 0, 0, 0, yTexSize
.width
,
963 yTexSize
.height
, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
965 mGL
->fActiveTexture(LOCAL_GL_TEXTURE1
);
966 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[1]);
967 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
, 0, 0, 0, uvTexSize
.width
,
968 uvTexSize
.height
, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
969 yuvData
->mCbChannel
);
970 mGL
->fActiveTexture(LOCAL_GL_TEXTURE2
);
971 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mYuvUploads
[2]);
972 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
, 0, 0, 0, uvTexSize
.width
,
973 uvTexSize
.height
, unpackFormat
, LOCAL_GL_UNSIGNED_BYTE
,
974 yuvData
->mCrChannel
);
978 const auto& clipRect
= yuvData
->GetPictureRect();
979 const auto srcOrigin
= OriginPos::BottomLeft
;
980 const bool yFlip
= (destOrigin
!= srcOrigin
);
982 const DrawBlitProg::BaseArgs baseArgs
= {SubRectMat3(clipRect
, yTexSize
),
983 yFlip
, destSize
, Nothing()};
984 const DrawBlitProg::YUVArgs yuvArgs
= {
985 SubRectMat3(clipRect
, uvTexSize
, divisors
), yuvData
->mYUVColorSpace
};
986 prog
->Draw(baseArgs
, &yuvArgs
);
990 // -------------------------------------
993 bool GLBlitHelper::BlitImage(layers::MacIOSurfaceImage
* const srcImage
,
994 const gfx::IntSize
& destSize
,
995 const OriginPos destOrigin
) const {
996 return BlitImage(srcImage
->GetSurface(), destSize
, destOrigin
);
999 static std::string
IntAsAscii(const int x
) {
1002 auto u
= static_cast<unsigned int>(x
);
1004 str
.insert(str
.begin(), u
& 0xff);
1007 str
.insert(str
.begin(), '\'');
1008 str
.push_back('\'');
1012 bool GLBlitHelper::BlitImage(MacIOSurface
* const iosurf
,
1013 const gfx::IntSize
& destSize
,
1014 const OriginPos destOrigin
) const {
1016 gfxCriticalError() << "Null MacIOSurface for GLBlitHelper::BlitImage";
1019 if (mGL
->GetContextType() != GLContextType::CGL
) {
1023 const auto glCGL
= static_cast<GLContextCGL
*>(mGL
);
1024 const auto cglContext
= glCGL
->GetCGLContext();
1026 const auto& srcOrigin
= OriginPos::BottomLeft
;
1028 DrawBlitProg::BaseArgs baseArgs
;
1029 baseArgs
.yFlip
= (destOrigin
!= srcOrigin
);
1030 baseArgs
.destSize
= destSize
;
1032 // TODO: The colorspace is known by the IOSurface, why override it?
1033 // See GetYUVColorSpace/GetFullRange()
1034 DrawBlitProg::YUVArgs yuvArgs
;
1035 yuvArgs
.colorSpace
= iosurf
->GetYUVColorSpace();
1037 const DrawBlitProg::YUVArgs
* pYuvArgs
= nullptr;
1039 auto planes
= iosurf
->GetPlaneCount();
1041 planes
= 1; // Bad API. No cookie.
1044 const GLenum texTarget
= LOCAL_GL_TEXTURE_RECTANGLE
;
1045 const char* const fragHeader
= kFragHeader_Tex2DRect
;
1047 const ScopedSaveMultiTex
saveTex(mGL
, planes
, texTarget
);
1048 const ScopedTexture
tex0(mGL
);
1049 const ScopedTexture
tex1(mGL
);
1050 const ScopedTexture
tex2(mGL
);
1051 const GLuint texs
[3] = {tex0
, tex1
, tex2
};
1053 const auto pixelFormat
= iosurf
->GetPixelFormat();
1054 if (mGL
->ShouldSpew()) {
1055 const auto formatStr
= IntAsAscii(pixelFormat
);
1056 printf_stderr("iosurf format: %s (0x%08x)\n", formatStr
.c_str(),
1060 const char* fragBody
;
1063 switch (pixelFormat
) {
1064 case kCVPixelFormatType_24RGB
:
1065 case kCVPixelFormatType_24BGR
:
1066 case kCVPixelFormatType_32ARGB
:
1067 case kCVPixelFormatType_32BGRA
:
1068 case kCVPixelFormatType_32ABGR
:
1069 case kCVPixelFormatType_32RGBA
:
1070 case kCVPixelFormatType_64ARGB
:
1071 case kCVPixelFormatType_48RGB
:
1072 fragBody
= kFragBody_RGBA
;
1074 case kCVPixelFormatType_422YpCbCr8
:
1075 case kCVPixelFormatType_422YpCbCr8_yuvs
:
1076 fragBody
= kFragBody_CrYCb
;
1077 pYuvArgs
= &yuvArgs
;
1081 if (pixelFormat
<= 0xff) {
1082 str
= std::to_string(pixelFormat
);
1084 str
= IntAsAscii(pixelFormat
);
1086 gfxCriticalError() << "Unhandled kCVPixelFormatType_*: " << str
;
1088 // Probably YUV though
1089 fragBody
= kFragBody_CrYCb
;
1090 pYuvArgs
= &yuvArgs
;
1095 fragBody
= kFragBody_NV12
;
1096 pYuvArgs
= &yuvArgs
;
1099 fragBody
= kFragBody_PlanarYUV
;
1100 pYuvArgs
= &yuvArgs
;
1103 gfxCriticalError() << "Unexpected plane count: " << planes
;
1107 for (uint32_t p
= 0; p
< planes
; p
++) {
1108 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ p
);
1109 mGL
->fBindTexture(texTarget
, texs
[p
]);
1110 mGL
->TexParams_SetClampNoMips(texTarget
);
1112 auto err
= iosurf
->CGLTexImageIOSurface2D(mGL
, cglContext
, p
);
1118 const auto width
= iosurf
->GetDevicePixelWidth(p
);
1119 const auto height
= iosurf
->GetDevicePixelHeight(p
);
1120 baseArgs
.texMatrix0
= SubRectMat3(0, 0, width
, height
);
1121 yuvArgs
.texMatrix1
= SubRectMat3(0, 0, width
/ 2.0, height
/ 2.0);
1125 const auto& prog
= GetDrawBlitProg({fragHeader
, fragBody
});
1126 prog
->Draw(baseArgs
, pYuvArgs
);
1131 // -----------------------------------------------------------------------------
1133 void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex
,
1134 const gfx::IntSize
& srcSize
,
1135 const gfx::IntSize
& destSize
,
1136 const GLenum srcTarget
) const {
1137 const char* fragHeader
;
1139 switch (srcTarget
) {
1140 case LOCAL_GL_TEXTURE_2D
:
1141 fragHeader
= kFragHeader_Tex2D
;
1142 texMatrix0
= Mat3::I();
1144 case LOCAL_GL_TEXTURE_RECTANGLE_ARB
:
1145 fragHeader
= kFragHeader_Tex2DRect
;
1146 texMatrix0
= SubRectMat3(0, 0, srcSize
.width
, srcSize
.height
);
1149 gfxCriticalError() << "Unexpected srcTarget: " << srcTarget
;
1152 const auto& prog
= GetDrawBlitProg({fragHeader
, kFragBody_RGBA
});
1154 const ScopedSaveMultiTex
saveTex(mGL
, 1, srcTarget
);
1155 mGL
->fBindTexture(srcTarget
, srcTex
);
1157 const bool yFlip
= false;
1158 const DrawBlitProg::BaseArgs baseArgs
= {texMatrix0
, yFlip
, destSize
,
1160 prog
->Draw(baseArgs
);
1163 // -----------------------------------------------------------------------------
1165 void GLBlitHelper::BlitFramebuffer(const gfx::IntRect
& srcRect
,
1166 const gfx::IntRect
& destRect
,
1167 GLuint filter
) const {
1168 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
1170 const ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
1171 mGL
->fBlitFramebuffer(srcRect
.x
, srcRect
.y
, srcRect
.XMost(), srcRect
.YMost(),
1172 destRect
.x
, destRect
.y
, destRect
.XMost(),
1173 destRect
.YMost(), LOCAL_GL_COLOR_BUFFER_BIT
, filter
);
1178 void GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB
,
1179 const GLuint destFB
,
1180 const gfx::IntRect
& srcRect
,
1181 const gfx::IntRect
& destRect
,
1182 GLuint filter
) const {
1183 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
1184 MOZ_GL_ASSERT(mGL
, !srcFB
|| mGL
->fIsFramebuffer(srcFB
));
1185 MOZ_GL_ASSERT(mGL
, !destFB
|| mGL
->fIsFramebuffer(destFB
));
1187 const ScopedBindFramebuffer
boundFB(mGL
);
1188 mGL
->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER
, srcFB
);
1189 mGL
->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER
, destFB
);
1191 BlitFramebuffer(srcRect
, destRect
, filter
);
1194 void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex
,
1195 const gfx::IntSize
& srcSize
,
1196 const gfx::IntSize
& destSize
,
1197 GLenum srcTarget
) const {
1198 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(srcTex
));
1200 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
1201 const ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
1202 const ScopedBindFramebuffer
bindFB(mGL
);
1203 mGL
->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER
, srcWrapper
.FB());
1204 BlitFramebuffer(gfx::IntRect({}, srcSize
), gfx::IntRect({}, destSize
));
1208 DrawBlitTextureToFramebuffer(srcTex
, srcSize
, destSize
, srcTarget
);
1211 void GLBlitHelper::BlitFramebufferToTexture(GLuint destTex
,
1212 const gfx::IntSize
& srcSize
,
1213 const gfx::IntSize
& destSize
,
1214 GLenum destTarget
) const {
1215 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(destTex
));
1217 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
1218 const ScopedFramebufferForTexture
destWrapper(mGL
, destTex
, destTarget
);
1219 const ScopedBindFramebuffer
bindFB(mGL
);
1220 mGL
->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER
, destWrapper
.FB());
1221 BlitFramebuffer(gfx::IntRect({}, srcSize
), gfx::IntRect({}, destSize
));
1225 ScopedBindTexture
autoTex(mGL
, destTex
, destTarget
);
1226 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
1227 mGL
->fCopyTexSubImage2D(destTarget
, 0, 0, 0, 0, 0, srcSize
.width
,
1231 void GLBlitHelper::BlitTextureToTexture(GLuint srcTex
, GLuint destTex
,
1232 const gfx::IntSize
& srcSize
,
1233 const gfx::IntSize
& destSize
,
1235 GLenum destTarget
) const {
1236 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(srcTex
));
1237 MOZ_GL_ASSERT(mGL
, mGL
->fIsTexture(destTex
));
1239 // Start down the CopyTexSubImage path, not the DrawBlit path.
1240 const ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
1241 const ScopedBindFramebuffer
bindFB(mGL
, srcWrapper
.FB());
1242 BlitFramebufferToTexture(destTex
, srcSize
, destSize
, destTarget
);
1245 // -------------------------------------
1247 bool GLBlitHelper::BlitImage(layers::GPUVideoImage
* const srcImage
,
1248 const gfx::IntSize
& destSize
,
1249 const OriginPos destOrigin
) const {
1250 const auto& data
= srcImage
->GetData();
1251 if (!data
) return false;
1253 const auto& desc
= data
->SD();
1257 layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder
);
1258 const auto& subdescUnion
=
1259 desc
.get_SurfaceDescriptorRemoteDecoder().subdesc();
1260 switch (subdescUnion
.type()) {
1261 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDMABuf
: {
1266 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorD3D10
: {
1267 const auto& subdesc
= subdescUnion
.get_SurfaceDescriptorD3D10();
1268 return BlitDescriptor(subdesc
, destSize
, destOrigin
);
1270 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDXGIYCbCr
: {
1271 const auto& subdesc
= subdescUnion
.get_SurfaceDescriptorDXGIYCbCr();
1272 return BlitDescriptor(subdesc
, destSize
, destOrigin
);
1276 case layers::RemoteDecoderVideoSubDescriptor::
1277 TSurfaceDescriptorMacIOSurface
: {
1278 const auto& subdesc
= subdescUnion
.get_SurfaceDescriptorMacIOSurface();
1279 RefPtr
<MacIOSurface
> surface
= MacIOSurface::LookupSurface(
1280 subdesc
.surfaceId(), !subdesc
.isOpaque(), subdesc
.yUVColorSpace());
1281 MOZ_ASSERT(surface
);
1285 return BlitImage(surface
, destSize
, destOrigin
);
1288 case layers::RemoteDecoderVideoSubDescriptor::Tnull_t
:
1289 // This GPUVideoImage isn't directly readable outside the GPU process.
1293 gfxCriticalError() << "Unhandled subdesc type: "
1294 << uint32_t(subdescUnion
.type());
1299 // -------------------------------------
1301 bool GLBlitHelper::BlitImage(layers::DMABUFSurfaceImage
* srcImage
,
1302 const gfx::IntSize
& destSize
,
1303 OriginPos destOrigin
) const {
1304 DMABufSurface
* surface
= srcImage
->GetSurface();
1306 gfxCriticalError() << "Null DMABUFSurface for GLBlitHelper::BlitImage";
1310 const auto& srcOrigin
= OriginPos::BottomLeft
;
1312 DrawBlitProg::BaseArgs baseArgs
;
1313 baseArgs
.yFlip
= (destOrigin
!= srcOrigin
);
1314 baseArgs
.destSize
= destSize
;
1316 // TODO: The colorspace is known by the DMABUFSurface, why override it?
1317 // See GetYUVColorSpace/GetFullRange()
1318 DrawBlitProg::YUVArgs yuvArgs
;
1319 yuvArgs
.colorSpace
= surface
->GetYUVColorSpace();
1321 const DrawBlitProg::YUVArgs
* pYuvArgs
= nullptr;
1323 const auto planes
= surface
->GetTextureCount();
1324 const GLenum texTarget
= LOCAL_GL_TEXTURE_2D
;
1326 const ScopedSaveMultiTex
saveTex(mGL
, planes
, texTarget
);
1327 const auto pixelFormat
= surface
->GetSurfaceType();
1329 const char* fragBody
;
1330 switch (pixelFormat
) {
1331 case DMABufSurface::SURFACE_RGBA
:
1332 fragBody
= kFragBody_RGBA
;
1334 case DMABufSurface::SURFACE_NV12
:
1335 fragBody
= kFragBody_NV12
;
1336 pYuvArgs
= &yuvArgs
;
1338 case DMABufSurface::SURFACE_YUV420
:
1339 fragBody
= kFragBody_PlanarYUV
;
1340 pYuvArgs
= &yuvArgs
;
1343 gfxCriticalError() << "Unexpected pixel format: " << pixelFormat
;
1347 for (const auto p
: IntegerRange(planes
)) {
1348 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ p
);
1349 mGL
->fBindTexture(texTarget
, surface
->GetTexture(p
));
1350 mGL
->TexParams_SetClampNoMips(texTarget
);
1353 // We support only NV12/YUV420 formats only with 1/2 texture scale.
1354 // We don't set cliprect as DMABus textures are created without padding.
1355 baseArgs
.texMatrix0
= SubRectMat3(0, 0, 1, 1);
1356 yuvArgs
.texMatrix1
= SubRectMat3(0, 0, 1, 1);
1358 const auto& prog
= GetDrawBlitProg({kFragHeader_Tex2D
, fragBody
});
1359 prog
->Draw(baseArgs
, pYuvArgs
);
1366 } // namespace mozilla