summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/chromium/ContentLayerChromium.cpp')
-rw-r--r--WebCore/platform/graphics/chromium/ContentLayerChromium.cpp160
1 files changed, 85 insertions, 75 deletions
diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
index 375a74b..d00faf8 100644
--- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
@@ -36,11 +36,13 @@
#include "GraphicsContext3D.h"
#include "LayerRendererChromium.h"
+#include "LayerTexture.h"
#include "RenderLayerBacking.h"
#if PLATFORM(SKIA)
#include "NativeImageSkia.h"
#include "PlatformContextSkia.h"
+#include "SkColorPriv.h"
#include "skia/ext/platform_canvas.h"
#elif PLATFORM(CG)
#include <CoreGraphics/CGBitmapContext.h>
@@ -68,8 +70,22 @@ ContentLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
" v_texCoord = a_texCoord; \n"
"} \n";
+#if PLATFORM(SKIA)
+ // Color is in RGBA order.
+ char rgbaFragmentShaderString[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "uniform float alpha; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor = texture2D(s_texture, v_texCoord); \n"
+ " gl_FragColor = texColor * alpha; \n"
+ "} \n";
+#endif
+
// Color is in BGRA order.
- char fragmentShaderString[] =
+ char bgraFragmentShaderString[] =
"precision mediump float; \n"
"varying vec2 v_texCoord; \n"
"uniform sampler2D s_texture; \n"
@@ -80,6 +96,12 @@ ContentLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context)
" gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; \n"
"} \n";
+#if PLATFORM(SKIA)
+ // Assuming the packing is either Skia default RGBA or Chromium default BGRA.
+ char* fragmentShaderString = SK_B32_SHIFT ? rgbaFragmentShaderString : bgraFragmentShaderString;
+#else
+ char* fragmentShaderString = bgraFragmentShaderString;
+#endif
m_contentShaderProgram = createShaderProgram(m_context, vertexShaderString, fragmentShaderString);
if (!m_contentShaderProgram) {
LOG_ERROR("ContentLayerChromium: Failed to create shader program");
@@ -123,12 +145,7 @@ ContentLayerChromium::~ContentLayerChromium()
void ContentLayerChromium::cleanupResources()
{
LayerChromium::cleanupResources();
- if (layerRenderer()) {
- if (m_contentsTexture) {
- layerRenderer()->deleteLayerTexture(m_contentsTexture);
- m_contentsTexture = 0;
- }
- }
+ m_contentsTexture.clear();
}
bool ContentLayerChromium::requiresClippedUpdateRect() const
@@ -142,33 +159,7 @@ bool ContentLayerChromium::requiresClippedUpdateRect() const
|| !layerRenderer()->checkTextureSize(m_bounds));
}
-void ContentLayerChromium::calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const
-{
- // For the given layer size and content rect, calculate:
- // 1) The minimal texture space rectangle to be uploaded, returned in dirtyRect.
- // 2) The rectangle to draw this texture in relative to the target render surface, returned in drawRect.
-
- ASSERT(m_targetRenderSurface);
- const IntRect clipRect = m_targetRenderSurface->contentRect();
-
- TransformationMatrix layerOriginTransform = drawTransform();
- layerOriginTransform.translate3d(-0.5 * m_bounds.width(), -0.5 * m_bounds.height(), 0);
-
- // For now we apply the large layer treatment only for layers that are either untransformed
- // or are purely translated. Their matrix is expected to be invertible.
- ASSERT(layerOriginTransform.isInvertible());
-
- TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse();
- IntRect clipRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect);
- clipRectInLayerCoords.intersect(IntRect(0, 0, m_bounds.width(), m_bounds.height()));
-
- dirtyRect = clipRectInLayerCoords;
-
- // Map back to the target surface coordinate system.
- drawRect = layerOriginTransform.mapRect(dirtyRect);
-}
-
-void ContentLayerChromium::updateContents()
+void ContentLayerChromium::updateContentsIfDirty()
{
RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client());
if (!backing || backing->paintingGoesToWindow())
@@ -183,6 +174,7 @@ void ContentLayerChromium::updateContents()
IntRect updateRect;
IntSize requiredTextureSize;
IntSize bitmapSize;
+ IntRect boundsRect(IntPoint(0, 0), m_bounds);
// FIXME: Remove this test when tiled layers are implemented.
if (requiresClippedUpdateRect()) {
@@ -194,33 +186,57 @@ void ContentLayerChromium::updateContents()
return;
}
- calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect);
- if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.size())) {
+ // Calculate the region of this layer that is currently visible.
+ const IntRect clipRect = m_targetRenderSurface->contentRect();
+
+ TransformationMatrix layerOriginTransform = drawTransform();
+ layerOriginTransform.translate3d(-0.5 * m_bounds.width(), -0.5 * m_bounds.height(), 0);
+
+ // For now we apply the large layer treatment only for layers that are either untransformed
+ // or are purely translated. Their matrix is expected to be invertible.
+ ASSERT(layerOriginTransform.isInvertible());
+
+ TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse();
+ IntRect visibleRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect);
+ visibleRectInLayerCoords.intersect(IntRect(0, 0, m_bounds.width(), m_bounds.height()));
+
+ // For normal layers, the center of the texture corresponds with the center of the layer.
+ // In large layers the center of the texture is the center of the visible region so we have
+ // to keep track of the offset in order to render correctly.
+ IntRect visibleRectInSurfaceCoords = layerOriginTransform.mapRect(visibleRectInLayerCoords);
+ m_layerCenterInSurfaceCoords = FloatRect(visibleRectInSurfaceCoords).center();
+
+ // If this is still too large to render, then skip the layer completely.
+ if (!layerRenderer()->checkTextureSize(visibleRectInLayerCoords.size())) {
m_skipsDraw = true;
return;
}
- // If the portion of the large layer that's visible hasn't changed
- // then we don't need to update it, _unless_ its contents have changed
- // in which case we only update the dirty bits.
- if (m_largeLayerDirtyRect == dirtyRect) {
- if (!m_dirtyRect.intersects(dirtyRect))
- return;
- dirtyRect.intersect(IntRect(m_dirtyRect));
- updateRect = dirtyRect;
- requiredTextureSize = m_largeLayerDirtyRect.size();
- } else {
- m_largeLayerDirtyRect = dirtyRect;
- requiredTextureSize = dirtyRect.size();
- updateRect = IntRect(IntPoint(0, 0), dirtyRect.size());
- }
+ // If the visible portion of the layer is different from the last upload, or if our backing
+ // texture has been evicted, then the whole layer is considered dirty.
+ if (visibleRectInLayerCoords != m_visibleRectInLayerCoords || !m_contentsTexture || !m_contentsTexture->isValid(requiredTextureSize, GraphicsContext3D::RGBA))
+ m_dirtyRect = boundsRect;
+ m_visibleRectInLayerCoords = visibleRectInLayerCoords;
+
+ // Calculate the portion of the dirty rectangle that is visible. m_dirtyRect is in layer space.
+ IntRect visibleDirtyRectInLayerSpace = enclosingIntRect(m_dirtyRect);
+ visibleDirtyRectInLayerSpace.intersect(visibleRectInLayerCoords);
+
+ // What the rectangles mean:
+ // dirtyRect: The region of this layer that will be updated.
+ // updateRect: The region of the layer's texture that will be uploaded into.
+ // requiredTextureSize: is the required size of this layer's texture.
+ dirtyRect = visibleDirtyRectInLayerSpace;
+ updateRect = dirtyRect;
+ IntSize visibleRectOffsetInLayerCoords(visibleRectInLayerCoords.x(), visibleRectInLayerCoords.y());
+ updateRect.move(-visibleRectOffsetInLayerCoords);
+ requiredTextureSize = visibleRectInLayerCoords.size();
} else {
dirtyRect = IntRect(m_dirtyRect);
- IntRect boundsRect(IntPoint(0, 0), m_bounds);
requiredTextureSize = m_bounds;
// If the texture needs to be reallocated then we must redraw the entire
// contents of the layer.
- if (requiredTextureSize != m_allocatedTextureSize)
+ if (!m_contentsTexture || !m_contentsTexture->isValid(requiredTextureSize, GraphicsContext3D::RGBA))
dirtyRect = boundsRect;
else {
// Clip the dirtyRect to the size of the layer to avoid drawing
@@ -289,36 +305,28 @@ void ContentLayerChromium::updateContents()
#error "Need to implement for your platform."
#endif
- unsigned textureId = m_contentsTexture;
- if (!textureId)
- textureId = layerRenderer()->createLayerTexture();
-
if (pixels)
- updateTextureRect(pixels, bitmapSize, requiredTextureSize, updateRect, textureId);
+ updateTextureRect(pixels, requiredTextureSize, updateRect);
}
-void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId)
+void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& requiredTextureSize, const IntRect& updateRect)
{
if (!pixels)
return;
GraphicsContext3D* context = layerRendererContext();
- context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId);
+ if (!m_contentsTexture)
+ m_contentsTexture = LayerTexture::create(context, layerRenderer()->textureManager());
- // If the texture id or size changed since last time then we need to tell GL
- // to re-allocate a texture.
- if (m_contentsTexture != textureId || requiredTextureSize != m_allocatedTextureSize) {
- ASSERT(bitmapSize == requiredTextureSize);
- GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
-
- m_contentsTexture = textureId;
- m_allocatedTextureSize = requiredTextureSize;
- } else {
- ASSERT(updateRect.width() <= m_allocatedTextureSize.width() && updateRect.height() <= m_allocatedTextureSize.height());
- ASSERT(updateRect.width() == bitmapSize.width() && updateRect.height() == bitmapSize.height());
- GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
+ if (!m_contentsTexture->reserve(requiredTextureSize, GraphicsContext3D::RGBA)) {
+ m_skipsDraw = true;
+ return;
}
+ m_contentsTexture->bindTexture();
+
+ GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
+
m_dirtyRect.setSize(FloatSize());
// Large layers always stay dirty, because they need to update when the content rect changes.
m_contentsDirty = requiresClippedUpdateRect();
@@ -330,21 +338,22 @@ void ContentLayerChromium::draw()
return;
ASSERT(layerRenderer());
+
const ContentLayerChromium::SharedValues* sv = layerRenderer()->contentLayerSharedValues();
ASSERT(sv && sv->initialized());
GraphicsContext3D* context = layerRendererContext();
GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
- GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTexture));
+ m_contentsTexture->bindTexture();
layerRenderer()->useShader(sv->contentShaderProgram());
GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0));
if (requiresClippedUpdateRect()) {
float m43 = drawTransform().m43();
TransformationMatrix transform;
- transform.translate3d(m_largeLayerDrawRect.center().x(), m_largeLayerDrawRect.center().y(), m43);
+ transform.translate3d(m_layerCenterInSurfaceCoords.x(), m_layerCenterInSurfaceCoords.y(), m43);
drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
- transform, m_largeLayerDrawRect.width(),
- m_largeLayerDrawRect.height(), drawOpacity(),
+ transform, m_visibleRectInLayerCoords.width(),
+ m_visibleRectInLayerCoords.height(), drawOpacity(),
sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
} else {
drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
@@ -352,6 +361,7 @@ void ContentLayerChromium::draw()
drawOpacity(), sv->shaderMatrixLocation(),
sv->shaderAlphaLocation());
}
+ m_contentsTexture->unreserve();
}
}