--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -113,16 +113,93 @@ const char* const kFragBody_PlanarYUV =
1.0); \n\
vec4 rgb = uColorMatrix * yuv; \n\
FRAG_COLOR = vec4(rgb.rgb, 1.0); \n\
} \n\
";
// --
+template<uint8_t N>
+/*static*/ Mat<N>
+Mat<N>::Zero()
+{
+ Mat<N> ret;
+ for (auto& x : ret.m) {
+ x = 0.0f;
+ }
+ return ret;
+}
+
+template<uint8_t N>
+/*static*/ Mat<N>
+Mat<N>::I()
+{
+ auto ret = Mat<N>::Zero();
+ for (uint8_t i = 0; i < N; i++) {
+ ret.at(i,i) = 1.0f;
+ }
+ return ret;
+}
+
+template<uint8_t N>
+Mat<N>
+Mat<N>::operator*(const Mat<N>& r) const
+{
+ Mat<N> ret;
+ for (uint8_t x = 0; x < N; x++) {
+ for (uint8_t y = 0; y < N; y++) {
+ float sum = 0.0f;
+ for (uint8_t i = 0; i < N; i++) {
+ sum += at(i,y) * r.at(x,i);
+ }
+ ret.at(x,y) = sum;
+ }
+ }
+ return ret;
+}
+
+Mat3
+SubRectMat3(const float x, const float y, const float w, const float h)
+{
+ auto ret = Mat3::Zero();
+ ret.at(0,0) = w;
+ ret.at(1,1) = h;
+ ret.at(2,0) = x;
+ ret.at(2,1) = y;
+ ret.at(2,2) = 1.0f;
+ return ret;
+}
+
+Mat3
+SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size)
+{
+ return SubRectMat3(subrect.x / size.width,
+ subrect.y / size.height,
+ subrect.width / size.width,
+ subrect.height / size.height);
+}
+
+Mat3
+SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
+ const gfx::IntSize& divisors)
+{
+ const float x = float(bigSubrect.x) / divisors.width;
+ const float y = float(bigSubrect.y) / divisors.height;
+ const float w = float(bigSubrect.width) / divisors.width;
+ const float h = float(bigSubrect.height) / divisors.height;
+ return SubRectMat3(x / smallSize.width,
+ y / smallSize.height,
+ w / smallSize.width,
+ h / smallSize.height);
+}
+
+
+// --
+
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;
@@ -261,16 +338,17 @@ public:
// 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);
+ MOZ_ASSERT(destSize.width && destSize.height);
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 );
@@ -289,29 +367,25 @@ public:
}
};
// --
DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog)
: mParent(*parent)
, mProg(prog)
- , mLoc_u1ForYFlip(mParent.mGL->fGetUniformLocation(mProg, "u1ForYFlip"))
- , mLoc_uSrcRect(mParent.mGL->fGetUniformLocation(mProg, "uSrcRect"))
- , mLoc_uTexSize0(mParent.mGL->fGetUniformLocation(mProg, "uTexSize0"))
- , mLoc_uTexSize1(mParent.mGL->fGetUniformLocation(mProg, "uTexSize1"))
- , mLoc_uDivisors(mParent.mGL->fGetUniformLocation(mProg, "uDivisors"))
+ , mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix"))
+ , mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0"))
+ , mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1"))
, mLoc_uColorMatrix(mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix"))
{
- MOZ_ASSERT(mLoc_u1ForYFlip != -1);
- MOZ_ASSERT(mLoc_uSrcRect != -1);
- MOZ_ASSERT(mLoc_uTexSize0 != -1);
+ MOZ_ASSERT(mLoc_uDestMatrix != -1);
+ MOZ_ASSERT(mLoc_uTexMatrix0 != -1);
if (mLoc_uColorMatrix != -1) {
- MOZ_ASSERT(mLoc_uTexSize1 != -1);
- MOZ_ASSERT(mLoc_uDivisors != -1);
+ MOZ_ASSERT(mLoc_uTexMatrix1 != -1);
}
}
DrawBlitProg::~DrawBlitProg()
{
const auto& gl = mParent.mGL;
if (!gl->MakeCurrent())
return;
@@ -324,26 +398,41 @@ DrawBlitProg::Draw(const BaseArgs& args,
{
const auto& gl = mParent.mGL;
const SaveRestoreCurrentProgram oldProg(gl);
gl->fUseProgram(mProg);
// --
- gl->fUniform1f(mLoc_u1ForYFlip, args.yFlip ? 1 : 0);
- gl->fUniform4f(mLoc_uSrcRect,
- args.srcRect.x, args.srcRect.y,
- args.srcRect.width, args.srcRect.height);
- gl->fUniform2f(mLoc_uTexSize0, args.texSize0.width, args.texSize0.height);
+ Mat3 destMatrix;
+ if (args.destRect) {
+ const auto& destRect = args.destRect.value();
+ destMatrix = SubRectMat3(destRect.x / args.destSize.width,
+ destRect.y / args.destSize.height,
+ destRect.width / args.destSize.width,
+ destRect.height / args.destSize.height);
+ } else {
+ destMatrix = Mat3::I();
+ }
+
+ if (args.yFlip) {
+ // Apply the y-flip matrix before the destMatrix.
+ // That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect.
+ destMatrix.at(2,1) += destMatrix.at(1,1);
+ destMatrix.at(1,1) *= -1.0f;
+ }
+
+ gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m);
+ gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.m);
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);
+ gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m);
+
const auto& colorMatrix = gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
}
// --
const ScopedDrawBlitState drawState(gl, args.destSize);
@@ -435,41 +524,34 @@ GLBlitHelper::GLBlitHelper(GLContext* co
#if __VERSION__ >= 130 \n\
#define ATTRIBUTE in \n\
#define VARYING out \n\
#else \n\
#define ATTRIBUTE attribute \n\
#define VARYING varying \n\
#endif \n\
\n\
- ATTRIBUTE vec2 aVert; \n\
+ ATTRIBUTE vec2 aVert; // [0.0-1.0] \n\
\n\
- uniform float u1ForYFlip; \n\
- uniform vec4 uSrcRect; \n\
- uniform vec2 uTexSize0; \n\
- uniform vec2 uTexSize1; \n\
- uniform vec2 uDivisors; \n\
+ uniform mat3 uDestMatrix; \n\
+ uniform mat3 uTexMatrix0; \n\
+ uniform mat3 uTexMatrix1; \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\
+ vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy; \n\
+ gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0); \n\
\n\
- vec2 texCoord = aVert; \n\
- texCoord.y = abs(u1ForYFlip - texCoord.y); \n\
- texCoord = texCoord * uSrcRect.zw + uSrcRect.xy; \n\
- \n\
- vTexCoord0 = texCoord / uTexSize0; \n\
- vTexCoord1 = texCoord / (uTexSize1 * uDivisors); \n\
+ vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy; \n\
+ vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy; \n\
} \n\
";
-
const char* const parts[] = {
mDrawBlitProg_VersionLine.get(),
kVertSource
};
mGL->fShaderSource(mDrawBlitProg_VertShader, ArrayLength(parts), parts, nullptr);
mGL->fCompileShader(mDrawBlitProg_VertShader);
}
@@ -573,37 +655,37 @@ GLBlitHelper::CreateDrawBlitProg(const D
mGL->fGetProgramInfoLog(prog, progLogLen, nullptr, progLog.get());
progLog[progLogLen] = 0;
const auto& vs = mDrawBlitProg_VertShader;
GLuint vsLogLen = 0;
mGL->fGetShaderiv(vs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&vsLogLen);
const UniquePtr<char[]> vsLog(new char[vsLogLen+1]);
mGL->fGetShaderInfoLog(vs, vsLogLen, nullptr, vsLog.get());
- progLog[progLogLen] = 0;
+ vsLog[vsLogLen] = 0;
GLuint fsLogLen = 0;
mGL->fGetShaderiv(fs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&fsLogLen);
const UniquePtr<char[]> fsLog(new char[fsLogLen+1]);
mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get());
- progLog[progLogLen] = 0;
+ fsLog[fsLogLen] = 0;
gfxCriticalError() << "DrawBlitProg link failed:\n"
<< "progLog: " << progLog.get() << "\n"
<< "vsLog: " << vsLog.get() << "\n"
<< "fsLog: " << fsLog.get() << "\n";
return nullptr;
}
// -----------------------------------------------------------------------------
bool
-GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
+GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage,
const gfx::IntSize& destSize,
- OriginPos destOrigin)
+ const OriginPos destOrigin)
{
switch (srcImage->GetFormat()) {
case ImageFormat::PLANAR_YCBCR:
return BlitImage(static_cast<PlanarYCbCrImage*>(srcImage), destSize, destOrigin);
#ifdef MOZ_WIDGET_ANDROID
case ImageFormat::SURFACE_TEXTURE:
return BlitImage(static_cast<layers::SurfaceTextureImage*>(srcImage), destSize,
@@ -613,18 +695,17 @@ GLBlitHelper::BlitImageToFramebuffer(lay
case ImageFormat::MAC_IOSURFACE:
return BlitImage(srcImage->AsMacIOSurfaceImage(), destSize, destOrigin);
#endif
#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);
+ return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize, destOrigin);
case ImageFormat::D3D9_RGB32_TEXTURE:
return false; // todo
#endif
default:
gfxCriticalError() << "Unhandled srcImage->GetFormat(): "
<< uint32_t(srcImage->GetFormat());
return false;
}
@@ -769,24 +850,28 @@ GLBlitHelper::BlitImage(layers::PlanarYC
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& clipRect = yuvData->GetPictureRect();
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 };
-
+ const DrawBlitProg::BaseArgs baseArgs = {
+ SubRectMat3(clipRect, yTexSize),
+ yFlip, destSize, Nothing()
+ };
+ const DrawBlitProg::YUVArgs yuvArgs = {
+ SubRectMat3(clipRect, uvTexSize, divisors),
+ yuvData->mYUVColorSpace
+ };
prog->Draw(baseArgs, &yuvArgs);
return true;
}
// -------------------------------------
#ifdef XP_MACOSX
bool
@@ -797,23 +882,24 @@ GLBlitHelper::BlitImage(layers::MacIOSur
if (mGL->GetContextType() != GLContextType::CGL) {
MOZ_ASSERT(false);
return false;
}
const auto glCGL = static_cast<GLContextCGL*>(mGL);
const auto cglContext = glCGL->GetCGLContext();
const auto& srcOrigin = OriginPos::BottomLeft;
- const bool yFlip = destOrigin != srcOrigin;
- const gfx::IntRect clipRect({0, 0}, srcImage->GetSize());
- const gfx::IntSize texRectNormFactor(1, 1);
- const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect,
- texRectNormFactor };
- DrawBlitProg::YUVArgs yuvArgs = { texRectNormFactor, {2,2}, YUVColorSpace::BT601 };
+ DrawBlitProg::BaseArgs baseArgs;
+ baseArgs.yFlip = (destOrigin != srcOrigin);
+ baseArgs.destSize = destSize;
+
+ DrawBlitProg::YUVArgs yuvArgs;
+ yuvArgs.colorSpace = YUVColorSpace::BT601;
+
const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
auto planes = iosurf->GetPlaneCount();
if (!planes) {
planes = 1; // Bad API. No cookie.
}
const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE;
@@ -913,16 +999,21 @@ GLBlitHelper::BlitImage(layers::MacIOSur
const nsPrintfCString errStr("CGLTexImageIOSurface2D(context, target, 0x%04x,"
" %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
internalFormats[p], uint32_t(width),
uint32_t(height), unpackFormats[p],
unpackTypes[p], p, err);
gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr << ")";
return false;
}
+
+ if (p == 0) {
+ baseArgs.texMatrix0 = SubRectMat3(0, 0, width, height);
+ yuvArgs.texMatrix1 = SubRectMat3(0, 0, width / 2.0, height / 2.0);
+ }
}
const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
if (!prog)
return false;
prog->Draw(baseArgs, pYuvArgs);
return true;
@@ -932,41 +1023,39 @@ GLBlitHelper::BlitImage(layers::MacIOSur
// -----------------------------------------------------------------------------
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);
-
- DrawBlitProg::Key key;
- gfx::IntSize texSizeDivisor;
+ const char* fragHeader;
+ Mat3 texMatrix0;
switch (srcTarget) {
case LOCAL_GL_TEXTURE_2D:
- key = {kFragHeader_Tex2D, kFragBody_RGBA};
- texSizeDivisor = srcSize;
+ fragHeader = kFragHeader_Tex2D;
+ texMatrix0 = Mat3::I();
break;
case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
- key = {kFragHeader_Tex2DRect, kFragBody_RGBA};
- texSizeDivisor = gfx::IntSize(1, 1);
+ fragHeader = kFragHeader_Tex2DRect;
+ texMatrix0 = SubRectMat3(0, 0, srcSize.width, srcSize.height);
break;
default:
gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
return;
}
- const auto& prog = GetDrawBlitProg(key);
+ const auto& prog = GetDrawBlitProg({ fragHeader, kFragBody_RGBA});
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 };
+ const DrawBlitProg::BaseArgs baseArgs = { texMatrix0, yFlip, destSize, Nothing() };
prog->Draw(baseArgs);
}
// -----------------------------------------------------------------------------
void
GLBlitHelper::BlitFramebuffer(const gfx::IntSize& srcSize,
const gfx::IntSize& destSize) const
--- a/gfx/gl/GLBlitHelperD3D.cpp
+++ b/gfx/gl/GLBlitHelperD3D.cpp
@@ -15,18 +15,17 @@
#include "mozilla/layers/D3D11YCbCrImage.h"
#include "mozilla/layers/TextureD3D11.h"
namespace mozilla {
namespace gl {
static EGLStreamKHR
-StreamFromD3DTexture(ID3D11Texture2D* const texD3D,
- const EGLAttrib* const postAttribs)
+StreamFromD3DTexture(ID3D11Texture2D* const texD3D, const EGLAttrib* const postAttribs)
{
auto& egl = sEGLLibrary;
if (!egl.IsExtensionSupported(GLLibraryEGL::NV_stream_consumer_gltexture_yuv) ||
!egl.IsExtensionSupported(GLLibraryEGL::ANGLE_stream_producer_d3d_texture_nv12))
{
return 0;
}
@@ -239,17 +238,18 @@ GLBlitHelper::BlitImage(layers::D3D11YCb
srcImage->mCbCrSize, srcImage->mColorSpace, destSize,
destOrigin);
}
// -------------------------------------
bool
GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
- const gfx::IntSize& destSize, OriginPos destOrigin) const
+ const gfx::IntSize& destSize,
+ const 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();
@@ -290,33 +290,39 @@ GLBlitHelper::BlitDescriptor(const layer
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 DrawBlitProg::BaseArgs baseArgs = {
+ SubRectMat3(clipRect, ySize),
+ yFlip, destSize, Nothing()
+ };
+ const DrawBlitProg::YUVArgs yuvArgs = {
+ SubRectMat3(clipRect, uvSize, divisors),
+ colorSpace
+ };
const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_NV12});
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 YUVColorSpace colorSpace, const gfx::IntSize& destSize,
+ const OriginPos destOrigin) const
{
const auto& d3d = GetD3D11();
if (!d3d)
return false;
const auto srcOrigin = OriginPos::BottomLeft;
gfx::IntSize divisors;
@@ -326,18 +332,24 @@ GLBlitHelper::BlitAngleYCbCr(const Windo
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 DrawBlitProg::BaseArgs baseArgs = {
+ SubRectMat3(clipRect, ySize),
+ yFlip, destSize, Nothing()
+ };
+ const DrawBlitProg::YUVArgs yuvArgs = {
+ SubRectMat3(clipRect, uvSize, divisors),
+ colorSpace
+ };
const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_PlanarYUV});
MOZ_RELEASE_ASSERT(prog);
prog->Draw(baseArgs, &yuvArgs);
return true;
}
} // namespace gl