| Index: Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp
|
| ===================================================================
|
| --- Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp (revision 92714)
|
| +++ Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp (working copy)
|
| @@ -84,6 +84,7 @@
|
| reset();
|
|
|
| m_tileSize = size;
|
| + m_tilingData.setMaxTextureSize(max(size.width(), size.height()));
|
| }
|
|
|
| LayerTexture* LayerTilerChromium::getSingleTexture()
|
| @@ -189,23 +190,16 @@
|
| IntRect LayerTilerChromium::tileLayerRect(const Tile* tile) const
|
| {
|
| const int index = m_tilingData.tileIndex(tile->i(), tile->j());
|
| - return m_tilingData.tileBoundsWithBorder(index);
|
| + IntRect layerRect = m_tilingData.tileBoundsWithBorder(index);
|
| + layerRect.setSize(m_tileSize);
|
| + return layerRect;
|
| }
|
|
|
| -IntRect LayerTilerChromium::tileTexRect(const Tile* tile) const
|
| -{
|
| - const int index = m_tilingData.tileIndex(tile->i(), tile->j());
|
| - return m_tilingData.tileBoundsWithOuterBorder(index);
|
| -}
|
| -
|
| void LayerTilerChromium::invalidateRect(const IntRect& contentRect)
|
| {
|
| if (contentRect.isEmpty() || m_skipsDraw)
|
| return;
|
|
|
| - IntSize oldLayerSize(m_tilingData.totalSizeX(), m_tilingData.totalSizeY());
|
| - const IntRect oldLayerRect = IntRect(IntPoint(), oldLayerSize);
|
| -
|
| growLayerToContain(contentRect);
|
|
|
| // Dirty rects are always in layer space, as the layer could be repositioned
|
| @@ -222,12 +216,6 @@
|
| IntRect bound = tileLayerRect(tile);
|
| bound.intersect(layerRect);
|
| tile->m_dirtyLayerRect.unite(bound);
|
| -
|
| - // Invalidate old layer area to clear any contents left from
|
| - // previous layer size.
|
| - IntRect oldBound = tileLayerRect(tile);
|
| - oldBound.intersect(oldLayerRect);
|
| - tile->m_dirtyLayerRect.unite(oldBound);
|
| }
|
| }
|
| }
|
| @@ -284,7 +272,6 @@
|
| // Create tiles as needed, expanding a dirty rect to contain all
|
| // the dirty regions currently being drawn.
|
| IntRect dirtyLayerRect;
|
| - IntSize tileSize;
|
| int left, top, right, bottom;
|
| contentRectToTileIndices(contentRect, left, top, right, bottom);
|
| for (int j = top; j <= bottom; ++j) {
|
| @@ -293,19 +280,16 @@
|
| if (!tile)
|
| tile = createTile(i, j);
|
|
|
| - IntSize texSize = tileTexRect(tile).size();
|
| - if (!tile->texture()->isValid(texSize, m_textureFormat))
|
| + if (!tile->texture()->isValid(m_tileSize, m_textureFormat))
|
| tile->m_dirtyLayerRect = tileLayerRect(tile);
|
|
|
| - if (!tile->texture()->reserve(texSize, m_textureFormat)) {
|
| + if (!tile->texture()->reserve(m_tileSize, m_textureFormat)) {
|
| m_skipsDraw = true;
|
| reset();
|
| return;
|
| }
|
|
|
| dirtyLayerRect.unite(tile->m_dirtyLayerRect);
|
| -
|
| - tileSize = tileSize.expandedTo(texSize);
|
| }
|
| }
|
|
|
| @@ -318,7 +302,7 @@
|
| if (dirtyLayerRect.isEmpty())
|
| return;
|
|
|
| - textureUpdater->prepareToUpdate(m_paintRect, tileSize, m_tilingData.borderTexels());
|
| + textureUpdater->prepareToUpdate(m_paintRect, m_tileSize, m_tilingData.borderTexels());
|
| }
|
|
|
| void LayerTilerChromium::updateRect(LayerTextureUpdater* textureUpdater)
|
| @@ -343,8 +327,7 @@
|
|
|
| // Calculate page-space rectangle to copy from.
|
| IntRect sourceRect = tileContentRect(tile);
|
| - IntRect texRect = tileTexRect(tile);
|
| - const IntPoint anchor = texRect.location();
|
| + const IntPoint anchor = sourceRect.location();
|
| sourceRect.intersect(layerRectToContentRect(tile->m_dirtyLayerRect));
|
| // Paint rect not guaranteed to line up on tile boundaries, so
|
| // make sure that sourceRect doesn't extend outside of it.
|
| @@ -394,12 +377,22 @@
|
| if (m_skipsDraw || !m_tiles.size() || contentRect.isEmpty())
|
| return;
|
|
|
| + // Use anti-aliasing programs when border texels are preset and transform
|
| + // is not an integer translation.
|
| + bool useAA = (m_tilingData.borderTexels() && !globalTransform.isIntegerTranslation());
|
| +
|
| switch (m_sampledTexelFormat) {
|
| case LayerTextureUpdater::SampledTexelFormatRGBA:
|
| - drawTiles(contentRect, globalTransform, opacity, layerRenderer()->tilerProgram());
|
| + if (useAA)
|
| + drawTiles(contentRect, globalTransform, opacity, layerRenderer()->tilerProgramAA(), layerRenderer()->tilerProgramAA()->fragmentShader().fragmentTexTransformLocation(), layerRenderer()->tilerProgramAA()->fragmentShader().edgeLocation());
|
| + else
|
| + drawTiles(contentRect, globalTransform, opacity, layerRenderer()->tilerProgram(), -1, -1);
|
| break;
|
| case LayerTextureUpdater::SampledTexelFormatBGRA:
|
| - drawTiles(contentRect, globalTransform, opacity, layerRenderer()->tilerProgramSwizzle());
|
| + if (useAA)
|
| + drawTiles(contentRect, globalTransform, opacity, layerRenderer()->tilerProgramSwizzleAA(), layerRenderer()->tilerProgramSwizzleAA()->fragmentShader().fragmentTexTransformLocation(), layerRenderer()->tilerProgramSwizzleAA()->fragmentShader().edgeLocation());
|
| + else
|
| + drawTiles(contentRect, globalTransform, opacity, layerRenderer()->tilerProgramSwizzle(), -1, -1);
|
| break;
|
| default:
|
| ASSERT_NOT_REACHED();
|
| @@ -411,17 +404,7 @@
|
| // Grow the tile array to contain this content rect.
|
| IntRect layerRect = contentRectToLayerRect(contentRect);
|
| IntSize rectSize = IntSize(layerRect.maxX(), layerRect.maxY());
|
| - IntSize texSize = m_tileSize;
|
|
|
| - // Use rect with border texels as max texture size when tile size
|
| - // has not been specified.
|
| - if (texSize.isEmpty()) {
|
| - texSize = rectSize;
|
| - if (m_tilingData.borderTexels())
|
| - texSize.expand(2, 2);
|
| - }
|
| -
|
| - m_tilingData.setMaxTextureSize(max(texSize.width(), texSize.height()));
|
| IntSize oldLayerSize(m_tilingData.totalSizeX(), m_tilingData.totalSizeY());
|
| IntSize newSize = rectSize.expandedTo(oldLayerSize);
|
| m_tilingData.setTotalSize(newSize.width(), newSize.height());
|
| @@ -457,15 +440,10 @@
|
| }
|
|
|
| template <class T>
|
| -void LayerTilerChromium::drawTiles(const IntRect& contentRect, const TransformationMatrix& globalTransform, float opacity, const T* program)
|
| +void LayerTilerChromium::drawTiles(const IntRect& contentRect, const TransformationMatrix& globalTransform, float opacity, const T* program, int fragmentTexTransformLocation, int edgeLocation)
|
| {
|
| - GraphicsContext3D* context = layerRendererContext();
|
| - GLC(context, context->useProgram(program->program()));
|
| - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0));
|
| - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
|
| + TransformationMatrix matrix(layerRenderer()->windowMatrix() * layerRenderer()->projectionMatrix() * globalTransform);
|
|
|
| - TransformationMatrix matrix(globalTransform);
|
| -
|
| // We don't care about Z component.
|
| TransformationMatrix matrixXYW =
|
| TransformationMatrix(matrix.m11(), matrix.m12(), 0, matrix.m14(),
|
| @@ -478,44 +456,65 @@
|
| return;
|
|
|
| TransformationMatrix inverse = matrixXYW.inverse();
|
| - IntRect bounds(m_layerPosition, IntSize(m_tilingData.totalSizeX(),
|
| - m_tilingData.totalSizeY()));
|
|
|
| - // Include outer border texels in bounds.
|
| - bounds.inflate(m_tilingData.borderTexels());
|
| + GraphicsContext3D* context = layerRendererContext();
|
| + GLC(context, context->useProgram(program->program()));
|
| + GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0));
|
| + GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
|
|
|
| - // Map bounds to device space.
|
| - FloatQuad boundsQuad = matrix.mapQuad(FloatQuad(bounds));
|
| + // Map content rectangle to device space.
|
| + FloatQuad deviceQuad = matrix.mapQuad(FloatQuad(contentRect));
|
|
|
| // Counter-clockwise?
|
| - float sign = isCCW(boundsQuad) ? -1 : 1;
|
| + float sign = isCCW(deviceQuad) ? -1 : 1;
|
|
|
| // Compute outer edges.
|
| - Edge leftEdge = computeEdge(boundsQuad.p4(), boundsQuad.p1(), sign);
|
| - Edge rightEdge = computeEdge(boundsQuad.p2(), boundsQuad.p3(), sign);
|
| - Edge topEdge = computeEdge(boundsQuad.p1(), boundsQuad.p2(), sign);
|
| - Edge bottomEdge = computeEdge(boundsQuad.p3(), boundsQuad.p4(), sign);
|
| + Edge leftEdge = computeEdge(deviceQuad.p4(), deviceQuad.p1(), sign);
|
| + Edge rightEdge = computeEdge(deviceQuad.p2(), deviceQuad.p3(), sign);
|
| + Edge topEdge = computeEdge(deviceQuad.p1(), deviceQuad.p2(), sign);
|
| + Edge bottomEdge = computeEdge(deviceQuad.p3(), deviceQuad.p4(), sign);
|
|
|
| - // Move outer edges to ensure that all partially covered pixels are
|
| - // processed.
|
| - float zDistance = m_tilingData.borderTexels() * 0.5f;
|
| - leftEdge.move(0, 0, zDistance);
|
| - rightEdge.move(0, 0, zDistance);
|
| - topEdge.move(0, 0, zDistance);
|
| - bottomEdge.move(0, 0, zDistance);
|
| + if (edgeLocation != -1) {
|
| + // Move outer edges to ensure that all partially covered pixels are
|
| + // processed.
|
| + leftEdge.move(0, 0, 0.5f);
|
| + rightEdge.move(0, 0, 0.5f);
|
| + topEdge.move(0, 0, 0.5f);
|
| + bottomEdge.move(0, 0, 0.5f);
|
|
|
| - GC3Dint filter = (m_tilingData.borderTexels() && !matrix.isIntegerTranslation()) ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST;
|
| + float edge[12];
|
| + edge[0] = leftEdge.x();
|
| + edge[1] = leftEdge.y();
|
| + edge[2] = leftEdge.z();
|
| + edge[3] = topEdge.x();
|
| + edge[4] = topEdge.y();
|
| + edge[5] = topEdge.z();
|
| + edge[6] = rightEdge.x();
|
| + edge[7] = rightEdge.y();
|
| + edge[8] = rightEdge.z();
|
| + edge[9] = bottomEdge.x();
|
| + edge[10] = bottomEdge.y();
|
| + edge[11] = bottomEdge.z();
|
| + GLC(context, context->uniform3fv(edgeLocation, edge, 4));
|
| + }
|
|
|
| Edge prevEdgeY = topEdge;
|
|
|
| int left, top, right, bottom;
|
| contentRectToTileIndices(contentRect, left, top, right, bottom);
|
| + IntRect layerRect = contentRectToLayerRect(contentRect);
|
| for (int j = top; j <= bottom; ++j) {
|
| Edge prevEdgeX = leftEdge;
|
|
|
| Edge edgeY = bottomEdge;
|
| if (j < (m_tilingData.numTilesY() - 1)) {
|
| - IntRect tileRect = m_tilingData.tileBounds(m_tilingData.tileIndex(0, j));
|
| + IntRect tileRect = unionRect(m_tilingData.tileBounds(m_tilingData.tileIndex(0, j)), m_tilingData.tileBounds(m_tilingData.tileIndex(m_tilingData.numTilesX() - 1, j)));
|
| + tileRect.intersect(layerRect);
|
| +
|
| + // Skip empty rows.
|
| + if (tileRect.isEmpty())
|
| + continue;
|
| +
|
| tileRect.move(m_layerPosition.x(), m_layerPosition.y());
|
|
|
| FloatPoint p1(tileRect.maxX(), tileRect.maxY());
|
| @@ -537,27 +536,58 @@
|
| ASSERT(tile->texture()->isReserved());
|
|
|
| tile->texture()->bindTexture();
|
| - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, filter));
|
| - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, filter));
|
|
|
| // Don't use tileContentRect here, as that contains the full
|
| // rect with border texels which shouldn't be drawn.
|
| IntRect tileRect = m_tilingData.tileBounds(m_tilingData.tileIndex(tile->i(), tile->j()));
|
| + IntRect displayRect = tileRect;
|
| + tileRect.intersect(layerRect);
|
| +
|
| + // Keep track of how the top left has moved, so the texture can be
|
| + // offset the same amount.
|
| + IntSize displayOffset = tileRect.minXMinYCorner() - displayRect.minXMinYCorner();
|
| +
|
| + // Skip empty tiles.
|
| + if (tileRect.isEmpty())
|
| + continue;
|
| +
|
| tileRect.move(m_layerPosition.x(), m_layerPosition.y());
|
|
|
| - IntPoint texOffset = m_tilingData.textureOffset();
|
| - IntRect texRect = tileTexRect(tile);
|
| - float tileWidth = static_cast<float>(texRect.width());
|
| - float tileHeight = static_cast<float>(texRect.height());
|
| - float texTranslateX = (texOffset.x() - tileRect.x()) / tileWidth;
|
| - float texTranslateY = (texOffset.y() - tileRect.y()) / tileHeight;
|
| - float texScaleX = tileRect.width() / tileWidth;
|
| - float texScaleY = tileRect.height() / tileHeight;
|
| + FloatRect clampRect(tileRect);
|
| + // Clamp texture coordinates to avoid sampling outside the layer
|
| + // by deflating the tile region half a texel or half a texel
|
| + // minus epsilon for one pixel layers. The resulting clamp region
|
| + // is mapped to the unit square by the vertex shader and mapped
|
| + // back to normalized texture coordinates by the fragment shader
|
| + // after being clamped to 0-1 range.
|
| + const float epsilon = 1 / 1024.0f;
|
| + float clampX = min(0.5, clampRect.width() / 2.0 - epsilon);
|
| + float clampY = min(0.5, clampRect.height() / 2.0 - epsilon);
|
| + clampRect.inflateX(-clampX);
|
| + clampRect.inflateY(-clampY);
|
| + FloatSize clampOffset = clampRect.minXMinYCorner() - FloatRect(tileRect).minXMinYCorner();
|
| +
|
| + FloatPoint texOffset = m_tilingData.textureOffset(tile->i(), tile->j()) + clampOffset + FloatSize(displayOffset);
|
| + float tileWidth = static_cast<float>(m_tileSize.width());
|
| + float tileHeight = static_cast<float>(m_tileSize.height());
|
| +
|
| + // Map clamping rectangle to unit square.
|
| + float vertexTexTranslateX = -clampRect.x() / clampRect.width();
|
| + float vertexTexTranslateY = -clampRect.y() / clampRect.height();
|
| + float vertexTexScaleX = tileRect.width() / clampRect.width();
|
| + float vertexTexScaleY = tileRect.height() / clampRect.height();
|
| +
|
| + // Map to normalized texture coordinates.
|
| + float fragmentTexTranslateX = texOffset.x() / tileWidth;
|
| + float fragmentTexTranslateY = texOffset.y() / tileHeight;
|
| + float fragmentTexScaleX = clampRect.width() / tileWidth;
|
| + float fragmentTexScaleY = clampRect.height() / tileHeight;
|
| +
|
| // OpenGL coordinate system is bottom-up.
|
| // If tile texture is top-down, we need to flip the texture coordinates.
|
| if (m_textureOrientation == LayerTextureUpdater::TopDownOrientation) {
|
| - texTranslateY = 1.0 - texTranslateY;
|
| - texScaleY *= -1.0;
|
| + fragmentTexTranslateY = 1.0 - fragmentTexTranslateY;
|
| + fragmentTexScaleY *= -1.0;
|
| }
|
|
|
| Edge edgeX = rightEdge;
|
| @@ -585,53 +615,50 @@
|
| // Normalize to tileRect.
|
| quad.scale(1.0f / tileRect.width(), 1.0f / tileRect.height());
|
|
|
| - drawTexturedQuad(context, quad, layerRenderer()->projectionMatrix(), matrix, tileRect.width(), tileRect.height(), opacity, texTranslateX, texTranslateY, texScaleX, texScaleY, program);
|
| + if (fragmentTexTransformLocation == -1) {
|
| + // Move fragment shader transform to vertex shader. We can do
|
| + // this while still producing correct results as
|
| + // fragmentTexTransformLocation should always be non-negative
|
| + // when tiles are transformed in a way that could result in
|
| + // sampling outside the layer.
|
| + vertexTexScaleX *= fragmentTexScaleX;
|
| + vertexTexScaleY *= fragmentTexScaleY;
|
| + vertexTexTranslateX *= fragmentTexScaleX;
|
| + vertexTexTranslateY *= fragmentTexScaleY;
|
| + vertexTexTranslateX += fragmentTexTranslateX;
|
| + vertexTexTranslateY += fragmentTexTranslateY;
|
| + } else
|
| + GLC(context, context->uniform4f(fragmentTexTransformLocation, fragmentTexTranslateX, fragmentTexTranslateY, fragmentTexScaleX, fragmentTexScaleY));
|
|
|
| + GLC(context, context->uniform4f(program->vertexShader().vertexTexTransformLocation(), vertexTexTranslateX, vertexTexTranslateY, vertexTexScaleX, vertexTexScaleY));
|
| +
|
| + float point[8];
|
| + point[0] = quad.p1().x();
|
| + point[1] = quad.p1().y();
|
| + point[2] = quad.p2().x();
|
| + point[3] = quad.p2().y();
|
| + point[4] = quad.p3().x();
|
| + point[5] = quad.p3().y();
|
| + point[6] = quad.p4().x();
|
| + point[7] = quad.p4().y();
|
| + GLC(context, context->uniform2fv(program->vertexShader().pointLocation(), point, 4));
|
| +
|
| + LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), globalTransform,
|
| + tileRect.width(), tileRect.height(), opacity,
|
| + program->vertexShader().matrixLocation(),
|
| + program->fragmentShader().alphaLocation());
|
| +
|
| prevEdgeX = edgeX;
|
| + // Reverse direction.
|
| + prevEdgeX.scale(-1, -1, -1);
|
| }
|
|
|
| prevEdgeY = edgeY;
|
| + // Reverse direction.
|
| + prevEdgeY.scale(-1, -1, -1);
|
| }
|
| }
|
|
|
| -template <class T>
|
| -void LayerTilerChromium::drawTexturedQuad(GraphicsContext3D* context, const FloatQuad& quad, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix,
|
| - float width, float height, float opacity,
|
| - float texTranslateX, float texTranslateY,
|
| - float texScaleX, float texScaleY,
|
| - const T* program)
|
| -{
|
| - static float glMatrix[16];
|
| -
|
| - TransformationMatrix renderMatrix = drawMatrix;
|
| -
|
| - // Apply a scaling factor to size the quad from 1x1 to its intended size.
|
| - renderMatrix.scale3d(width, height, 1);
|
| -
|
| - // Apply the projection matrix before sending the transform over to the shader.
|
| - LayerChromium::toGLMatrix(&glMatrix[0], projectionMatrix * renderMatrix);
|
| -
|
| - GLC(context, context->uniformMatrix4fv(program->vertexShader().matrixLocation(), false, &glMatrix[0], 1));
|
| -
|
| - GLC(context, context->uniform1f(program->fragmentShader().alphaLocation(), opacity));
|
| -
|
| - GLC(context, context->uniform4f(program->vertexShader().texTransformLocation(),
|
| - texTranslateX, texTranslateY, texScaleX, texScaleY));
|
| -
|
| - float point[8];
|
| - point[0] = quad.p1().x();
|
| - point[1] = quad.p1().y();
|
| - point[2] = quad.p2().x();
|
| - point[3] = quad.p2().y();
|
| - point[4] = quad.p3().x();
|
| - point[5] = quad.p3().y();
|
| - point[6] = quad.p4().x();
|
| - point[7] = quad.p4().y();
|
| - GLC(context, context->uniform2fv(program->vertexShader().pointLocation(), point, 4));
|
| -
|
| - GLC(context, context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0));
|
| -}
|
| -
|
| } // namespace WebCore
|
|
|
| #endif // USE(ACCELERATED_COMPOSITING)
|
|
|