--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5244,19 +5244,27 @@ CanvasRenderingContext2D::DrawImage(cons
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGB, srcImage->GetSize().width, srcImage->GetSize().height, 0, LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5, nullptr);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
- bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage, srcImage->GetSize(),
- videoTexture, LOCAL_GL_TEXTURE_2D,
- destOrigin);
+ bool ok = false;
+ do {
+ const gl::ScopedFramebufferForTexture autoFBForTex(gl, videoTexture);
+ if (!autoFBForTex.IsComplete()) {
+ MOZ_ASSERT(false, "ScopedFramebufferForTexture not complete.");
+ break;
+ }
+ const gl::ScopedBindFramebuffer bindFB(gl, autoFBForTex.FB());
+ ok = gl->BlitHelper()->BlitImageToFramebuffer(srcImage, srcImage->GetSize(),
+ destOrigin);
+ } while (false);
if (ok) {
NativeSurface texSurf;
texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE;
texSurf.mFormat = SurfaceFormat::R5G6B5_UINT16;
texSurf.mSize.width = srcImage->GetSize().width;
texSurf.mSize.height = srcImage->GetSize().height;
texSurf.mSurface = (void*)((uintptr_t)videoTexture);
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -696,19 +696,17 @@ TexUnpackImage::TexOrSubImage(bool isSub
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
fallbackReason = "bug: failed to confirm FB for blit";
break;
}
const gfx::IntSize destSize(mWidth, mHeight);
const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
- if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(),
- dstOrigin))
- {
+ if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, dstOrigin)) {
fallbackReason = "likely bug: failed to blit";
break;
}
// Blitting was successful, so we're done!
*out_error = 0;
return true;
} while (false);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -716,16 +716,22 @@ WebGLContext::InitAndValidateGL(FailureR
if (IsWebGL2() &&
!InitWebGL2(out_failReason))
{
// Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
return false;
}
+ if (!gl->IsSupported(GLFeature::vertex_array_object)) {
+ *out_failReason = { "FEATURE_FAILURE_WEBGL_VAOS",
+ "Requires vertex_array_object." };
+ return false;
+ }
+
mDefaultVertexArray = WebGLVertexArray::Create(this);
mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
mBoundVertexArray = mDefaultVertexArray;
// OpenGL core profiles remove the default VAO object from version
// 4.0.0. We create a default VAO for all core profiles,
// regardless of version.
//
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1828,18 +1828,21 @@ ScopedCopyTexImageSource::ScopedCopyTexI
MOZ_CRASH("GFX: Temp framebuffer is not complete.");
}
// Restore RB binding.
scopedRB.Unwrap(); // This function should really have a better name.
// Draw-blit rgbaTex into rgbaFB.
const gfx::IntSize srcSize(srcWidth, srcHeight);
- gl->BlitHelper()->DrawBlitTextureToFramebuffer(scopedTex.Texture(), rgbaFB,
- srcSize, srcSize);
+ {
+ const gl::ScopedBindFramebuffer bindFB(gl, rgbaFB);
+ gl->BlitHelper()->DrawBlitTextureToFramebuffer(scopedTex.Texture(), srcSize,
+ srcSize);
+ }
// Restore Tex2D binding and destroy the temp tex.
scopedBindTex.Unwrap();
scopedTex.Unwrap();
// Leave RB and FB alive, and FB bound.
mRB = rgbaRB;
mFB = rgbaFB;
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -7,18 +7,20 @@
#include "gfxUtils.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
#include "GLScreenBuffer.h"
#include "ScopedGLHelpers.h"
#include "mozilla/Preferences.h"
#include "ImageContainer.h"
#include "HeapCopyOfStackArray.h"
+#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/UniquePtr.h"
+#include "GPUVideoImage.h"
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidSurfaceTexture.h"
#include "GLImages.h"
#include "GLLibraryEGL.h"
#endif
#ifdef XP_MACOSX
@@ -27,992 +29,930 @@
#endif
using mozilla::layers::PlanarYCbCrImage;
using mozilla::layers::PlanarYCbCrData;
namespace mozilla {
namespace gl {
-GLBlitHelper::GLBlitHelper(GLContext* gl)
+// --
+
+ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, const uint8_t texCount,
+ const GLenum texTarget)
+ : mGL(*gl)
+ , mTexCount(texCount)
+ , mTexTarget(texTarget)
+ , mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE))
+{
+ GLenum texBinding;
+ switch (mTexTarget) {
+ case LOCAL_GL_TEXTURE_2D:
+ texBinding = LOCAL_GL_TEXTURE_BINDING_2D;
+ break;
+ case LOCAL_GL_TEXTURE_RECTANGLE:
+ texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE;
+ break;
+ case LOCAL_GL_TEXTURE_EXTERNAL:
+ texBinding = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
+ break;
+ default:
+ gfxCriticalError() << "Unhandled texTarget: " << texTarget;
+ }
+
+ for (uint8_t i = 0; i < mTexCount; i++) {
+ mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ if (mGL.IsSupported(GLFeature::sampler_objects)) {
+ mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING);
+ mGL.fBindSampler(i, 0);
+ }
+ mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding);
+ }
+}
+
+ScopedSaveMultiTex::~ScopedSaveMultiTex()
+{
+ for (uint8_t i = 0; i < mTexCount; i++) {
+ mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ if (mGL.IsSupported(GLFeature::sampler_objects)) {
+ mGL.fBindSampler(i, mOldTexSampler[i]);
+ }
+ mGL.fBindTexture(mTexTarget, mOldTex[i]);
+ }
+ mGL.fActiveTexture(mOldTexUnit);
+}
+
+// --
+
+class ScopedBindArrayBuffer final
+{
+ GLContext& mGL;
+ const GLuint mOldVBO;
+
+public:
+ ScopedBindArrayBuffer(GLContext* const gl, const GLuint vbo)
+ : mGL(*gl)
+ , mOldVBO(mGL.GetIntAs<GLuint>(LOCAL_GL_ARRAY_BUFFER_BINDING))
+ {
+ mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
+ }
+
+ ~ScopedBindArrayBuffer()
+ {
+ mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mOldVBO);
+ }
+};
+
+// --
+
+class ScopedBindVAO final
+{
+ GLContext& mGL;
+ const GLuint mOldVAO;
+
+public:
+ ScopedBindVAO(GLContext* const gl, const GLuint vao)
+ : mGL(*gl)
+ , mOldVAO(mGL.GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING))
+ {
+ mGL.fBindVertexArray(vao);
+ }
+
+ ~ScopedBindVAO()
+ {
+ mGL.fBindVertexArray(mOldVAO);
+ }
+};
+
+// --
+
+class ScopedShader final
+{
+ GLContext& mGL;
+ const GLuint mName;
+
+public:
+ ScopedShader(GLContext* const gl, const GLenum shaderType)
+ : mGL(*gl)
+ , mName(mGL.fCreateShader(shaderType))
+ { }
+
+ ~ScopedShader()
+ {
+ mGL.fDeleteShader(mName);
+ }
+
+ operator GLuint() const { return mName; }
+};
+
+// --
+
+class SaveRestoreCurrentProgram final
+{
+ GLContext& mGL;
+ const GLuint mOld;
+
+public:
+ explicit SaveRestoreCurrentProgram(GLContext* const gl)
+ : mGL(*gl)
+ , mOld(mGL.GetIntAs<GLuint>(LOCAL_GL_CURRENT_PROGRAM))
+ { }
+
+ ~SaveRestoreCurrentProgram()
+ {
+ mGL.fUseProgram(mOld);
+ }
+};
+
+// --
+
+class ScopedDrawBlitState final
+{
+ GLContext& mGL;
+
+ const bool blend;
+ const bool cullFace;
+ const bool depthTest;
+ const bool dither;
+ const bool polyOffsFill;
+ const bool sampleAToC;
+ const bool sampleCover;
+ const bool scissor;
+ const bool stencil;
+ Maybe<bool> rasterizerDiscard;
+
+ realGLboolean colorMask[4];
+ GLint viewport[4];
+
+public:
+ ScopedDrawBlitState(GLContext* const gl, const gfx::IntSize& destSize)
+ : mGL(*gl)
+ , blend (mGL.PushEnabled(LOCAL_GL_BLEND, false))
+ , cullFace (mGL.PushEnabled(LOCAL_GL_CULL_FACE, false))
+ , depthTest (mGL.PushEnabled(LOCAL_GL_DEPTH_TEST, false))
+ , dither (mGL.PushEnabled(LOCAL_GL_DITHER, true))
+ , polyOffsFill(mGL.PushEnabled(LOCAL_GL_POLYGON_OFFSET_FILL, false))
+ , sampleAToC (mGL.PushEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false))
+ , sampleCover (mGL.PushEnabled(LOCAL_GL_SAMPLE_COVERAGE, false))
+ , scissor (mGL.PushEnabled(LOCAL_GL_SCISSOR_TEST, false))
+ , stencil (mGL.PushEnabled(LOCAL_GL_STENCIL_TEST, false))
+ {
+ if (mGL.IsSupported(GLFeature::transform_feedback2)) {
+ // Technically transform_feedback2 requires transform_feedback, which actually
+ // adds RASTERIZER_DISCARD.
+ rasterizerDiscard = Some(mGL.PushEnabled(LOCAL_GL_RASTERIZER_DISCARD, false));
+ }
+
+ mGL.fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
+ mGL.fColorMask(true, true, true, true);
+
+ mGL.fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+ mGL.fViewport(0, 0, destSize.width, destSize.height);
+ }
+
+ ~ScopedDrawBlitState()
+ {
+ mGL.SetEnabled(LOCAL_GL_BLEND, blend );
+ mGL.SetEnabled(LOCAL_GL_CULL_FACE, cullFace );
+ mGL.SetEnabled(LOCAL_GL_DEPTH_TEST, depthTest );
+ mGL.SetEnabled(LOCAL_GL_DITHER, dither );
+ mGL.SetEnabled(LOCAL_GL_POLYGON_OFFSET_FILL, polyOffsFill);
+ mGL.SetEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, sampleAToC );
+ mGL.SetEnabled(LOCAL_GL_SAMPLE_COVERAGE, sampleCover );
+ mGL.SetEnabled(LOCAL_GL_SCISSOR_TEST, scissor );
+ mGL.SetEnabled(LOCAL_GL_STENCIL_TEST, stencil );
+ if (rasterizerDiscard) {
+ mGL.SetEnabled(LOCAL_GL_RASTERIZER_DISCARD, rasterizerDiscard.value());
+ }
+
+ mGL.fColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
+ mGL.fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+ }
+};
+
+// --
+
+DrawBlitProg::DrawBlitProg(GLBlitHelper* const parent, const GLuint prog)
+ : mParent(*parent)
+ , mProg(prog)
+ , mLoc_u1ForYFlip(mParent.mGL->fGetUniformLocation(mProg, "u1ForYFlip"))
+ , mLoc_uClipRect(mParent.mGL->fGetUniformLocation(mProg, "uClipRect"))
+ , mLoc_uTexSize0(mParent.mGL->fGetUniformLocation(mProg, "uTexSize0"))
+ , mLoc_uTexSize1(mParent.mGL->fGetUniformLocation(mProg, "uTexSize1"))
+ , mLoc_uDivisors(mParent.mGL->fGetUniformLocation(mProg, "uDivisors"))
+ , mLoc_uColorMatrix(mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix"))
+{
+ MOZ_ASSERT(mLoc_u1ForYFlip != -1);
+ MOZ_ASSERT(mLoc_uClipRect != -1);
+ MOZ_ASSERT(mLoc_uTexSize0 != -1);
+ if (mLoc_uColorMatrix != -1) {
+ MOZ_ASSERT(mLoc_uTexSize1 != -1);
+ MOZ_ASSERT(mLoc_uDivisors != -1);
+ }
+}
+
+DrawBlitProg::~DrawBlitProg()
+{
+ const auto& gl = mParent.mGL;
+ if (!gl->MakeCurrent())
+ return;
+
+ gl->fDeleteProgram(mProg);
+}
+
+void
+DrawBlitProg::Draw(const BaseArgs& args, const YUVArgs* const argsYUV) const
+{
+ const auto& gl = mParent.mGL;
+
+ const SaveRestoreCurrentProgram oldProg(gl);
+ gl->fUseProgram(mProg);
+
+ // --
+
+ gl->fUniform1f(mLoc_u1ForYFlip, args.yFlip ? 1 : 0);
+ gl->fUniform4f(mLoc_uClipRect,
+ args.clipRect.x, args.clipRect.y,
+ args.clipRect.width, args.clipRect.height);
+ gl->fUniform2f(mLoc_uTexSize0, args.texSize0.width, args.texSize0.height);
+
+ MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1));
+ if (argsYUV) {
+ gl->fUniform2f(mLoc_uTexSize1, argsYUV->texSize1.width, argsYUV->texSize1.height);
+ gl->fUniform2f(mLoc_uDivisors, argsYUV->divisors.width, argsYUV->divisors.height);
+ const auto& colorMatrix = gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
+ gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
+ }
+
+ // --
+
+ const ScopedDrawBlitState drawState(gl, args.destSize);
+ const ScopedBindVAO bindVAO(gl, mParent.mQuadVAO);
+ gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+}
+
+// --
+
+GLBlitHelper::GLBlitHelper(GLContext* const gl)
: mGL(gl)
- , mTexBlit_Buffer(0)
- , mTexBlit_VertShader(0)
- , mTex2DBlit_FragShader(0)
- , mTex2DRectBlit_FragShader(0)
- , mTex2DBlit_Program(0)
- , mTex2DRectBlit_Program(0)
- , mYFlipLoc(-1)
- , mTextureTransformLoc(-1)
- , mTexExternalBlit_FragShader(0)
- , mTexYUVPlanarBlit_FragShader(0)
- , mTexNV12PlanarBlit_FragShader(0)
- , mTexExternalBlit_Program(0)
- , mTexYUVPlanarBlit_Program(0)
- , mTexNV12PlanarBlit_Program(0)
- , mFBO(0)
- , mSrcTexY(0)
- , mSrcTexCb(0)
- , mSrcTexCr(0)
- , mSrcTexEGL(0)
- , mYTexScaleLoc(-1)
- , mCbCrTexScaleLoc(-1)
- , mYuvColorMatrixLoc(-1)
- , mTexWidth(0)
- , mTexHeight(0)
- , mCurYScale(1.0f)
- , mCurCbCrScale(1.0f)
+ , mQuadVAO(0)
+ , mYuvUploads{0}
+ , mYuvUploads_YSize(0, 0)
+ , mYuvUploads_UVSize(0, 0)
{
+ if (!mGL->IsSupported(GLFeature::vertex_array_object)) {
+ gfxCriticalError() << "GLBlitHelper requires vertex_array_object.";
+ return;
+ }
+
+ GLuint vbo = 0;
+ mGL->fGenBuffers(1, &vbo);
+ {
+ const ScopedBindArrayBuffer bindVBO(mGL, vbo);
+
+ const float quadData[] = {
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1
+ };
+ const HeapCopyOfStackArray<float> heapQuadData(quadData);
+ mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, heapQuadData.ByteLength(),
+ heapQuadData.Data(), LOCAL_GL_STATIC_DRAW);
+
+ mGL->fGenVertexArrays(1, &mQuadVAO);
+ const ScopedBindVAO bindVAO(mGL, mQuadVAO);
+ mGL->fEnableVertexAttribArray(0);
+ mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, false, 0, 0);
+ }
+ mGL->fDeleteBuffers(1, &vbo);
+
+ // --
+
+ const char kVertSource[] = "\
+ attribute vec2 aVert; \n\
+ \n\
+ uniform float u1ForYFlip; \n\
+ uniform vec4 uClipRect; \n\
+ uniform vec2 uTexSize0; \n\
+ uniform vec2 uTexSize1; \n\
+ uniform vec2 uDivisors; \n\
+ \n\
+ varying vec2 vTexCoord0; \n\
+ varying vec2 vTexCoord1; \n\
+ \n\
+ void main(void) \n\
+ { \n\
+ vec2 vertPos = aVert * 2.0 - 1.0; \n\
+ gl_Position = vec4(vertPos, 0.0, 1.0); \n\
+ \n\
+ vec2 texCoord = aVert; \n\
+ texCoord.y = abs(u1ForYFlip - texCoord.y); \n\
+ texCoord = texCoord * uClipRect.zw + uClipRect.xy; \n\
+ \n\
+ vTexCoord0 = texCoord / uTexSize0; \n\
+ vTexCoord1 = texCoord / (uTexSize1 * uDivisors); \n\
+ } \n\
+ ";
+ const ScopedShader vs(mGL, LOCAL_GL_VERTEX_SHADER);
+ const char* const parts[] = {
+ kVertSource
+ };
+ mGL->fShaderSource(vs, 1, parts, nullptr);
+ mGL->fCompileShader(vs);
+
+ const auto fnCreateProgram = [&](const DrawBlitType type,
+ const char* const fragHeader,
+ const char* const fragBody)
+ {
+ const ScopedShader fs(mGL, LOCAL_GL_FRAGMENT_SHADER);
+ const char* const parts[] = {
+ fragHeader,
+ fragBody
+ };
+ mGL->fShaderSource(fs, 2, parts, nullptr);
+ mGL->fCompileShader(fs);
+
+ const auto prog = mGL->fCreateProgram();
+ mGL->fAttachShader(prog, vs);
+ mGL->fAttachShader(prog, fs);
+
+ mGL->fBindAttribLocation(prog, 0, "aPosition");
+ mGL->fLinkProgram(prog);
+
+ GLenum status = 0;
+ mGL->fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, (GLint*)&status);
+ if (status == LOCAL_GL_TRUE) {
+ mGL->fUseProgram(prog);
+ const char* samplerNames[] = {
+ "uTex0",
+ "uTex1",
+ "uTex2"
+ };
+ for (int i = 0; i < 3; i++) {
+ const auto loc = mGL->fGetUniformLocation(prog, samplerNames[i]);
+ if (loc == -1)
+ break;
+ mGL->fUniform1i(loc, i);
+ }
+
+ auto obj = MakeUnique<DrawBlitProg>(this, prog);
+ mDrawBlitProgs.insert({uint8_t(type), Move(obj)});
+ return;
+ }
+
+ GLuint progLogLen = 0;
+ mGL->fGetProgramiv(prog, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&progLogLen);
+ const UniquePtr<char[]> progLog(new char[progLogLen]);
+ mGL->fGetProgramInfoLog(prog, progLogLen, nullptr, progLog.get());
+
+ GLuint vsLogLen = 0;
+ mGL->fGetShaderiv(vs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&vsLogLen);
+ const UniquePtr<char[]> vsLog(new char[vsLogLen]);
+ mGL->fGetShaderInfoLog(vs, vsLogLen, nullptr, vsLog.get());
+
+ GLuint fsLogLen = 0;
+ mGL->fGetShaderiv(fs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&fsLogLen);
+ const UniquePtr<char[]> fsLog(new char[fsLogLen]);
+ mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get());
+
+ gfxCriticalError() << "Link failed for DrawBlitType: " << uint8_t(type) << ":\n"
+ << "progLog: " << progLog.get() << "\n"
+ << "vsLog: " << vsLog.get() << "\n"
+ << "fsLog: " << fsLog.get() << "\n";
+ };
+
+ const char kFragHeader_Tex2D[] = "\
+ #define SAMPLER sampler2D \n\
+ #define TEXTURE texture2D \n\
+ ";
+ const char kFragHeader_Tex2DRect[] = "\
+ #define SAMPLER sampler2DRect \n\
+ #define TEXTURE texture2DRect \n\
+ ";
+ const char kFragHeader_TexExt[] = "\
+ #extension GL_OES_EGL_image_external : require \n\
+ #define SAMPLER samplerExternalOES \n\
+ #define TEXTURE texture2D \n\
+ ";
+
+ const char kFragBody_RGBA[] = "\
+ #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
+ precision highp float; \n\
+ #else \n\
+ precision mediump float; \n\
+ #endif \n\
+ \n\
+ varying vec2 vTexCoord0; \n\
+ uniform SAMPLER uTex0; \n\
+ \n\
+ void main(void) \n\
+ { \n\
+ gl_FragColor = TEXTURE(uTex0, vTexCoord0); \n\
+ } \n\
+ ";
+ /*
+ const char kFragBody_YUV[] = "\
+ #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
+ precision highp float; \n\
+ #else \n\
+ precision mediump float; \n\
+ #endif \n\
+ \n\
+ varying vec2 vTexCoord0; \n\
+ uniform SAMPLER uTex0; \n\
+ uniform mat4 uColorMatrix; \n\
+ \n\
+ void main(void) \n\
+ { \n\
+ vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).xyz, \n\
+ 1.0); \n\
+ vec4 rgb = uColorMatrix * yuv; \n\
+ gl_FragColor = vec4(rgb.rgb, 1.0); \n\
+ } \n\
+ ";
+ */
+ const char kFragBody_NV12[] = "\
+ #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
+ precision highp float; \n\
+ #else \n\
+ precision mediump float; \n\
+ #endif \n\
+ \n\
+ varying vec2 vTexCoord0; \n\
+ varying vec2 vTexCoord1; \n\
+ uniform SAMPLER uTex0; \n\
+ uniform SAMPLER uTex1; \n\
+ uniform mat4 uColorMatrix; \n\
+ \n\
+ void main(void) \n\
+ { \n\
+ vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
+ TEXTURE(uTex1, vTexCoord1).xy, \n\
+ 1.0); \n\
+ vec4 rgb = uColorMatrix * yuv; \n\
+ gl_FragColor = vec4(rgb.rgb, 1.0); \n\
+ //gl_FragColor = yuv; \n\
+ } \n\
+ ";
+ const char kFragBody_PlanarYUV[] = "\
+ #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
+ precision highp float; \n\
+ #else \n\
+ precision mediump float; \n\
+ #endif \n\
+ \n\
+ varying vec2 vTexCoord0; \n\
+ varying vec2 vTexCoord1; \n\
+ uniform SAMPLER uTex0; \n\
+ uniform SAMPLER uTex1; \n\
+ uniform SAMPLER uTex2; \n\
+ uniform mat4 uColorMatrix; \n\
+ \n\
+ void main(void) \n\
+ { \n\
+ vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
+ TEXTURE(uTex1, vTexCoord1).x, \n\
+ TEXTURE(uTex2, vTexCoord1).x, \n\
+ 1.0); \n\
+ vec4 rgb = uColorMatrix * yuv; \n\
+ gl_FragColor = vec4(rgb.rgb, 1.0); \n\
+ } \n\
+ ";
+
+ const SaveRestoreCurrentProgram oldProg(mGL);
+
+ fnCreateProgram(DrawBlitType::Tex2DRGBA, kFragHeader_Tex2D, kFragBody_RGBA);
+ fnCreateProgram(DrawBlitType::Tex2DPlanarYUV, kFragHeader_Tex2D, kFragBody_PlanarYUV);
+ if (mGL->IsExtensionSupported(GLContext::ARB_texture_rectangle)) {
+ fnCreateProgram(DrawBlitType::TexRectRGBA, kFragHeader_Tex2DRect, kFragBody_RGBA);
+ }
+ if (mGL->IsExtensionSupported(GLContext::OES_EGL_image_external)) {
+ fnCreateProgram(DrawBlitType::TexExtNV12, kFragHeader_TexExt, kFragBody_NV12);
+ fnCreateProgram(DrawBlitType::TexExtPlanarYUV, kFragHeader_TexExt, kFragBody_PlanarYUV);
+ }
}
GLBlitHelper::~GLBlitHelper()
{
if (!mGL->MakeCurrent())
return;
- DeleteTexBlitProgram();
+ mGL->fDeleteVertexArrays(1, &mQuadVAO);
+}
- GLuint tex[] = {
- mSrcTexY,
- mSrcTexCb,
- mSrcTexCr,
- mSrcTexEGL,
- };
-
- mSrcTexY = mSrcTexCb = mSrcTexCr = mSrcTexEGL = 0;
- mGL->fDeleteTextures(ArrayLength(tex), tex);
-
- if (mFBO) {
- mGL->fDeleteFramebuffers(1, &mFBO);
- }
- mFBO = 0;
+const DrawBlitProg*
+GLBlitHelper::GetDrawBlitProg(const DrawBlitType type) const
+{
+ const auto itr = mDrawBlitProgs.find(uint8_t(type));
+ if (itr == mDrawBlitProgs.end())
+ return nullptr;
+ return itr->second.get();
}
-// Allowed to be destructive of state we restore in functions below.
-bool
-GLBlitHelper::InitTexQuadProgram(BlitType target)
-{
- const char kTexBlit_VertShaderSource[] = "\
- #version 100 \n\
- #ifdef GL_ES \n\
- precision mediump float; \n\
- #endif \n\
- attribute vec2 aPosition; \n\
- \n\
- uniform float uYflip; \n\
- varying vec2 vTexCoord; \n\
- \n\
- void main(void) \n\
- { \n\
- vTexCoord = aPosition; \n\
- vTexCoord.y = abs(vTexCoord.y - uYflip); \n\
- vec2 vertPos = aPosition * 2.0 - 1.0; \n\
- gl_Position = vec4(vertPos, 0.0, 1.0); \n\
- } \n\
- ";
-
- const char kTex2DBlit_FragShaderSource[] = "\
- #version 100 \n\
- #ifdef GL_ES \n\
- #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
- precision highp float; \n\
- #else \n\
- precision mediump float; \n\
- #endif \n\
- #endif \n\
- uniform sampler2D uTexUnit; \n\
- \n\
- varying vec2 vTexCoord; \n\
- \n\
- void main(void) \n\
- { \n\
- gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
- } \n\
- ";
+// -----------------------------------------------------------------------------
- const char kTex2DRectBlit_FragShaderSource[] = "\
- #version 100 \n\
- #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
- precision highp float; \n\
- #else \n\
- precision mediump float; \n\
- #endif \n\
- \n\
- uniform sampler2D uTexUnit; \n\
- uniform vec2 uTexCoordMult; \n\
- \n\
- varying vec2 vTexCoord; \n\
- \n\
- void main(void) \n\
- { \n\
- gl_FragColor = texture2DRect(uTexUnit, \n\
- vTexCoord * uTexCoordMult); \n\
- } \n\
- ";
-#ifdef ANDROID /* MOZ_WIDGET_ANDROID */
- const char kTexExternalBlit_FragShaderSource[] = "\
- #version 100 \n\
- #extension GL_OES_EGL_image_external : require \n\
- #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
- precision highp float; \n\
- #else \n\
- precision mediump float; \n\
- #endif \n\
- varying vec2 vTexCoord; \n\
- uniform mat4 uTextureTransform; \n\
- uniform samplerExternalOES uTexUnit; \n\
- \n\
- void main() \n\
- { \n\
- gl_FragColor = texture2D(uTexUnit, \n\
- (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy); \n\
- } \n\
- ";
-#endif
- /* From Rec601:
- [R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
- [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
- [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
+bool
+GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
+ const gfx::IntSize& destSize,
+ OriginPos destOrigin)
+{
+ switch (srcImage->GetFormat()) {
+ case ImageFormat::PLANAR_YCBCR:
+ return BlitImage(static_cast<PlanarYCbCrImage*>(srcImage), destSize, destOrigin);
- For [0,1] instead of [0,255], and to 5 places:
- [R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
- [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
- [B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
+#ifdef MOZ_WIDGET_ANDROID
+ case ImageFormat::SURFACE_TEXTURE:
+ return BlitImage(static_cast<layers::SurfaceTextureImage*>(srcImage));
- From Rec709:
- [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [ Y - 16]
- [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444] x [Cb - 128]
- [B] [1.1643835616438356, 2.1124017857142854, 0.0] [Cr - 128]
-
- For [0,1] instead of [0,255], and to 5 places:
- [R] [1.16438, 0.00000, 1.79274] [ Y - 0.06275]
- [G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
- [B] [1.16438, 2.11240, 0.00000] [Cr - 0.50196]
- */
- const char kTexYUVPlanarBlit_FragShaderSource[] = "\
- #version 100 \n\
- #ifdef GL_ES \n\
- precision mediump float; \n\
- #endif \n\
- varying vec2 vTexCoord; \n\
- uniform sampler2D uYTexture; \n\
- uniform sampler2D uCbTexture; \n\
- uniform sampler2D uCrTexture; \n\
- uniform vec2 uYTexScale; \n\
- uniform vec2 uCbCrTexScale; \n\
- uniform mat3 uYuvColorMatrix; \n\
- void main() \n\
- { \n\
- float y = texture2D(uYTexture, vTexCoord * uYTexScale).r; \n\
- float cb = texture2D(uCbTexture, vTexCoord * uCbCrTexScale).r; \n\
- float cr = texture2D(uCrTexture, vTexCoord * uCbCrTexScale).r; \n\
- y = y - 0.06275; \n\
- cb = cb - 0.50196; \n\
- cr = cr - 0.50196; \n\
- vec3 yuv = vec3(y, cb, cr); \n\
- gl_FragColor.rgb = uYuvColorMatrix * yuv; \n\
- gl_FragColor.a = 1.0; \n\
- } \n\
- ";
-
+ case ImageFormat::EGLIMAGE:
+ return BlitImage(static_cast<layers::EGLImageImage*>(srcImage), destSize,
+ destOrigin);
+#endif
#ifdef XP_MACOSX
- const char kTexNV12PlanarBlit_FragShaderSource[] = "\
- #version 100 \n\
- #extension GL_ARB_texture_rectangle : require \n\
- #ifdef GL_ES \n\
- precision mediump float \n\
- #endif \n\
- varying vec2 vTexCoord; \n\
- uniform sampler2DRect uYTexture; \n\
- uniform sampler2DRect uCbCrTexture; \n\
- uniform vec2 uYTexScale; \n\
- uniform vec2 uCbCrTexScale; \n\
- void main() \n\
- { \n\
- float y = texture2DRect(uYTexture, vTexCoord * uYTexScale).r; \n\
- float cb = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).r; \n\
- float cr = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).a; \n\
- y = (y - 0.06275) * 1.16438; \n\
- cb = cb - 0.50196; \n\
- cr = cr - 0.50196; \n\
- gl_FragColor.r = y + cr * 1.59603; \n\
- gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb; \n\
- gl_FragColor.b = y + cb * 2.01723; \n\
- gl_FragColor.a = 1.0; \n\
- } \n\
- ";
+ case ImageFormat::MAC_IOSURFACE:
+ return BlitImage(srcImage->AsMacIOSurfaceImage());
#endif
-
- bool success = false;
-
- GLuint* programPtr;
- GLuint* fragShaderPtr;
- const char* fragShaderSource;
- switch (target) {
- case ConvertEGLImage:
- case BlitTex2D:
- programPtr = &mTex2DBlit_Program;
- fragShaderPtr = &mTex2DBlit_FragShader;
- fragShaderSource = kTex2DBlit_FragShaderSource;
- break;
- case BlitTexRect:
- programPtr = &mTex2DRectBlit_Program;
- fragShaderPtr = &mTex2DRectBlit_FragShader;
- fragShaderSource = kTex2DRectBlit_FragShaderSource;
- break;
-#ifdef ANDROID
- case ConvertSurfaceTexture:
- programPtr = &mTexExternalBlit_Program;
- fragShaderPtr = &mTexExternalBlit_FragShader;
- fragShaderSource = kTexExternalBlit_FragShaderSource;
- break;
-#endif
- case ConvertPlanarYCbCr:
- programPtr = &mTexYUVPlanarBlit_Program;
- fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
- fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
- break;
-#ifdef XP_MACOSX
- case ConvertMacIOSurfaceImage:
- programPtr = &mTexNV12PlanarBlit_Program;
- fragShaderPtr = &mTexNV12PlanarBlit_FragShader;
- fragShaderSource = kTexNV12PlanarBlit_FragShaderSource;
- break;
+#ifdef XP_WIN
+ case ImageFormat::GPU_VIDEO:
+ return BlitImage(static_cast<layers::GPUVideoImage*>(srcImage), destSize,
+ destOrigin);
+ case ImageFormat::D3D11_YCBCR_IMAGE:
+ return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize,
+ destOrigin);
#endif
default:
+ gfxCriticalError() << "Unhandled srcImage->GetFormat(): "
+ << uint32_t(srcImage->GetFormat());
return false;
}
-
- GLuint& program = *programPtr;
- GLuint& fragShader = *fragShaderPtr;
-
- // Use do-while(false) to let us break on failure
- do {
- if (program) {
- // Already have it...
- success = true;
- break;
- }
-
- if (!mTexBlit_Buffer) {
-
- /* CCW tri-strip:
- * 2---3
- * | \ |
- * 0---1
- */
- GLfloat verts[] = {
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- 0.0f, 1.0f,
- 1.0f, 1.0f
- };
- HeapCopyOfStackArray<GLfloat> vertsOnHeap(verts);
-
- MOZ_ASSERT(!mTexBlit_Buffer);
- mGL->fGenBuffers(1, &mTexBlit_Buffer);
- mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
-
- // Make sure we have a sane size.
- mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, vertsOnHeap.ByteLength(), vertsOnHeap.Data(), LOCAL_GL_STATIC_DRAW);
- }
-
- if (!mTexBlit_VertShader) {
-
- const char* vertShaderSource = kTexBlit_VertShaderSource;
-
- mTexBlit_VertShader = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER);
- mGL->fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr);
- mGL->fCompileShader(mTexBlit_VertShader);
- }
-
- MOZ_ASSERT(!fragShader);
- fragShader = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
- mGL->fShaderSource(fragShader, 1, &fragShaderSource, nullptr);
- mGL->fCompileShader(fragShader);
-
- program = mGL->fCreateProgram();
- mGL->fAttachShader(program, mTexBlit_VertShader);
- mGL->fAttachShader(program, fragShader);
- mGL->fBindAttribLocation(program, 0, "aPosition");
- mGL->fLinkProgram(program);
-
- if (GLContext::ShouldSpew()) {
- GLint status = 0;
- mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
- if (status != LOCAL_GL_TRUE) {
- NS_ERROR("Vert shader compilation failed.");
-
- GLint length = 0;
- mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
- if (!length) {
- printf_stderr("No shader info log available.\n");
- break;
- }
-
- auto buffer = MakeUnique<char[]>(length);
- mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer.get());
-
- printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
- break;
- }
-
- status = 0;
- mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status);
- if (status != LOCAL_GL_TRUE) {
- NS_ERROR("Frag shader compilation failed.");
-
- GLint length = 0;
- mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
- if (!length) {
- printf_stderr("No shader info log available.\n");
- break;
- }
-
- auto buffer = MakeUnique<char[]>(length);
- mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer.get());
-
- printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
- break;
- }
- }
-
- GLint status = 0;
- mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &status);
- if (status != LOCAL_GL_TRUE) {
- if (GLContext::ShouldSpew()) {
- NS_ERROR("Linking blit program failed.");
- GLint length = 0;
- mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
- if (!length) {
- printf_stderr("No program info log available.\n");
- break;
- }
-
- auto buffer = MakeUnique<char[]>(length);
- mGL->fGetProgramInfoLog(program, length, nullptr, buffer.get());
-
- printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get());
- }
- break;
- }
-
- // Cache and set attribute and uniform
- mGL->fUseProgram(program);
- switch (target) {
-#ifdef ANDROID
- case ConvertSurfaceTexture:
-#endif
- case BlitTex2D:
- case BlitTexRect:
- case ConvertEGLImage: {
- GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
- MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
- mGL->fUniform1i(texUnitLoc, 0);
- break;
- }
- case ConvertPlanarYCbCr: {
- GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
- GLint texCb = mGL->fGetUniformLocation(program, "uCbTexture");
- GLint texCr = mGL->fGetUniformLocation(program, "uCrTexture");
- mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
- mCbCrTexScaleLoc = mGL->fGetUniformLocation(program, "uCbCrTexScale");
- mYuvColorMatrixLoc = mGL->fGetUniformLocation(program, "uYuvColorMatrix");
-
- DebugOnly<bool> hasUniformLocations = texY != -1 &&
- texCb != -1 &&
- texCr != -1 &&
- mYTexScaleLoc != -1 &&
- mCbCrTexScaleLoc != -1 &&
- mYuvColorMatrixLoc != -1;
- MOZ_ASSERT(hasUniformLocations, "uniforms not found");
-
- mGL->fUniform1i(texY, Channel_Y);
- mGL->fUniform1i(texCb, Channel_Cb);
- mGL->fUniform1i(texCr, Channel_Cr);
- break;
- }
- case ConvertMacIOSurfaceImage: {
-#ifdef XP_MACOSX
- GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
- GLint texCbCr = mGL->fGetUniformLocation(program, "uCbCrTexture");
- mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
- mCbCrTexScaleLoc= mGL->fGetUniformLocation(program, "uCbCrTexScale");
-
- DebugOnly<bool> hasUniformLocations = texY != -1 &&
- texCbCr != -1 &&
- mYTexScaleLoc != -1 &&
- mCbCrTexScaleLoc != -1;
- MOZ_ASSERT(hasUniformLocations, "uniforms not found");
-
- mGL->fUniform1i(texY, Channel_Y);
- mGL->fUniform1i(texCbCr, Channel_Cb);
-#endif
- break;
- }
- default:
- return false;
- }
- MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
- mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
- MOZ_ASSERT(mYFlipLoc != -1, "uniform: uYflip not found");
- mTextureTransformLoc = mGL->fGetUniformLocation(program, "uTextureTransform");
- if (mTextureTransformLoc >= 0) {
- // Set identity matrix as default
- gfx::Matrix4x4 identity;
- mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &identity._11);
- }
- success = true;
- } while (false);
-
- if (!success) {
- // Clean up:
- DeleteTexBlitProgram();
- return false;
- }
-
- mGL->fUseProgram(program);
- mGL->fEnableVertexAttribArray(0);
- mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
- mGL->fVertexAttribPointer(0,
- 2,
- LOCAL_GL_FLOAT,
- false,
- 0,
- nullptr);
- return true;
-}
-
-bool
-GLBlitHelper::UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize)
-{
- if (!InitTexQuadProgram(target)) {
- return false;
- }
-
- if (target == BlitTexRect) {
- GLint texCoordMultLoc = mGL->fGetUniformLocation(mTex2DRectBlit_Program, "uTexCoordMult");
- MOZ_ASSERT(texCoordMultLoc != -1, "uniform not found");
- mGL->fUniform2f(texCoordMultLoc, srcSize.width, srcSize.height);
- }
-
- return true;
-}
-
-void
-GLBlitHelper::DeleteTexBlitProgram()
-{
- if (mTexBlit_Buffer) {
- mGL->fDeleteBuffers(1, &mTexBlit_Buffer);
- mTexBlit_Buffer = 0;
- }
- if (mTexBlit_VertShader) {
- mGL->fDeleteShader(mTexBlit_VertShader);
- mTexBlit_VertShader = 0;
- }
- if (mTex2DBlit_FragShader) {
- mGL->fDeleteShader(mTex2DBlit_FragShader);
- mTex2DBlit_FragShader = 0;
- }
- if (mTex2DRectBlit_FragShader) {
- mGL->fDeleteShader(mTex2DRectBlit_FragShader);
- mTex2DRectBlit_FragShader = 0;
- }
- if (mTex2DBlit_Program) {
- mGL->fDeleteProgram(mTex2DBlit_Program);
- mTex2DBlit_Program = 0;
- }
- if (mTex2DRectBlit_Program) {
- mGL->fDeleteProgram(mTex2DRectBlit_Program);
- mTex2DRectBlit_Program = 0;
- }
- if (mTexExternalBlit_FragShader) {
- mGL->fDeleteShader(mTexExternalBlit_FragShader);
- mTexExternalBlit_FragShader = 0;
- }
- if (mTexYUVPlanarBlit_FragShader) {
- mGL->fDeleteShader(mTexYUVPlanarBlit_FragShader);
- mTexYUVPlanarBlit_FragShader = 0;
- }
- if (mTexNV12PlanarBlit_FragShader) {
- mGL->fDeleteShader(mTexNV12PlanarBlit_FragShader);
- mTexNV12PlanarBlit_FragShader = 0;
- }
- if (mTexExternalBlit_Program) {
- mGL->fDeleteProgram(mTexExternalBlit_Program);
- mTexExternalBlit_Program = 0;
- }
- if (mTexYUVPlanarBlit_Program) {
- mGL->fDeleteProgram(mTexYUVPlanarBlit_Program);
- mTexYUVPlanarBlit_Program = 0;
- }
- if (mTexNV12PlanarBlit_Program) {
- mGL->fDeleteProgram(mTexNV12PlanarBlit_Program);
- mTexNV12PlanarBlit_Program = 0;
- }
}
-void
-GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
- const gfx::IntSize& srcSize,
- const gfx::IntSize& destSize,
- bool internalFBs)
-{
- MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
- MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
-
- MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
-
- ScopedBindFramebuffer boundFB(mGL);
- ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
-
- if (internalFBs) {
- mGL->Screen()->BindReadFB_Internal(srcFB);
- mGL->Screen()->BindDrawFB_Internal(destFB);
- } else {
- mGL->BindReadFB(srcFB);
- mGL->BindDrawFB(destFB);
- }
-
- mGL->fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
- 0, 0, destSize.width, destSize.height,
- LOCAL_GL_COLOR_BUFFER_BIT,
- LOCAL_GL_NEAREST);
-}
-
-void
-GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
- const gfx::IntSize& srcSize,
- const gfx::IntSize& destSize,
- const GLFormats& srcFormats,
- bool internalFBs)
-{
- MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
- MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
-
- if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
- BlitFramebufferToFramebuffer(srcFB, destFB,
- srcSize, destSize,
- internalFBs);
- return;
- }
-
- GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
- MOZ_ASSERT(tex);
-
- BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize, internalFBs);
- BlitTextureToFramebuffer(tex, destFB, srcSize, destSize, internalFBs);
-
- mGL->fDeleteTextures(1, &tex);
-}
-
-void
-GLBlitHelper::BindAndUploadYUVTexture(Channel which,
- uint32_t width,
- uint32_t height,
- void* data,
- bool needsAllocation)
-{
- MOZ_ASSERT(which < Channel_Max, "Invalid channel!");
- GLuint* srcTexArr[3] = {&mSrcTexY, &mSrcTexCb, &mSrcTexCr};
- GLuint& tex = *srcTexArr[which];
-
- // RED textures aren't valid in GLES2, and ALPHA textures are not valid in desktop GL Core Profiles.
- // So use R8 textures on GL3.0+ and GLES3.0+, but LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
- GLenum format;
- GLenum internalFormat;
- if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
- mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300)) {
- format = LOCAL_GL_RED;
- internalFormat = LOCAL_GL_R8;
- } else {
- format = LOCAL_GL_LUMINANCE;
- internalFormat = LOCAL_GL_LUMINANCE;
- }
-
- if (!tex) {
- MOZ_ASSERT(needsAllocation);
- tex = CreateTexture(mGL, internalFormat, format, LOCAL_GL_UNSIGNED_BYTE,
- gfx::IntSize(width, height), false);
- }
- mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + which);
-
- mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
- if (!needsAllocation) {
- mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
- 0,
- 0,
- 0,
- width,
- height,
- format,
- LOCAL_GL_UNSIGNED_BYTE,
- data);
- } else {
- mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
- 0,
- internalFormat,
- width,
- height,
- 0,
- format,
- LOCAL_GL_UNSIGNED_BYTE,
- data);
- }
-}
-
-void
-GLBlitHelper::BindAndUploadEGLImage(EGLImage image, GLuint target)
-{
- MOZ_ASSERT(image != EGL_NO_IMAGE, "Bad EGLImage");
-
- if (!mSrcTexEGL) {
- mGL->fGenTextures(1, &mSrcTexEGL);
- mGL->fBindTexture(target, mSrcTexEGL);
- mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
- mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
- mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
- mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
- } else {
- mGL->fBindTexture(target, mSrcTexEGL);
- }
- mGL->fEGLImageTargetTexture2D(target, image);
-}
+// -------------------------------------
#ifdef MOZ_WIDGET_ANDROID
-
-#define ATTACH_WAIT_MS 50
-
bool
-GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage)
+GLBlitHelper::BlitImage(layers::SurfaceTextureImage* srcImage)
{
// FIXME
+ gfxCriticalError() << "BlitImage(SurfaceTextureImage) not implemented.";
return false;
}
bool
-GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image)
+GLBlitHelper::BlitImage(layers::EGLImageImage* const srcImage,
+ const gfx::IntSize& destSize, const OriginPos destOrigin)
{
- EGLImage eglImage = image->GetImage();
- EGLSync eglSync = image->GetSync();
-
+ const EGLImage eglImage = srcImage->GetImage();
+ const EGLSync eglSync = srcImage->GetSync();
if (eglSync) {
EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), eglSync, 0, LOCAL_EGL_FOREVER);
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
return false;
}
}
- ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
-
- int oldBinding = 0;
- mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldBinding);
-
- BindAndUploadEGLImage(eglImage, LOCAL_GL_TEXTURE_2D);
-
- mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
-
- mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldBinding);
- return true;
-}
-
-#endif
-
-bool
-GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage)
-{
- ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
- const PlanarYCbCrData* yuvData = yuvImage->GetData();
+ GLuint tex = 0;
+ mGL->fGenTextures(1, &tex);
- bool needsAllocation = false;
- if (mTexWidth != yuvData->mYStride || mTexHeight != yuvData->mYSize.height) {
- mTexWidth = yuvData->mYStride;
- mTexHeight = yuvData->mYSize.height;
- needsAllocation = true;
- }
-
- GLint oldTex[3];
- for (int i = 0; i < 3; i++) {
- mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
- mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
- }
-
- {
- const ResetUnpackState reset(mGL);
- BindAndUploadYUVTexture(Channel_Y, yuvData->mYStride, yuvData->mYSize.height, yuvData->mYChannel, needsAllocation);
- BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
- BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
- }
-
- if (needsAllocation) {
- mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f);
- mGL->fUniform2f(mCbCrTexScaleLoc, (float)yuvData->mCbCrSize.width/yuvData->mCbCrStride, 1.0f);
- }
-
- const auto& yuvToRgb = gfxUtils::YuvToRgbMatrix3x3ColumnMajor(yuvData->mYUVColorSpace);
- mGL->fUniformMatrix3fv(mYuvColorMatrixLoc, 1, 0, yuvToRgb);
+ const ScopedSaveMultiTex saveTex(mGL, 1, LOCAL_GL_TEXTURE_2D);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
+ mGL->TexParams_SetClampNoMips();
+ mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, eglImage);
- mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
- for (int i = 0; i < 3; i++) {
- mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
- mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
- }
- return true;
-}
-
-#ifdef XP_MACOSX
-bool
-GLBlitHelper::BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage)
-{
- ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
- MacIOSurface* surf = ioImage->GetSurface();
-
- GLint oldTex[2];
- for (int i = 0; i < 2; i++) {
- mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
- mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
- }
-
- GLuint textures[2];
- mGL->fGenTextures(2, textures);
+ const auto& srcOrigin = srcImage->GetOriginPos();
+ const bool yFlip = destOrigin != srcOrigin;
+ const gfx::IntRect clipRect(0, 0, 1, 1);
+ const gfx::IntSize texSizeDivisor(1, 1);
+ const DrawBlitProg::DrawArgs baseArgs = { destSize, yFlip, clipRect, texSizeDivisor };
- mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
- mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[0]);
- mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
- mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
- surf->CGLTexImageIOSurface2D(mGL,
- gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
- 0);
- mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
+ const auto& prog = GetDrawBlitProg(DrawBlitType::Tex2DRGB);
+ MOZ_RELEASE_ASSERT(prog);
+ prog->Draw(baseArgs);
- mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
- mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[1]);
- mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
- mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
- surf->CGLTexImageIOSurface2D(mGL,
- gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
- 1);
- mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
-
- mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
- for (int i = 0; i < 2; i++) {
- mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
- mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
- }
-
- mGL->fDeleteTextures(2, textures);
+ mGL->fDeleteTextures(1, &tex);
return true;
}
#endif
-bool
-GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
- const gfx::IntSize& destSize,
- GLuint destFB,
- OriginPos destOrigin)
-{
- ScopedGLDrawState autoStates(mGL);
-
- BlitType type;
- OriginPos srcOrigin;
+// -------------------------------------
- switch (srcImage->GetFormat()) {
- case ImageFormat::PLANAR_YCBCR:
- type = ConvertPlanarYCbCr;
-#if defined(MOZ_WIDGET_ANDROID)
- srcOrigin = OriginPos::TopLeft;
-#else
- srcOrigin = OriginPos::BottomLeft;
-#endif // defined(MOZ_WIDGET_ANDROID)
- break;
-
-#ifdef MOZ_WIDGET_ANDROID
- case ImageFormat::SURFACE_TEXTURE:
- type = ConvertSurfaceTexture;
- srcOrigin = srcImage->AsSurfaceTextureImage()->GetOriginPos();
- break;
- case ImageFormat::EGLIMAGE:
- type = ConvertEGLImage;
- srcOrigin = srcImage->AsEGLImageImage()->GetOriginPos();
- break;
-#endif
-#ifdef XP_MACOSX
- case ImageFormat::MAC_IOSURFACE:
- type = ConvertMacIOSurfaceImage;
- srcOrigin = OriginPos::TopLeft;
- break;
-#endif
-
- default:
+bool
+GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
+ gfx::IntSize* const out_divisors)
+{
+ const uint8_t widthDivisor = (ySize.width == uvSize.width ) ? 1 : 2;
+ const uint8_t heightDivisor = (ySize.height == uvSize.height) ? 1 : 2;
+ const gfx::IntSize divisors((ySize.width == uvSize.width ) ? 1 : 2,
+ (ySize.height == uvSize.height) ? 1 : 2);
+ if (uvSize.width * divisors.width != ySize.width ||
+ uvSize.height * divisors.height != ySize.height)
+ {
return false;
}
-
- bool init = InitTexQuadProgram(type);
- if (!init) {
- return false;
- }
-
- const bool needsYFlip = (srcOrigin != destOrigin);
- mGL->fUniform1f(mYFlipLoc, needsYFlip ? (float)1.0 : (float)0.0);
-
- ScopedBindFramebuffer boundFB(mGL, destFB);
- mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE);
- mGL->fViewport(0, 0, destSize.width, destSize.height);
-
- switch (type) {
- case ConvertPlanarYCbCr:
- return BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
-
-#ifdef MOZ_WIDGET_ANDROID
- case ConvertSurfaceTexture:
- return BlitSurfaceTextureImage(static_cast<layers::SurfaceTextureImage*>(srcImage));
-
- case ConvertEGLImage:
- return BlitEGLImageImage(static_cast<layers::EGLImageImage*>(srcImage));
-#endif
-
-#ifdef XP_MACOSX
- case ConvertMacIOSurfaceImage:
- return BlitMacIOSurfaceImage(srcImage->AsMacIOSurfaceImage());
-#endif
-
- default:
- return false;
- }
+ *out_divisors = divisors;
+ return true;
}
bool
-GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
- const gfx::IntSize& destSize,
- GLuint destTex,
- GLenum destTarget,
- OriginPos destOrigin)
+GLBlitHelper::BlitImage(layers::PlanarYCbCrImage* const yuvImage,
+ const gfx::IntSize& destSize, const OriginPos destOrigin)
{
- ScopedFramebufferForTexture autoFBForTex(mGL, destTex, destTarget);
- if (!autoFBForTex.IsComplete())
+ const auto& prog = GetDrawBlitProg(DrawBlitType::Tex2DPlanarYUV);
+ MOZ_RELEASE_ASSERT(prog);
+
+ if (!mYuvUploads[0]) {
+ mGL->fGenTextures(3, mYuvUploads);
+ const ScopedBindTexture bindTex(mGL, mYuvUploads[0]);
+ mGL->TexParams_SetClampNoMips();
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]);
+ mGL->TexParams_SetClampNoMips();
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]);
+ mGL->TexParams_SetClampNoMips();
+ }
+
+ // --
+
+ const PlanarYCbCrData* const yuvData = yuvImage->GetData();
+
+ if (yuvData->mYSkip || yuvData->mCbSkip || yuvData->mCrSkip ||
+ yuvData->mYSize.width < 0 || yuvData->mYSize.height < 0 ||
+ yuvData->mCbCrSize.width < 0 || yuvData->mCbCrSize.height < 0 ||
+ yuvData->mYStride < 0 || yuvData->mCbCrStride < 0)
+ {
+ gfxCriticalError() << "Unusual PlanarYCbCrData: "
+ << yuvData->mYSkip << ","
+ << yuvData->mCbSkip << ","
+ << yuvData->mCrSkip << ", "
+ << yuvData->mYSize.width << ","
+ << yuvData->mYSize.height << ", "
+ << yuvData->mCbCrSize.width << ","
+ << yuvData->mCbCrSize.height << ", "
+ << yuvData->mYStride << ","
+ << yuvData->mCbCrStride;
+ return false;
+ }
+
+ const gfx::IntSize yTexSize(yuvData->mYStride, yuvData->mYSize.height);
+ const gfx::IntSize uvTexSize(yuvData->mCbCrStride, yuvData->mCbCrSize.height);
+ gfx::IntSize divisors;
+ if (!GuessDivisors(yTexSize, uvTexSize, &divisors)) {
+ gfxCriticalError() << "GuessDivisors failed:"
+ << yTexSize.width << ","
+ << yTexSize.height << ", "
+ << uvTexSize.width << ","
+ << uvTexSize.height;
return false;
+ }
- return BlitImageToFramebuffer(srcImage, destSize, autoFBForTex.FB(), destOrigin);
+ // --
+
+ // RED textures aren't valid in GLES2, and ALPHA textures are not valid in desktop GL Core Profiles.
+ // So use R8 textures on GL3.0+ and GLES3.0+, but LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
+ GLenum internalFormat;
+ GLenum unpackFormat;
+ if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
+ mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300))
+ {
+ internalFormat = LOCAL_GL_R8;
+ unpackFormat = LOCAL_GL_RED;
+ } else {
+ internalFormat = LOCAL_GL_LUMINANCE;
+ unpackFormat = LOCAL_GL_LUMINANCE;
+ }
+
+ // --
+
+ const ScopedSaveMultiTex saveTex(mGL, 3, LOCAL_GL_TEXTURE_2D);
+ const ResetUnpackState reset(mGL);
+
+ if (yTexSize != mYuvUploads_YSize ||
+ uvTexSize != mYuvUploads_UVSize)
+ {
+ mYuvUploads_YSize = yTexSize;
+ mYuvUploads_UVSize = uvTexSize;
+
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]);
+ mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat,
+ yTexSize.width, yTexSize.height, 0,
+ unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
+ for (int i = 1; i < 2; i++) {
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[i]);
+ mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat,
+ uvTexSize.width, uvTexSize.height, 0,
+ unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
+ }
+ }
+
+ // --
+
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]);
+ mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
+ yTexSize.width, yTexSize.height,
+ unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mYChannel);
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]);
+ mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
+ uvTexSize.width, uvTexSize.height,
+ unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mCbChannel);
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE2);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]);
+ mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
+ uvTexSize.width, uvTexSize.height,
+ unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mCrChannel);
+
+ // --
+
+ const auto srcOrigin = OriginPos::BottomLeft;
+ const bool yFlip = (destOrigin != srcOrigin);
+ const auto& clipRect = yuvData->GetPictureRect();
+ const auto& colorSpace = yuvData->mYUVColorSpace;
+
+ const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, yTexSize };
+ const DrawBlitProg::YUVArgs yuvArgs = { uvTexSize, divisors, colorSpace };
+
+ prog->Draw(baseArgs, &yuvArgs);
+ return true;
+}
+
+// -------------------------------------
+
+#ifdef XP_MACOSX
+#error TODO
+bool
+GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* ioImage)
+{
+ MacIOSurface* const iosurf = ioImage->GetSurface();
+MacIOSurfaceLib::IOSurfaceGetPixelFormat
+ const uint32_t pixelFormat = MacIOSurfaceLib::iosurf->GetPixelFormat();
+ DrawBlitType type;
+ int planes;
+ Maybe<YUVColorSpace> colorSpace = Nothing();
+ if (pixelFormat == '420v') {
+ type = DrawBlitType::TexRectNV12;
+ planes = 2;
+ colorSpace = Some(
+ } else if (pixelFormat == '2vuy') {
+ type = DrawBlitType::TexRectRGB;
+ planes = 1;
+ } else {
+ gfxCriticalError() << "Unrecognized pixelFormat: " << pixelFormat;
+ return false;
+ }
+
+ const auto& prog = GetDrawBlitProg(type);
+ MOZ_RELEASE_ASSERT(prog);
+
+ if (!mIOSurfaceTexs[0]) {
+ mGL->fGenTextures(2, &mIOSurfaceTexs);
+ const ScopedBindTexture bindTex(mGL, mIOSurfaceTexs[0], LOCAL_GL_TEXTURE_RECTANGLE);
+ mGL->TexParams_SetClampNoMips(LOCAL_GL_TEXTURE_RECTANGLE);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE, mIOSurfaceTexs[1]);
+ mGL->TexParams_SetClampNoMips(LOCAL_GL_TEXTURE_RECTANGLE);
+ }
+
+ const ScopedBindMultiTex bindTex(mGL, LOCAL_GL_TEXTURE_RECTANGLE, planes,
+ mIOSurfaceTexs);
+ const auto& cglContext = gl::GLContextCGL::Cast(mGL)->GetCGLContext();
+ for (int i = 0; i < planes; i++) {
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ surf->CGLTexImageIOSurface2D(mGL, cglContext, i);
+ }
+ mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
+ mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
+
+ const auto& srcOrigin = OriginPos::TopLeft;
+ const auto& texMatrix = TexMatrixForOrigins(srcOrigin, destOrigin);
+ prog->Draw(texMatrix, destSize);
+ return true;
+}
+#endif
+
+// -----------------------------------------------------------------------------
+
+void
+GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
+ const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize,
+ const GLenum srcTarget) const
+{
+ const gfx::IntRect clipRect(0, 0, srcSize.width, srcSize.height);
+
+ DrawBlitType type;
+ gfx::IntSize texSizeDivisor;
+ switch (srcTarget) {
+ case LOCAL_GL_TEXTURE_2D:
+ type = DrawBlitType::Tex2DRGBA;
+ texSizeDivisor = srcSize;
+ break;
+ case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
+ type = DrawBlitType::TexRectRGBA;
+ texSizeDivisor = gfx::IntSize(1, 1);
+ break;
+ default:
+ gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
+ }
+ const auto& prog = GetDrawBlitProg(type);
+ MOZ_ASSERT(prog);
+
+ const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget);
+ mGL->fBindTexture(srcTarget, srcTex);
+
+ const bool yFlip = false;
+ const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, texSizeDivisor };
+ prog->Draw(baseArgs);
+}
+
+// -----------------------------------------------------------------------------
+
+void
+GLBlitHelper::BlitFramebuffer(const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize) const
+{
+ MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+
+ const ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
+ mGL->fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
+ 0, 0, destSize.width, destSize.height,
+ LOCAL_GL_COLOR_BUFFER_BIT,
+ LOCAL_GL_NEAREST);
+}
+
+// --
+
+void
+GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB, const GLuint destFB,
+ const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize) const
+{
+ MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+ MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
+ MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
+
+ const ScopedBindFramebuffer boundFB(mGL);
+ mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB);
+ mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB);
+
+ BlitFramebuffer(srcSize, destSize);
}
void
-GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
- const gfx::IntSize& srcSize,
+GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
- GLenum srcTarget,
- bool internalFBs)
+ GLenum srcTarget) const
{
MOZ_ASSERT(mGL->fIsTexture(srcTex));
- MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
- ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
- MOZ_DIAGNOSTIC_ASSERT(srcWrapper.IsComplete());
-
- BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
- srcSize, destSize,
- internalFBs);
+ const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
+ const ScopedBindFramebuffer bindFB(mGL);
+ mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcWrapper.FB());
+ BlitFramebuffer(srcSize, destSize);
return;
}
- DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget,
- internalFBs);
-}
-
-
-void
-GLBlitHelper::DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
- const gfx::IntSize& srcSize,
- const gfx::IntSize& destSize,
- GLenum srcTarget,
- bool internalFBs)
-{
- BlitType type;
- switch (srcTarget) {
- case LOCAL_GL_TEXTURE_2D:
- type = BlitTex2D;
- break;
- case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
- type = BlitTexRect;
- break;
- default:
- MOZ_CRASH("GFX: Fatal Error: Bad `srcTarget`.");
- break;
- }
-
- ScopedGLDrawState autoStates(mGL);
- const ScopedBindFramebuffer bindFB(mGL);
- if (internalFBs) {
- mGL->Screen()->BindFB_Internal(destFB);
- } else {
- mGL->BindFB(destFB);
- }
-
- // Does destructive things to (only!) what we just saved above.
- bool good = UseTexQuadProgram(type, srcSize);
- if (!good) {
- // We're up against the wall, so bail.
- MOZ_DIAGNOSTIC_ASSERT(false,
- "Error: Failed to prepare to blit texture->framebuffer.\n");
- mGL->fScissor(0, 0, destSize.width, destSize.height);
- mGL->fColorMask(1, 1, 1, 1);
- mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
- return;
- }
-
- const ScopedBindTexture bindTex(mGL, srcTex, srcTarget);
- mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+ DrawBlitTextureToFramebuffer(srcTex, srcSize, destSize, srcTarget);
}
void
-GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
+GLBlitHelper::BlitFramebufferToTexture(GLuint destTex,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
- GLenum destTarget,
- bool internalFBs)
+ GLenum destTarget) const
{
- // On the Android 4.3 emulator, IsFramebuffer may return false incorrectly.
- MOZ_ASSERT_IF(mGL->Renderer() != GLRenderer::AndroidEmulator, !srcFB || mGL->fIsFramebuffer(srcFB));
MOZ_ASSERT(mGL->fIsTexture(destTex));
if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
- ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
-
- BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(),
- srcSize, destSize,
- internalFBs);
+ const ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
+ const ScopedBindFramebuffer bindFB(mGL);
+ mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destWrapper.FB());
+ BlitFramebuffer(srcSize, destSize);
return;
}
ScopedBindTexture autoTex(mGL, destTex, destTarget);
-
- ScopedBindFramebuffer boundFB(mGL);
- if (internalFBs) {
- mGL->Screen()->BindFB_Internal(srcFB);
- } else {
- mGL->BindFB(srcFB);
- }
-
ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
mGL->fCopyTexSubImage2D(destTarget, 0,
- 0, 0,
- 0, 0,
- srcSize.width, srcSize.height);
+ 0, 0,
+ 0, 0,
+ srcSize.width, srcSize.height);
}
void
GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
- GLenum srcTarget, GLenum destTarget)
+ GLenum srcTarget, GLenum destTarget) const
{
MOZ_ASSERT(mGL->fIsTexture(srcTex));
MOZ_ASSERT(mGL->fIsTexture(destTex));
- // Generally, just use the CopyTexSubImage path
- ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
-
- BlitFramebufferToTexture(srcWrapper.FB(), destTex,
- srcSize, destSize, destTarget);
+ // Start down the CopyTexSubImage path, not the DrawBlit path.
+ const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
+ const ScopedBindFramebuffer bindFB(mGL, srcWrapper.FB());
+ BlitFramebufferToTexture(destTex, srcSize, destSize, destTarget);
}
} // namespace gl
} // namespace mozilla
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -5,160 +5,186 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GLBLITHELPER_H_
#define GLBLITHELPER_H_
#include "GLContextTypes.h"
#include "GLConsts.h"
#include "nsSize.h"
+#include "ipc/IPCMessageUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/gfx/Point.h"
+#ifdef XP_WIN
+#include <windows.h>
+#endif
+
namespace mozilla {
namespace layers {
+class D3D11YCbCrImage;
class Image;
+class GPUVideoImage;
class PlanarYCbCrImage;
class SurfaceTextureImage;
class MacIOSurfaceImage;
class EGLImageImage;
+class SurfaceDescriptorD3D10;
+class SurfaceDescriptorDXGIYCbCr;
} // namespace layers
namespace gl {
+class BindAnglePlanes;
class GLContext;
+bool
+GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
+ gfx::IntSize* const out_divisors);
+
+class DrawBlitProg final
+{
+ GLBlitHelper& mParent;
+ const GLuint mProg;
+ const GLint mLoc_u1ForYFlip;
+ const GLint mLoc_uClipRect;
+ const GLint mLoc_uTexSize0;
+ const GLint mLoc_uTexSize1;
+ const GLint mLoc_uDivisors;
+ const GLint mLoc_uColorMatrix;
+
+public:
+ DrawBlitProg(GLBlitHelper* parent, GLuint prog);
+ ~DrawBlitProg();
+
+ struct BaseArgs final {
+ gfx::IntSize destSize;
+ bool yFlip;
+ gfx::IntRect clipRect;
+ gfx::IntSize texSize0;
+ };
+ struct YUVArgs final {
+ gfx::IntSize texSize1;
+ gfx::IntSize divisors;
+ YUVColorSpace colorSpace;
+ };
+
+ void Draw(const BaseArgs& args, const YUVArgs* argsYUV = nullptr) const;
+};
+
+class ScopedSaveMultiTex final
+{
+ GLContext& mGL;
+ const uint8_t mTexCount;
+ const GLenum mTexTarget;
+ const GLuint mOldTexUnit;
+ GLuint mOldTexSampler[3];
+ GLuint mOldTex[3];
+
+public:
+ ScopedSaveMultiTex(GLContext* gl, uint8_t texCount, GLenum texTarget);
+ ~ScopedSaveMultiTex();
+};
+
/** Buffer blitting helper */
class GLBlitHelper final
{
- enum Channel
+ friend class BindAnglePlanes;
+ friend class DrawBlitProg;
+ friend class GLContext;
+
+ enum class DrawBlitType : uint8_t
{
- Channel_Y = 0,
- Channel_Cb,
- Channel_Cr,
- Channel_Max,
+ Tex2DRGBA,
+ Tex2DPlanarYUV,
+ TexRectRGBA,
+ //TexExtYUV,
+ TexExtNV12,
+ TexExtPlanarYUV,
};
- /**
- * BlitTex2D is used to copy blit the content of a GL_TEXTURE_2D object,
- * BlitTexRect is used to copy blit the content of a GL_TEXTURE_RECT object,
- * The difference between BlitTex2D and BlitTexRect is the texture type, which affect
- * the fragment shader a bit.
- *
- * ConvertPlnarYcbCr is used to color convert copy blit the PlanarYCbCrImage
- * into a normal RGB texture by create textures of each color channel, and
- * convert it in GPU.
- * Convert type is created for canvas.
- */
- enum BlitType
- {
- BlitTex2D,
- BlitTexRect,
- ConvertPlanarYCbCr,
- ConvertSurfaceTexture,
- ConvertEGLImage,
- ConvertMacIOSurfaceImage
- };
- // The GLContext is the sole owner of the GLBlitHelper.
- GLContext* mGL;
+ GLContext* const mGL;
+ std::map<uint8_t, UniquePtr<DrawBlitProg>> mDrawBlitProgs;
- GLuint mTexBlit_Buffer;
- GLuint mTexBlit_VertShader;
- GLuint mTex2DBlit_FragShader;
- GLuint mTex2DRectBlit_FragShader;
- GLuint mTex2DBlit_Program;
- GLuint mTex2DRectBlit_Program;
+ GLuint mQuadVAO;
- GLint mYFlipLoc;
+ GLuint mYuvUploads[3];
+ gfx::IntSize mYuvUploads_YSize;
+ gfx::IntSize mYuvUploads_UVSize;
- GLint mTextureTransformLoc;
+#ifdef XP_WIN
+ mutable RefPtr<ID3D11Device> mD3D11;
+
+ ID3D11Device* GetD3D11() const;
+#endif
- // Data for image blit path
- GLuint mTexExternalBlit_FragShader;
- GLuint mTexYUVPlanarBlit_FragShader;
- GLuint mTexNV12PlanarBlit_FragShader;
- GLuint mTexExternalBlit_Program;
- GLuint mTexYUVPlanarBlit_Program;
- GLuint mTexNV12PlanarBlit_Program;
- GLuint mFBO;
- GLuint mSrcTexY;
- GLuint mSrcTexCb;
- GLuint mSrcTexCr;
- GLuint mSrcTexEGL;
- GLint mYTexScaleLoc;
- GLint mCbCrTexScaleLoc;
- GLint mYuvColorMatrixLoc;
- int mTexWidth;
- int mTexHeight;
+
- // Cache some uniform values
- float mCurYScale;
- float mCurCbCrScale;
-
- void UseBlitProgram();
- void SetBlitFramebufferForDestTexture(GLuint aTexture);
+ const DrawBlitProg* GetDrawBlitProg(DrawBlitType type) const;
- bool UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize);
- bool InitTexQuadProgram(BlitType target = BlitTex2D);
- void DeleteTexBlitProgram();
- void BindAndUploadYUVTexture(Channel which, uint32_t width, uint32_t height, void* data, bool allocation);
- void BindAndUploadEGLImage(EGLImage image, GLuint target);
-
- bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage);
+ bool BlitImage(layers::PlanarYCbCrImage* yuvImage, const gfx::IntSize& destSize,
+ OriginPos destOrigin);
#ifdef MOZ_WIDGET_ANDROID
// Blit onto the current FB.
- bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage);
- bool BlitEGLImageImage(layers::EGLImageImage* eglImage);
+ bool BlitImage(layers::SurfaceTextureImage* stImage);
+ bool BlitImage(layers::EGLImageImage* eglImage);
#endif
#ifdef XP_MACOSX
- bool BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage);
+ bool BlitImage(layers::MacIOSurfaceImage* ioImage);
#endif
explicit GLBlitHelper(GLContext* gl);
-
- friend class GLContext;
-
public:
~GLBlitHelper();
- // If you don't have |srcFormats| for the 2nd definition,
- // then you'll need the framebuffer_blit extensions to use
- // the first BlitFramebufferToFramebuffer.
- void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
- const gfx::IntSize& srcSize,
- const gfx::IntSize& destSize,
- bool internalFBs = false);
+ void BlitFramebuffer(const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize) const;
void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
const gfx::IntSize& srcSize,
- const gfx::IntSize& destSize,
- const GLFormats& srcFormats,
- bool internalFBs = false);
- void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
- const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize) const;
+ void BlitFramebufferToTexture(GLuint destTex, const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
- GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
- bool internalFBs = false);
- void DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
- const gfx::IntSize& srcSize,
- const gfx::IntSize& destSize,
- GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
- bool internalFBs = false);
- void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
- const gfx::IntSize& srcSize,
+ GLenum destTarget = LOCAL_GL_TEXTURE_2D) const;
+ void BlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
- GLenum destTarget = LOCAL_GL_TEXTURE_2D,
- bool internalFBs = false);
+ GLenum srcTarget = LOCAL_GL_TEXTURE_2D) const;
void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
- GLenum destTarget = LOCAL_GL_TEXTURE_2D);
+ GLenum destTarget = LOCAL_GL_TEXTURE_2D) const;
+
+
+ void DrawBlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize,
+ GLenum srcTarget = LOCAL_GL_TEXTURE_2D) const;
+
bool BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize,
- GLuint destFB, OriginPos destOrigin);
- bool BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize,
- GLuint destTex, GLenum destTarget, OriginPos destOrigin);
+ OriginPos destOrigin);
+
+private:
+#ifdef XP_WIN
+ // GLBlitHelperD3D.cpp:
+ bool BlitImage(layers::GPUVideoImage* srcImage, const gfx::IntSize& destSize,
+ OriginPos destOrigin) const;
+ bool BlitImage(layers::D3D11YCbCrImage* srcImage, const gfx::IntSize& destSize,
+ OriginPos destOrigin) const;
+
+ bool BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
+ const gfx::IntSize& destSize, OriginPos destOrigin) const;
+
+ bool BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
+ const gfx::IntRect& clipRect,
+ const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
+ const YUVColorSpace colorSpace,
+ const gfx::IntSize& destSize, OriginPos destOrigin) const;
+
+ bool BlitAnglePlanes(uint8_t numPlanes, const RefPtr<ID3D11Texture2D>* texD3DList,
+ const DrawBlitProg* prog, const DrawBlitProg::BaseArgs& baseArgs,
+ const DrawBlitProg::YUVArgs* const yuvArgs) const;
+#endif
};
} // namespace gl
} // namespace mozilla
#endif // GLBLITHELPER_H_
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLBlitHelperD3D.cpp
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GLBlitHelper.h"
+
+#include <d3d11.h>
+
+#include "GLContext.h"
+#include "GLLibraryEGL.h"
+#include "GPUVideoImage.h"
+#include "ScopedGLHelpers.h"
+
+#include "mozilla/layers/D3D11YCbCrImage.h"
+#include "mozilla/layers/TextureD3D11.h"
+
+namespace mozilla {
+namespace gl {
+
+static EGLStreamKHR
+StreamFromD3DTexture(ID3D11Texture2D* const texD3D,
+ const EGLAttrib* const postAttribs)
+{
+ auto& egl = sEGLLibrary;
+ const auto& display = egl.Display();
+ const auto stream = egl.fCreateStreamKHR(display, nullptr);
+ MOZ_ASSERT(stream);
+ if (!stream)
+ return 0;
+ EGLBoolean ok = 1;
+ MOZ_ALWAYS_TRUE( ok &= egl.fStreamConsumerGLTextureExternalAttribsNV(display, stream,
+ nullptr) );
+ MOZ_ALWAYS_TRUE( ok &= egl.fCreateStreamProducerD3DTextureNV12ANGLE(display, stream,
+ nullptr) );
+ MOZ_ALWAYS_TRUE( ok &= egl.fStreamPostD3DTextureNV12ANGLE(display, stream, texD3D,
+ postAttribs) );
+ if (ok)
+ return stream;
+
+ (void)egl.fDestroyStreamKHR(display, stream);
+ return 0;
+}
+
+static RefPtr<ID3D11Texture2D>
+OpenSharedTexture(ID3D11Device* const d3d, const WindowsHandle handle)
+{
+ RefPtr<ID3D11Texture2D> tex;
+ auto hr = d3d->OpenSharedResource((HANDLE)handle, __uuidof(ID3D11Texture2D),
+ (void**)(ID3D11Texture2D**)getter_AddRefs(tex));
+ if (FAILED(hr)) {
+ MOZ_ASSERT(false, "OpenSharedResource should not fail");
+ return nullptr;
+ }
+ return tex;
+}
+
+// -------------------------------------
+
+class BindAnglePlanes final
+{
+ const GLBlitHelper& mParent;
+ const uint8_t mNumPlanes;
+ const ScopedSaveMultiTex mMultiTex;
+ GLuint mTempTexs[3];
+ EGLStreamKHR mStreams[3];
+ RefPtr<IDXGIKeyedMutex> mMutexList[3];
+ bool mSuccess;
+
+public:
+ BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes,
+ const RefPtr<ID3D11Texture2D>* const texD3DList,
+ const EGLAttrib* const* postAttribsList = nullptr)
+ : mParent(*parent)
+ , mNumPlanes(numPlanes)
+ , mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL)
+ , mTempTexs{0}
+ , mStreams{0}
+ , mSuccess(true)
+ {
+ MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);
+
+ const auto& gl = mParent.mGL;
+ auto& egl = sEGLLibrary;
+ const auto& display = egl.Display();
+
+ gl->fGenTextures(numPlanes, mTempTexs);
+
+ for (uint8_t i = 0; i < mNumPlanes; i++) {
+ gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]);
+ const EGLAttrib* postAttribs = nullptr;
+ if (postAttribsList) {
+ postAttribs = postAttribsList[i];
+ }
+ mStreams[i] = StreamFromD3DTexture(texD3DList[i], postAttribs);
+ mSuccess &= bool(mStreams[i]);
+ }
+
+ if (mSuccess) {
+ for (uint8_t i = 0; i < mNumPlanes; i++) {
+ MOZ_ALWAYS_TRUE( egl.fStreamConsumerAcquireKHR(display, mStreams[i]) );
+
+ auto& mutex = mMutexList[i];
+ texD3DList[i]->QueryInterface(_uuidof(IDXGIKeyedMutex),
+ (void**)getter_AddRefs(mutex));
+ if (mutex) {
+ HRESULT hr = mutex->AcquireSync(0, 100);
+ if (hr != S_OK) {
+ NS_WARNING("Acquire sync didn't manage to return within 2 seconds.");
+ mSuccess = false;
+ }
+ }
+ }
+ }
+ }
+
+ ~BindAnglePlanes()
+ {
+ const auto& gl = mParent.mGL;
+ auto& egl = sEGLLibrary;
+ const auto& display = egl.Display();
+
+ if (mSuccess) {
+ for (uint8_t i = 0; i < mNumPlanes; i++) {
+ MOZ_ALWAYS_TRUE( egl.fStreamConsumerReleaseKHR(display, mStreams[i]) );
+ if (mMutexList[i]) {
+ mMutexList[i]->ReleaseSync(0);
+ }
+ }
+ }
+
+ for (uint8_t i = 0; i < mNumPlanes; i++) {
+ (void)egl.fDestroyStreamKHR(display, mStreams[i]);
+ }
+
+ gl->fDeleteTextures(mNumPlanes, mTempTexs);
+ }
+
+ const bool& Success() const { return mSuccess; }
+};
+
+// -------------------------------------
+
+ID3D11Device*
+GLBlitHelper::GetD3D11() const
+{
+ if (mD3D11)
+ return mD3D11;
+
+ if (!mGL->IsANGLE())
+ return nullptr;
+
+ auto& egl = sEGLLibrary;
+ EGLDeviceEXT deviceEGL = 0;
+ MOZ_ALWAYS_TRUE( egl.fQueryDisplayAttribEXT(egl.Display(), LOCAL_EGL_DEVICE_EXT,
+ (EGLAttrib*)&deviceEGL) );
+ if (!egl.fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE,
+ (EGLAttrib*)(ID3D11Device**)getter_AddRefs(mD3D11)))
+ {
+ MOZ_ASSERT(false, "d3d9?");
+ return nullptr;
+ }
+ return mD3D11;
+}
+
+// -------------------------------------
+
+bool
+GLBlitHelper::BlitImage(layers::GPUVideoImage* const srcImage,
+ const gfx::IntSize& destSize, const OriginPos destOrigin) const
+{
+ const auto& data = srcImage->GetData();
+ if (!data)
+ return false;
+
+ const auto& desc = data->SD();
+ const auto& subdescUnion = desc.subdesc();
+ switch (subdescUnion.type()) {
+ case subdescUnion.TSurfaceDescriptorD3D10:
+ {
+ const auto& subdesc = subdescUnion.get_SurfaceDescriptorD3D10();
+ return BlitDescriptor(subdesc, destSize, destOrigin);
+ }
+ case subdescUnion.TSurfaceDescriptorDXGIYCbCr:
+ {
+ const auto& subdesc = subdescUnion.get_SurfaceDescriptorDXGIYCbCr();
+
+ const auto& clipSize = subdesc.size();
+ const auto& ySize = subdesc.sizeY();
+ const auto& uvSize = subdesc.sizeCbCr();
+
+ const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
+ const auto colorSpace = YUVColorSpace::BT601;
+
+ const WindowsHandle handles[3] = {
+ subdesc.handleY(),
+ subdesc.handleCb(),
+ subdesc.handleCr()
+ };
+ return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
+ destOrigin);
+ }
+ default:
+ gfxCriticalError() << "Unhandled subdesc type: " << uint32_t(subdescUnion.type());
+ return false;
+ }
+}
+
+// -------------------------------------
+
+bool
+GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage,
+ const gfx::IntSize& destSize, const OriginPos destOrigin) const
+{
+ const auto& data = srcImage->GetData();
+ if (!data)
+ return false;
+
+ const auto& clipRect = srcImage->mPictureRect;
+ const auto& colorSpace = srcImage->mColorSpace;
+
+ const WindowsHandle handles[3] = {
+ (WindowsHandle)data->mHandles[0],
+ (WindowsHandle)data->mHandles[1],
+ (WindowsHandle)data->mHandles[2]
+ };
+ return BlitAngleYCbCr(handles, srcImage->mPictureRect, srcImage->mYSize,
+ srcImage->mCbCrSize, srcImage->mColorSpace, destSize,
+ destOrigin);
+}
+
+// -------------------------------------
+
+bool
+GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
+ const gfx::IntSize& destSize, OriginPos destOrigin) const
+{
+ const auto& d3d = GetD3D11();
+ if (!d3d)
+ return false;
+
+ const auto& handle = desc.handle();
+ const auto& format = desc.format();
+ const auto& clipSize = desc.size();
+
+ const auto srcOrigin = OriginPos::BottomLeft;
+ const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
+ const auto colorSpace = YUVColorSpace::BT601;
+
+ if (format != gfx::SurfaceFormat::NV12) {
+ gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
+ << uint32_t(format);
+ return nullptr;
+ }
+
+ const auto tex = OpenSharedTexture(d3d, handle);
+ const RefPtr<ID3D11Texture2D> texList[2] = { tex, tex };
+ const EGLAttrib postAttribs0[] = {
+ LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
+ LOCAL_EGL_NONE
+ };
+ const EGLAttrib postAttribs1[] = {
+ LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
+ LOCAL_EGL_NONE
+ };
+ const EGLAttrib* const postAttribsList[2] = { postAttribs0, postAttribs1 };
+ // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
+ //return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);
+
+ const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList);
+
+ D3D11_TEXTURE2D_DESC texDesc = {0};
+ tex->GetDesc(&texDesc);
+
+ const gfx::IntSize ySize(texDesc.Width, texDesc.Height);
+ const gfx::IntSize divisors(2, 2);
+ MOZ_ASSERT(ySize.width % divisors.width == 0);
+ MOZ_ASSERT(ySize.height % divisors.height == 0);
+ const gfx::IntSize uvSize(ySize.width / divisors.width,
+ ySize.height / divisors.height);
+
+ const bool yFlip = destOrigin != srcOrigin;
+ const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, ySize };
+ const DrawBlitProg::YUVArgs yuvArgs = { uvSize, divisors, colorSpace };
+
+ const auto& prog = GetDrawBlitProg(DrawBlitType::TexExtNV12);
+ MOZ_RELEASE_ASSERT(prog);
+ prog->Draw(baseArgs, &yuvArgs);
+ return true;
+}
+
+// --
+
+bool
+GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
+ const gfx::IntRect& clipRect,
+ const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
+ const YUVColorSpace colorSpace,
+ const gfx::IntSize& destSize, OriginPos destOrigin) const
+{
+ const auto& d3d = GetD3D11();
+ if (!d3d)
+ return false;
+
+ const auto srcOrigin = OriginPos::BottomLeft;
+
+ gfx::IntSize divisors;
+ if (!GuessDivisors(ySize, uvSize, &divisors))
+ return false;
+
+ const RefPtr<ID3D11Texture2D> texList[3] = {
+ OpenSharedTexture(d3d, handleList[0]),
+ OpenSharedTexture(d3d, handleList[1]),
+ OpenSharedTexture(d3d, handleList[2])
+ };
+ const BindAnglePlanes bindPlanes(this, 3, texList);
+
+ const bool yFlip = destOrigin != srcOrigin;
+ const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, ySize };
+ const DrawBlitProg::YUVArgs yuvArgs = { uvSize, divisors, colorSpace };
+
+ const auto& prog = GetDrawBlitProg(DrawBlitType::TexExtPlanarYUV);
+ MOZ_RELEASE_ASSERT(prog);
+ prog->Draw(baseArgs, &yuvArgs);
+ return true;
+}
+
+} // namespace gl
+} // namespace mozilla
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1412,16 +1412,30 @@ public:
realGLboolean fIsEnabled(GLenum capability) {
BEFORE_GL_CALL;
realGLboolean retval = mSymbols.fIsEnabled(capability);
AFTER_GL_CALL;
return retval;
}
+ void SetEnabled(const GLenum cap, const bool val) {
+ if (val) {
+ fEnable(cap);
+ } else {
+ fDisable(cap);
+ }
+ }
+
+ bool PushEnabled(const GLenum cap, const bool newVal) {
+ const auto oldVal = fIsEnabled(cap);
+ SetEnabled(cap, newVal);
+ return oldVal;
+ }
+
realGLboolean fIsProgram(GLuint program) {
BEFORE_GL_CALL;
realGLboolean retval = mSymbols.fIsProgram(program);
AFTER_GL_CALL;
return retval;
}
realGLboolean fIsShader(GLuint shader) {
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -109,17 +109,17 @@ public:
const SurfaceCaps& minCaps,
nsACString* const out_FailureId);
protected:
friend class GLContextProviderEGL;
friend class GLContextEGLFactory;
public:
- const EGLConfig mConfig;
+ const EGLConfig mConfig;
protected:
EGLSurface mSurface;
public:
const EGLContext mContext;
protected:
EGLSurface mSurfaceOverride;
RefPtr<gfxASurface> mThebesSurface;
bool mBound;
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -603,16 +603,17 @@ GLLibraryEGL::EnsureInitialized(bool for
if (!fnLoadSymbols(streamSymbols)) {
NS_ERROR("EGL supports KHR_stream without exposing its functions!");
MarkExtensionUnsupported(KHR_stream);
}
}
if (IsExtensionSupported(KHR_stream_consumer_gltexture)) {
const GLLibraryLoader::SymLoadStruct streamConsumerSymbols[] = {
+ SYMBOL(StreamConsumerGLTextureExternalKHR),
SYMBOL(StreamConsumerAcquireKHR),
SYMBOL(StreamConsumerReleaseKHR),
END_OF_SYMBOLS
};
if (!fnLoadSymbols(streamConsumerSymbols)) {
NS_ERROR("EGL supports KHR_stream_consumer_gltexture without exposing its functions!");
MarkExtensionUnsupported(KHR_stream_consumer_gltexture);
}
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -293,16 +293,19 @@ public:
EGLBoolean fDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) const
WRAP( fDestroyStreamKHR(dpy, stream) )
EGLBoolean fQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint* value) const
WRAP( fQueryStreamKHR(dpy, stream, attribute, value) )
// KHR_stream_consumer_gltexture
+ EGLBoolean fStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) const
+ WRAP( fStreamConsumerGLTextureExternalKHR(dpy, stream) )
+
EGLBoolean fStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) const
WRAP( fStreamConsumerAcquireKHR(dpy, stream) )
EGLBoolean fStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) const
WRAP( fStreamConsumerReleaseKHR(dpy, stream) )
// EXT_device_query
EGLBoolean fQueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib* value) const
@@ -453,16 +456,18 @@ private:
//KHR_stream
EGLStreamKHR (GLAPIENTRY * fCreateStreamKHR)(EGLDisplay dpy, const EGLint* attrib_list);
EGLBoolean (GLAPIENTRY * fDestroyStreamKHR)(EGLDisplay dpy, EGLStreamKHR stream);
EGLBoolean (GLAPIENTRY * fQueryStreamKHR)(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint* value);
// KHR_stream_consumer_gltexture
+ EGLBoolean (GLAPIENTRY * fStreamConsumerGLTextureExternalKHR)(EGLDisplay dpy,
+ EGLStreamKHR stream);
EGLBoolean (GLAPIENTRY * fStreamConsumerAcquireKHR)(EGLDisplay dpy,
EGLStreamKHR stream);
EGLBoolean (GLAPIENTRY * fStreamConsumerReleaseKHR)(EGLDisplay dpy,
EGLStreamKHR stream);
// EXT_device_query
EGLBoolean (GLAPIENTRY * fQueryDisplayAttribEXT)(EGLDisplay dpy,
EGLint attribute,
EGLAttrib* value);
--- a/gfx/gl/HeapCopyOfStackArray.h
+++ b/gfx/gl/HeapCopyOfStackArray.h
@@ -18,17 +18,17 @@ namespace mozilla {
// Useful to retain the convenience of declaring static arrays, while
// avoiding passing stack pointers to the GL (see bug 1005658).
template <typename ElemType>
class HeapCopyOfStackArray
{
public:
template<size_t N>
- MOZ_IMPLICIT HeapCopyOfStackArray(ElemType (&array)[N])
+ MOZ_IMPLICIT HeapCopyOfStackArray(const ElemType (&array)[N])
: mArrayLength(N)
, mArrayData(MakeUnique<ElemType[]>(N))
{
memcpy(mArrayData.get(), &array[0], N * sizeof(ElemType));
}
ElemType* Data() const { return mArrayData.get(); }
size_t ArrayLength() const { return mArrayLength; }
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -418,85 +418,16 @@ ScopedVertexAttribPointer::UnwrapImpl()
mGL->fVertexAttribPointer(mAttribIndex, mAttribSize, mAttribType, mAttribNormalized, mAttribStride, mAttribPointer);
if (mAttribEnabled)
mGL->fEnableVertexAttribArray(mAttribIndex);
else
mGL->fDisableVertexAttribArray(mAttribIndex);
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer);
}
-ScopedGLDrawState::ScopedGLDrawState(GLContext* aGL)
- : blend (aGL, LOCAL_GL_BLEND, false)
- , cullFace (aGL, LOCAL_GL_CULL_FACE, false)
- , depthTest (aGL, LOCAL_GL_DEPTH_TEST, false)
- , dither (aGL, LOCAL_GL_DITHER, false)
- , polyOffsFill(aGL, LOCAL_GL_POLYGON_OFFSET_FILL, false)
- , sampleAToC (aGL, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false)
- , sampleCover (aGL, LOCAL_GL_SAMPLE_COVERAGE, false)
- , scissor (aGL, LOCAL_GL_SCISSOR_TEST, false)
- , stencil (aGL, LOCAL_GL_STENCIL_TEST, false)
- , mGL(aGL)
-{
- mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram);
- mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer);
- mGL->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &maxAttrib);
- attrib_enabled = MakeUnique<GLint[]>(maxAttrib);
-
- for (GLuint i = 0; i < maxAttrib; i++) {
- mGL->fGetVertexAttribiv(i, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib_enabled[i]);
- mGL->fDisableVertexAttribArray(i);
- }
- // Only Attrib0's client side state affected
- mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size);
- mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride);
- mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type);
- mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized);
- mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding);
- mGL->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer);
- mGL->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
- mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
- mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, scissorBox);
-}
-
-ScopedGLDrawState::~ScopedGLDrawState()
-{
- MOZ_ASSERT(mGL->IsCurrent());
-
- mGL->fScissor(scissorBox[0], scissorBox[1],
- scissorBox[2], scissorBox[3]);
-
- mGL->fViewport(viewport[0], viewport[1],
- viewport[2], viewport[3]);
-
- mGL->fColorMask(colorMask[0],
- colorMask[1],
- colorMask[2],
- colorMask[3]);
-
- for (unsigned int i = 0; i < maxAttrib; i++) {
- if (attrib_enabled[i])
- mGL->fEnableVertexAttribArray(i);
- else
- mGL->fDisableVertexAttribArray(i);
- }
-
-
- mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding);
- mGL->fVertexAttribPointer(0,
- attrib0_size,
- attrib0_type,
- attrib0_normalized,
- attrib0_stride,
- attrib0_pointer);
-
- mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer);
-
- mGL->fUseProgram(boundProgram);
-}
-
////////////////////////////////////////////////////////////////////////
// ScopedPackState
ScopedPackState::ScopedPackState(GLContext* gl)
: ScopedGLWrapper<ScopedPackState>(gl)
{
mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
--- a/gfx/gl/ScopedGLHelpers.h
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -117,17 +117,17 @@ struct ScopedTexture
{
friend struct ScopedGLWrapper<ScopedTexture>;
protected:
GLuint mTexture;
public:
explicit ScopedTexture(GLContext* aGL);
- GLuint Texture() { return mTexture; }
+ GLuint Texture() const { return mTexture; }
protected:
void UnwrapImpl();
};
struct ScopedFramebuffer
: public ScopedGLWrapper<ScopedFramebuffer>
@@ -304,49 +304,16 @@ public:
GLsizei stride, GLuint buffer, const GLvoid* pointer);
explicit ScopedVertexAttribPointer(GLContext* aGL, GLuint index);
protected:
void WrapImpl(GLuint index);
void UnwrapImpl();
};
-struct ScopedGLDrawState
-{
- explicit ScopedGLDrawState(GLContext* gl);
- ~ScopedGLDrawState();
-
- GLuint boundProgram;
- GLuint boundBuffer;
-
- ScopedGLState blend;
- ScopedGLState cullFace;
- ScopedGLState depthTest;
- ScopedGLState dither;
- ScopedGLState polyOffsFill;
- ScopedGLState sampleAToC;
- ScopedGLState sampleCover;
- ScopedGLState scissor;
- ScopedGLState stencil;
-
- GLuint maxAttrib;
- UniquePtr<GLint[]> attrib_enabled;
- GLint attrib0_size;
- GLint attrib0_stride;
- GLint attrib0_type;
- GLint attrib0_normalized;
- GLint attrib0_bufferBinding;
- void* attrib0_pointer;
-
- realGLboolean colorMask[4];
- GLint viewport[4];
- GLint scissorBox[4];
- GLContext* const mGL;
-};
-
struct ScopedPackState
: public ScopedGLWrapper<ScopedPackState>
{
friend struct ScopedGLWrapper<ScopedPackState>;
protected:
GLint mAlignment;
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -60,17 +60,19 @@ SharedSurface::ProdCopy(SharedSurface* s
src->LockProd();
srcNeedsUnlock = true;
}
if (dest->mAttachType == AttachmentType::GLTexture) {
GLuint destTex = dest->ProdTexture();
GLenum destTarget = dest->ProdTextureTarget();
- gl->BlitHelper()->BlitFramebufferToTexture(0, destTex,
+ const ScopedBindFramebuffer bindFB(gl, 0);
+
+ gl->BlitHelper()->BlitFramebufferToTexture(destTex,
src->mSize,
dest->mSize,
destTarget,
true);
} else if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
@@ -105,17 +107,19 @@ SharedSurface::ProdCopy(SharedSurface* s
dest->LockProd();
destNeedsUnlock = true;
}
if (src->mAttachType == AttachmentType::GLTexture) {
GLuint srcTex = src->ProdTexture();
GLenum srcTarget = src->ProdTextureTarget();
- gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0,
+ const ScopedBindFramebuffer bindFB(gl, 0);
+
+ gl->BlitHelper()->BlitTextureToFramebuffer(srcTex,
src->mSize,
dest->mSize,
srcTarget,
!!gl->Screen());
} else if (src->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint srcRB = src->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
@@ -153,36 +157,37 @@ SharedSurface::ProdCopy(SharedSurface* s
srcTarget, destTarget);
return;
}
if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
-
- gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(),
- src->mSize, dest->mSize, srcTarget);
+ const ScopedBindFramebuffer bindFB(gl, destWrapper.FB());
+ gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, src->mSize, dest->mSize,
+ srcTarget);
return;
}
MOZ_CRASH("GFX: Unhandled dest->mAttachType 3.");
}
if (src->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint srcRB = src->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
if (dest->mAttachType == AttachmentType::GLTexture) {
GLuint destTex = dest->ProdTexture();
GLenum destTarget = dest->ProdTextureTarget();
+ const ScopedBindFramebuffer bindFB(gl, srcWrapper.FB());
- gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex,
- src->mSize, dest->mSize, destTarget);
+ gl->BlitHelper()->BlitFramebufferToTexture(destTex, src->mSize, dest->mSize,
+ destTarget);
return;
}
if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
--- a/gfx/gl/SharedSurfaceD3D11Interop.cpp
+++ b/gfx/gl/SharedSurfaceD3D11Interop.cpp
@@ -466,18 +466,18 @@ SharedSurface_D3D11Interop::ProducerAcqu
}
void
SharedSurface_D3D11Interop::ProducerReleaseImpl()
{
MOZ_ASSERT(mLockedForGL);
if (mProdTex) {
- mGL->BlitHelper()->DrawBlitTextureToFramebuffer(mProdTex, mInteropFB, mSize,
- mSize);
+ const ScopedBindFramebuffer bindFB(mGL, mInteropFB);
+ mGL->BlitHelper()->DrawBlitTextureToFramebuffer(mProdTex, mSize, mSize);
}
if (mNeedsFinish) {
mGL->fFinish();
} else {
// We probably don't even need this.
mGL->fFlush();
}
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -64,16 +64,17 @@ if CONFIG['MOZ_X11']:
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
EXPORTS += [
'GLContextWGL.h',
'SharedSurfaceANGLE.h', # Needs <windows.h> for `HANDLE`.
'SharedSurfaceD3D11Interop.h',
'WGLLibrary.h',
]
UNIFIED_SOURCES += [
+ 'GLBlitHelperD3D.cpp',
'GLContextProviderWGL.cpp',
'SharedSurfaceANGLE.cpp',
'SharedSurfaceD3D11Interop.cpp',
]
if CONFIG['MOZ_ENABLE_SKIA_GPU']:
EXPORTS += ['SkiaGLGlue.h']
SOURCES += [
'SkiaGLGlue.cpp',
--- a/gfx/layers/D3D11YCbCrImage.cpp
+++ b/gfx/layers/D3D11YCbCrImage.cpp
@@ -92,32 +92,41 @@ D3D11YCbCrImage::SetData(KnowsCompositor
aData.mCbCrStride * aData.mCbCrSize.height);
ctx->UpdateSubresource(textureCr,
0,
nullptr,
aData.mCrChannel,
aData.mCbCrStride,
aData.mCbCrStride * aData.mCbCrSize.height);
-
+
return true;
}
IntSize
D3D11YCbCrImage::GetSize()
{
return mPictureRect.Size();
}
TextureClient*
D3D11YCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
{
return mTextureClient;
}
+const DXGIYCbCrTextureData*
+D3D11YCbCrImage::GetData() const
+{
+ if (!mTextureClient)
+ return nullptr;
+
+ return static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData());
+}
+
already_AddRefed<SourceSurface>
D3D11YCbCrImage::GetAsSourceSurface()
{
if (!mTextureClient) {
gfxWarning()
<< "GetAsSourceSurface() called on uninitialized D3D11YCbCrImage.";
return nullptr;
}
--- a/gfx/layers/D3D11YCbCrImage.h
+++ b/gfx/layers/D3D11YCbCrImage.h
@@ -7,20 +7,24 @@
#define GFX_D3D11_YCBCR_IMAGE_H
#include "d3d11.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "mozilla/Maybe.h"
#include "ImageContainer.h"
namespace mozilla {
+namespace gl {
+class GLBlitHelper;
+}
namespace layers {
class ImageContainer;
class DXGIYCbCrTextureClient;
+class DXGIYCbCrTextureData;
class D3D11YCbCrRecycleAllocator : public TextureClientRecycleAllocator
{
public:
explicit D3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator,
ID3D11Device* aDevice)
: TextureClientRecycleAllocator(aAllocator)
, mDevice(aDevice)
@@ -41,16 +45,17 @@ protected:
RefPtr<ID3D11Device> mDevice;
Maybe<gfx::IntSize> mYSize;
Maybe<gfx::IntSize> mCbCrSize;
};
class D3D11YCbCrImage : public Image
{
+ friend class gl::GLBlitHelper;
public:
D3D11YCbCrImage();
virtual ~D3D11YCbCrImage();
// Copies the surface into a sharable texture's surface, and initializes
// the image.
bool SetData(KnowsCompositor* aAllocator,
ImageContainer* aContainer,
@@ -60,16 +65,19 @@ public:
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
gfx::IntRect GetPictureRect() override { return mPictureRect; }
private:
+ const DXGIYCbCrTextureData* GetData() const;
+
+private:
gfx::IntSize mYSize;
gfx::IntSize mCbCrSize;
gfx::IntRect mPictureRect;
YUVColorSpace mColorSpace;
RefPtr<TextureClient> mTextureClient;
};
} // namepace layers
--- a/gfx/layers/GLImages.cpp
+++ b/gfx/layers/GLImages.cpp
@@ -73,22 +73,21 @@ GLImage::GetAsSourceSurface()
ScopedFramebufferForTexture autoFBForTex(sSnapshotContext, scopedTex.Texture());
if (!autoFBForTex.IsComplete()) {
gfxCriticalError() << "GetAsSourceSurface: ScopedFramebufferForTexture failed.";
return nullptr;
}
const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
-
- if (!sSnapshotContext->BlitHelper()->BlitImageToFramebuffer(this, size,
- autoFBForTex.FB(),
- destOrigin))
{
- return nullptr;
+ const ScopedBindFramebuffer bindFB(sSnapshotContext, autoFBForTex.FB());
+ if (!sSnapshotContext->BlitHelper()->BlitImageToFramebuffer(this, size, destOrigin)) {
+ return nullptr;
+ }
}
RefPtr<gfx::DataSourceSurface> source =
gfx::Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8A8);
if (NS_WARN_IF(!source)) {
return nullptr;
}
--- a/gfx/layers/GPUVideoImage.h
+++ b/gfx/layers/GPUVideoImage.h
@@ -40,22 +40,29 @@ public:
TextureFlags::RECYCLE,
ImageBridgeChild::GetSingleton().get());
}
~GPUVideoImage() override {}
gfx::IntSize GetSize() override { return mSize; }
- virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override
- {
+ GPUVideoTextureData* GetData() const {
if (!mTextureClient) {
return nullptr;
}
- GPUVideoTextureData* data = mTextureClient->GetInternalData()->AsGPUVideoTextureData();
+ return mTextureClient->GetInternalData()->AsGPUVideoTextureData();
+ }
+
+ virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override
+ {
+ GPUVideoTextureData* data = GetData();
+ if (!data) {
+ return nullptr;
+ }
return data->GetAsSourceSurface();
}
virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override
{
MOZ_ASSERT(aForwarder == ImageBridgeChild::GetSingleton(), "Must only use GPUVideo on ImageBridge");
return mTextureClient;
}
--- a/gfx/layers/client/GPUVideoTextureClient.h
+++ b/gfx/layers/client/GPUVideoTextureClient.h
@@ -43,14 +43,17 @@ public:
{
return this;
}
protected:
RefPtr<dom::VideoDecoderManagerChild> mManager;
SurfaceDescriptorGPUVideo mSD;
gfx::IntSize mSize;
+
+public:
+ const SurfaceDescriptorGPUVideo& SD() const { return mSD; }
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_GPUVIDEOTEXTURECLIENT_H
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -13,16 +13,20 @@
#include "mozilla/layers/TextureHost.h"
#include "gfxWindowsPlatform.h"
#include "mozilla/GfxMessageUtils.h"
#include <d3d11.h>
#include "d3d9.h"
#include <vector>
namespace mozilla {
+namespace gl {
+class GLBlitHelper;
+}
+
namespace layers {
class MOZ_RAII AutoTextureLock
{
public:
AutoTextureLock(IDXGIKeyedMutex* aMutex, HRESULT& aResult,
uint32_t aTimeout = 0);
~AutoTextureLock();
@@ -123,16 +127,17 @@ protected:
already_AddRefed<TextureClient>
CreateD3D11extureClientWithDevice(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags,
ID3D11Device* aDevice,
LayersIPCChannel* aAllocator);
class DXGIYCbCrTextureData : public TextureData
{
+ friend class gl::GLBlitHelper;
public:
static DXGIYCbCrTextureData*
Create(IDirect3DTexture9* aTextureY,
IDirect3DTexture9* aTextureCb,
IDirect3DTexture9* aTextureCr,
HANDLE aHandleY,
HANDLE aHandleCb,
HANDLE aHandleCr,
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -84,17 +84,17 @@ struct SurfaceDescriptorSharedGLTexture
union GPUVideoSubDescriptor {
SurfaceDescriptorD3D10;
SurfaceDescriptorDXGIYCbCr;
null_t;
};
struct SurfaceDescriptorGPUVideo {
uint64_t handle;
- GPUVideoSubDescriptor desc;
+ GPUVideoSubDescriptor subdesc;
};
struct RGBDescriptor {
IntSize size;
SurfaceFormat format;
bool hasIntermediateBuffer;
};
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1106,57 +1106,39 @@ gfxUtils::EncodeSourceSurface(SourceSurf
const nsAString& aOutputOptions,
BinaryOrData aBinaryOrData,
FILE* aFile)
{
return EncodeSourceSurfaceInternal(aSurface, aMimeType, aOutputOptions,
aBinaryOrData, aFile, nullptr);
}
-/* From Rec601:
-[R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
-[G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
-[B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
-
-For [0,1] instead of [0,255], and to 5 places:
-[R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
-[G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
-[B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
-
-From Rec709:
-[R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [ Y - 16]
-[G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444] x [Cb - 128]
-[B] [1.1643835616438356, 2.1124017857142854, 0.0] [Cr - 128]
-
-For [0,1] instead of [0,255], and to 5 places:
-[R] [1.16438, 0.00000, 1.79274] [ Y - 0.06275]
-[G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
-[B] [1.16438, 2.11240, 0.00000] [Cr - 0.50196]
-*/
-
-static const float kRec601[9] = {
- 1.16438f, 0.00000f, 1.59603f,
- 1.16438f,-0.39176f,-0.81297f,
- 1.16438f, 2.01723f, 0.00000f,
+// https://jdashg.github.io/misc/colors/from-coeffs.html
+const float kBT601NarrowYCbCrToRGB_RowMajor[16] = {
+ 1.16438f, 0.00000f, 1.59603f,-0.87420f,
+ 1.16438f,-0.39176f,-0.81297f, 0.53167f,
+ 1.16438f, 2.01723f, 0.00000f,-1.08563f,
+ 0.00000f, 0.00000f, 0.00000f, 1.00000f
};
-static const float kRec709[9] = {
- 1.16438f, 0.00000f, 1.79274f,
- 1.16438f,-0.21325f,-0.53291f,
- 1.16438f, 2.11240f, 0.00000f,
+const float kBT709NarrowYCbCrToRGB_RowMajor[16] = {
+ 1.16438f, 0.00000f, 1.79274f,-0.97295f,
+ 1.16438f,-0.21325f,-0.53291f, 0.30148f,
+ 1.16438f, 2.11240f, 0.00000f,-1.13340f,
+ 0.00000f, 0.00000f, 0.00000f, 1.00000f
};
/* static */ const float*
gfxUtils::YuvToRgbMatrix4x3RowMajor(YUVColorSpace aYUVColorSpace)
{
- #define X(x) { x[0], x[1], x[2], 0.0f, \
- x[3], x[4], x[5], 0.0f, \
- x[6], x[7], x[8], 0.0f }
+ #define X(x) { x[0], x[1], x[ 2], 0.0f, \
+ x[4], x[5], x[ 6], 0.0f, \
+ x[8], x[9], x[10], 0.0f }
- static const float rec601[12] = X(kRec601);
- static const float rec709[12] = X(kRec709);
+ static const float rec601[12] = X(kBT601NarrowYCbCrToRGB_RowMajor);
+ static const float rec709[12] = X(kBT709NarrowYCbCrToRGB_RowMajor);
#undef X
switch (aYUVColorSpace) {
case YUVColorSpace::BT601:
return rec601;
case YUVColorSpace::BT709:
return rec709;
@@ -1164,22 +1146,46 @@ gfxUtils::YuvToRgbMatrix4x3RowMajor(YUVC
MOZ_ASSERT(false, "unknown aYUVColorSpace");
return rec601;
}
}
/* static */ const float*
gfxUtils::YuvToRgbMatrix3x3ColumnMajor(YUVColorSpace aYUVColorSpace)
{
- #define X(x) { x[0], x[3], x[6], \
- x[1], x[4], x[7], \
- x[2], x[5], x[8] }
+ #define X(x) { x[0], x[4], x[ 8], \
+ x[1], x[5], x[ 9], \
+ x[2], x[6], x[10] }
+
+ static const float rec601[9] = X(kBT601NarrowYCbCrToRGB_RowMajor);
+ static const float rec709[9] = X(kBT709NarrowYCbCrToRGB_RowMajor);
+
+ #undef X
- static const float rec601[9] = X(kRec601);
- static const float rec709[9] = X(kRec709);
+ switch (aYUVColorSpace) {
+ case YUVColorSpace::BT601:
+ return rec601;
+ case YUVColorSpace::BT709:
+ return rec709;
+ default: // YUVColorSpace::UNKNOWN
+ MOZ_ASSERT(false, "unknown aYUVColorSpace");
+ return rec601;
+ }
+}
+
+/* static */ const float*
+gfxUtils::YuvToRgbMatrix4x4ColumnMajor(YUVColorSpace aYUVColorSpace)
+{
+ #define X(x) { x[0], x[4], x[ 8], x[12], \
+ x[1], x[5], x[ 9], x[13], \
+ x[2], x[6], x[10], x[14], \
+ x[3], x[7], x[11], x[15] }
+
+ static const float rec601[16] = X(kBT601NarrowYCbCrToRGB_RowMajor);
+ static const float rec709[16] = X(kBT709NarrowYCbCrToRGB_RowMajor);
#undef X
switch (aYUVColorSpace) {
case YUVColorSpace::BT601:
return rec601;
case YUVColorSpace::BT709:
return rec709;
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -153,16 +153,17 @@ public:
/**
* Clears surface to aColor (which defaults to transparent black).
*/
static void ClearThebesSurface(gfxASurface* aSurface);
static const float* YuvToRgbMatrix4x3RowMajor(mozilla::YUVColorSpace aYUVColorSpace);
static const float* YuvToRgbMatrix3x3ColumnMajor(mozilla::YUVColorSpace aYUVColorSpace);
+ static const float* YuvToRgbMatrix4x4ColumnMajor(mozilla::YUVColorSpace aYUVColorSpace);
/**
* Creates a copy of aSurface, but having the SurfaceFormat aFormat.
*
* This function always creates a new surface. Do not call it if aSurface's
* format is the same as aFormat. Such a non-conversion would just be an
* unnecessary and wasteful copy (this function asserts to prevent that).
*