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