summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/chromium/LayerRendererChromium.cpp')
-rw-r--r--WebCore/platform/graphics/chromium/LayerRendererChromium.cpp664
1 files changed, 197 insertions, 467 deletions
diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
index 2f70efa..cf23871 100644
--- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
+++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
@@ -35,10 +35,10 @@
#include "LayerRendererChromium.h"
#include "CanvasLayerChromium.h"
+#include "ContentLayerChromium.h"
#include "GLES2Context.h"
#include "LayerChromium.h"
#include "NotImplemented.h"
-#include "TransformLayerChromium.h"
#if PLATFORM(SKIA)
#include "NativeImageSkia.h"
#include "PlatformContextSkia.h"
@@ -50,101 +50,6 @@
namespace WebCore {
-#ifndef NDEBUG
-static WTFLogChannel LogLayerRenderer = { 0x00000000, "LayerRenderer", WTFLogChannelOn };
-#endif
-
-static void checkGLError()
-{
-#ifndef NDEBUG
- GLenum error = glGetError();
- if (error)
- LOG_ERROR("GL Error: %d " , error);
-#endif
-}
-
-static GLuint loadShader(GLenum type, const char* shaderSource)
-{
- GLuint shader = glCreateShader(type);
- if (!shader)
- return 0;
- glShaderSource(shader, 1, &shaderSource, 0);
- glCompileShader(shader);
- GLint compiled;
- glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- glDeleteShader(shader);
- return 0;
- }
- return shader;
-}
-
-static GLuint loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
-{
- GLuint vertexShader;
- GLuint fragmentShader;
- GLuint programObject;
- GLint linked;
- vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource);
- if (!vertexShader)
- return 0;
- fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
- if (!fragmentShader) {
- glDeleteShader(vertexShader);
- return 0;
- }
- programObject = glCreateProgram();
- if (!programObject)
- return 0;
- glAttachShader(programObject, vertexShader);
- glAttachShader(programObject, fragmentShader);
- glLinkProgram(programObject);
- glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
- if (!linked) {
- glDeleteProgram(programObject);
- return 0;
- }
- glDeleteShader(vertexShader);
- glDeleteShader(fragmentShader);
- return programObject;
-}
-
-bool LayerRendererChromium::createLayerShader(ShaderProgramType type, const char* vertexShaderSource, const char* fragmentShaderSource)
-{
- unsigned programId = loadShaderProgram(vertexShaderSource, fragmentShaderSource);
- ASSERT(programId);
-
- ShaderProgram* program = &m_shaderPrograms[type];
-
- program->m_shaderProgramId = programId;
- program->m_samplerLocation = glGetUniformLocation(programId, "s_texture");
- program->m_matrixLocation = glGetUniformLocation(programId, "matrix");
- program->m_alphaLocation = glGetUniformLocation(programId, "alpha");
-
- return programId;
-}
-
-
-static void toGLMatrix(float* flattened, const TransformationMatrix& m)
-{
- flattened[0] = m.m11();
- flattened[1] = m.m12();
- flattened[2] = m.m13();
- flattened[3] = m.m14();
- flattened[4] = m.m21();
- flattened[5] = m.m22();
- flattened[6] = m.m23();
- flattened[7] = m.m24();
- flattened[8] = m.m31();
- flattened[9] = m.m32();
- flattened[10] = m.m33();
- flattened[11] = m.m34();
- flattened[12] = m.m41();
- flattened[13] = m.m42();
- flattened[14] = m.m43();
- flattened[15] = m.m44();
-}
-
static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top, float nearZ, float farZ)
{
float deltaX = right - left;
@@ -162,21 +67,6 @@ static TransformationMatrix orthoMatrix(float left, float right, float bottom, f
return ortho;
}
-// Creates a GL texture object to be used for transfering the layer's bitmap into.
-static GLuint createLayerTexture()
-{
- GLuint textureId = 0;
- glGenTextures(1, &textureId);
- glBindTexture(GL_TEXTURE_2D, textureId);
- // Do basic linear filtering on resize.
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE.
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- return textureId;
-}
-
static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b)
{
const TransformationMatrix& transformA = a->drawTransform();
@@ -185,51 +75,35 @@ static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b)
return transformA.m43() < transformB.m43();
}
-ShaderProgram::ShaderProgram()
- : m_shaderProgramId(0)
- , m_samplerLocation(-1)
- , m_matrixLocation(-1)
- , m_alphaLocation(-1)
-{
-}
-
PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GLES2Context> gles2Context)
{
return new LayerRendererChromium(gles2Context);
}
LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GLES2Context> gles2Context)
- : m_rootLayerTextureWidth(0)
+ : m_rootLayerTextureId(0)
+ , m_rootLayerTextureWidth(0)
, m_rootLayerTextureHeight(0)
- , m_positionLocation(0)
- , m_texCoordLocation(1)
+ , m_scrollShaderProgram(0)
, m_rootLayer(0)
, m_needsDisplay(false)
, m_scrollPosition(IntPoint(-1, -1))
- , m_currentShaderProgramType(NumShaderProgramTypes)
+ , m_currentShader(0)
, m_gles2Context(gles2Context)
{
- m_quadVboIds[Vertices] = m_quadVboIds[LayerElements] = 0;
- m_hardwareCompositing = (m_gles2Context && initializeSharedGLObjects());
+ m_hardwareCompositing = (m_gles2Context && initializeSharedObjects());
}
LayerRendererChromium::~LayerRendererChromium()
{
- if (m_hardwareCompositing) {
- makeContextCurrent();
- glDeleteBuffers(3, m_quadVboIds);
-
- for (int i = 0; i < NumShaderProgramTypes; i++) {
- if (m_shaderPrograms[i].m_shaderProgramId)
- glDeleteProgram(m_shaderPrograms[i].m_shaderProgramId);
- }
- }
+ cleanupSharedObjects();
+}
- // Free up all GL textures.
- for (TextureIdMap::iterator iter = m_textureIdMap.begin(); iter != m_textureIdMap.end(); ++iter) {
- glDeleteTextures(1, &(iter->second));
- iter->first->setLayerRenderer(0);
- }
+void LayerRendererChromium::debugGLCall(const char* command, const char* file, int line)
+{
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR)
+ LOG_ERROR("GL command failed: File: %s\n\tLine %d\n\tcommand: %s, error %x\n", file, line, command, error);
}
// Creates a canvas and an associated graphics context that the root layer will
@@ -268,43 +142,14 @@ void LayerRendererChromium::setRootLayerCanvasSize(const IntSize& size)
m_rootLayerCanvasSize = size;
}
-void LayerRendererChromium::useShaderProgram(ShaderProgramType programType)
+void LayerRendererChromium::useShader(unsigned programId)
{
- if (programType != m_currentShaderProgramType) {
- ShaderProgram* program = &m_shaderPrograms[programType];
- glUseProgram(program->m_shaderProgramId);
- m_currentShaderProgramType = programType;
-
- // Set the uniform locations matching the program.
- m_samplerLocation = program->m_samplerLocation;
- m_matrixLocation = program->m_matrixLocation;
- m_alphaLocation = program->m_alphaLocation;
+ if (programId != m_currentShader) {
+ GLC(glUseProgram(programId));
+ m_currentShader = programId;
}
}
-void LayerRendererChromium::drawTexturedQuad(const TransformationMatrix& matrix, float width, float height, float opacity)
-{
- static GLfloat glMatrix[16];
-
- TransformationMatrix renderMatrix = matrix;
-
- // 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.
- renderMatrix.multiply(m_projectionMatrix);
-
- toGLMatrix(&glMatrix[0], renderMatrix);
-
- glUniformMatrix4fv(m_matrixLocation, 1, false, &glMatrix[0]);
-
- if (m_alphaLocation != -1)
- glUniform1f(m_alphaLocation, opacity);
-
- glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
-}
-
-
// Updates the contents of the root layer texture that fall inside the updateRect
// and re-composits all sublayers.
void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& visibleRect,
@@ -315,17 +160,13 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect&
if (!m_rootLayer)
return;
- // If the size of the visible area has changed then allocate a new texture
- // to store the contents of the root layer and adjust the projection matrix
- // and viewport.
makeContextCurrent();
- checkGLError();
-
- glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId);
-
- checkGLError();
+ GLC(glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId));
+ // If the size of the visible area has changed then allocate a new texture
+ // to store the contents of the root layer and adjust the projection matrix
+ // and viewport.
int visibleRectWidth = visibleRect.width();
int visibleRectHeight = visibleRect.height();
if (visibleRectWidth != m_rootLayerTextureWidth || visibleRectHeight != m_rootLayerTextureHeight) {
@@ -333,38 +174,18 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect&
m_rootLayerTextureHeight = visibleRect.height();
m_projectionMatrix = orthoMatrix(0, visibleRectWidth, visibleRectHeight, 0, -1000, 1000);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
- checkGLError();
+ GLC(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
}
// The GL viewport covers the entire visible area, including the scrollbars.
- glViewport(0, 0, visibleRectWidth, visibleRectHeight);
-
- checkGLError();
-
- // The layer, scroll and debug border shaders all use the same vertex attributes
- // so we can bind them only once.
- glBindBuffer(GL_ARRAY_BUFFER, m_quadVboIds[Vertices]);
- checkGLError();
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadVboIds[LayerElements]);
- checkGLError();
- GLuint offset = 0;
- glVertexAttribPointer(m_positionLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(offset));
- checkGLError();
- offset += 3 * sizeof(GLfloat);
- glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(offset));
- checkGLError();
- glEnableVertexAttribArray(m_positionLocation);
- checkGLError();
- glEnableVertexAttribArray(m_texCoordLocation);
- checkGLError();
- glActiveTexture(GL_TEXTURE0);
- checkGLError();
- glDisable(GL_DEPTH_TEST);
- checkGLError();
- glDisable(GL_CULL_FACE);
- checkGLError();
+ GLC(glViewport(0, 0, visibleRectWidth, visibleRectHeight));
+
+ // Bind the common vertex attributes used for drawing all the layers.
+ LayerChromium::prepareForDraw(layerSharedValues());
+
+ GLC(glDisable(GL_DEPTH_TEST));
+ GLC(glDisable(GL_CULL_FACE));
+ GLC(glDepthFunc(GL_LEQUAL));
if (m_scrollPosition == IntPoint(-1, -1))
m_scrollPosition = scrollPosition;
@@ -390,21 +211,21 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect&
#error "Need to implement for your platform."
#endif
- scrolledLayerMatrix.translate3d((int)floorf(0.5 * visibleRect.width()) - scrollDelta.x(),
- (int)floorf(0.5 * visibleRect.height()) + scaleFactor * scrollDelta.y(), 0);
+ scrolledLayerMatrix.translate3d(0.5 * visibleRect.width() - scrollDelta.x(),
+ 0.5 * visibleRect.height() + scaleFactor * scrollDelta.y(), 0);
scrolledLayerMatrix.scale3d(1, -1, 1);
- // Switch shaders to avoid RGB swizzling.
- useShaderProgram(ScrollLayerProgram);
- glUniform1i(m_shaderPrograms[ScrollLayerProgram].m_samplerLocation, 0);
- checkGLError();
-
- drawTexturedQuad(scrolledLayerMatrix, visibleRect.width(), visibleRect.height(), 1);
- checkGLError();
+ useShader(m_scrollShaderProgram);
+ GLC(glUniform1i(m_scrollShaderSamplerLocation, 0));
+ LayerChromium::drawTexturedQuad(m_projectionMatrix, scrolledLayerMatrix,
+ visibleRect.width(), visibleRect.height(), 1,
+ m_scrollShaderMatrixLocation, -1);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height());
-
- checkGLError();
+ GLC(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height()));
+ m_scrollPosition = scrollPosition;
+ } else if (abs(scrollDelta.y()) > contentRect.height() || abs(scrollDelta.x()) > contentRect.width()) {
+ // Scrolling larger than the contentRect size does not preserve any of the pixels, so there is
+ // no need to copy framebuffer pixels back into the texture.
m_scrollPosition = scrollPosition;
}
@@ -423,154 +244,92 @@ void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect&
ASSERT(rootLayerWidth == updateRect.width() && rootLayerHeight == updateRect.height());
void* pixels = bitmap.getPixels();
- checkGLError();
// Copy the contents of the updated rect to the root layer texture.
- glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- checkGLError();
+ GLC(glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels));
#elif PLATFORM(CG)
// Get the contents of the updated rect.
ASSERT(static_cast<int>(CGBitmapContextGetWidth(m_rootLayerCGContext.get())) == updateRect.width() && static_cast<int>(CGBitmapContextGetHeight(m_rootLayerCGContext.get())) == updateRect.height());
void* pixels = m_rootLayerBackingStore.data();
- checkGLError();
// Copy the contents of the updated rect to the root layer texture.
// The origin is at the lower left in Core Graphics' coordinate system. We need to correct for this here.
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- updateRect.x(), m_rootLayerTextureHeight - updateRect.y() - updateRect.height(),
- updateRect.width(), updateRect.height(),
- GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- checkGLError();
+ GLC(glTexSubImage2D(GL_TEXTURE_2D, 0,
+ updateRect.x(), m_rootLayerTextureHeight - updateRect.y() - updateRect.height(),
+ updateRect.width(), updateRect.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE, pixels));
#else
#error "Need to implement for your platform."
#endif
}
glClearColor(0, 0, 1, 1);
- checkGLError();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- checkGLError();
// Render the root layer using a quad that takes up the entire visible area of the window.
- useShaderProgram(ContentLayerProgram);
- checkGLError();
- glUniform1i(m_samplerLocation, 0);
- checkGLError();
+ // We reuse the shader program used by ContentLayerChromium.
+ const ContentLayerChromium::SharedValues* contentLayerValues = contentLayerSharedValues();
+ useShader(contentLayerValues->contentShaderProgram());
+ GLC(glUniform1i(contentLayerValues->shaderSamplerLocation(), 0));
TransformationMatrix layerMatrix;
layerMatrix.translate3d(visibleRect.width() * 0.5f, visibleRect.height() * 0.5f, 0);
- drawTexturedQuad(layerMatrix, visibleRect.width(), visibleRect.height(), 1);
- checkGLError();
+ LayerChromium::drawTexturedQuad(m_projectionMatrix, layerMatrix,
+ visibleRect.width(), visibleRect.height(), 1,
+ contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation());
// If culling is enabled then we will cull the backface.
- glCullFace(GL_BACK);
- checkGLError();
+ GLC(glCullFace(GL_BACK));
// The orthographic projection is setup such that Y starts at zero and
// increases going down the page so we need to adjust the winding order of
// front facing triangles.
- glFrontFace(GL_CW);
- checkGLError();
+ GLC(glFrontFace(GL_CW));
// The shader used to render layers returns pre-multiplied alpha colors
// so we need to send the blending mode appropriately.
- glEnable(GL_BLEND);
- checkGLError();
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- checkGLError();
+ GLC(glEnable(GL_BLEND));
+ GLC(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
// Translate all the composited layers by the scroll position.
TransformationMatrix matrix;
matrix.translate3d(-m_scrollPosition.x(), -m_scrollPosition.y(), 0);
+ // Traverse the layer tree and update the layer transforms.
float opacity = 1;
- m_layerList.shrink(0);
const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers();
- for (size_t i = 0; i < sublayers.size(); i++)
- updateLayersRecursive(sublayers[i].get(), matrix, opacity, visibleRect);
-
- // Sort layers by the z coordinate of their center so that layers further
- // away get drawn first.
- std::stable_sort(m_layerList.begin(), m_layerList.end(), compareLayerZ);
+ size_t i;
+ for (i = 0; i < sublayers.size(); i++)
+ updateLayersRecursive(sublayers[i].get(), matrix, opacity);
// Enable scissoring to avoid rendering composited layers over the scrollbars.
- glEnable(GL_SCISSOR_TEST);
- glScissor(0, visibleRect.height() - contentRect.height(), contentRect.width(), contentRect.height());
+ GLC(glEnable(GL_SCISSOR_TEST));
+ GLC(glScissor(0, visibleRect.height() - contentRect.height(), contentRect.width(), contentRect.height()));
- for (size_t j = 0; j < m_layerList.size(); j++)
- drawLayer(m_layerList[j]);
+ // Traverse the layer tree one more time to draw the layers.
+ m_visibleRect = visibleRect;
+ for (i = 0; i < sublayers.size(); i++)
+ drawLayersRecursive(sublayers[i].get());
- glDisable(GL_SCISSOR_TEST);
+ GLC(glDisable(GL_SCISSOR_TEST));
- glFlush();
m_gles2Context->swapBuffers();
m_needsDisplay = false;
}
-// Returns the id of the texture currently associated with the layer or
-// -1 if the id hasn't been registered yet.
-int LayerRendererChromium::getTextureId(LayerChromium* layer)
+// FIXME: This method should eventually be replaced by a proper texture manager.
+unsigned LayerRendererChromium::createLayerTexture()
{
- TextureIdMap::iterator textureId = m_textureIdMap.find(layer);
- if (textureId != m_textureIdMap.end())
- return textureId->second;
-
- return -1;
-}
-
-// Allocates a new texture for the layer and registers it in the textureId map.
-// FIXME: We will need to come up with a more sophisticated allocation strategy here.
-int LayerRendererChromium::assignTextureForLayer(LayerChromium* layer)
-{
- GLuint textureId = createLayerTexture();
-
- // FIXME: Check that textureId is valid
- m_textureIdMap.set(layer, textureId);
-
- layer->setLayerRenderer(this);
-
+ GLuint textureId = 0;
+ GLC(glGenTextures(1, &textureId));
+ GLC(glBindTexture(GL_TEXTURE_2D, textureId));
+ // Do basic linear filtering on resize.
+ GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE.
+ GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
return textureId;
}
-bool LayerRendererChromium::freeLayerTexture(LayerChromium* layer)
-{
- TextureIdMap::iterator textureId = m_textureIdMap.find(layer);
- if (textureId == m_textureIdMap.end())
- return false;
- // Free up the texture.
- glDeleteTextures(1, &(textureId->second));
- m_textureIdMap.remove(textureId);
- return true;
-}
-
-// Draws a debug border around the layer's bounds.
-void LayerRendererChromium::drawDebugBorder(LayerChromium* layer, const TransformationMatrix& matrix)
-{
- static GLfloat glMatrix[16];
- Color borderColor = layer->borderColor();
- if (!borderColor.alpha())
- return;
-
- useShaderProgram(DebugBorderProgram);
- TransformationMatrix renderMatrix = matrix;
- IntSize bounds = layer->bounds();
- renderMatrix.scale3d(bounds.width(), bounds.height(), 1);
- renderMatrix.multiply(m_projectionMatrix);
- toGLMatrix(&glMatrix[0], renderMatrix);
- unsigned borderMatrixLocation = m_shaderPrograms[DebugBorderProgram].m_matrixLocation;
- glUniformMatrix4fv(borderMatrixLocation, 1, false, &glMatrix[0]);
-
- glUniform4f(m_borderColorLocation, borderColor.red() / 255.0,
- borderColor.green() / 255.0,
- borderColor.blue() / 255.0,
- 1);
-
- glLineWidth(layer->borderWidth());
-
- // The indices for the line are stored in the same array as the triangle indices.
- glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, (void*)(6 * sizeof(unsigned short)));
- checkGLError();
-}
-
// Returns true if any part of the layer falls within the visibleRect
bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const TransformationMatrix& matrix, const IntRect& visibleRect)
{
@@ -588,9 +347,9 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform
return mappedRect.intersects(FloatRect(-1, -1, 2, 2));
}
-// Updates and caches the layer transforms and opacity values that will be used
-// when rendering them.
-void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity, const IntRect& visibleRect)
+// Recursively walks the layer tree starting at the given node and updates the
+// transform and opacity values.
+void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity)
{
// Compute the new matrix transformation that will be applied to this layer and
// all its sublayers. It's important to remember that the layer's position
@@ -627,23 +386,11 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
// M = M[p] * Tr[l] * M[l] * Tr[c]
localMatrix.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
- // Check if the layer falls within the visible bounds of the page.
- bool layerVisible = isLayerVisible(layer, localMatrix, visibleRect);
-
- bool skipLayer = false;
- if (bounds.width() > 2048 || bounds.height() > 2048) {
- if (layer->drawsContent())
- LOG(LayerRenderer, "Skipping layer with size %d %d", bounds.width(), bounds.height());
- skipLayer = true;
- }
-
// Calculate the layer's opacity.
opacity *= layer->opacity();
layer->setDrawTransform(localMatrix);
layer->setDrawOpacity(opacity);
- if (layerVisible && !skipLayer)
- m_layerList.append(layer);
// Flatten to 2D if the layer doesn't preserve 3D.
if (!layer->preserves3D()) {
@@ -667,29 +414,71 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
for (size_t i = 0; i < sublayers.size(); i++)
- updateLayersRecursive(sublayers[i].get(), localMatrix, opacity, visibleRect);
+ updateLayersRecursive(sublayers[i].get(), localMatrix, opacity);
+
+ layer->setLayerRenderer(this);
+}
+
+// Recursively walk the layer tree and draw the layers.
+void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer)
+{
+ static bool depthTestEnabledForSubtree = false;
+
+ // Check if the layer falls within the visible bounds of the page.
+ bool layerVisible = isLayerVisible(layer, layer->drawTransform(), m_visibleRect);
+
+ // Enable depth testing for this layer and all its descendants if preserves3D is set.
+ bool mustClearDepth = false;
+ if (layer->preserves3D()) {
+ if (!depthTestEnabledForSubtree) {
+ GLC(glEnable(GL_DEPTH_TEST));
+ depthTestEnabledForSubtree = true;
+
+ // Need to clear the depth buffer when we're done rendering this subtree.
+ mustClearDepth = true;
+ }
+ }
+
+ if (layerVisible)
+ drawLayer(layer);
+
+ // If we're using depth testing then we need to sort the children in Z to
+ // get the transparency to work properly.
+ if (depthTestEnabledForSubtree) {
+ const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
+ Vector<LayerChromium*> sublayerList;
+ size_t i;
+ for (i = 0; i < sublayers.size(); i++)
+ sublayerList.append(sublayers[i].get());
+
+ // Sort by the z coordinate of the layer center so that layers further away
+ // are drawn first.
+ std::stable_sort(sublayerList.begin(), sublayerList.end(), compareLayerZ);
+
+ for (i = 0; i < sublayerList.size(); i++)
+ drawLayersRecursive(sublayerList[i]);
+ } else {
+ const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
+ for (size_t i = 0; i < sublayers.size(); i++)
+ drawLayersRecursive(sublayers[i].get());
+ }
+
+ if (mustClearDepth) {
+ GLC(glDisable(GL_DEPTH_TEST));
+ GLC(glClear(GL_DEPTH_BUFFER_BIT));
+ depthTestEnabledForSubtree = false;
+ }
}
void LayerRendererChromium::drawLayer(LayerChromium* layer)
{
- const TransformationMatrix& localMatrix = layer->drawTransform();
IntSize bounds = layer->bounds();
if (layer->drawsContent()) {
- int textureId;
- if (layer->ownsTexture())
- textureId = layer->textureId();
- else {
- textureId = getTextureId(layer);
- // If no texture has been created for the layer yet then create one now.
- if (textureId == -1)
- textureId = assignTextureForLayer(layer);
- }
-
- // Redraw the contents of the layer if necessary.
+ // Update the contents of the layer if necessary.
if (layer->contentsDirty()) {
// Update the backing texture contents for any dirty portion of the layer.
- layer->updateTextureContents(textureId);
+ layer->updateContents();
m_gles2Context->makeCurrent();
}
@@ -698,13 +487,11 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer)
else
glEnable(GL_CULL_FACE);
- glBindTexture(GL_TEXTURE_2D, textureId);
- useShaderProgram(static_cast<ShaderProgramType>(layer->shaderProgramId()));
- drawTexturedQuad(localMatrix, bounds.width(), bounds.height(), layer->drawOpacity());
+ layer->draw();
}
// Draw the debug border if there is one.
- drawDebugBorder(layer, localMatrix);
+ layer->drawDebugBorder();
}
bool LayerRendererChromium::makeContextCurrent()
@@ -712,21 +499,22 @@ bool LayerRendererChromium::makeContextCurrent()
return m_gles2Context->makeCurrent();
}
-void LayerRendererChromium::bindCommonAttribLocations(ShaderProgramType program)
+// Checks whether a given size is within the maximum allowed texture size range.
+bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize)
{
- unsigned programId = m_shaderPrograms[program].m_shaderProgramId;
- glBindAttribLocation(programId, m_positionLocation, "a_position");
- glBindAttribLocation(programId, m_texCoordLocation, "a_texCoord");
-
- // Re-link the program for the new attribute locations to take effect.
- glLinkProgram(programId);
- checkGLError();
+ if (textureSize.width() > m_maxTextureSize || textureSize.height() > m_maxTextureSize)
+ return false;
+ return true;
}
-bool LayerRendererChromium::initializeSharedGLObjects()
+bool LayerRendererChromium::initializeSharedObjects()
{
- // Shaders for drawing the layer contents.
- char vertexShaderString[] =
+ makeContextCurrent();
+
+ // Vertex and fragment shaders for rendering the scrolled root layer quad.
+ // They differ from a regular content layer shader in that they don't swizzle
+ // the colors or take an alpha value.
+ char scrollVertexShaderString[] =
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"uniform mat4 matrix; \n"
@@ -736,30 +524,6 @@ bool LayerRendererChromium::initializeSharedGLObjects()
" gl_Position = matrix * a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
- // Note differences between Skia and Core Graphics versions:
- // - Skia uses BGRA and origin is upper left
- // - Core Graphics uses RGBA and origin is lower left
- char fragmentShaderString[] =
- "precision mediump float; \n"
- "varying vec2 v_texCoord; \n"
- "uniform sampler2D s_texture; \n"
- "uniform float alpha; \n"
- "void main() \n"
- "{ \n"
-#if PLATFORM(SKIA)
- " vec4 texColor = texture2D(s_texture, v_texCoord); \n"
- " gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha; \n"
-#elif PLATFORM(CG)
- " vec4 texColor = texture2D(s_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n"
- " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
-#else
-#error "Need to implement for your platform."
-#endif
- "} \n";
-
- // Fragment shader used for rendering the scrolled root layer quad. It differs
- // from fragmentShaderString in that it doesn't swizzle the colors and doesn't
- // take an alpha value.
char scrollFragmentShaderString[] =
"precision mediump float; \n"
"varying vec2 v_texCoord; \n"
@@ -770,101 +534,67 @@ bool LayerRendererChromium::initializeSharedGLObjects()
" gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w); \n"
"} \n";
- // Canvas layers need to be flipped vertically and their colors shouldn't be
- // swizzled.
- char canvasFragmentShaderString[] =
- "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, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n"
- " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
- "} \n";
-
- // Shaders for drawing the debug borders around the layers.
- char borderVertexShaderString[] =
- "attribute vec4 a_position; \n"
- "uniform mat4 matrix; \n"
- "void main() \n"
- "{ \n"
- " gl_Position = matrix * a_position; \n"
- "} \n";
- char borderFragmentShaderString[] =
- "precision mediump float; \n"
- "uniform vec4 color; \n"
- "void main() \n"
- "{ \n"
- " gl_FragColor = color; \n"
- "} \n";
-
- GLfloat vertices[] = { -0.5f, 0.5f, 0.0f, // Position 0
- 0.0f, 1.0f, // TexCoord 0
- -0.5f, -0.5f, 0.0f, // Position 1
- 0.0f, 0.0f, // TexCoord 1
- 0.5f, -0.5f, 0.0f, // Position 2
- 1.0f, 0.0f, // TexCoord 2
- 0.5f, 0.5f, 0.0f, // Position 3
- 1.0f, 1.0f // TexCoord 3
- };
- GLushort indices[] = { 0, 1, 2, 0, 2, 3, // The two triangles that make up the layer quad.
- 0, 1, 2, 3}; // A line path for drawing the layer border.
-
- makeContextCurrent();
-
- if (!createLayerShader(ContentLayerProgram, vertexShaderString, fragmentShaderString)) {
- LOG_ERROR("Failed to create shader program for content layers");
- return false;
- }
- LayerChromium::setShaderProgramId(ContentLayerProgram);
-
- if (!createLayerShader(CanvasLayerProgram, vertexShaderString, canvasFragmentShaderString)) {
- LOG_ERROR("Failed to create shader program for Canvas layers");
+ m_scrollShaderProgram = LayerChromium::createShaderProgram(scrollVertexShaderString, scrollFragmentShaderString);
+ if (!m_scrollShaderProgram) {
+ LOG_ERROR("LayerRendererChromium: Failed to create scroll shader program");
+ cleanupSharedObjects();
return false;
}
- CanvasLayerChromium::setShaderProgramId(CanvasLayerProgram);
- if (!createLayerShader(ScrollLayerProgram, vertexShaderString, scrollFragmentShaderString)) {
- LOG_ERROR("Failed to create shader program for scrolling layer");
+ GLC(m_scrollShaderSamplerLocation = glGetUniformLocation(m_scrollShaderProgram, "s_texture"));
+ GLC(m_scrollShaderMatrixLocation = glGetUniformLocation(m_scrollShaderProgram, "matrix"));
+ if (m_scrollShaderSamplerLocation == -1 || m_scrollShaderMatrixLocation == -1) {
+ LOG_ERROR("Failed to initialize scroll shader.");
+ cleanupSharedObjects();
return false;
}
- if (!createLayerShader(DebugBorderProgram, borderVertexShaderString, borderFragmentShaderString)) {
- LOG_ERROR("Failed to create shader program for debug borders");
- return false;
- }
-
- // Specify the attrib location for the position and texCoord and make it the same for all programs to
- // avoid binding re-binding the vertex attributes.
- bindCommonAttribLocations(ContentLayerProgram);
- bindCommonAttribLocations(CanvasLayerProgram);
- bindCommonAttribLocations(DebugBorderProgram);
- bindCommonAttribLocations(ScrollLayerProgram);
-
- // Get the location of the color uniform for the debug border shader program.
- m_borderColorLocation = glGetUniformLocation(m_shaderPrograms[DebugBorderProgram].m_shaderProgramId, "color");
-
- glGenBuffers(3, m_quadVboIds);
- glBindBuffer(GL_ARRAY_BUFFER, m_quadVboIds[Vertices]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_quadVboIds[LayerElements]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
-
// Create a texture object to hold the contents of the root layer.
m_rootLayerTextureId = createLayerTexture();
if (!m_rootLayerTextureId) {
LOG_ERROR("Failed to create texture for root layer");
+ cleanupSharedObjects();
return false;
}
// Turn off filtering for the root layer to avoid blurring from the repeated
// writes and reads to the framebuffer that happen while scrolling.
- glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ GLC(glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId));
+ GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+ GLC(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+
+ // Get the max texture size supported by the system.
+ GLC(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize));
+
+ m_layerSharedValues = adoptPtr(new LayerChromium::SharedValues());
+ m_contentLayerSharedValues = adoptPtr(new ContentLayerChromium::SharedValues());
+ m_canvasLayerSharedValues = adoptPtr(new CanvasLayerChromium::SharedValues());
+ if (!m_layerSharedValues->initialized() || !m_contentLayerSharedValues->initialized() || !m_canvasLayerSharedValues->initialized()) {
+ cleanupSharedObjects();
+ return false;
+ }
return true;
}
+
+void LayerRendererChromium::cleanupSharedObjects()
+{
+ makeContextCurrent();
+
+ m_layerSharedValues.clear();
+ m_contentLayerSharedValues.clear();
+ m_canvasLayerSharedValues.clear();
+
+ if (m_scrollShaderProgram) {
+ GLC(glDeleteProgram(m_scrollShaderProgram));
+ m_scrollShaderProgram = 0;
+ }
+
+ if (m_rootLayerTextureId) {
+ GLC(glDeleteTextures(1, &m_rootLayerTextureId));
+ m_rootLayerTextureId = 0;
+ }
+}
+
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)