Bug 1728955: part 6) Log result of Windows' `OleSetClipboardResult`. r=masayuki
[gecko.git] / gfx / gl / GLBlitHelper.cpp
blob12823041d3d535aa41b2964a463889e58276b9d4
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"
9 #include "GLContext.h"
10 #include "GLScreenBuffer.h"
11 #include "GPUVideoImage.h"
12 #include "HeapCopyOfStackArray.h"
13 #include "ImageContainer.h"
14 #include "ScopedGLHelpers.h"
15 #include "gfxUtils.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"
29 #endif
31 #ifdef XP_MACOSX
32 # include "GLContextCGL.h"
33 # include "MacIOSurfaceImage.h"
34 #endif
36 #ifdef XP_WIN
37 # include "mozilla/layers/D3D11ShareHandleImage.h"
38 # include "mozilla/layers/D3D11YCbCrImage.h"
39 #endif
41 #ifdef MOZ_WAYLAND
42 # include "mozilla/layers/DMABUFSurfaceImage.h"
43 # include "mozilla/widget/DMABufSurface.h"
44 #endif
46 using mozilla::layers::PlanarYCbCrData;
47 using mozilla::layers::PlanarYCbCrImage;
49 namespace mozilla {
50 namespace gl {
52 // --
54 const char* const kFragHeader_Tex2D =
56 #define SAMPLER sampler2D \n\
57 #if __VERSION__ >= 130 \n\
58 #define TEXTURE texture \n\
59 #else \n\
60 #define TEXTURE texture2D \n\
61 #endif \n\
63 const char* const kFragHeader_Tex2DRect =
65 #define SAMPLER sampler2DRect \n\
66 #if __VERSION__ >= 130 \n\
67 #define TEXTURE texture \n\
68 #else \n\
69 #define TEXTURE texture2DRect \n\
70 #endif \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\
77 #else \n\
78 #define TEXTURE texture2D \n\
79 #endif \n\
80 #define SAMPLER samplerExternalOES \n\
83 const char* const kFragBody_RGBA =
85 VARYING vec2 vTexCoord0; \n\
86 uniform SAMPLER uTex0; \n\
87 \n\
88 void main(void) \n\
89 { \n\
90 FRAG_COLOR = TEXTURE(uTex0, vTexCoord0); \n\
91 } \n\
93 const char* const kFragBody_CrYCb =
95 VARYING vec2 vTexCoord0; \n\
96 uniform SAMPLER uTex0; \n\
97 uniform MAT4X3 uColorMatrix; \n\
98 \n\
99 void main(void) \n\
100 { \n\
101 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr, \n\
102 1.0); \n\
103 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
104 } \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\
114 void main(void) \n\
115 { \n\
116 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
117 TEXTURE(uTex1, vTexCoord1).xy, \n\
118 1.0); \n\
119 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
120 } \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\
131 void main(void) \n\
132 { \n\
133 vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
134 TEXTURE(uTex1, vTexCoord1).x, \n\
135 TEXTURE(uTex2, vTexCoord1).x, \n\
136 1.0); \n\
137 FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
138 } \n\
141 // --
143 template <uint8_t N>
144 /*static*/ Mat<N> Mat<N>::Zero() {
145 Mat<N> ret;
146 for (auto& x : ret.m) {
147 x = 0.0f;
149 return ret;
152 template <uint8_t N>
153 /*static*/ Mat<N> Mat<N>::I() {
154 auto ret = Mat<N>::Zero();
155 for (uint8_t i = 0; i < N; i++) {
156 ret.at(i, i) = 1.0f;
158 return ret;
161 template <uint8_t N>
162 Mat<N> Mat<N>::operator*(const Mat<N>& r) const {
163 Mat<N> ret;
164 for (uint8_t x = 0; x < N; x++) {
165 for (uint8_t y = 0; y < N; y++) {
166 float sum = 0.0f;
167 for (uint8_t i = 0; i < N; i++) {
168 sum += at(i, y) * r.at(x, i);
170 ret.at(x, y) = sum;
173 return ret;
176 Mat3 SubRectMat3(const float x, const float y, const float w, const float h) {
177 auto ret = Mat3::Zero();
178 ret.at(0, 0) = w;
179 ret.at(1, 1) = h;
180 ret.at(2, 0) = x;
181 ret.at(2, 1) = y;
182 ret.at(2, 2) = 1.0f;
183 return ret;
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);
203 // --
205 ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl,
206 const uint8_t texCount,
207 const GLenum texTarget)
208 : mGL(*gl),
209 mTexCount(texCount),
210 mTexTarget(texTarget),
211 mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE)) {
212 GLenum texBinding;
213 switch (mTexTarget) {
214 case LOCAL_GL_TEXTURE_2D:
215 texBinding = LOCAL_GL_TEXTURE_BINDING_2D;
216 break;
217 case LOCAL_GL_TEXTURE_RECTANGLE:
218 texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE;
219 break;
220 case LOCAL_GL_TEXTURE_EXTERNAL:
221 texBinding = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
222 break;
223 default:
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);
248 // --
250 class ScopedBindArrayBuffer final {
251 GLContext& mGL;
252 const GLuint mOldVBO;
254 public:
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); }
263 // --
265 class ScopedShader final {
266 GLContext& mGL;
267 const GLuint mName;
269 public:
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; }
278 // --
280 class SaveRestoreCurrentProgram final {
281 GLContext& mGL;
282 const GLuint mOld;
284 public:
285 explicit SaveRestoreCurrentProgram(GLContext* const gl)
286 : mGL(*gl), mOld(mGL.GetIntAs<GLuint>(LOCAL_GL_CURRENT_PROGRAM)) {}
288 ~SaveRestoreCurrentProgram() { mGL.fUseProgram(mOld); }
291 // --
293 class ScopedDrawBlitState final {
294 GLContext& mGL;
296 const bool blend;
297 const bool cullFace;
298 const bool depthTest;
299 const bool dither;
300 const bool polyOffsFill;
301 const bool sampleAToC;
302 const bool sampleCover;
303 const bool scissor;
304 const bool stencil;
305 Maybe<bool> rasterizerDiscard;
307 realGLboolean colorMask[4];
308 GLint viewport[4];
310 public:
311 ScopedDrawBlitState(GLContext* const gl, const gfx::IntSize& destSize)
312 : mGL(*gl),
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.
325 rasterizerDiscard =
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]);
356 // --
358 DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog)
359 : mParent(*parent),
360 mProg(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")),
364 mLoc_uColorMatrix(
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};
377 GLint size = 0;
378 GLenum type = 0;
379 for (int32_t i = 0; i < numActiveUniforms; i++) {
380 gl->fGetActiveUniform(mProg, i, kMaxNameSize, nullptr, &size, &type,
381 name);
382 if (strcmp("uColorMatrix", name) == 0) {
383 mType_uColorMatrix = type;
384 break;
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);
405 // --
407 Mat3 destMatrix;
408 if (args.destRect) {
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);
414 } else {
415 destMatrix = Mat3::I();
418 if (args.yFlip) {
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));
429 if (argsYUV) {
430 gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m);
432 const auto& colorMatrix =
433 gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
434 float mat4x3[4 * 3];
435 switch (mType_uColorMatrix) {
436 case LOCAL_GL_FLOAT_MAT4:
437 gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
438 break;
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);
446 break;
447 default:
448 gfxCriticalError() << "Bad mType_uColorMatrix: "
449 << gfx::hexa(mType_uColorMatrix);
453 // --
455 const ScopedDrawBlitState drawState(gl, args.destSize);
457 GLuint oldVAO;
458 GLint vaa0Enabled;
459 GLint vaa0Size;
460 GLenum vaa0Type;
461 GLint vaa0Normalized;
462 GLsizei vaa0Stride;
463 GLvoid* vaa0Pointer;
464 if (mParent.mQuadVAO) {
465 oldVAO = gl->GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING);
466 gl->fBindVertexArray(mParent.mQuadVAO);
467 } else {
468 // clang-format off
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);
475 // clang-format on
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);
486 } else {
487 if (vaa0Enabled) {
488 gl->fEnableVertexAttribArray(0);
489 } else {
490 gl->fDisableVertexAttribArray(0);
492 gl->fVertexAttribPointer(0, vaa0Size, vaa0Type, bool(vaa0Normalized),
493 vaa0Stride, vaa0Pointer);
497 // --
499 GLBlitHelper::GLBlitHelper(GLContext* const gl)
500 : mGL(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);
526 // --
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.
533 if (mGL->IsGLES()) {
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\
544 #else \n\
545 #define ATTRIBUTE attribute \n\
546 #define VARYING varying \n\
547 #endif \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\
558 void main(void) \n\
559 { \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\
565 } \n\
567 const char* const parts[] = {mDrawBlitProg_VersionLine.get(), kVertSource};
568 mGL->fShaderSource(mDrawBlitProg_VertShader, ArrayLength(parts), parts,
569 nullptr);
570 mGL->fCompileShader(mDrawBlitProg_VertShader);
573 GLBlitHelper::~GLBlitHelper() {
574 for (const auto& pair : mDrawBlitProgs) {
575 const auto& ptr = pair.second;
576 delete ptr;
578 mDrawBlitProgs.clear();
580 if (!mGL->MakeCurrent()) return;
582 mGL->fDeleteShader(mDrawBlitProg_VertShader);
583 mGL->fDeleteBuffers(1, &mQuadVBO);
585 if (mQuadVAO) {
586 mGL->fDeleteVertexArrays(1, &mQuadVAO);
590 // --
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;
597 if (didInsert) {
598 pair.second = CreateDrawBlitProg(pair.first);
600 return pair.second;
603 const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg(
604 const DrawBlitProg::Key& key) const {
605 const char kFragHeader_Global[] =
607 #ifdef GL_ES \n\
608 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
609 precision highp float; \n\
610 #else \n\
611 precision mediump float; \n\
612 #endif \n\
613 #endif \n\
615 #if __VERSION__ >= 130 \n\
616 #define VARYING in \n\
617 #define FRAG_COLOR oFragColor \n\
618 out vec4 FRAG_COLOR; \n\
619 #else \n\
620 #define VARYING varying \n\
621 #define FRAG_COLOR gl_FragColor \n\
622 #endif \n\
624 #if __VERSION__ >= 120 \n\
625 #define MAT4X3 mat4x3 \n\
626 #else \n\
627 #define MAT4X3 mat4 \n\
628 #endif \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);
644 GLenum status = 0;
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;
666 GLuint vsLogLen = 0;
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());
670 vsLog[vsLogLen] = 0;
672 GLuint fsLogLen = 0;
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());
676 fsLog[fsLogLen] = 0;
678 gfxCriticalError() << "DrawBlitProg link failed:\n"
679 << "progLog: " << progLog.get() << "\n"
680 << "vsLog: " << vsLog.get() << "\n"
681 << "fsLog: " << fsLog.get() << "\n";
682 MOZ_CRASH();
685 // -----------------------------------------------------------------------------
687 #ifdef XP_MACOSX
688 static RefPtr<MacIOSurface> LookupSurface(
689 const layers::SurfaceDescriptorMacIOSurface& sd) {
690 return MacIOSurface::LookupSurface(sd.surfaceId(), !sd.isOpaque(),
691 sd.yUVColorSpace());
693 #endif
695 bool GLBlitHelper::BlitSdToFramebuffer(const layers::SurfaceDescriptor& asd,
696 const gfx::IntSize& destSize,
697 const OriginPos destOrigin) {
698 const auto sdType = asd.type();
699 switch (sdType) {
700 #ifdef XP_WIN
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);
709 #endif
710 #ifdef XP_MACOSX
711 case layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
712 const auto& sd = asd.get_SurfaceDescriptorMacIOSurface();
713 const auto surf = LookupSurface(sd);
714 if (!surf) {
715 NS_WARNING("LookupSurface(MacIOSurface) failed");
716 // Sometimes that frame for our handle gone already. That's life, for
717 // now.
718 return false;
720 return BlitImage(surf, destSize, destOrigin);
722 #endif
723 default:
724 return false;
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,
734 destOrigin);
736 case ImageFormat::SURFACE_TEXTURE:
737 #ifdef MOZ_WIDGET_ANDROID
738 return BlitImage(static_cast<layers::SurfaceTextureImage*>(srcImage),
739 destSize, destOrigin);
740 #else
741 MOZ_ASSERT(false);
742 return false;
743 #endif
745 case ImageFormat::MAC_IOSURFACE:
746 #ifdef XP_MACOSX
747 return BlitImage(srcImage->AsMacIOSurfaceImage(), destSize, destOrigin);
748 #else
749 MOZ_ASSERT(false);
750 return false;
751 #endif
753 case ImageFormat::GPU_VIDEO:
754 return BlitImage(static_cast<layers::GPUVideoImage*>(srcImage), destSize,
755 destOrigin);
756 #ifdef XP_WIN
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
765 #else
766 case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE:
767 case ImageFormat::D3D11_YCBCR_IMAGE:
768 case ImageFormat::D3D9_RGB32_TEXTURE:
769 MOZ_ASSERT(false);
770 return false;
771 #endif
772 case ImageFormat::DMABUF:
773 #ifdef MOZ_WAYLAND
774 return BlitImage(static_cast<layers::DMABUFSurfaceImage*>(srcImage),
775 destSize, destOrigin);
776 #else
777 return false;
778 #endif
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
786 return false;
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) {
799 return false;
802 const ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
804 if (!surfaceTexture->IsAttachedToGLContext((int64_t)mGL)) {
805 GLuint tex;
806 mGL->MakeCurrent();
807 mGL->fGenTextures(1, &tex);
809 if (NS_FAILED(surfaceTexture->AttachToGLContext((int64_t)mGL, tex))) {
810 mGL->fDeleteTextures(1, &tex);
811 return false;
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);
822 Mat3 transform3;
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
849 // directly.
850 const DrawBlitProg::BaseArgs baseArgs = {transform3, yFlip, destSize,
851 Nothing()};
852 prog->Draw(baseArgs, nullptr);
854 if (surfaceTexture->IsSingleBuffer()) {
855 surfaceTexture->ReleaseTexImage();
858 return true;
860 #endif
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) {
870 return false;
872 *out_divisors = divisors;
873 return true;
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();
891 // --
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;
905 return false;
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;
914 return false;
917 // --
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;
923 GLenum unpackFormat;
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;
928 } else {
929 internalFormat = LOCAL_GL_LUMINANCE;
930 unpackFormat = LOCAL_GL_LUMINANCE;
933 // --
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,
948 nullptr);
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);
958 // --
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,
964 yuvData->mYChannel);
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);
976 // --
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);
987 return true;
990 // -------------------------------------
992 #ifdef XP_MACOSX
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) {
1000 std::string str;
1001 str.reserve(6);
1002 auto u = static_cast<unsigned int>(x);
1003 while (u) {
1004 str.insert(str.begin(), u & 0xff);
1005 u >>= 8;
1007 str.insert(str.begin(), '\'');
1008 str.push_back('\'');
1009 return str;
1012 bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
1013 const gfx::IntSize& destSize,
1014 const OriginPos destOrigin) const {
1015 if (!iosurf) {
1016 gfxCriticalError() << "Null MacIOSurface for GLBlitHelper::BlitImage";
1017 return false;
1019 if (mGL->GetContextType() != GLContextType::CGL) {
1020 MOZ_ASSERT(false);
1021 return false;
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();
1040 if (!planes) {
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(),
1057 pixelFormat);
1060 const char* fragBody;
1061 switch (planes) {
1062 case 1:
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;
1073 break;
1074 case kCVPixelFormatType_422YpCbCr8:
1075 case kCVPixelFormatType_422YpCbCr8_yuvs:
1076 fragBody = kFragBody_CrYCb;
1077 pYuvArgs = &yuvArgs;
1078 break;
1079 default: {
1080 std::string str;
1081 if (pixelFormat <= 0xff) {
1082 str = std::to_string(pixelFormat);
1083 } else {
1084 str = IntAsAscii(pixelFormat);
1086 gfxCriticalError() << "Unhandled kCVPixelFormatType_*: " << str;
1088 // Probably YUV though
1089 fragBody = kFragBody_CrYCb;
1090 pYuvArgs = &yuvArgs;
1091 break;
1093 break;
1094 case 2:
1095 fragBody = kFragBody_NV12;
1096 pYuvArgs = &yuvArgs;
1097 break;
1098 case 3:
1099 fragBody = kFragBody_PlanarYUV;
1100 pYuvArgs = &yuvArgs;
1101 break;
1102 default:
1103 gfxCriticalError() << "Unexpected plane count: " << planes;
1104 return false;
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);
1113 if (err) {
1114 return false;
1117 if (p == 0) {
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);
1127 return true;
1129 #endif
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;
1138 Mat3 texMatrix0;
1139 switch (srcTarget) {
1140 case LOCAL_GL_TEXTURE_2D:
1141 fragHeader = kFragHeader_Tex2D;
1142 texMatrix0 = Mat3::I();
1143 break;
1144 case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
1145 fragHeader = kFragHeader_Tex2DRect;
1146 texMatrix0 = SubRectMat3(0, 0, srcSize.width, srcSize.height);
1147 break;
1148 default:
1149 gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
1150 return;
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,
1159 Nothing()};
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);
1176 // --
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));
1205 return;
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));
1222 return;
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,
1228 srcSize.height);
1231 void GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
1232 const gfx::IntSize& srcSize,
1233 const gfx::IntSize& destSize,
1234 GLenum srcTarget,
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();
1255 MOZ_ASSERT(
1256 desc.type() ==
1257 layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder);
1258 const auto& subdescUnion =
1259 desc.get_SurfaceDescriptorRemoteDecoder().subdesc();
1260 switch (subdescUnion.type()) {
1261 case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDMABuf: {
1262 // TODO.
1263 return false;
1265 #ifdef XP_WIN
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);
1274 #endif
1275 #ifdef XP_MACOSX
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);
1282 if (!surface) {
1283 return false;
1285 return BlitImage(surface, destSize, destOrigin);
1287 #endif
1288 case layers::RemoteDecoderVideoSubDescriptor::Tnull_t:
1289 // This GPUVideoImage isn't directly readable outside the GPU process.
1290 // Abort.
1291 return false;
1292 default:
1293 gfxCriticalError() << "Unhandled subdesc type: "
1294 << uint32_t(subdescUnion.type());
1295 return false;
1299 // -------------------------------------
1300 #ifdef MOZ_WAYLAND
1301 bool GLBlitHelper::BlitImage(layers::DMABUFSurfaceImage* srcImage,
1302 const gfx::IntSize& destSize,
1303 OriginPos destOrigin) const {
1304 DMABufSurface* surface = srcImage->GetSurface();
1305 if (!surface) {
1306 gfxCriticalError() << "Null DMABUFSurface for GLBlitHelper::BlitImage";
1307 return false;
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;
1333 break;
1334 case DMABufSurface::SURFACE_NV12:
1335 fragBody = kFragBody_NV12;
1336 pYuvArgs = &yuvArgs;
1337 break;
1338 case DMABufSurface::SURFACE_YUV420:
1339 fragBody = kFragBody_PlanarYUV;
1340 pYuvArgs = &yuvArgs;
1341 break;
1342 default:
1343 gfxCriticalError() << "Unexpected pixel format: " << pixelFormat;
1344 return false;
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);
1361 return true;
1363 #endif
1365 } // namespace gl
1366 } // namespace mozilla