From: commit-queue@webkit.org Date: Tue, 3 Jul 2012 04:25:35 +0000 (+0000) Subject: [TextureMapper] The TextureMapper should support edge-distance anti-antialiasing X-Git-Tag: 070512121124~167 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=27e8235ce84c743d254c99b81ac91dc28c3a6228;p=profile%2Fivi%2Fwebkit-efl.git [TextureMapper] The TextureMapper should support edge-distance anti-antialiasing https://bugs.webkit.org/show_bug.cgi?id=90308 Patch by Martin Robinson on 2012-07-02 Reviewed by Noam Rosenthal. Source/WebCore: Add an edge-distance anti-aliasing implementation for the TextureMapper. Currently this implementation is not active for tiled layers. This implementation is based on the one in the Chromium compositor originally written by David Raveman. When a layer is transformed in a way that leaves its edge dimensions across pixel boundaries, edge distance anti-aliasing will do a cheaper form of anti-aliasing than full-scene anti-aliasing to make the transition from the layer pixel to the background pixel smoother. No new tests. This will be covered by pixel tests for Qt and GTK+ accelerated compositing and 3D transforms, when those test harnesses are capable of producing pixel output (in progress). * platform/graphics/texmap/TextureMapper.h: Add an enum which is used to tell the texture mapper what edges of a texture are exposed. This will be used for properly dealing with tiled layers in the future. * platform/graphics/texmap/TextureMapperBackingStore.cpp: Properly pass information about exposed layer edges to the TextureMapper while painting. * platform/graphics/texmap/TextureMapperBackingStore.h: (TextureMapperTile): Modified arguments include exposed edges. * platform/graphics/texmap/TextureMapperGL.cpp: (WebCore::TextureMapperGL::drawQuad): Renamed from drawRect, this method can now draw quads that have non unit-rect texture coordinates. This is necessary because the edge distance approach draws such quad. (WebCore::TextureMapperGL::drawBorder): Call drawQuad now instead of drawRect. (WebCore::TextureMapperGL::drawTexture): Pass the exposedEdges argument down. (WebCore::TextureMapperGL::drawTextureRectangleARB): Call drawQuad now instead of drawRect. (WebCore::viewportMatrix): Added this helper which can calculate the viewport transform based on the current OpenGL viewport settings. (WebCore::scaleLineEquationCoeffecientsToOptimizeDistanceCalculation): Added this helper which optimizes the fragment shader by precalculating some constant parts of the distance calculation. (WebCore::getStandardEquationCoeffecientsForLine): Given two end points of line segment get the coeffecients of the line in the standard form of the line equation. (WebCore::quadToEdgeArray): Converts a FloatQuad to an array of four sets of pre-scaled line coefficients so that they can be passed to OpenGL. (WebCore::scaledVectorDifference): Helper which helps expand a quad of arbitrary orientation. (WebCore::inflateQuad): Inflate a quad of arbitrary orientation. The transform may flip it so we have to look at neighboring points to expand the quad. (WebCore::TextureMapperGL::drawTextureWithAntialiasing): Activate the anti-aliasing program and set up all uniforms. (WebCore::TextureMapperGL::drawTexturedQuadWithProgram): Abstract out common operations from drawTexture to be used with drawTextureWithAntialiasing. * platform/graphics/texmap/TextureMapperGL.h: (WebCore::TextureMapperGL::DrawQuad::DrawQuad): Add this small type which stores information necessary to draw a quad -- it's original destination rect and the final size mapped to texture coordinates. (TextureMapperGL): * platform/graphics/texmap/TextureMapperImageBuffer.cpp: Add the new exposedEdges argument. * platform/graphics/texmap/TextureMapperImageBuffer.h: Ditto. * platform/graphics/texmap/TextureMapperShaderManager.cpp: Add the new fragment shader for doing edge-distance AA and a program which uses that shader. * platform/graphics/texmap/TextureMapperShaderManager.h: Ditto. Source/WebKit2: * UIProcess/texmap/LayerBackingStore.cpp: (WebKit::LayerBackingStore::paintToTextureMapper): Update the method to call paint with the new argument. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121729 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 0237184..8f3fd46 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,66 @@ +2012-07-02 Martin Robinson + + [TextureMapper] The TextureMapper should support edge-distance anti-antialiasing + https://bugs.webkit.org/show_bug.cgi?id=90308 + + Reviewed by Noam Rosenthal. + + Add an edge-distance anti-aliasing implementation for the TextureMapper. Currently + this implementation is not active for tiled layers. This implementation is based + on the one in the Chromium compositor originally written by David Raveman. + + When a layer is transformed in a way that leaves its edge dimensions across pixel + boundaries, edge distance anti-aliasing will do a cheaper form of anti-aliasing + than full-scene anti-aliasing to make the transition from the layer pixel + to the background pixel smoother. + + No new tests. This will be covered by pixel tests for Qt and GTK+ accelerated + compositing and 3D transforms, when those test harnesses are capable of + producing pixel output (in progress). + + * platform/graphics/texmap/TextureMapper.h: Add an enum which is used to tell + the texture mapper what edges of a texture are exposed. This will be used for + properly dealing with tiled layers in the future. + * platform/graphics/texmap/TextureMapperBackingStore.cpp: Properly pass information + about exposed layer edges to the TextureMapper while painting. + * platform/graphics/texmap/TextureMapperBackingStore.h: + (TextureMapperTile): Modified arguments include exposed edges. + * platform/graphics/texmap/TextureMapperGL.cpp: + (WebCore::TextureMapperGL::drawQuad): Renamed from drawRect, this method can now + draw quads that have non unit-rect texture coordinates. This is necessary because + the edge distance approach draws such quad. + (WebCore::TextureMapperGL::drawBorder): Call drawQuad now instead of drawRect. + (WebCore::TextureMapperGL::drawTexture): Pass the exposedEdges argument down. + (WebCore::TextureMapperGL::drawTextureRectangleARB): Call drawQuad now instead of + drawRect. + (WebCore::viewportMatrix): Added this helper which can calculate the viewport + transform based on the current OpenGL viewport settings. + (WebCore::scaleLineEquationCoeffecientsToOptimizeDistanceCalculation): Added this + helper which optimizes the fragment shader by precalculating some constant parts + of the distance calculation. + (WebCore::getStandardEquationCoeffecientsForLine): Given two end points of line segment + get the coeffecients of the line in the standard form of the line equation. + (WebCore::quadToEdgeArray): Converts a FloatQuad to an array of four sets of pre-scaled + line coefficients so that they can be passed to OpenGL. + (WebCore::scaledVectorDifference): Helper which helps expand a quad of arbitrary + orientation. + (WebCore::inflateQuad): Inflate a quad of arbitrary orientation. The transform may + flip it so we have to look at neighboring points to expand the quad. + (WebCore::TextureMapperGL::drawTextureWithAntialiasing): Activate the anti-aliasing + program and set up all uniforms. + (WebCore::TextureMapperGL::drawTexturedQuadWithProgram): Abstract out common operations + from drawTexture to be used with drawTextureWithAntialiasing. + * platform/graphics/texmap/TextureMapperGL.h: + (WebCore::TextureMapperGL::DrawQuad::DrawQuad): Add this small type which stores information + necessary to draw a quad -- it's original destination rect and the final size mapped to + texture coordinates. + (TextureMapperGL): + * platform/graphics/texmap/TextureMapperImageBuffer.cpp: Add the new exposedEdges argument. + * platform/graphics/texmap/TextureMapperImageBuffer.h: Ditto. + * platform/graphics/texmap/TextureMapperShaderManager.cpp: Add the new fragment shader for + doing edge-distance AA and a program which uses that shader. + * platform/graphics/texmap/TextureMapperShaderManager.h: Ditto. + 2012-07-02 Dan Bernstein Column height and count calculation ignores most overflow diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h index f1da424..00ea3e3 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -112,8 +112,17 @@ public: static PassOwnPtr create(AccelerationMode newMode = SoftwareMode); virtual ~TextureMapper() { } + enum ExposedEdges { + NoEdges = 0, + LeftEdge = 1 << 0, + RightEdge = 1 << 1, + TopEdge = 1 << 2, + BottomEdge = 1 << 3, + AllEdges = LeftEdge | RightEdge | TopEdge | BottomEdge, + }; + virtual void drawBorder(const Color&, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) = 0; - virtual void drawTexture(const BitmapTexture&, const FloatRect& target, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0f, const BitmapTexture* maskTexture = 0) = 0; + virtual void drawTexture(const BitmapTexture&, const FloatRect& target, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0f, const BitmapTexture* maskTexture = 0, unsigned exposedEdges = AllEdges) = 0; // makes a surface the target for the following drawTexture calls. virtual void bindSurface(BitmapTexture* surface) = 0; diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp index 3f4ec6e..efa659f 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp @@ -87,10 +87,10 @@ void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* imag m_texture->updateContents(image, targetRect, sourceOffset); } -void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, BitmapTexture* mask) +void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, BitmapTexture* mask, const unsigned exposedEdges) { if (texture().get()) - textureMapper->drawTexture(*texture().get(), rect(), transform, opacity, mask); + textureMapper->drawTexture(*texture().get(), rect(), transform, opacity, mask, exposedEdges); } TextureMapperTiledBackingStore::TextureMapperTiledBackingStore() @@ -107,13 +107,27 @@ void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapp m_image.clear(); } +unsigned TextureMapperBackingStore::calculateExposedTileEdges(const FloatRect& totalRect, const FloatRect& tileRect) +{ + unsigned exposedEdges = TextureMapper::NoEdges; + if (!tileRect.x()) + exposedEdges |= TextureMapper::LeftEdge; + if (!tileRect.y()) + exposedEdges |= TextureMapper::TopEdge; + if (tileRect.width() + tileRect.x() >= totalRect.width()) + exposedEdges |= TextureMapper::RightEdge; + if (tileRect.height() + tileRect.y() >= totalRect.height()) + exposedEdges |= TextureMapper::BottomEdge; + return exposedEdges; +} + void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity, BitmapTexture* mask) { updateContentsFromImageIfNeeded(textureMapper); TransformationMatrix adjustedTransform = transform; adjustedTransform.multiply(TransformationMatrix::rectToRect(rect(), targetRect)); for (size_t i = 0; i < m_tiles.size(); ++i) { - m_tiles[i].paint(textureMapper, adjustedTransform, opacity, mask); + m_tiles[i].paint(textureMapper, adjustedTransform, opacity, mask, calculateExposedTileEdges(rect(), m_tiles[i].rect())); if (m_drawsDebugBorders) textureMapper->drawBorder(m_debugBorderColor, m_debugBorderWidth, m_tiles[i].rect(), adjustedTransform); } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h index 95abe53..0f71c45 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h @@ -39,6 +39,9 @@ public: virtual PassRefPtr texture() const = 0; virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float, BitmapTexture*) = 0; virtual ~TextureMapperBackingStore() { } + +protected: + static unsigned calculateExposedTileEdges(const FloatRect& totalRect, const FloatRect& tileRect); }; #if USE(GRAPHICS_SURFACE) @@ -82,7 +85,7 @@ public: inline void setRect(const FloatRect& rect) { m_rect = rect; } void updateContents(TextureMapper*, Image*, const IntRect&); - virtual void paint(TextureMapper*, const TransformationMatrix&, float, BitmapTexture*); + virtual void paint(TextureMapper*, const TransformationMatrix&, float, BitmapTexture*, const unsigned exposedEdges); virtual ~TextureMapperTile() { } TextureMapperTile(const FloatRect& rect) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp index fae02aa..0b6fc8a 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp @@ -236,6 +236,7 @@ TextureMapperGL::TextureMapperGL() : TextureMapper(OpenGLMode) , m_data(new TextureMapperGLData) , m_context(0) + , m_enableEdgeDistanceAntialiasing(false) { } @@ -304,19 +305,24 @@ void TextureMapperGL::endPainting() #endif } -void TextureMapperGL::drawRect(const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram* shaderProgram, GLenum drawingMode, bool needsBlending) +void TextureMapperGL::drawQuad(const DrawQuad& quadToDraw, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram* shaderProgram, GLenum drawingMode, bool needsBlending) { GL_CMD(glEnableVertexAttribArray(shaderProgram->vertexAttrib())); GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0)); - const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; - GL_CMD(glVertexAttribPointer(shaderProgram->vertexAttrib(), 2, GL_FLOAT, GL_FALSE, 0, unitRect)); + + const GLfloat quad[] = { + quadToDraw.targetRectMappedToUnitSquare.p1().x(), quadToDraw.targetRectMappedToUnitSquare.p1().x(), + quadToDraw.targetRectMappedToUnitSquare.p2().x(), quadToDraw.targetRectMappedToUnitSquare.p2().y(), + quadToDraw.targetRectMappedToUnitSquare.p3().x(), quadToDraw.targetRectMappedToUnitSquare.p3().y(), + quadToDraw.targetRectMappedToUnitSquare.p4().x(), quadToDraw.targetRectMappedToUnitSquare.p4().y() + }; + GL_CMD(glVertexAttribPointer(shaderProgram->vertexAttrib(), 2, GL_FLOAT, GL_FALSE, 0, quad)); TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multiply(modelViewMatrix).multiply(TransformationMatrix( - targetRect.width(), 0, 0, 0, - 0, targetRect.height(), 0, 0, + quadToDraw.originalTargetRect.width(), 0, 0, 0, + 0, quadToDraw.originalTargetRect.height(), 0, 0, 0, 0, 1, 0, - targetRect.x(), targetRect.y(), 0, 1)); - + quadToDraw.originalTargetRect.x(), quadToDraw.originalTargetRect.y(), 0, 1)); const GLfloat m4[] = { matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(), matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(), @@ -351,10 +357,10 @@ void TextureMapperGL::drawBorder(const Color& color, float width, const FloatRec alpha)); GL_CMD(glLineWidth(width)); - drawRect(targetRect, modelViewMatrix, program.get(), GL_LINE_LOOP, color.hasAlpha()); + drawQuad(targetRect, modelViewMatrix, program.get(), GL_LINE_LOOP, color.hasAlpha()); } -void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* mask) +void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* mask, unsigned exposedEdges) { if (!texture.isValid()) return; @@ -363,7 +369,7 @@ void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& return; const BitmapTextureGL& textureGL = static_cast(texture); - drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : SupportsBlending, textureGL.size(), targetRect, matrix, opacity, mask); + drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : SupportsBlending, textureGL.size(), targetRect, matrix, opacity, mask, exposedEdges); } #if defined(GL_ARB_texture_rectangle) @@ -396,12 +402,16 @@ void TextureMapperGL::drawTextureRectangleARB(uint32_t texture, Flags flags, con } bool needsBlending = (flags & SupportsBlending) || opacity < 0.99 || maskTexture; - drawRect(targetRect, modelViewMatrix, program.get(), GL_TRIANGLE_FAN, needsBlending); + drawQuad(targetRect, modelViewMatrix, program.get(), GL_TRIANGLE_FAN, needsBlending); } #endif // defined(GL_ARB_texture_rectangle) -void TextureMapperGL::drawTexture(uint32_t texture, Flags flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture) +void TextureMapperGL::drawTexture(uint32_t texture, Flags flags, const IntSize& /* textureSize */, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) { + bool needsAntiliaing = m_enableEdgeDistanceAntialiasing && !modelViewMatrix.isIntegerTranslation(); + if (needsAntiliaing && drawTextureWithAntialiasing(texture, flags, targetRect, modelViewMatrix, opacity, maskTexture, exposedEdges)) + return; + RefPtr program; if (maskTexture) program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::OpacityAndMask); @@ -409,6 +419,142 @@ void TextureMapperGL::drawTexture(uint32_t texture, Flags flags, const IntSize& program = data().sharedGLData().textureMapperShaderManager.getShaderProgram(TextureMapperShaderManager::Simple); GL_CMD(glUseProgram(program->id())); + drawTexturedQuadWithProgram(program.get(), texture, flags, targetRect, modelViewMatrix, opacity, maskTexture); +} + +static TransformationMatrix viewportMatrix() +{ + GLint viewport[4]; + GL_CMD(glGetIntegerv(GL_VIEWPORT, viewport)); + + TransformationMatrix matrix; + matrix.translate3d(viewport[0], viewport[1], 0); + matrix.scale3d(viewport[2], viewport[3], 0); + + // Map x, y and z to unit square from OpenGL normalized device + // coordinates which are -1 to 1 on every axis. + matrix.translate3d(0.5, 0.5, 0.5); + matrix.scale3d(0.5, 0.5, 0.5); + + return matrix; +} + +static void scaleLineEquationCoeffecientsToOptimizeDistanceCalculation(float* coeffecients) +{ + // In the fragment shader we want to calculate the distance from this + // line to a point (p), which is given by the formula: + // (A*p.x + B*p.y + C) / sqrt (a^2 + b^2) + // We can do a small amount of precalculation here to reduce the + // amount of math in the shader by scaling the coeffecients now. + float scale = 1.0 / FloatPoint(coeffecients[0], coeffecients[1]).length(); + coeffecients[0] = coeffecients[0] * scale; + coeffecients[1] = coeffecients[1] * scale; + coeffecients[2] = coeffecients[2] * scale; +} + +static void getStandardEquationCoeffecientsForLine(const FloatPoint& p1, const FloatPoint& p2, float* coeffecients) +{ + // Given two points, the standard equation of a line (Ax + By + C = 0) + // can be calculated via the formula: + // (p1.y – p2.y)x + (p1.x – p2.x)y + ((p1.x*p2.y) – (p2.x*p1.y)) = 0 + coeffecients[0] = p1.y() - p2.y(); + coeffecients[1] = p2.x() - p1.x(); + coeffecients[2] = p1.x() * p2.y() - p2.x() * p1.y(); + scaleLineEquationCoeffecientsToOptimizeDistanceCalculation(coeffecients); +} + +static void quadToEdgeArray(const FloatQuad& quad, float* edgeArray) +{ + if (quad.isCounterclockwise()) { + getStandardEquationCoeffecientsForLine(quad.p4(), quad.p3(), edgeArray); + getStandardEquationCoeffecientsForLine(quad.p3(), quad.p2(), edgeArray + 3); + getStandardEquationCoeffecientsForLine(quad.p2(), quad.p1(), edgeArray + 6); + getStandardEquationCoeffecientsForLine(quad.p1(), quad.p4(), edgeArray + 9); + return; + } + getStandardEquationCoeffecientsForLine(quad.p4(), quad.p1(), edgeArray); + getStandardEquationCoeffecientsForLine(quad.p1(), quad.p2(), edgeArray + 3); + getStandardEquationCoeffecientsForLine(quad.p2(), quad.p3(), edgeArray + 6); + getStandardEquationCoeffecientsForLine(quad.p3(), quad.p4(), edgeArray + 9); +} + +static FloatSize scaledVectorDifference(const FloatPoint& point1, const FloatPoint& point2, float scale) +{ + FloatSize vector = point1 - point2; + if (vector.diagonalLengthSquared()) + vector.scale(1.0 / vector.diagonalLength()); + + vector.scale(scale); + return vector; +} + +static FloatQuad inflateQuad(const FloatQuad& quad, float distance) +{ + FloatQuad expandedQuad = quad; + expandedQuad.setP1(expandedQuad.p1() + scaledVectorDifference(quad.p1(), quad.p2(), distance)); + expandedQuad.setP4(expandedQuad.p4() + scaledVectorDifference(quad.p4(), quad.p3(), distance)); + + expandedQuad.setP1(expandedQuad.p1() + scaledVectorDifference(quad.p1(), quad.p4(), distance)); + expandedQuad.setP2(expandedQuad.p2() + scaledVectorDifference(quad.p2(), quad.p3(), distance)); + + expandedQuad.setP2(expandedQuad.p2() + scaledVectorDifference(quad.p2(), quad.p1(), distance)); + expandedQuad.setP3(expandedQuad.p3() + scaledVectorDifference(quad.p3(), quad.p4(), distance)); + + expandedQuad.setP3(expandedQuad.p3() + scaledVectorDifference(quad.p3(), quad.p2(), distance)); + expandedQuad.setP4(expandedQuad.p4() + scaledVectorDifference(quad.p4(), quad.p1(), distance)); + + return expandedQuad; +} + +bool TextureMapperGL::drawTextureWithAntialiasing(uint32_t texture, Flags flags, const FloatRect& originalTargetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) +{ + // The antialiasing path does not support mask textures at the moment. + if (maskTexture) + return false; + + // For now we punt on rendering tiled layers with antialiasing. It's quite hard + // to render them without seams. + if (exposedEdges != AllEdges) + return false; + + // The goal here is render a slightly larger (0.75 pixels in screen space) quad and to + // gradually taper off the alpha values to do a simple version of edge distance + // antialiasing. Note here that we are also including the viewport matrix (which + // translates from normalized device coordinates to screen coordinates), because these + // values are consumed in the fragment shader, which works in screen coordinates. + TransformationMatrix screenSpaceTransform = viewportMatrix().multiply(TransformationMatrix(data().projectionMatrix)).multiply(modelViewMatrix).to2dTransform(); + if (!screenSpaceTransform.isInvertible()) + return false; + FloatQuad quadInScreenSpace = screenSpaceTransform.mapQuad(originalTargetRect); + + const float inflationDistance = 0.75; + FloatQuad expandedQuadInScreenSpace = inflateQuad(quadInScreenSpace, inflationDistance); + + // In the non-antialiased case the vertices passed are the unit rectangle and double + // as the texture coordinates (0,0 1,0, 1,1 and 0,1). Here we map the expanded quad + // coordinates in screen space back to the original rect's texture coordinates. + // This has the effect of slightly increasing the size of the original quad's geometry + // in the vertex shader. + FloatQuad expandedQuadInTextureCoordinates = screenSpaceTransform.inverse().mapQuad(expandedQuadInScreenSpace); + expandedQuadInTextureCoordinates.move(-originalTargetRect.x(), -originalTargetRect.y()); + expandedQuadInTextureCoordinates.scale(1 / originalTargetRect.width(), 1 / originalTargetRect.height()); + + // We prepare both the expanded quad for the fragment shader as well as the rectangular bounding + // box of that quad, as that seems necessary to properly antialias backfacing quads. + float targetQuadEdges[24]; + quadToEdgeArray(expandedQuadInScreenSpace, targetQuadEdges); + quadToEdgeArray(inflateQuad(quadInScreenSpace.boundingBox(), inflationDistance), targetQuadEdges + 12); + + RefPtr program = data().sharedGLData().textureMapperShaderManager.antialiasingNoMaskProgram(); + GL_CMD(glUseProgram(program->id())); + GL_CMD(glUniform3fv(program->expandedQuadEdgesInScreenSpaceLocation(), 8, targetQuadEdges)); + + drawTexturedQuadWithProgram(program.get(), texture, flags, DrawQuad(originalTargetRect, expandedQuadInTextureCoordinates), modelViewMatrix, opacity, 0 /* maskTexture */); + return true; +} + +void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* program, uint32_t texture, Flags flags, const DrawQuad& quadToDraw, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture) +{ GL_CMD(glEnableVertexAttribArray(program->vertexAttrib())); GL_CMD(glActiveTexture(GL_TEXTURE0)); GL_CMD(glBindTexture(GL_TEXTURE_2D, texture)); @@ -428,7 +574,7 @@ void TextureMapperGL::drawTexture(uint32_t texture, Flags flags, const IntSize& } bool needsBlending = (flags & SupportsBlending) || opacity < 0.99 || maskTexture; - drawRect(targetRect, modelViewMatrix, program.get(), GL_TRIANGLE_FAN, needsBlending); + drawQuad(quadToDraw, modelViewMatrix, program, GL_TRIANGLE_FAN, needsBlending); } bool BitmapTextureGL::canReuseWith(const IntSize& contentsSize, Flags) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h index e75bb08..39a5a30 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h @@ -50,11 +50,13 @@ public: // TextureMapper implementation virtual void drawBorder(const Color&, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) OVERRIDE; - virtual void drawTexture(const BitmapTexture&, const FloatRect&, const TransformationMatrix&, float opacity, const BitmapTexture* maskTexture) OVERRIDE; - virtual void drawTexture(uint32_t texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture); + virtual void drawTexture(const BitmapTexture&, const FloatRect&, const TransformationMatrix&, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) OVERRIDE; + virtual void drawTexture(uint32_t texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges = AllEdges); + #if defined(GL_ARB_texture_rectangle) virtual void drawTextureRectangleARB(uint32_t texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture); #endif + virtual void bindSurface(BitmapTexture* surface) OVERRIDE; virtual void beginClip(const TransformationMatrix&, const FloatRect&) OVERRIDE; virtual void beginPainting(PaintFlags = 0) OVERRIDE; @@ -69,6 +71,7 @@ public: void drawFiltered(const BitmapTexture& sourceTexture, const BitmapTexture& contentTexture, const FilterOperation&, int pass); #endif + void setEnableEdgeDistanceAntialiasing(bool enabled) { m_enableEdgeDistanceAntialiasing = enabled; } private: @@ -94,7 +97,21 @@ private: Vector clipStack; }; - void drawRect(const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram*, GLenum drawingMode, bool needsBlending); + struct DrawQuad { + DrawQuad(const FloatRect& originalTargetRect, const FloatQuad& targetRectMappedToUnitSquare = FloatRect(FloatPoint(), FloatSize(1, 1))) + : originalTargetRect(originalTargetRect) + , targetRectMappedToUnitSquare(targetRectMappedToUnitSquare) + { + } + + FloatRect originalTargetRect; + FloatQuad targetRectMappedToUnitSquare; + }; + + bool drawTextureWithAntialiasing(uint32_t texture, Flags, const FloatRect& originalTargetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges); + void drawTexturedQuadWithProgram(TextureMapperShaderProgram*, uint32_t texture, Flags, const DrawQuad&, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture); + void drawQuad(const DrawQuad&, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram*, GLenum drawingMode, bool needsBlending); + bool beginScissorClip(const TransformationMatrix&, const FloatRect&); void bindDefaultSurface(); ClipStack& clipStack(); @@ -102,6 +119,8 @@ private: TextureMapperGLData* m_data; GraphicsContext* m_context; ClipStack m_clipStack; + bool m_enableEdgeDistanceAntialiasing; + friend class BitmapTextureGL; }; diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp index 79470b3..d5019e6 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp @@ -82,7 +82,7 @@ void TextureMapperImageBuffer::beginClip(const TransformationMatrix& matrix, con #endif } -void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture) +void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture, unsigned /* exposedEdges */) { GraphicsContext* context = currentContext(); if (!context) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h index ebcba4b..473bab2 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h @@ -52,7 +52,7 @@ public: // TextureMapper implementation virtual void drawBorder(const Color& color, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix = TransformationMatrix()) OVERRIDE { }; - virtual void drawTexture(const BitmapTexture&, const FloatRect& targetRect, const TransformationMatrix&, float opacity, const BitmapTexture* maskTexture) OVERRIDE; + virtual void drawTexture(const BitmapTexture&, const FloatRect& targetRect, const TransformationMatrix&, float opacity, const BitmapTexture* maskTexture, unsigned exposedEdges) OVERRIDE; virtual void beginClip(const TransformationMatrix&, const FloatRect&) OVERRIDE; virtual void bindSurface(BitmapTexture* surface) OVERRIDE { m_currentSurface = surface;} virtual void endClip() OVERRIDE { graphicsContext()->restore(); } diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp index 39777fe..0fbdbe9 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.cpp @@ -1,6 +1,7 @@ /* Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) Copyright (C) 2012 Igalia S.L. + Copyright (C) 2011 Google Inc. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -105,6 +106,44 @@ static const char* fragmentShaderSourceSimple = } ); +static const char* fragmentShaderSourceAntialiasingNoMask = + FRAGMENT_SHADER( + uniform sampler2D s_source; + varying highp vec2 v_sourceTexCoord; + uniform lowp float u_opacity; + uniform vec3 u_expandedQuadEdgesInScreenSpace[8]; + void main() + { + vec4 sampledColor = texture2D(s_source, clamp(v_sourceTexCoord, 0.0, 1.0)); + vec3 pos = vec3(gl_FragCoord.xy, 1); + + // The data passed in u_expandedQuadEdgesInScreenSpace is merely the + // pre-scaled coeffecients of the line equations describing the four edges + // of the expanded quad in screen space and the rectangular bounding box + // of the expanded quad. + // + // We are doing a simple distance calculation here according to the formula: + // (A*p.x + B*p.y + C) / sqrt(A^2 + B^2) = distance from line to p + // Note that A, B and C have already been scaled by 1 / sqrt(A^2 + B^2). + float a0 = clamp(dot(u_expandedQuadEdgesInScreenSpace[0], pos), 0.0, 1.0); + float a1 = clamp(dot(u_expandedQuadEdgesInScreenSpace[1], pos), 0.0, 1.0); + float a2 = clamp(dot(u_expandedQuadEdgesInScreenSpace[2], pos), 0.0, 1.0); + float a3 = clamp(dot(u_expandedQuadEdgesInScreenSpace[3], pos), 0.0, 1.0); + float a4 = clamp(dot(u_expandedQuadEdgesInScreenSpace[4], pos), 0.0, 1.0); + float a5 = clamp(dot(u_expandedQuadEdgesInScreenSpace[5], pos), 0.0, 1.0); + float a6 = clamp(dot(u_expandedQuadEdgesInScreenSpace[6], pos), 0.0, 1.0); + float a7 = clamp(dot(u_expandedQuadEdgesInScreenSpace[7], pos), 0.0, 1.0); + + // Now we want to reduce the alpha value of the fragment if it is close to the + // edges of the expanded quad (or rectangular bounding box -- which seems to be + // important for backfacing quads). Note that we are combining the contribution + // from the (top || bottom) and (left || right) edge by simply multiplying. This follows + // the approach described at: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html, + // in this case without using Gaussian weights. + gl_FragColor = sampledColor * u_opacity * min(min(a0, a2) * min(a1, a3), min(a4, a6) * min(a5, a7)); + } + ); + static const char* fragmentShaderSourceRectSimple = FRAGMENT_SHADER( uniform sampler2DRect s_source; @@ -156,6 +195,11 @@ PassRefPtr TextureMapperShaderManager::sol return static_pointer_cast(getShaderProgram(SolidColor)); } +PassRefPtr TextureMapperShaderManager::antialiasingNoMaskProgram() +{ + return static_pointer_cast(getShaderProgram(AntialiasingNoMask)); +} + PassRefPtr TextureMapperShaderManager::getShaderProgram(ShaderType shaderType) { RefPtr program; @@ -173,6 +217,9 @@ PassRefPtr TextureMapperShaderManager::getShaderProg case RectSimple: program = TextureMapperShaderProgramRectSimple::create(); break; + case AntialiasingNoMask: + program = TextureMapperShaderProgramAntialiasingNoMask::create(); + break; case OpacityAndMask: program = TextureMapperShaderProgramOpacityAndMask::create(); break; @@ -216,11 +263,13 @@ void TextureMapperShaderProgram::initializeProgram() GLuint programID = glCreateProgram(); glCompileShader(vertexShader); glCompileShader(fragmentShader); + glAttachShader(programID, vertexShader); glAttachShader(programID, fragmentShader); glLinkProgram(programID); m_vertexAttrib = glGetAttribLocation(programID, "a_vertex"); + m_id = programID; m_vertexShader = vertexShader; m_fragmentShader = fragmentShader; @@ -296,6 +345,17 @@ TextureMapperShaderProgramRectOpacityAndMask::TextureMapperShaderProgramRectOpac getUniformLocation(m_opacityLocation, "u_opacity"); } +TextureMapperShaderProgramAntialiasingNoMask::TextureMapperShaderProgramAntialiasingNoMask() + : TextureMapperShaderProgram(vertexShaderSourceSimple, fragmentShaderSourceAntialiasingNoMask) +{ + initializeProgram(); + getUniformLocation(m_matrixLocation, "u_matrix"); + getUniformLocation(m_sourceTextureLocation, "s_source"); + getUniformLocation(m_opacityLocation, "u_opacity"); + getUniformLocation(m_expandedQuadEdgesInScreenSpaceLocation, "u_expandedQuadEdgesInScreenSpace"); + getUniformLocation(m_flipLocation, "u_flip"); +} + TextureMapperShaderManager::TextureMapperShaderManager() { ASSERT(initializeOpenGLShims()); diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.h b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.h index f5a6e95..785498e 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderManager.h @@ -177,11 +177,29 @@ private: GLint m_colorLocation; }; +class TextureMapperShaderProgramAntialiasingNoMask : public TextureMapperShaderProgram { +public: + static PassRefPtr create() + { + return adoptRef(new TextureMapperShaderProgramAntialiasingNoMask()); + } + + GLint expandedQuadVerticesInTextureCoordinatesLocation() { return m_expandedQuadVerticesInTextureCordinatesLocation; } + GLint expandedQuadEdgesInScreenSpaceLocation() { return m_expandedQuadEdgesInScreenSpaceLocation; } + +private: + TextureMapperShaderProgramAntialiasingNoMask(); + + GLint m_expandedQuadVerticesInTextureCordinatesLocation; + GLint m_expandedQuadEdgesInScreenSpaceLocation; +}; + class TextureMapperShaderManager { public: enum ShaderType { Invalid = 0, // HashMaps do not like 0 as a key. Simple, + AntialiasingNoMask, RectSimple, OpacityAndMask, RectOpacityAndMask, @@ -198,6 +216,7 @@ public: PassRefPtr getShaderProgram(ShaderType); PassRefPtr solidColorProgram(); + PassRefPtr antialiasingNoMaskProgram(); private: typedef HashMap, DefaultHash::Hash, HashTraits > TextureMapperShaderProgramMap; diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog index 5a5c72a..658165e 100644 --- a/Source/WebKit2/ChangeLog +++ b/Source/WebKit2/ChangeLog @@ -1,3 +1,14 @@ +2012-07-02 Martin Robinson + + [TextureMapper] The TextureMapper should support edge-distance anti-antialiasing + https://bugs.webkit.org/show_bug.cgi?id=90308 + + Reviewed by Noam Rosenthal. + + * UIProcess/texmap/LayerBackingStore.cpp: + (WebKit::LayerBackingStore::paintToTextureMapper): Update the method to call paint with + the new argument. + 2012-07-02 Benjamin Poulain Do not do any logging initialization when logging is disabled diff --git a/Source/WebKit2/UIProcess/texmap/LayerBackingStore.cpp b/Source/WebKit2/UIProcess/texmap/LayerBackingStore.cpp index caaffe9..4fa682d 100644 --- a/Source/WebKit2/UIProcess/texmap/LayerBackingStore.cpp +++ b/Source/WebKit2/UIProcess/texmap/LayerBackingStore.cpp @@ -121,8 +121,13 @@ void LayerBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const tilesToPaint.prepend(&tile); } + // TODO: When the TextureMapper makes a distinction between some edges exposed and no edges + // exposed, the value passed should be an accurate reflection of the tile subset that we are + // passing. For now we just "estimate" since LayerBackingStore doesn't keep information about + // the total tiled surface rect at the moment. + unsigned edgesExposed = m_tiles.size() > 1 ? TextureMapper::NoEdges : TextureMapper::AllEdges; for (size_t i = 0; i < tilesToPaint.size(); ++i) - tilesToPaint[i]->paint(textureMapper, transform, opacity, mask); + tilesToPaint[i]->paint(textureMapper, transform, opacity, mask, edgesExposed); } void LayerBackingStore::commitTileOperations(TextureMapper* textureMapper)