--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -2,16 +2,17 @@
* 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/. */
#ifndef MOZILLA_GFX_MATRIX_H_
#define MOZILLA_GFX_MATRIX_H_
#include "Types.h"
+#include "Triangle.h"
#include "Rect.h"
#include "Point.h"
#include "Quaternion.h"
#include <iosfwd>
#include <math.h>
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/FloatingPoint.h"
@@ -698,16 +699,23 @@ public:
if (max_x < min_x || max_y < min_y) {
return RectTyped<TargetUnits, F>(0, 0, 0, 0);
}
return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x, max_y - min_y);
}
+ template<class F>
+ RectTyped<TargetUnits, F> TransformAndClipBounds(const TriangleTyped<SourceUnits, F>& aTriangle,
+ const RectTyped<TargetUnits, F>& aClip) const
+ {
+ return TransformAndClipBounds(aTriangle.BoundingBox(), aClip);
+ }
+
/**
* TransformAndClipRect projects a rectangle and clips against view frustum
* clipping planes in homogenous space so that its projected vertices are
* constrained within the 2d rectangle passed in aClip.
* The resulting vertices are populated in aVerts. aVerts must be
* pre-allocated to hold at least kTransformAndClipRectMaxVerts Points.
* The vertex count is returned by TransformAndClipRect. It is possible to
* emit fewer that 3 vertices, indicating that aRect will not be visible
--- a/gfx/2d/Polygon.h
+++ b/gfx/2d/Polygon.h
@@ -181,31 +181,17 @@ public:
// Add the intersection point to both polygons.
aBackPoints.AppendElement(p);
aFrontPoints.AppendElement(p);
}
}
}
- void TransformToLayerSpace(const Matrix4x4Typed<Units, Units>& aTransform)
- {
- TransformPoints(aTransform);
- mNormal = Point3DTyped<Units>(0.0f, 0.0f, 1.0f);
- }
-
- void TransformToScreenSpace(const Matrix4x4Typed<Units, Units>& aTransform)
- {
- TransformPoints(aTransform);
-
- // Normal vectors should be transformed using inverse transpose.
- mNormal = aTransform.Inverse().Transpose().TransformPoint(mNormal);
- }
-
- nsTArray<TriangleTyped<Units>> Triangulate() const
+ nsTArray<TriangleTyped<Units>> ToTriangles() const
{
nsTArray<TriangleTyped<Units>> triangles;
if (mPoints.Length() < 3) {
return triangles;
}
for (size_t i = 1; i < mPoints.Length() - 1; ++i) {
@@ -213,16 +199,30 @@ public:
Point(mPoints[i].x, mPoints[i].y),
Point(mPoints[i+1].x, mPoints[i+1].y));
triangles.AppendElement(Move(triangle));
}
return triangles;
}
+ void TransformToLayerSpace(const Matrix4x4Typed<Units, Units>& aTransform)
+ {
+ TransformPoints(aTransform);
+ mNormal = Point3DTyped<Units>(0.0f, 0.0f, 1.0f);
+ }
+
+ void TransformToScreenSpace(const Matrix4x4Typed<Units, Units>& aTransform)
+ {
+ TransformPoints(aTransform);
+
+ // Normal vectors should be transformed using inverse transpose.
+ mNormal = aTransform.Inverse().Transpose().TransformPoint(mNormal);
+ }
+
private:
void ClipPolygonWithEdge(Polygon3DTyped<Units>& aPolygon,
const PointTyped<Units>& aFirst,
const PointTyped<Units>& aSecond) const
{
const Point3DTyped<Units> a(aFirst.x, aFirst.y, 0.0f);
const Point3DTyped<Units> b(aSecond.x, aSecond.y, 0.0f);
const Point3DTyped<Units> normal(b.y - a.y, a.x - b.x, 0.0f);
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -227,16 +227,109 @@ Compositor::DrawDiagnosticsInternal(Diag
color.r *= flash;
color.g *= flash;
color.b *= flash;
}
SlowDrawRect(aVisibleRect, color, aClipRect, aTransform, lWidth);
}
+static void
+UpdateTextureCoordinates(gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aRect,
+ const gfx::Rect& aIntersection,
+ gfx::Rect aTextureCoords)
+{
+ // Calculate the relative offset of the intersection within the layer.
+ float dx = (aIntersection.x - aRect.x) / aRect.width;
+ float dy = (aIntersection.y - aRect.y) / aRect.height;
+
+ // Update the texture offset.
+ float x = aTextureCoords.x + dx * aTextureCoords.width;
+ float y = aTextureCoords.y + dy * aTextureCoords.height;
+
+ // Scale the texture width and height.
+ float w = aTextureCoords.width * aIntersection.width / aRect.width;
+ float h = aTextureCoords.height * aIntersection.height / aRect.height;
+
+ static const auto ValidateAndClamp = [](float& f) {
+ // Allow some numerical inaccuracy.
+ MOZ_ASSERT(f >= -0.0001f && f <= 1.0001f);
+
+ if (f >= 1.0f) f = 1.0f;
+ if (f <= 0.0f) f = 0.0f;
+ };
+
+ auto UpdatePoint = [&](const gfx::Point& p, gfx::Point& t)
+ {
+ t.x = x + (p.x - aIntersection.x) / aIntersection.width * w;
+ t.y = y + (p.y - aIntersection.y) / aIntersection.height * h;
+
+ ValidateAndClamp(t.x);
+ ValidateAndClamp(t.y);
+ };
+
+ UpdatePoint(aTriangle.p1, aTriangle.textureCoords.p1);
+ UpdatePoint(aTriangle.p2, aTriangle.textureCoords.p2);
+ UpdatePoint(aTriangle.p3, aTriangle.textureCoords.p3);
+}
+
+void
+Compositor::DrawGeometry(const gfx::Rect& aRect,
+ const gfx::IntRect& aClipRect,
+ const EffectChain& aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect,
+ const Maybe<gfx::Polygon3D>& aGeometry)
+{
+ if (!aGeometry) {
+ DrawQuad(aRect, aClipRect, aEffectChain,
+ aOpacity, aTransform, aVisibleRect);
+ return;
+ }
+
+ // Cull invisible polygons.
+ if (aRect.Intersect(aGeometry->BoundingBox()).IsEmpty()) {
+ return;
+ }
+
+ gfx::Polygon3D clipped = aGeometry->ClipPolygon(aRect);
+ nsTArray<gfx::Triangle> triangles = clipped.ToTriangles();
+
+ for (gfx::Triangle& geometry : triangles) {
+ const gfx::Rect intersection = aRect.Intersect(geometry.BoundingBox());
+
+ // Cull invisible triangles.
+ if (intersection.IsEmpty()) {
+ continue;
+ }
+
+ MOZ_ASSERT(aRect.width > 0.0f && aRect.height > 0.0f);
+ MOZ_ASSERT(intersection.width > 0.0f && intersection.height > 0.0f);
+
+ gfx::TexturedTriangle triangle(Move(geometry));
+ triangle.width = aRect.width;
+ triangle.height = aRect.height;
+
+ // Since the texture was created for non-split geometry, we need to
+ // update the texture coordinates to account for the split.
+ if (aEffectChain.mPrimaryEffect->mType == EffectTypes::RGB) {
+ TexturedEffect* texturedEffect =
+ static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
+
+ UpdateTextureCoordinates(triangle, aRect, intersection,
+ texturedEffect->mTextureCoords);
+ }
+
+ DrawTriangle(triangle, aClipRect, aEffectChain,
+ aOpacity, aTransform, aVisibleRect);
+ }
+}
+
void
Compositor::SlowDrawRect(const gfx::Rect& aRect, const gfx::Color& aColor,
const gfx::IntRect& aClipRect,
const gfx::Matrix4x4& aTransform, int aStrokeWidth)
{
// TODO This should draw a rect using a single draw call but since
// this is only used for debugging overlays it's not worth optimizing ATM.
float opacity = 1.0f;
@@ -485,16 +578,28 @@ Compositor::ComputeBackdropCopyRect(cons
gfx::Matrix4x4 transform;
transform.PostScale(rtSize.width, rtSize.height, 1.0);
transform.PostTranslate(-result.x, -result.y, 0.0);
transform.PostScale(1 / float(result.width), 1 / float(result.height), 1.0);
*aOutTransform = transform;
return result;
}
+gfx::IntRect
+Compositor::ComputeBackdropCopyRect(const gfx::Triangle& aTriangle,
+ const gfx::IntRect& aClipRect,
+ const gfx::Matrix4x4& aTransform,
+ gfx::Matrix4x4* aOutTransform,
+ gfx::Rect* aOutLayerQuad)
+{
+ gfx::Rect boundingBox = aTriangle.BoundingBox();
+ return ComputeBackdropCopyRect(boundingBox, aClipRect, aTransform,
+ aOutTransform, aOutLayerQuad);
+}
+
void
Compositor::SetInvalid()
{
mParent = nullptr;
}
bool
Compositor::IsValid() const
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -7,18 +7,20 @@
#define MOZILLA_GFX_COMPOSITOR_H
#include "Units.h" // for ScreenPoint
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/RefPtr.h" // for already_AddRefed, RefCounted
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/MatrixFwd.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for IntSize, Point
+#include "mozilla/gfx/Polygon.h" // for Polygon3D
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
#include "mozilla/gfx/Types.h" // for Float
+#include "mozilla/gfx/Triangle.h" // for Triangle, TexturedTriangle
#include "mozilla/layers/CompositorTypes.h" // for DiagnosticTypes, etc
#include "mozilla/layers/FenceUtils.h" // for FenceHandle
#include "mozilla/layers/LayersTypes.h" // for LayersBackend
#include "mozilla/widget/CompositorWidget.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsRegion.h"
#include <vector>
#include "mozilla/WidgetUtils.h"
@@ -305,16 +307,35 @@ public:
virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) = 0;
/**
* Declare an offset to use when rendering layers. This will be ignored when
* rendering to a target instead of the screen.
*/
virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) = 0;
+ void DrawGeometry(const gfx::Rect& aRect,
+ const gfx::IntRect& aClipRect,
+ const EffectChain &aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect,
+ const Maybe<gfx::Polygon3D>& aGeometry);
+
+ void DrawGeometry(const gfx::Rect& aRect,
+ const gfx::IntRect& aClipRect,
+ const EffectChain &aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const Maybe<gfx::Polygon3D>& aGeometry)
+ {
+ DrawGeometry(aRect, aClipRect, aEffectChain, aOpacity,
+ aTransform, aRect, aGeometry);
+ }
+
/**
* Tell the compositor to draw a quad. What to do draw and how it is
* drawn is specified by aEffectChain. aRect is the quad to draw, in user space.
* aTransform transforms from user space to screen space. If texture coords are
* required, these will be in the primary effect in the effect chain.
* aVisibleRect is used to determine which edges should be antialiased,
* without applying the effect to the inner edges of a tiled layer.
*/
@@ -329,16 +350,26 @@ public:
* layer.
*/
void DrawQuad(const gfx::Rect& aRect, const gfx::IntRect& aClipRect,
const EffectChain& aEffectChain,
gfx::Float aOpacity, const gfx::Matrix4x4& aTransform) {
DrawQuad(aRect, aClipRect, aEffectChain, aOpacity, aTransform, aRect);
}
+ virtual void DrawTriangle(const gfx::TexturedTriangle& aTriangle,
+ const gfx::IntRect& aClipRect,
+ const EffectChain& aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect)
+ {
+ MOZ_CRASH("Compositor::DrawTriangle is not implemented for the current platform!");
+ }
+
/**
* Draw an unfilled solid color rect. Typically used for debugging overlays.
*/
void SlowDrawRect(const gfx::Rect& aRect, const gfx::Color& color,
const gfx::IntRect& aClipRect = gfx::IntRect(),
const gfx::Matrix4x4& aTransform = gfx::Matrix4x4(),
int aStrokeWidth = 1);
@@ -587,22 +618,28 @@ protected:
/**
* Given a layer rect, clip, and transform, compute the area of the backdrop that
* needs to be copied for mix-blending. The output transform translates from 0..1
* space into the backdrop rect space.
*
* The transformed layer quad is also optionally returned - this is the same as
* the result rect, before rounding.
*/
- gfx::IntRect ComputeBackdropCopyRect(
- const gfx::Rect& aRect,
- const gfx::IntRect& aClipRect,
- const gfx::Matrix4x4& aTransform,
- gfx::Matrix4x4* aOutTransform,
- gfx::Rect* aOutLayerQuad = nullptr);
+ gfx::IntRect ComputeBackdropCopyRect(const gfx::Rect& aRect,
+ const gfx::IntRect& aClipRect,
+ const gfx::Matrix4x4& aTransform,
+ gfx::Matrix4x4* aOutTransform,
+ gfx::Rect* aOutLayerQuad = nullptr);
+
+ gfx::IntRect ComputeBackdropCopyRect(const gfx::Triangle& aTriangle,
+ const gfx::IntRect& aClipRect,
+ const gfx::Matrix4x4& aTransform,
+ gfx::Matrix4x4* aOutTransform,
+ gfx::Rect* aOutLayerQuad = nullptr);
+
/**
* An array of locks that will need to be unlocked after the next composition.
*/
nsTArray<RefPtr<TextureHost>> mUnlockAfterComposition;
/**
* An array of TextureHosts that will need to call NotifyNotUsed() after the next composition.
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -17,16 +17,17 @@
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxPrefs.h" // for gfxPrefs
#include "gfxRect.h" // for gfxRect
#include "gfxUtils.h" // for gfxUtils, etc
#include "mozilla/ArrayUtils.h" // for ArrayLength
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
+#include "mozilla/gfx/Triangle.h" // for Triangle
#include "mozilla/gfx/gfxVars.h" // for gfxVars
#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
#include "mozilla/layers/CompositingRenderTargetOGL.h"
#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
#include "mozilla/layers/TextureHost.h" // for TextureSource, etc
#include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsAppRunner.h"
@@ -53,16 +54,19 @@ namespace mozilla {
using namespace std;
using namespace gfx;
namespace layers {
using namespace mozilla::gl;
+static const GLuint kCoordinateAttributeIndex = 0;
+static const GLuint kTexCoordinateAttributeIndex = 1;
+
static void
BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
{
MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
aSourceMask->BindTexture(aTexUnit, gfx::SamplingFilter::LINEAR);
aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
aProgram->SetMaskLayerTransform(aTransform);
@@ -183,16 +187,17 @@ CompositorOGL::CleanupResources()
RefPtr<GLContext> ctx = mGLContext->GetSharedContext();
if (!ctx) {
ctx = mGLContext;
}
if (!ctx->MakeCurrent()) {
// Leak resources!
mQuadVBO = 0;
+ mTriangleVBO = 0;
mGLContext = nullptr;
mPrograms.clear();
return;
}
for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
iter != mPrograms.end();
iter++) {
@@ -202,16 +207,21 @@ CompositorOGL::CleanupResources()
ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
if (mQuadVBO) {
ctx->fDeleteBuffers(1, &mQuadVBO);
mQuadVBO = 0;
}
+ if (mTriangleVBO) {
+ ctx->fDeleteBuffers(1, &mTriangleVBO);
+ mTriangleVBO = 0;
+ }
+
mGLContext->MakeCurrent();
mBlitTextureImageHelper = nullptr;
mContextStateTracker.DestroyOGL(mGLContext);
// On the main thread the Widget will be destroyed soon and calling MakeCurrent
// after that could cause a crash (at least with GLX, see bug 1059793), unless
@@ -352,20 +362,21 @@ CompositorOGL::Initialize(nsCString* con
* texture2DRect).
*/
if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){
*out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
return false;
}
}
- /* Create a simple quad VBO */
+ // Create a VBO for triangle vertices.
+ mGLContext->fGenBuffers(1, &mTriangleVBO);
+ /* Create a simple quad VBO */
mGLContext->fGenBuffers(1, &mQuadVBO);
- mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
// 4 quads, with the number of the quad (vertexID) encoded in w.
GLfloat vertices[] = {
0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
@@ -388,16 +399,18 @@ CompositorOGL::Initialize(nsCString* con
0.0f, 0.0f, 0.0f, 3.0f,
1.0f, 0.0f, 0.0f, 3.0f,
0.0f, 1.0f, 0.0f, 3.0f,
1.0f, 0.0f, 0.0f, 3.0f,
0.0f, 1.0f, 0.0f, 3.0f,
1.0f, 1.0f, 0.0f, 3.0f,
};
HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
+
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
verticesOnHeap.ByteLength(),
verticesOnHeap.Data(),
LOCAL_GL_STATIC_DRAW);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
nsCOMPtr<nsIConsoleService>
console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
@@ -437,52 +450,34 @@ static IntSize
CalculatePOTSize(const IntSize& aSize, GLContext* gl)
{
if (CanUploadNonPowerOfTwo(gl))
return aSize;
return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height));
}
-// |aRect| is the rectangle we want to draw to. We will draw it with
-// up to 4 draw commands if necessary to avoid wrapping.
-// |aTexCoordRect| is the rectangle from the texture that we want to
-// draw using the given program.
-// |aTexture| is the texture we are drawing. Its actual size can be
-// larger than the rectangle given by |texCoordRect|.
-void
-CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
- const Rect& aRect,
- const Rect& aTexCoordRect,
- TextureSource *aTexture)
+gfx::Rect
+CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect, TextureSource* aTexture)
{
- Rect scaledTexCoordRect = aTexCoordRect;
-
// If the OpenGL setup does not support non-power-of-two textures then the
// texture's width and height will have been increased to the next
// power-of-two (unless already a power of two). In that case we must scale
// the texture coordinates to account for that.
if (!CanUploadNonPowerOfTwo(mGLContext)) {
const IntSize& textureSize = aTexture->GetSize();
const IntSize potSize = CalculatePOTSize(textureSize, mGLContext);
if (potSize != textureSize) {
const float xScale = (float)textureSize.width / (float)potSize.width;
const float yScale = (float)textureSize.height / (float)potSize.height;
- scaledTexCoordRect.Scale(xScale, yScale);
+ textureRect.Scale(xScale, yScale);
}
}
- Rect layerRects[4];
- Rect textureRects[4];
- size_t rects = DecomposeIntoNoRepeatRects(aRect,
- scaledTexCoordRect,
- &layerRects,
- &textureRects);
-
- BindAndDrawQuads(aProg, rects, layerRects, textureRects);
+ return textureRect;
}
void
CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget)
{
MOZ_ASSERT(aRenderTarget);
const gfx::IntSize& size = aRenderTarget->mInitParams.mSize;
@@ -991,29 +986,57 @@ CompositorOGL::DrawQuad(const Rect& aRec
const EffectChain &aEffectChain,
Float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect)
{
PROFILER_LABEL("CompositorOGL", "DrawQuad",
js::ProfileEntry::Category::GRAPHICS);
+ DrawGeometry(aRect, aClipRect, aEffectChain,
+ aOpacity, aTransform, aVisibleRect);
+}
+
+void
+CompositorOGL::DrawTriangle(const gfx::TexturedTriangle& aTriangle,
+ const gfx::IntRect& aClipRect,
+ const EffectChain& aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect)
+{
+ PROFILER_LABEL("CompositorOGL", "DrawTriangle",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ DrawGeometry(aTriangle, aClipRect, aEffectChain,
+ aOpacity, aTransform, aVisibleRect);
+}
+
+template<typename Geometry>
+void
+CompositorOGL::DrawGeometry(const Geometry& aGeometry,
+ const IntRect& aClipRect,
+ const EffectChain &aEffectChain,
+ Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect)
+{
MOZ_ASSERT(mFrameInProgress, "frame not started");
MOZ_ASSERT(mCurrentRenderTarget, "No destination");
MakeCurrent();
IntPoint offset = mCurrentRenderTarget->GetOrigin();
IntSize size = mCurrentRenderTarget->GetSize();
Rect renderBound(0, 0, size.width, size.height);
renderBound.IntersectRect(renderBound, Rect(aClipRect));
renderBound.MoveBy(offset);
- Rect destRect = aTransform.TransformAndClipBounds(aRect, renderBound);
+ Rect destRect = aTransform.TransformAndClipBounds(aGeometry, renderBound);
// XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
// quads. Fix me.
mPixelsFilled += destRect.width * destRect.height;
// Do a simple culling if this rect is out of target buffer.
// Inflate a small size to avoid some numerical imprecision issue.
destRect.Inflate(1, 1);
@@ -1101,22 +1124,26 @@ CompositorOGL::DrawQuad(const Rect& aRec
// could be visible
bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
!aTransform.Is2DIntegerTranslation();
bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect,
maskType, blendMode, colorMatrix,
bEnableAA);
+
config.SetOpacity(aOpacity != 1.f);
+ ApplyPrimitiveConfig(config, aGeometry);
+
ShaderProgramOGL *program = GetShaderProgramFor(config);
ActivateProgram(program);
program->SetProjectionMatrix(mProjMatrix);
program->SetLayerTransform(aTransform);
LayerScope::SetLayerTransform(aTransform);
+
if (colorMatrix) {
EffectColorMatrix* effectColorMatrix =
static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
program->SetColorMatrix(effectColorMatrix->mColorMatrix);
}
if (BlendOpIsMixBlendMode(blendMode)) {
gfx::Matrix4x4 backdropTransform;
@@ -1124,28 +1151,30 @@ CompositorOGL::DrawQuad(const Rect& aRec
if (gl()->IsExtensionSupported(GLContext::NV_texture_barrier)) {
// The NV_texture_barrier extension lets us read directly from the
// backbuffer. Let's do that.
// We need to tell OpenGL about this, so that it can make sure everything
// on the GPU is happening in the right order.
gl()->fTextureBarrier();
mixBlendBackdrop = mCurrentRenderTarget->GetTextureHandle();
} else {
- gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform, &backdropTransform);
+ gfx::IntRect rect = ComputeBackdropCopyRect(aGeometry, aClipRect,
+ aTransform, &backdropTransform);
mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
createdMixBlendBackdropTexture = true;
}
program->SetBackdropTransform(backdropTransform);
}
program->SetRenderOffset(offset.x, offset.y);
LayerScope::SetRenderOffset(offset.x, offset.y);
if (aOpacity != 1.f)
program->SetLayerOpacity(aOpacity);
+
if (config.mFeatures & ENABLE_TEXTURE_RECT) {
TextureSourceOGL* source = nullptr;
if (aEffectChain.mPrimaryEffect->mType == EffectTypes::COMPONENT_ALPHA) {
EffectComponentAlpha* effectComponentAlpha =
static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
source = effectComponentAlpha->mOnWhite->AsSourceOGL();
} else {
TexturedEffect* texturedEffect =
@@ -1234,17 +1263,17 @@ CompositorOGL::DrawQuad(const Rect& aRec
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
}
if (mixBlendBackdrop) {
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1);
}
didSetBlendMode = SetBlendMode(gl(), blendMode);
- BindAndDrawQuad(program, aRect);
+ BindAndDrawGeometry(program, aGeometry);
}
break;
case EffectTypes::RGB: {
TexturedEffect* texturedEffect =
static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
TextureSource *source = texturedEffect->mTexture;
@@ -1261,17 +1290,18 @@ CompositorOGL::DrawQuad(const Rect& aRec
if (maskType != MaskType::MaskNone) {
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
}
if (mixBlendBackdrop) {
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
}
- BindAndDrawQuadWithTextureRect(program, aRect, texturedEffect->mTextureCoords, source);
+ BindAndDrawGeometryWithTextureRect(program, aGeometry,
+ texturedEffect->mTextureCoords, source);
}
break;
case EffectTypes::YCBCR: {
EffectYCbCr* effectYCbCr =
static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
TextureSource* sourceYCbCr = effectYCbCr->mTexture;
const int Y = 0, Cb = 1, Cr = 2;
TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
@@ -1292,20 +1322,20 @@ CompositorOGL::DrawQuad(const Rect& aRec
if (maskType != MaskType::MaskNone) {
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
}
if (mixBlendBackdrop) {
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4);
}
didSetBlendMode = SetBlendMode(gl(), blendMode);
- BindAndDrawQuadWithTextureRect(program,
- aRect,
- effectYCbCr->mTextureCoords,
- sourceYCbCr->GetSubSource(Y));
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectYCbCr->mTextureCoords,
+ sourceYCbCr->GetSubSource(Y));
}
break;
case EffectTypes::NV12: {
EffectNV12* effectNV12 =
static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get());
TextureSource* sourceNV12 = effectNV12->mTexture;
const int Y = 0, CbCr = 1;
TextureSourceOGL* sourceY = sourceNV12->GetSubSource(Y)->AsSourceOGL();
@@ -1329,20 +1359,20 @@ CompositorOGL::DrawQuad(const Rect& aRec
if (maskType != MaskType::MaskNone) {
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
}
if (mixBlendBackdrop) {
BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3);
}
didSetBlendMode = SetBlendMode(gl(), blendMode);
- BindAndDrawQuadWithTextureRect(program,
- aRect,
- effectNV12->mTextureCoords,
- sourceNV12->GetSubSource(Y));
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectNV12->mTextureCoords,
+ sourceNV12->GetSubSource(Y));
}
break;
case EffectTypes::RENDER_TARGET: {
EffectRenderTarget* effectRenderTarget =
static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
RefPtr<CompositingRenderTargetOGL> surface
= static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
@@ -1368,17 +1398,17 @@ CompositorOGL::DrawQuad(const Rect& aRec
program->SetTexCoordMultiplier(surface->GetSize().width,
surface->GetSize().height);
}
// Drawing is always flipped, but when copying between surfaces we want to avoid
// this. Pass true for the flip parameter to introduce a second flip
// that cancels the other one out.
didSetBlendMode = SetBlendMode(gl(), blendMode);
- BindAndDrawQuad(program, aRect);
+ BindAndDrawGeometry(program, aGeometry);
}
break;
case EffectTypes::COMPONENT_ALPHA: {
MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER, "Can't support blend modes with component alpha!");
EffectComponentAlpha* effectComponentAlpha =
static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
@@ -1399,29 +1429,29 @@ CompositorOGL::DrawQuad(const Rect& aRec
if (maskType != MaskType::MaskNone) {
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
}
// Pass 1.
gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
LOCAL_GL_ONE, LOCAL_GL_ONE);
program->SetTexturePass2(false);
- BindAndDrawQuadWithTextureRect(program,
- aRect,
- effectComponentAlpha->mTextureCoords,
- effectComponentAlpha->mOnBlack);
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectComponentAlpha->mTextureCoords,
+ effectComponentAlpha->mOnBlack);
// Pass 2.
gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
LOCAL_GL_ONE, LOCAL_GL_ONE);
program->SetTexturePass2(true);
- BindAndDrawQuadWithTextureRect(program,
- aRect,
- effectComponentAlpha->mTextureCoords,
- effectComponentAlpha->mOnBlack);
+ BindAndDrawGeometryWithTextureRect(program,
+ aGeometry,
+ effectComponentAlpha->mTextureCoords,
+ effectComponentAlpha->mOnBlack);
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
}
break;
default:
MOZ_ASSERT(false, "Unhandled effect type");
break;
@@ -1432,17 +1462,128 @@ CompositorOGL::DrawQuad(const Rect& aRec
LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
}
if (createdMixBlendBackdropTexture) {
gl()->fDeleteTextures(1, &mixBlendBackdrop);
}
// in case rendering has used some other GL context
MakeCurrent();
- LayerScope::DrawEnd(mGLContext, aEffectChain, aRect.width, aRect.height);
+
+ LayerScope::DrawEnd(mGLContext, aEffectChain,
+ aGeometry.width, aGeometry.height);
+}
+
+void
+CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
+ const gfx::Rect& aRect,
+ const gfx::Rect& aTextureRect)
+{
+ BindAndDrawQuad(aProgram, aRect, aTextureRect);
+}
+
+void
+CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
+ const gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aTextureRect)
+{
+ NS_ASSERTION(aProgram->HasInitialized(), "Shader program not correctly initialized");
+
+ const gfx::TexturedTriangle& t = aTriangle;
+ const gfx::Triangle& tex = t.textureCoords;
+
+ GLfloat vertices[] = {
+ t.p1.x, t.p1.y, 0.0f, 1.0f, tex.p1.x, tex.p1.y,
+ t.p2.x, t.p2.y, 0.0f, 1.0f, tex.p2.x, tex.p2.y,
+ t.p3.x, t.p3.y, 0.0f, 1.0f, tex.p3.x, tex.p3.y
+ };
+
+ HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO);
+ mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
+ verticesOnHeap.ByteLength(),
+ verticesOnHeap.Data(),
+ LOCAL_GL_STREAM_DRAW);
+
+ const GLsizei stride = 6 * sizeof(GLfloat);
+ InitializeVAO(kCoordinateAttributeIndex, 4, stride, 0);
+ InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 4 * sizeof(GLfloat));
+
+ mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 3);
+
+ mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
+ mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
+// |aRect| is the rectangle we want to draw to. We will draw it with
+// up to 4 draw commands if necessary to avoid wrapping.
+// |aTexCoordRect| is the rectangle from the texture that we want to
+// draw using the given program.
+// |aTexture| is the texture we are drawing. Its actual size can be
+// larger than the rectangle given by |texCoordRect|.
+void
+CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
+ const Rect& aRect,
+ const Rect& aTexCoordRect,
+ TextureSource *aTexture)
+{
+ Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture);
+ Rect layerRects[4];
+ Rect textureRects[4];
+ size_t rects = DecomposeIntoNoRepeatRects(aRect,
+ scaledTexCoordRect,
+ &layerRects,
+ &textureRects);
+
+ BindAndDrawQuads(aProg, rects, layerRects, textureRects);
+}
+
+void
+CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
+ const gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aTexCoordRect,
+ TextureSource *aTexture)
+{
+ BindAndDrawGeometry(aProg, aTriangle,
+ GetTextureCoordinates(aTexCoordRect, aTexture));
+}
+
+void
+CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
+ int aQuads,
+ const Rect* aLayerRects,
+ const Rect* aTextureRects)
+{
+ NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
+
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+ InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0);
+
+ aProg->SetLayerRects(aLayerRects);
+ if (aProg->GetTextureCount() > 0) {
+ aProg->SetTextureRects(aTextureRects);
+ }
+
+ // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
+ // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
+ mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
+ mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
+ mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+ LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
+}
+
+void
+CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents,
+ const GLsizei aStride, const size_t aOffset)
+{
+ mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT,
+ LOCAL_GL_FALSE, aStride,
+ reinterpret_cast<GLvoid*>(aOffset));
+ mGLContext->fEnableVertexAttribArray(aAttrib);
}
void
CompositorOGL::EndFrame()
{
PROFILER_LABEL("CompositorOGL", "EndFrame",
js::ProfileEntry::Category::GRAPHICS);
@@ -1615,43 +1756,16 @@ void
CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return;
}
mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
}
-void
-CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
- int aQuads,
- const Rect* aLayerRects,
- const Rect* aTextureRects)
-{
- NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
-
- const GLuint coordAttribIndex = 0;
-
- mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
- mGLContext->fVertexAttribPointer(coordAttribIndex, 4,
- LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
- (GLvoid*) 0);
- mGLContext->fEnableVertexAttribArray(coordAttribIndex);
-
- aProg->SetLayerRects(aLayerRects);
- if (aProg->GetTextureCount() > 0) {
- aProg->SetTextureRects(aTextureRects);
- }
-
- // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
- // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
- mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
- LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
-}
-
GLBlitTextureImageHelper*
CompositorOGL::BlitTextureImageHelper()
{
if (!mBlitTextureImageHelper) {
mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
}
return mBlitTextureImageHelper.get();
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -15,16 +15,17 @@
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Attributes.h" // for override, final
#include "mozilla/RefPtr.h" // for already_AddRefed, RefPtr
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/MatrixFwd.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for IntSize, Point
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
+#include "mozilla/gfx/Triangle.h" // for Triangle
#include "mozilla/gfx/Types.h" // for Float, SurfaceFormat, etc
#include "mozilla/layers/Compositor.h" // for SurfaceInitMode, Compositor, etc
#include "mozilla/layers/CompositorTypes.h" // for MaskType::MaskType::NumMaskTypes, etc
#include "mozilla/layers/LayersTypes.h"
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsTArray.h" // for AutoTArray, nsTArray, etc
@@ -206,16 +207,23 @@ public:
virtual void DrawQuad(const gfx::Rect& aRect,
const gfx::IntRect& aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Rect& aVisibleRect) override;
+ virtual void DrawTriangle(const gfx::TexturedTriangle& aTriangle,
+ const gfx::IntRect& aClipRect,
+ const EffectChain& aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect) override;
+
virtual void EndFrame() override;
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
virtual bool SupportsPartialTextureUpdate() override;
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override
{
if (!mGLContext)
@@ -304,16 +312,24 @@ public:
return gfx::IntSize (mSurfaceSize.width, mSurfaceSize.height);
}
const ScreenPoint& GetScreenRenderOffset() const {
return mRenderOffset;
}
private:
+ template<typename Geometry>
+ void DrawGeometry(const Geometry& aGeometry,
+ const gfx::IntRect& aClipRect,
+ const EffectChain &aEffectChain,
+ gfx::Float aOpacity,
+ const gfx::Matrix4x4& aTransform,
+ const gfx::Rect& aVisibleRect);
+
void PrepareViewport(CompositingRenderTargetOGL *aRenderTarget);
/** Widget associated with this compositor */
LayoutDeviceIntSize mWidgetSize;
RefPtr<GLContext> mGLContext;
UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
gfx::Matrix4x4 mProjMatrix;
@@ -334,16 +350,22 @@ private:
#endif
/**
* VBO that has some basics in it for a textured quad, including vertex
* coords and texcoords.
*/
GLuint mQuadVBO;
+
+ /**
+ * VBO that stores dynamic triangle geometry.
+ */
+ GLuint mTriangleVBO;
+
bool mHasBGRA;
/**
* When rendering to some EGL surfaces (e.g. on Android), we rely on being told
* about size changes (via SetSurfaceSize) rather than pulling this information
* from the widget.
*/
bool mUseExternalSurfaceSize;
@@ -368,51 +390,93 @@ private:
gfx::IntRect *aClipRectOut = nullptr,
gfx::IntRect *aRenderBoundsOut = nullptr) override;
ShaderConfigOGL GetShaderConfigFor(Effect *aEffect,
MaskType aMask = MaskType::MaskNone,
gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
bool aColorMatrix = false,
bool aDEAAEnabled = false) const;
+
ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig);
+ void ApplyPrimitiveConfig(ShaderConfigOGL& aConfig,
+ const gfx::Rect&)
+ {
+ aConfig.SetDynamicGeometry(false);
+ }
+
+ void ApplyPrimitiveConfig(ShaderConfigOGL& aConfig,
+ const gfx::TexturedTriangle&)
+ {
+ aConfig.SetDynamicGeometry(true);
+ }
+
/**
* Create a FBO backed by a texture.
* Note that the texture target type will be
* of the type returned by FBOTextureTarget; different
* shaders are required to sample from the different
* texture types.
*/
void CreateFBOWithTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
GLuint aSourceFrameBuffer,
GLuint *aFBO, GLuint *aTexture);
+
GLuint CreateTexture(const gfx::IntRect& aRect, bool aCopyFromSource, GLuint aSourceFrameBuffer);
+ gfx::Point3D GetLineCoefficients(const gfx::Point& aPoint1,
+ const gfx::Point& aPoint2);
+
+ void ActivateProgram(ShaderProgramOGL *aProg);
+
+ void CleanupResources();
+
void BindAndDrawQuads(ShaderProgramOGL *aProg,
int aQuads,
const gfx::Rect* aLayerRect,
const gfx::Rect* aTextureRect);
+
void BindAndDrawQuad(ShaderProgramOGL *aProg,
const gfx::Rect& aLayerRect,
- const gfx::Rect& aTextureRect = gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f)) {
+ const gfx::Rect& aTextureRect =
+ gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f))
+ {
gfx::Rect layerRects[4];
gfx::Rect textureRects[4];
layerRects[0] = aLayerRect;
textureRects[0] = aTextureRect;
BindAndDrawQuads(aProg, 1, layerRects, textureRects);
}
- void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
- const gfx::Rect& aRect,
- const gfx::Rect& aTexCoordRect,
- TextureSource *aTexture);
- gfx::Point3D GetLineCoefficients(const gfx::Point& aPoint1,
- const gfx::Point& aPoint2);
- void ActivateProgram(ShaderProgramOGL *aProg);
- void CleanupResources();
+
+ void BindAndDrawGeometry(ShaderProgramOGL* aProgram,
+ const gfx::Rect& aRect,
+ const gfx::Rect& aTextureRect =
+ gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f));
+
+ void BindAndDrawGeometry(ShaderProgramOGL* aProgram,
+ const gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aTextureRect =
+ gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f));
+
+ void BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
+ const gfx::Rect& aRect,
+ const gfx::Rect& aTexCoordRect,
+ TextureSource *aTexture);
+
+ void BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
+ const gfx::TexturedTriangle& aTriangle,
+ const gfx::Rect& aTexCoordRect,
+ TextureSource *aTexture);
+
+ void InitializeVAO(const GLuint aAttribIndex, const GLint aComponents,
+ const GLsizei aStride, const size_t aOffset);
+
+ gfx::Rect GetTextureCoordinates(gfx::Rect textureRect,
+ TextureSource* aTexture);
/**
* Bind the texture behind the current render target as the backdrop for a
* mix-blend shader.
*/
void BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit);
/**
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -156,16 +156,22 @@ ShaderConfigOGL::SetDEAA(bool aEnabled)
}
void
ShaderConfigOGL::SetCompositionOp(gfx::CompositionOp aOp)
{
mCompositionOp = aOp;
}
+void
+ShaderConfigOGL::SetDynamicGeometry(bool aEnabled)
+{
+ SetFeature(ENABLE_DYNAMIC_GEOMETRY, aEnabled);
+}
+
/* static */ ProgramProfileOGL
ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
{
ProgramProfileOGL result;
ostringstream fs, vs;
AddUniforms(result);
@@ -182,37 +188,49 @@ ProgramProfileOGL::GetProfileFor(ShaderC
if (aConfig.mFeatures & ENABLE_DEAA) {
vs << "uniform mat4 uLayerTransformInverse;" << endl;
vs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
vs << "uniform vec2 uVisibleCenter;" << endl;
vs << "uniform vec2 uViewportSize;" << endl;
}
vs << "uniform vec2 uRenderTargetOffset;" << endl;
vs << "attribute vec4 aCoord;" << endl;
+ result.mAttributes.AppendElement(Pair<nsCString, GLuint> {"aCoord", 0});
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << "uniform mat4 uTextureTransform;" << endl;
vs << "uniform vec4 uTextureRects[4];" << endl;
vs << "varying vec2 vTexCoord;" << endl;
+
+ if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
+ vs << "attribute vec2 aTexCoord;" << endl;
+ result.mAttributes.AppendElement(Pair<nsCString, GLuint> {"aTexCoord", 1});
+ }
}
if (BlendOpIsMixBlendMode(blendOp)) {
vs << "uniform mat4 uBackdropTransform;" << endl;
vs << "varying vec2 vBackdropCoord;" << endl;
}
if (aConfig.mFeatures & ENABLE_MASK) {
vs << "uniform mat4 uMaskTransform;" << endl;
vs << "varying vec3 vMaskCoord;" << endl;
}
vs << "void main() {" << endl;
- vs << " int vertexID = int(aCoord.w);" << endl;
- vs << " vec4 layerRect = uLayerRects[vertexID];" << endl;
- vs << " vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
+
+ if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
+ vs << " vec4 finalPosition = vec4(aCoord.xy, 0.0, 1.0);" << endl;
+ } else {
+ vs << " int vertexID = int(aCoord.w);" << endl;
+ vs << " vec4 layerRect = uLayerRects[vertexID];" << endl;
+ vs << " vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
+ }
+
vs << " finalPosition = uLayerTransform * finalPosition;" << endl;
if (aConfig.mFeatures & ENABLE_DEAA) {
// XXX kip - The DEAA shader could be made simpler if we switch to
// using dynamic vertex buffers instead of sending everything
// in through uniforms. This would enable passing information
// about how to dilate each vertex explicitly and eliminate the
// need to extrapolate this with the sub-pixel coverage
@@ -248,32 +266,43 @@ ProgramProfileOGL::GetProfileFor(ShaderC
vs << " vec4 visibleCenter = uLayerTransform * vec4(uVisibleCenter, 0.0, 1.0);" << endl;
vs << " vec2 dilateDir = finalPosition.xy / finalPosition.w - visibleCenter.xy / visibleCenter.w;" << endl;
vs << " vec2 offset = sign(dilateDir) * 0.5;" << endl;
vs << " finalPosition.xy += offset * finalPosition.w;" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
// We must adjust the texture coordinates to compensate for the dilation
vs << " coordAdjusted = uLayerTransformInverse * finalPosition;" << endl;
vs << " coordAdjusted /= coordAdjusted.w;" << endl;
- vs << " coordAdjusted.xy -= layerRect.xy;" << endl;
- vs << " coordAdjusted.xy /= layerRect.zw;" << endl;
+
+ if (!(aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY)) {
+ vs << " coordAdjusted.xy -= layerRect.xy;" << endl;
+ vs << " coordAdjusted.xy /= layerRect.zw;" << endl;
+ }
}
vs << " }" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
+ if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
+ vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;" << endl;
+ } else {
+ vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
+ vs << " vec2 texCoord = coordAdjusted.xy * textureRect.zw + textureRect.xy;" << endl;
+ vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
+ }
+ }
+ } else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
+ if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
+ vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;" << endl;
+ } else {
vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
- vs << " vec2 texCoord = coordAdjusted.xy * textureRect.zw + textureRect.xy;" << endl;
+ vs << " vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
}
+ }
- } else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
- vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
- vs << " vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
- vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
- }
if (aConfig.mFeatures & ENABLE_MASK) {
vs << " vMaskCoord.xy = (uMaskTransform * (finalPosition / finalPosition.w)).xy;" << endl;
// correct for perspective correct interpolation, see comment in D3D11 shader
vs << " vMaskCoord.z = 1.0;" << endl;
vs << " vMaskCoord *= finalPosition.w;" << endl;
}
vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
@@ -857,16 +886,21 @@ ShaderProgramOGL::CreateProgram(const ch
if (!vertexShader || !fragmentShader)
return false;
GLint result = mGL->fCreateProgram();
mGL->fAttachShader(result, vertexShader);
mGL->fAttachShader(result, fragmentShader);
+ for (Pair<nsCString, GLuint>& attribute : mProfile.mAttributes) {
+ mGL->fBindAttribLocation(result, attribute.second(),
+ attribute.first().get());
+ }
+
mGL->fLinkProgram(result);
GLint success, len;
mGL->fGetProgramiv(result, LOCAL_GL_LINK_STATUS, &success);
mGL->fGetProgramiv(result, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
/* Even if linking is successful, there may still be warnings. Print them
* in a debug build. The > 10 is to catch silly compilers that might put
* some whitespace in the log but otherwise leave it empty.
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_OGLSHADERPROGRAM_H
#define GFX_OGLSHADERPROGRAM_H
#include "GLContext.h" // for fast inlines of glUniform*
#include "gfxTypes.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/Pair.h" // for Pair
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Types.h"
#include "nsDebug.h" // for NS_ASSERTION
#include "nsPoint.h" // for nsIntPoint
#include "nsTArray.h" // for nsTArray
#include "mozilla/layers/CompositorTypes.h"
@@ -34,17 +35,18 @@ enum ShaderFeatures {
ENABLE_TEXTURE_COMPONENT_ALPHA=0x20,
ENABLE_TEXTURE_NO_ALPHA=0x40,
ENABLE_TEXTURE_RB_SWAP=0x80,
ENABLE_OPACITY=0x100,
ENABLE_BLUR=0x200,
ENABLE_COLOR_MATRIX=0x400,
ENABLE_MASK=0x800,
ENABLE_NO_PREMUL_ALPHA=0x1000,
- ENABLE_DEAA=0x2000
+ ENABLE_DEAA=0x2000,
+ ENABLE_DYNAMIC_GEOMETRY=0x4000
};
class KnownUniform {
public:
// this needs to be kept in sync with strings in 'AddUniforms'
enum KnownUniformName {
NotAKnownUniform = -1,
@@ -221,16 +223,17 @@ public:
void SetNV12(bool aEnabled);
void SetComponentAlpha(bool aEnabled);
void SetColorMatrix(bool aEnabled);
void SetBlur(bool aEnabled);
void SetMask(bool aEnabled);
void SetDEAA(bool aEnabled);
void SetCompositionOp(gfx::CompositionOp aOp);
void SetNoPremultipliedAlpha();
+ void SetDynamicGeometry(bool aEnabled);
bool operator< (const ShaderConfigOGL& other) const {
return mFeatures < other.mFeatures ||
(mFeatures == other.mFeatures &&
(int)mCompositionOp < (int)other.mCompositionOp);
}
public:
@@ -272,16 +275,19 @@ struct ProgramProfileOGL
* ShaderConfigOGL
*/
static ProgramProfileOGL GetProfileFor(ShaderConfigOGL aConfig);
// the source code for the program's shaders
std::string mVertexShaderString;
std::string mFragmentShaderString;
+ // the vertex attributes
+ nsTArray<Pair<nsCString, GLuint>> mAttributes;
+
KnownUniform mUniforms[KnownUniform::KnownUniformCount];
nsTArray<const char *> mDefines;
size_t mTextureCount;
ProgramProfileOGL() :
mTextureCount(0)
{}
--- a/gfx/tests/gtest/TestPolygon.cpp
+++ b/gfx/tests/gtest/TestPolygon.cpp
@@ -18,17 +18,17 @@ TEST(Polygon3D, TriangulateRectangle)
{
const Polygon3D p {
Point3D(0.0f, 0.0f, 1.0f),
Point3D(0.0f, 1.0f, 1.0f),
Point3D(1.0f, 1.0f, 1.0f),
Point3D(1.0f, 0.0f, 1.0f)
};
- const nsTArray<Triangle> triangles = p.Triangulate();
+ const nsTArray<Triangle> triangles = p.ToTriangles();
const nsTArray<Triangle> expected = {
Triangle(Point(0.0f, 0.0f), Point(0.0f, 1.0f), Point(1.0f, 1.0f)),
Triangle(Point(0.0f, 0.0f), Point(1.0f, 1.0f), Point(1.0f, 0.0f))
};
AssertArrayEQ(triangles, expected);
}
@@ -37,17 +37,17 @@ TEST(Polygon3D, TriangulatePentagon)
const Polygon3D p {
Point3D(0.0f, 0.0f, 1.0f),
Point3D(0.0f, 1.0f, 1.0f),
Point3D(0.5f, 1.5f, 1.0f),
Point3D(1.0f, 1.0f, 1.0f),
Point3D(1.0f, 0.0f, 1.0f)
};
- const nsTArray<Triangle> triangles = p.Triangulate();
+ const nsTArray<Triangle> triangles = p.ToTriangles();
const nsTArray<Triangle> expected = {
Triangle(Point(0.0f, 0.0f), Point(0.0f, 1.0f), Point(0.5f, 1.5f)),
Triangle(Point(0.0f, 0.0f), Point(0.5f, 1.5f), Point(1.0f, 1.0f)),
Triangle(Point(0.0f, 0.0f), Point(1.0f, 1.0f), Point(1.0f, 0.0f))
};
AssertArrayEQ(triangles, expected);
}