diff options
Diffstat (limited to 'WebCore/platform/graphics/chromium/ContentLayerChromium.cpp')
-rw-r--r-- | WebCore/platform/graphics/chromium/ContentLayerChromium.cpp | 160 |
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(); } } |