void WebGLLayerChromium::setLayerRenderer(LayerRendererChromium* newLayerRenderer) { if (layerRenderer() != newLayerRenderer) { if (m_context) { if (layerRenderer()) layerRenderer()->removeChildContext(m_context); if (newLayerRenderer) newLayerRenderer->addChildContext(m_context); } LayerChromium::setLayerRenderer(newLayerRenderer); } }
void CanvasLayerChromium::draw() { ASSERT(layerRenderer()); const CanvasLayerChromium::SharedValues* sv = layerRenderer()->canvasLayerSharedValues(); ASSERT(sv && sv->initialized()); GLC(glActiveTexture(GL_TEXTURE0)); GLC(glBindTexture(GL_TEXTURE_2D, m_textureId)); layerRenderer()->useShader(sv->canvasShaderProgram()); GLC(glUniform1i(sv->shaderSamplerLocation(), 0)); drawTexturedQuad(layerRenderer()->projectionMatrix(), drawTransform(), bounds().width(), bounds().height(), drawOpacity(), sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); }
void ContentLayerChromium::updateLayerSize(const IntSize& layerSize) { if (!m_tiler) return; const IntSize tileSize(min(defaultTileSize, layerSize.width()), min(defaultTileSize, layerSize.height())); // Tile if both dimensions large, or any one dimension large and the other // extends into a second tile. This heuristic allows for long skinny layers // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space. const bool anyDimensionLarge = layerSize.width() > maxUntiledSize || layerSize.height() > maxUntiledSize; const bool anyDimensionOneTile = layerSize.width() <= defaultTileSize || layerSize.height() <= defaultTileSize; const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile; bool isTiled; if (m_tilingOption == AlwaysTile) isTiled = true; else if (m_tilingOption == NeverTile) isTiled = false; else isTiled = autoTiled; IntSize requestedSize = isTiled ? tileSize : layerSize; const int maxSize = layerRenderer()->maxTextureSize(); IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize)); m_tiler->setTileSize(clampedSize); }
void ContentLayerChromium::draw() { if (m_skipsDraw) 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)); layerRenderer()->useShader(sv->contentShaderProgram()); GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0)); drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), bounds().width(), bounds().height(), drawOpacity(), sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); }
void CCCanvasLayerImpl::draw(const IntRect&) { ASSERT(layerRenderer()); const CCCanvasLayerImpl::Program* program = layerRenderer()->canvasLayerProgram(); ASSERT(program && program->initialized()); GraphicsContext3D* context = layerRenderer()->context(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); GC3Denum sfactor = m_premultipliedAlpha ? GraphicsContext3D::ONE : GraphicsContext3D::SRC_ALPHA; GLC(context, context->blendFunc(sfactor, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); layerRenderer()->useShader(program->program()); GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), bounds().width(), bounds().height(), drawOpacity(), program->vertexShader().matrixLocation(), program->fragmentShader().alphaLocation()); }
void VideoLayerChromium::drawRGBA(const SharedValues* sv) { GraphicsContext3D* context = layerRendererContext(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textures[VideoFrameChromium::rgbPlane])); layerRenderer()->useShader(sv->rgbaShaderProgram()); unsigned frameWidth = m_frameSizes[VideoFrameChromium::rgbPlane].width(); unsigned textureWidth = m_textureSizes[VideoFrameChromium::rgbPlane].width(); float widthScaleFactor = static_cast<float>(frameWidth) / textureWidth; GLC(context, context->uniform1f(sv->rgbaWidthScaleFactorLocation(), widthScaleFactor)); GLC(context, context->uniform1i(sv->rgbaTextureLocation(), 0)); drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), bounds().width(), bounds().height(), drawOpacity(), sv->rgbaShaderMatrixLocation(), sv->rgbaAlphaLocation()); }
PassOwnPtr<LayerTextureUpdater> ContentLayerChromium::createTextureUpdater() { OwnPtr<LayerPainterChromium> painter = adoptPtr(new ContentLayerPainter(m_owner)); #if USE(SKIA) if (layerRenderer()->accelerateDrawing()) return adoptPtr(new LayerTextureUpdaterSkPicture(layerRendererContext(), painter.release(), layerRenderer()->skiaContext())); #endif return adoptPtr(new LayerTextureUpdaterBitmap(layerRendererContext(), painter.release(), layerRenderer()->contextSupportsMapSub())); }
void RenderSurfaceChromium::cleanupResources() { if (!m_contentsTexture) return; ASSERT(layerRenderer()); m_contentsTexture.clear(); }
bool RenderSurfaceChromium::prepareContentsTexture() { IntSize requiredSize(m_contentRect.size()); TextureManager* textureManager = layerRenderer()->textureManager(); if (!m_contentsTexture) m_contentsTexture = LayerTexture::create(layerRenderer()->context(), textureManager); if (m_contentsTexture->isReserved()) return true; if (!m_contentsTexture->reserve(requiredSize, GraphicsContext3D::RGBA)) { m_skipsDraw = true; return false; } m_skipsDraw = false; return true; }
bool ContentLayerChromium::requiresClippedUpdateRect() const { // To avoid allocating excessively large textures, switch into "large layer mode" if // one of the layer's dimensions is larger than 2000 pixels or the size of // surface it's rendering into. This is a temporary measure until layer tiling is implemented. static const int maxLayerSize = 2000; return (m_bounds.width() > max(maxLayerSize, m_targetRenderSurface->contentRect().width()) || m_bounds.height() > max(maxLayerSize, m_targetRenderSurface->contentRect().height()) || !layerRenderer()->checkTextureSize(m_bounds)); }
void ContentLayerChromium::createTilerIfNeeded() { if (m_tiler) return; m_tiler = LayerTilerChromium::create( layerRenderer(), createTextureUpdater(), IntSize(defaultTileSize, defaultTileSize), LayerTilerChromium::HasBorderTexels); }
PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint) { if (!context) return 0; RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context, contentPaint))); if (!layerRenderer->hardwareCompositing()) return 0; return layerRenderer.release(); }
PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(CCLayerTreeHostImpl* owner, PassRefPtr<GraphicsContext3D> context) { #if USE(SKIA) if (owner->settings().acceleratePainting && !contextSupportsAcceleratedPainting(context.get())) return nullptr; #endif OwnPtr<LayerRendererChromium> layerRenderer(adoptPtr(new LayerRendererChromium(owner, context))); if (!layerRenderer->initialize()) return nullptr; return layerRenderer.release(); }
void VideoLayerChromium::cleanupResources() { LayerChromium::cleanupResources(); releaseCurrentFrame(); if (!layerRenderer()) return; GraphicsContext3D* context = layerRendererContext(); for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { if (m_textures[plane]) GLC(context, context->deleteTexture(m_textures[plane])); } }
void VideoLayerChromium::draw() { if (m_skipsDraw) return; ASSERT(layerRenderer()); const VideoLayerChromium::SharedValues* sv = layerRenderer()->videoLayerSharedValues(); ASSERT(sv && sv->initialized()); switch (m_frameFormat) { case VideoFrameChromium::YV12: drawYUV(sv); break; case VideoFrameChromium::RGBA: drawRGBA(sv); break; default: // FIXME: Implement other paths. notImplemented(); break; } releaseCurrentFrame(); }
void CCPluginLayerImpl::draw() { ASSERT(layerRenderer()); const CCPluginLayerImpl::Program* program = layerRenderer()->pluginLayerProgram(); ASSERT(program && program->initialized()); GraphicsContext3D* context = layerRenderer()->context(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); // FIXME: setting the texture parameters every time is redundant. Move this code somewhere // where it will only happen once per texture. GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); layerRenderer()->useShader(program->program()); GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); LayerChromium::drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), bounds().width(), bounds().height(), drawOpacity(), program->vertexShader().matrixLocation(), program->fragmentShader().alphaLocation()); }
bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, VideoFrameChromium* frame, unsigned textureFormat) { ASSERT(context); ASSERT(frame); for (unsigned plane = 0; plane < frame->planes(); plane++) { IntSize planeTextureSize = frame->requiredTextureSize(plane); // If the renderer cannot handle this large of a texture, return false. // FIXME: Remove this test when tiled layers are implemented. if (!layerRenderer()->checkTextureSize(planeTextureSize)) return false; if (!m_textures[plane]) m_textures[plane] = layerRenderer()->createLayerTexture(); if (!planeTextureSize.isZero() && planeTextureSize != m_textureSizes[plane]) { allocateTexture(context, m_textures[plane], planeTextureSize, textureFormat); m_textureSizes[plane] = planeTextureSize; m_frameSizes[plane] = IntSize(frame->width(), frame->height()); } } return true; }
void ContentLayerChromium::paintContentsIfDirty(const IntRect& targetSurfaceRect) { ASSERT(drawsContent()); ASSERT(layerRenderer()); updateLayerSize(layerBounds().size()); IntRect layerRect = visibleLayerRect(targetSurfaceRect); if (layerRect.isEmpty()) return; IntRect dirty = enclosingIntRect(m_dirtyRect); dirty.intersect(layerBounds()); m_tiler->invalidateRect(dirty); m_tiler->prepareToUpdate(layerRect); m_dirtyRect = FloatRect(); }
void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId, MipmapUse requestMipmap) { if (!pixels) return; GraphicsContext3D* context = layerRendererContext(); context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); bool generateMipmap = (requestMipmap == useMipmap) && (layerRenderer()->contentLayerSharedValues()->npotSupported() || (isPowerOfTwo(updateRect.width()) && isPowerOfTwo(updateRect.height()))); // 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)); if (generateMipmap) { GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR_MIPMAP_LINEAR)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); } else { GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); } 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 (generateMipmap) GLC(context, context->generateMipmap(GraphicsContext3D::TEXTURE_2D)); m_dirtyRect.setSize(FloatSize()); m_contentsDirty = false; }
void RenderSurfaceChromium::draw(const IntRect&) { if (m_skipsDraw || !m_contentsTexture) return; // FIXME: By using the same RenderSurface for both the content and its reflection, // it's currently not possible to apply a separate mask to the reflection layer // or correctly handle opacity in reflections (opacity must be applied after drawing // both the layer and its reflection). The solution is to introduce yet another RenderSurface // to draw the layer and its reflection in. For now we only apply a separate reflection // mask if the contents don't have a mask of their own. CCLayerImpl* replicaMaskLayer = m_maskLayer; if (!m_maskLayer && m_owningLayer->replicaLayer()) replicaMaskLayer = m_owningLayer->replicaLayer()->maskLayer(); layerRenderer()->setScissorToRect(m_scissorRect); // Reflection draws before the layer. if (m_owningLayer->replicaLayer()) drawSurface(replicaMaskLayer, m_replicaDrawTransform); drawSurface(m_maskLayer, m_drawTransform); }
void RenderSurfaceChromium::drawSurface(CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform) { GraphicsContext3D* context3D = layerRenderer()->context(); int shaderMatrixLocation = -1; int shaderAlphaLocation = -1; const RenderSurfaceChromium::Program* program = layerRenderer()->renderSurfaceProgram(); const RenderSurfaceChromium::MaskProgram* maskProgram = layerRenderer()->renderSurfaceMaskProgram(); ASSERT(program && program->initialized()); bool useMask = false; if (maskLayer && maskLayer->drawsContent()) { if (!maskLayer->bounds().isEmpty()) { context3D->makeContextCurrent(); layerRenderer()->useShader(maskProgram->program()); GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context3D, context3D->uniform1i(maskProgram->fragmentShader().samplerLocation(), 0)); m_contentsTexture->bindTexture(); GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE1)); GLC(context3D, context3D->uniform1i(maskProgram->fragmentShader().maskSamplerLocation(), 1)); maskLayer->bindContentsTexture(); GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0)); shaderMatrixLocation = maskProgram->vertexShader().matrixLocation(); shaderAlphaLocation = maskProgram->fragmentShader().alphaLocation(); useMask = true; } } if (!useMask) { layerRenderer()->useShader(program->program()); m_contentsTexture->bindTexture(); GLC(context3D, context3D->uniform1i(program->fragmentShader().samplerLocation(), 0)); shaderMatrixLocation = program->vertexShader().matrixLocation(); shaderAlphaLocation = program->fragmentShader().alphaLocation(); } LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), drawTransform, m_contentRect.width(), m_contentRect.height(), m_drawOpacity, shaderMatrixLocation, shaderAlphaLocation); }
void RenderSurfaceChromium::drawSurface(LayerChromium* maskLayer, const TransformationMatrix& drawTransform) { GraphicsContext3D* context3D = layerRenderer()->context(); int shaderMatrixLocation = -1; int shaderAlphaLocation = -1; const RenderSurfaceChromium::SharedValues* sv = layerRenderer()->renderSurfaceSharedValues(); ASSERT(sv && sv->initialized()); bool useMask = false; if (maskLayer && maskLayer->drawsContent()) { maskLayer->updateContentsIfDirty(); if (!maskLayer->bounds().isEmpty()) { context3D->makeContextCurrent(); layerRenderer()->useShader(sv->maskShaderProgram()); GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0)); m_contentsTexture->bindTexture(); GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE1)); maskLayer->bindContentsTexture(); GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0)); shaderMatrixLocation = sv->maskShaderMatrixLocation(); shaderAlphaLocation = sv->maskShaderAlphaLocation(); useMask = true; } } if (!useMask) { layerRenderer()->useShader(sv->shaderProgram()); m_contentsTexture->bindTexture(); shaderMatrixLocation = sv->shaderMatrixLocation(); shaderAlphaLocation = sv->shaderAlphaLocation(); } LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), drawTransform, m_contentRect.width(), m_contentRect.height(), m_drawOpacity, shaderMatrixLocation, shaderAlphaLocation); m_contentsTexture->unreserve(); if (maskLayer) maskLayer->unreserveContentsTexture(); }
void ContentLayerChromium::updateContents() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) return; ASSERT(drawsContent()); ASSERT(layerRenderer()); void* pixels = 0; IntRect dirtyRect; IntRect updateRect; IntSize requiredTextureSize; IntSize bitmapSize; // FIXME: Remove this test when tiled layers are implemented. if (requiresClippedUpdateRect()) { // A layer with 3D transforms could require an arbitrarily large number // of texels to be repainted, so ignore these layers until tiling is // implemented. if (!drawTransform().isIdentityOrTranslation()) { m_skipsDraw = true; return; } calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect); if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.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()); } } 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) dirtyRect = boundsRect; else { // Clip the dirtyRect to the size of the layer to avoid drawing // outside the bounds of the backing texture. dirtyRect.intersect(boundsRect); } updateRect = dirtyRect; } if (dirtyRect.isEmpty()) return; #if PLATFORM(SKIA) const SkBitmap* skiaBitmap = 0; OwnPtr<skia::PlatformCanvas> canvas; OwnPtr<PlatformContextSkia> skiaContext; OwnPtr<GraphicsContext> graphicsContext; canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false)); skiaContext.set(new PlatformContextSkia(canvas.get())); // This is needed to get text to show up correctly. // FIXME: Does this take us down a very slow text rendering path? skiaContext->setDrawingToImageBuffer(true); graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get()))); // Bring the canvas into the coordinate system of the paint rect. canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); m_owner->paintGraphicsLayerContents(*graphicsContext, dirtyRect); const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); skiaBitmap = &bitmap; ASSERT(skiaBitmap); SkAutoLockPixels lock(*skiaBitmap); SkBitmap::Config skiaConfig = skiaBitmap->config(); // FIXME: do we need to support more image configurations? if (skiaConfig == SkBitmap::kARGB_8888_Config) { pixels = skiaBitmap->getPixels(); bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); } #elif PLATFORM(CG) Vector<uint8_t> tempVector; int rowBytes = 4 * dirtyRect.width(); tempVector.resize(rowBytes * dirtyRect.height()); memset(tempVector.data(), 0, tempVector.size()); RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); RetainPtr<CGContextRef> contextCG(AdoptCF, CGBitmapContextCreate(tempVector.data(), dirtyRect.width(), dirtyRect.height(), 8, rowBytes, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); CGContextTranslateCTM(contextCG.get(), 0, dirtyRect.height()); CGContextScaleCTM(contextCG.get(), 1, -1); GraphicsContext graphicsContext(contextCG.get()); // Translate the graphics context into the coordinate system of the dirty rect. graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y()); m_owner->paintGraphicsLayerContents(graphicsContext, dirtyRect); pixels = tempVector.data(); bitmapSize = dirtyRect.size(); #else #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); }
WebGLLayerChromium::~WebGLLayerChromium() { if (m_context && layerRenderer()) layerRenderer()->removeChildContext(m_context); }