LayerRendererChromium.cpp [plain text]
#include "config.h"
#if USE(ACCELERATED_COMPOSITING)
#include "LayerRendererChromium.h"
#include "Canvas2DLayerChromium.h"
#include "Extensions3DChromium.h"
#include "FloatQuad.h"
#include "GeometryBinding.h"
#include "GraphicsContext3D.h"
#include "LayerChromium.h"
#include "LayerTexture.h"
#include "NotImplemented.h"
#include "TextStream.h"
#include "TextureManager.h"
#include "TreeSynchronizer.h"
#include "TraceEvent.h"
#include "WebGLLayerChromium.h"
#include "cc/CCLayerImpl.h"
#if USE(SKIA)
#include "NativeImageSkia.h"
#include "PlatformContextSkia.h"
#elif USE(CG)
#include <CoreGraphics/CGBitmapContext.h>
#endif
#include <wtf/CurrentTime.h>
namespace WebCore {
static size_t textureMemoryLimitBytes = 64 * 1024 * 1024;
#ifndef NDEBUG
bool LayerRendererChromium::s_inPaintLayerContents = false;
#endif
static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top)
{
float deltaX = right - left;
float deltaY = top - bottom;
TransformationMatrix ortho;
if (!deltaX || !deltaY)
return ortho;
ortho.setM11(2.0f / deltaX);
ortho.setM41(-(right + left) / deltaX);
ortho.setM22(2.0f / deltaY);
ortho.setM42(-(top + bottom) / deltaY);
ortho.setM33(0);
return ortho;
}
static bool isScaleOrTranslation(const TransformationMatrix& m)
{
return !m.m12() && !m.m13() && !m.m14()
&& !m.m21() && !m.m23() && !m.m24()
&& !m.m31() && !m.m32() && !m.m43()
&& m.m44();
}
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();
}
LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context,
PassOwnPtr<TilePaintInterface> contentPaint)
: m_viewportScrollPosition(IntPoint(-1, -1))
, m_rootLayer(0)
, m_rootLayerContentPaint(contentPaint)
, m_currentShader(0)
, m_currentRenderSurface(0)
, m_offscreenFramebufferId(0)
, m_compositeOffscreen(false)
, m_context(context)
, m_childContextsWereCopied(false)
, m_contextSupportsLatch(false)
, m_animating(false)
, m_defaultRenderSurface(0)
{
m_contextSupportsLatch = m_context->getExtensions()->supports("GL_CHROMIUM_latch");
m_contextSupportsMapSub = m_context->getExtensions()->supports("GL_CHROMIUM_map_sub");
if (m_contextSupportsMapSub)
m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_map_sub");
m_hardwareCompositing = initializeSharedObjects();
m_rootLayerContentTiler = LayerTilerChromium::create(this, IntSize(256, 256), LayerTilerChromium::NoBorderTexels);
ASSERT(m_rootLayerContentTiler);
m_headsUpDisplay = CCHeadsUpDisplay::create(this);
}
LayerRendererChromium::~LayerRendererChromium()
{
m_headsUpDisplay.clear(); cleanupSharedObjects();
}
GraphicsContext3D* LayerRendererChromium::context()
{
return m_context.get();
}
void LayerRendererChromium::debugGLCall(GraphicsContext3D* context, const char* command, const char* file, int line)
{
unsigned long error = context->getError();
if (error != GraphicsContext3D::NO_ERROR)
LOG_ERROR("GL command failed: File: %s\n\tLine %d\n\tcommand: %s, error %x\n", file, line, command, static_cast<int>(error));
}
void LayerRendererChromium::useShader(unsigned programId)
{
if (programId != m_currentShader) {
GLC(m_context.get(), m_context->useProgram(programId));
m_currentShader = programId;
}
}
void LayerRendererChromium::invalidateRootLayerRect(const IntRect& dirtyRect)
{
m_rootLayerContentTiler->invalidateRect(dirtyRect);
}
void LayerRendererChromium::updateRootLayerContents()
{
TRACE_EVENT("LayerRendererChromium::updateRootLayerContents", this, 0);
m_rootLayerContentTiler->update(*m_rootLayerContentPaint, m_viewportVisibleRect);
}
void LayerRendererChromium::drawRootLayer()
{
TransformationMatrix scroll;
scroll.translate(-m_viewportVisibleRect.x(), -m_viewportVisibleRect.y());
m_rootLayerContentTiler->uploadCanvas();
m_rootLayerContentTiler->draw(m_viewportVisibleRect, scroll, 1.0f);
}
void LayerRendererChromium::setViewport(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition)
{
bool visibleRectChanged = m_viewportVisibleRect.size() != visibleRect.size();
m_viewportVisibleRect = visibleRect;
m_viewportContentRect = contentRect;
m_viewportScrollPosition = scrollPosition;
if (visibleRectChanged) {
m_currentRenderSurface = 0;
m_rootLayerContentTiler->invalidateEntireLayer();
}
}
void LayerRendererChromium::updateAndDrawLayers()
{
m_headsUpDisplay->onFrameBegin(currentTime());
ASSERT(m_hardwareCompositing);
if (!m_rootLayer)
return;
updateRootLayerContents();
if (!m_rootLayer)
return;
{
TRACE_EVENT("LayerRendererChromium::synchronizeTrees", this, 0);
m_rootCCLayerImpl = TreeSynchronizer::synchronizeTrees(m_rootLayer.get(), m_rootCCLayerImpl.get());
}
LayerList renderSurfaceLayerList;
updateLayers(renderSurfaceLayerList);
if (hardwareCompositing() && m_contextSupportsLatch) {
if (m_childContextsWereCopied) {
Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions());
ChildContextMap::iterator i = m_childContexts.begin();
for (; i != m_childContexts.end(); ++i) {
Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions());
GC3Duint latchId;
childExt->getChildToParentLatchCHROMIUM(&latchId);
parentExt->waitLatchCHROMIUM(latchId);
}
}
m_childContextsWereCopied = false;
}
drawLayers(renderSurfaceLayerList);
m_textureManager->unprotectAllTextures();
if (hardwareCompositing() && m_contextSupportsLatch) {
Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions());
ChildContextMap::iterator i = m_childContexts.begin();
for (; i != m_childContexts.end(); ++i) {
Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions());
GC3Duint latchId;
childExt->getParentToChildLatchCHROMIUM(&latchId);
parentExt->setLatchCHROMIUM(latchId);
}
}
if (isCompositingOffscreen())
copyOffscreenTextureToDisplay();
}
void LayerRendererChromium::updateLayers(LayerList& renderSurfaceLayerList)
{
TRACE_EVENT("LayerRendererChromium::updateLayers", this, 0);
CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl();
if (!rootDrawLayer->renderSurface())
rootDrawLayer->createRenderSurface();
ASSERT(rootDrawLayer->renderSurface());
rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), m_viewportVisibleRect.size());
IntRect rootScissorRect(m_viewportVisibleRect);
rootScissorRect.move(-m_viewportScrollPosition.x(), -m_viewportScrollPosition.y());
rootDrawLayer->setScissorRect(rootScissorRect);
m_defaultRenderSurface = rootDrawLayer->renderSurface();
renderSurfaceLayerList.append(rootDrawLayer);
TransformationMatrix identityMatrix;
m_defaultRenderSurface->m_layerList.clear();
updatePropertiesAndRenderSurfaces(rootDrawLayer, identityMatrix, renderSurfaceLayerList, m_defaultRenderSurface->m_layerList);
#ifndef NDEBUG
s_inPaintLayerContents = true;
#endif
paintLayerContents(renderSurfaceLayerList);
#ifndef NDEBUG
s_inPaintLayerContents = false;
#endif
updateCompositorResourcesRecursive(m_rootLayer.get());
if (hardwareCompositing() && m_contextSupportsLatch) {
m_childContextsWereCopied = true;
ChildContextMap::iterator i = m_childContexts.begin();
for (; i != m_childContexts.end(); ++i) {
Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions());
GC3Duint childToParentLatchId, parentToChildLatchId;
ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId);
ext->getChildToParentLatchCHROMIUM(&childToParentLatchId);
ext->setLatchCHROMIUM(childToParentLatchId);
ext->waitLatchCHROMIUM(parentToChildLatchId);
}
}
}
void LayerRendererChromium::paintLayerContents(const LayerList& renderSurfaceLayerList)
{
for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex].get();
RenderSurfaceChromium* renderSurface = renderSurfaceLayer->renderSurface();
ASSERT(renderSurface);
renderSurfaceLayer->setLayerRenderer(this);
if (!renderSurface->m_layerList.size())
continue;
LayerList& layerList = renderSurface->m_layerList;
ASSERT(layerList.size());
for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex) {
CCLayerImpl* ccLayerImpl = layerList[layerIndex].get();
if (ccLayerImpl->renderSurface() && ccLayerImpl->renderSurface() != renderSurface)
continue;
LayerChromium* layer = ccLayerImpl->owner();
layer->setLayerRenderer(this);
if (layer->maskLayer())
layer->maskLayer()->setLayerRenderer(this);
if (layer->replicaLayer()) {
layer->replicaLayer()->setLayerRenderer(this);
if (layer->replicaLayer()->maskLayer())
layer->replicaLayer()->maskLayer()->setLayerRenderer(this);
}
if (layer->bounds().isEmpty())
continue;
IntRect targetSurfaceRect = ccLayerImpl->targetRenderSurface() ? ccLayerImpl->targetRenderSurface()->contentRect() : m_defaultRenderSurface->contentRect();
IntRect scissorRect = layer->ccLayerImpl()->scissorRect();
if (!scissorRect.isEmpty())
targetSurfaceRect.intersect(scissorRect);
if (layer->drawsContent())
layer->paintContentsIfDirty(targetSurfaceRect);
if (layer->maskLayer() && layer->maskLayer()->drawsContent())
layer->maskLayer()->paintContentsIfDirty(targetSurfaceRect);
if (layer->replicaLayer() && layer->replicaLayer()->drawsContent())
layer->replicaLayer()->paintContentsIfDirty(targetSurfaceRect);
if (layer->replicaLayer() && layer->replicaLayer()->maskLayer() && layer->replicaLayer()->maskLayer()->drawsContent())
layer->replicaLayer()->maskLayer()->paintContentsIfDirty(targetSurfaceRect);
}
}
}
void LayerRendererChromium::drawLayers(const LayerList& renderSurfaceLayerList)
{
TRACE_EVENT("LayerRendererChromium::drawLayers", this, 0);
CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl();
makeContextCurrent();
GLC(m_context.get(), m_context->viewport(0, 0, m_viewportVisibleRect.width(), m_viewportVisibleRect.height()));
m_sharedGeometry->prepareForDraw();
GLC(m_context.get(), m_context->disable(GraphicsContext3D::DEPTH_TEST));
GLC(m_context.get(), m_context->disable(GraphicsContext3D::CULL_FACE));
GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND));
useRenderSurface(m_defaultRenderSurface);
m_context->clearColor(0, 0, 1, 1);
m_context->colorMask(true, true, true, true);
m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
m_context->colorMask(true, true, true, false);
drawRootLayer();
m_context->colorMask(true, true, true, true);
GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND));
GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST));
for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex].get();
ASSERT(renderSurfaceLayer->renderSurface());
if (!renderSurfaceLayer->renderSurface()->m_layerList.size())
continue;
if (useRenderSurface(renderSurfaceLayer->renderSurface())) {
if (renderSurfaceLayer != rootDrawLayer) {
GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
GLC(m_context.get(), m_context->clearColor(0, 0, 0, 0));
GLC(m_context.get(), m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT));
GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST));
}
LayerList& layerList = renderSurfaceLayer->renderSurface()->m_layerList;
ASSERT(layerList.size());
for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex)
drawLayer(layerList[layerIndex].get(), renderSurfaceLayer->renderSurface());
}
}
if (m_headsUpDisplay->enabled()) {
GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND));
GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
useRenderSurface(m_defaultRenderSurface);
m_headsUpDisplay->draw();
}
GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND));
}
void LayerRendererChromium::finish()
{
TRACE_EVENT("LayerRendererChromium::finish", this, 0);
m_context->finish();
}
void LayerRendererChromium::present()
{
TRACE_EVENT("LayerRendererChromium::present", this, 0);
m_context->prepareTexture();
m_headsUpDisplay->onPresent();
}
void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer)
{
m_rootLayer = layer;
if (m_rootLayer)
m_rootLayer->setLayerRenderer(this);
m_rootLayerContentTiler->invalidateEntireLayer();
}
void LayerRendererChromium::setLayerRendererRecursive(LayerChromium* layer)
{
const Vector<RefPtr<LayerChromium> >& children = layer->children();
for (size_t i = 0; i < children.size(); ++i)
setLayerRendererRecursive(children[i].get());
if (layer->maskLayer())
setLayerRendererRecursive(layer->maskLayer());
if (layer->replicaLayer())
setLayerRendererRecursive(layer->replicaLayer());
layer->setLayerRenderer(this);
}
void LayerRendererChromium::transferRootLayer(LayerRendererChromium* other)
{
other->setLayerRendererRecursive(m_rootLayer.get());
other->m_rootLayer = m_rootLayer.release();
}
void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect)
{
ASSERT(rect.maxX() <= m_viewportVisibleRect.width() && rect.maxY() <= m_viewportVisibleRect.height());
if (!pixels)
return;
makeContextCurrent();
GLC(m_context.get(), m_context->readPixels(rect.x(), rect.y(), rect.width(), rect.height(),
GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
}
unsigned LayerRendererChromium::createLayerTexture()
{
unsigned textureId = 0;
GLC(m_context.get(), textureId = m_context->createTexture());
GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
return textureId;
}
void LayerRendererChromium::deleteLayerTexture(unsigned textureId)
{
if (!textureId)
return;
GLC(m_context.get(), m_context->deleteTexture(textureId));
}
bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const TransformationMatrix& matrix, const IntRect& visibleRect)
{
TransformationMatrix renderMatrix = matrix;
renderMatrix.scale3d(layer->bounds().width(), layer->bounds().height(), 1);
renderMatrix = m_projectionMatrix * renderMatrix;
FloatRect layerRect(-0.5, -0.5, 1, 1);
FloatRect mappedRect = renderMatrix.mapRect(layerRect);
return mappedRect.intersects(FloatRect(-1, -1, 2, 2));
}
void LayerRendererChromium::updatePropertiesAndRenderSurfaces(CCLayerImpl* layer, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layerList)
{
IntSize bounds = layer->bounds();
FloatPoint anchorPoint = layer->anchorPoint();
FloatPoint position = layer->position();
float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
TransformationMatrix layerLocalTransform;
layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ());
layerLocalTransform.multiply(layer->transform());
layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
TransformationMatrix combinedTransform = parentMatrix;
combinedTransform = combinedTransform.multiply(layerLocalTransform);
FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height());
IntRect transformedLayerRect;
bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform);
bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D();
bool useSurfaceForMasking = layer->maskLayer();
bool useSurfaceForReflection = layer->replicaLayer();
bool useSurfaceForFlatDescendants = layer->parent() && layer->parent()->preserves3D() && !layer->preserves3D() && layer->descendantsDrawsContent();
if (useSurfaceForMasking || useSurfaceForReflection || useSurfaceForFlatDescendants || ((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawsContent())) {
RenderSurfaceChromium* renderSurface = layer->renderSurface();
if (!renderSurface)
renderSurface = layer->createRenderSurface();
TransformationMatrix drawTransform;
drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
layer->setDrawTransform(drawTransform);
transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height());
renderSurface->m_drawOpacity = layer->opacity();
if (layer->parent() && layer->parent()->preserves3D())
renderSurface->m_drawOpacity *= layer->parent()->drawOpacity();
layer->setDrawOpacity(1);
TransformationMatrix layerOriginTransform = combinedTransform;
layerOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
renderSurface->m_originTransform = layerOriginTransform;
layer->setScissorRect(IntRect());
renderSurface->m_scissorRect = layer->parent() ? layer->parent()->scissorRect() : layer->scissorRect();
renderSurface->m_layerList.clear();
if (layer->maskLayer()) {
renderSurface->m_maskLayer = layer->maskLayer();
layer->maskLayer()->setTargetRenderSurface(renderSurface);
} else
renderSurface->m_maskLayer = 0;
if (layer->replicaLayer() && layer->replicaLayer()->maskLayer())
layer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface);
renderSurfaceLayerList.append(layer);
} else {
layer->setDrawTransform(combinedTransform);
transformedLayerRect = enclosingIntRect(layer->drawTransform().mapRect(layerRect));
layer->setDrawOpacity(layer->opacity());
if (layer->parent()) {
if (layer->parent()->preserves3D())
layer->setDrawOpacity(layer->drawOpacity() * layer->parent()->drawOpacity());
layer->setScissorRect(layer->parent()->scissorRect());
layer->setTargetRenderSurface(layer->parent()->targetRenderSurface());
}
if (layer != m_rootCCLayerImpl.get())
layer->clearRenderSurface();
if (layer->masksToBounds()) {
IntRect scissor = transformedLayerRect;
if (!layer->scissorRect().isEmpty())
scissor.intersect(layer->scissorRect());
layer->setScissorRect(scissor);
}
}
if (layer->renderSurface())
layer->setTargetRenderSurface(layer->renderSurface());
else {
ASSERT(layer->parent());
layer->setTargetRenderSurface(layer->parent()->targetRenderSurface());
}
if (layer->drawsContent())
layer->setDrawableContentRect(transformedLayerRect);
else
layer->setDrawableContentRect(IntRect());
TransformationMatrix sublayerMatrix = layer->drawTransform();
if (!layer->preserves3D()) {
sublayerMatrix.setM13(0);
sublayerMatrix.setM23(0);
sublayerMatrix.setM31(0);
sublayerMatrix.setM32(0);
sublayerMatrix.setM33(1);
sublayerMatrix.setM34(0);
sublayerMatrix.setM43(0);
}
sublayerMatrix.multiply(layer->sublayerTransform());
sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
LayerList& descendants = (layer->renderSurface() ? layer->renderSurface()->m_layerList : layerList);
descendants.append(layer);
unsigned thisLayerIndex = descendants.size() - 1;
for (size_t i = 0; i < layer->children().size(); ++i) {
CCLayerImpl* child = layer->children()[i].get();
updatePropertiesAndRenderSurfaces(child, sublayerMatrix, renderSurfaceLayerList, descendants);
if (child->renderSurface()) {
RenderSurfaceChromium* childRenderSurface = child->renderSurface();
IntRect drawableContentRect = layer->drawableContentRect();
drawableContentRect.unite(enclosingIntRect(childRenderSurface->drawableContentRect()));
layer->setDrawableContentRect(drawableContentRect);
descendants.append(child);
} else {
IntRect drawableContentRect = layer->drawableContentRect();
drawableContentRect.unite(child->drawableContentRect());
layer->setDrawableContentRect(drawableContentRect);
}
}
if (layer->masksToBounds() || useSurfaceForMasking) {
IntRect drawableContentRect = layer->drawableContentRect();
drawableContentRect.intersect(transformedLayerRect);
layer->setDrawableContentRect(drawableContentRect);
}
if (layer->renderSurface() && layer != m_rootCCLayerImpl.get()) {
RenderSurfaceChromium* renderSurface = layer->renderSurface();
renderSurface->m_contentRect = layer->drawableContentRect();
FloatPoint surfaceCenter = renderSurface->contentRectCenter();
FloatSize centerOffsetDueToClipping;
if (!layer->replicaLayer()) {
if (!layer->scissorRect().isEmpty())
renderSurface->m_contentRect.intersect(layer->scissorRect());
FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter();
centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
}
renderSurface->m_contentRect.setWidth(std::min(renderSurface->m_contentRect.width(), m_maxTextureSize));
renderSurface->m_contentRect.setHeight(std::min(renderSurface->m_contentRect.height(), m_maxTextureSize));
if (renderSurface->m_contentRect.isEmpty())
renderSurface->m_layerList.clear();
layer->setScissorRect(layer->drawableContentRect());
renderSurface->m_drawTransform = renderSurface->m_originTransform;
renderSurface->m_drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0);
if (layer->replicaLayer()) {
renderSurface->m_replicaDrawTransform = renderSurface->m_originTransform;
renderSurface->m_replicaDrawTransform.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0);
renderSurface->m_replicaDrawTransform.multiply(layer->replicaLayer()->transform());
renderSurface->m_replicaDrawTransform.translate3d(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height(), 0);
}
}
if (layer->preserves3D() && (!layer->parent() || !layer->parent()->preserves3D()))
m_layerSorter.sort(&descendants.at(thisLayerIndex), descendants.end());
}
void LayerRendererChromium::updateCompositorResourcesRecursive(LayerChromium* layer)
{
const Vector<RefPtr<LayerChromium> >& children = layer->children();
for (size_t i = 0; i < children.size(); ++i)
updateCompositorResourcesRecursive(children[i].get());
if (layer->bounds().isEmpty())
return;
if (layer->maskLayer())
updateCompositorResourcesRecursive(layer->maskLayer());
if (layer->replicaLayer())
updateCompositorResourcesRecursive(layer->replicaLayer());
CCLayerImpl* drawLayer = layer->ccLayerImpl();
if (drawLayer->drawsContent())
drawLayer->updateCompositorResources();
layer->pushPropertiesTo(drawLayer);
}
void LayerRendererChromium::setCompositeOffscreen(bool compositeOffscreen)
{
if (m_compositeOffscreen == compositeOffscreen)
return;
m_compositeOffscreen = compositeOffscreen;
if (!m_compositeOffscreen && m_rootLayer)
m_rootLayer->ccLayerImpl()->clearRenderSurface();
}
LayerTexture* LayerRendererChromium::getOffscreenLayerTexture()
{
return m_compositeOffscreen ? m_rootLayer->ccLayerImpl()->renderSurface()->m_contentsTexture.get() : 0;
}
void LayerRendererChromium::copyOffscreenTextureToDisplay()
{
if (m_compositeOffscreen) {
makeContextCurrent();
useRenderSurface(0);
m_defaultRenderSurface->m_drawTransform.makeIdentity();
m_defaultRenderSurface->m_drawTransform.translate3d(0.5 * m_defaultRenderSurface->m_contentRect.width(),
0.5 * m_defaultRenderSurface->m_contentRect.height(), 0);
m_defaultRenderSurface->m_drawOpacity = 1;
m_defaultRenderSurface->draw(m_defaultRenderSurface->m_contentRect);
}
}
bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurface)
{
if (m_currentRenderSurface == renderSurface)
return true;
m_currentRenderSurface = renderSurface;
if ((renderSurface == m_defaultRenderSurface && !m_compositeOffscreen) || (!renderSurface && m_compositeOffscreen)) {
GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
if (renderSurface)
setDrawViewportRect(renderSurface->m_contentRect, true);
else
setDrawViewportRect(m_defaultRenderSurface->m_contentRect, true);
return true;
}
GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId));
if (!renderSurface->prepareContentsTexture())
return false;
renderSurface->m_contentsTexture->framebufferTexture2D();
#if !defined ( NDEBUG )
if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
ASSERT_NOT_REACHED();
return false;
}
#endif
setDrawViewportRect(renderSurface->m_contentRect, false);
return true;
}
void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* targetSurface)
{
if (layer->renderSurface() && layer->renderSurface() != targetSurface) {
layer->renderSurface()->draw(layer->getDrawRect());
return;
}
if (!layer->drawsContent())
return;
if (layer->bounds().isEmpty()) {
layer->unreserveContentsTexture();
return;
}
setScissorToRect(layer->scissorRect());
IntRect targetSurfaceRect = m_currentRenderSurface ? m_currentRenderSurface->contentRect() : m_defaultRenderSurface->contentRect();
IntRect scissorRect = layer->scissorRect();
if (!scissorRect.isEmpty())
targetSurfaceRect.intersect(scissorRect);
IntRect layerRect = layer->getDrawRect();
bool isLayerVisible = targetSurfaceRect.intersects(layerRect);
if (!isLayerVisible) {
layer->unreserveContentsTexture();
return;
}
TransformationMatrix combinedDrawMatrix = (layer->targetRenderSurface() ? layer->targetRenderSurface()->drawTransform().multiply(layer->drawTransform()) : layer->drawTransform());
if (!layer->doubleSided()) {
FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds()));
FloatQuad mappedLayer = combinedDrawMatrix.mapQuad(FloatQuad(layerRect));
FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1();
FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1();
FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0);
FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0);
FloatPoint3D zAxis = xAxis.cross(yAxis);
if (zAxis.z() < 0) {
layer->unreserveContentsTexture();
return;
}
}
layer->draw(targetSurfaceRect);
layer->drawDebugBorder();
}
void LayerRendererChromium::setScissorToRect(const IntRect& requestedScissor)
{
IntRect contentRect = (m_currentRenderSurface ? m_currentRenderSurface->m_contentRect : m_defaultRenderSurface->m_contentRect);
const IntRect scissorRect = requestedScissor.isEmpty() ? contentRect : requestedScissor;
int scissorX = scissorRect.x() - contentRect.x();
int scissorY;
if (m_currentRenderSurface == m_defaultRenderSurface && !m_compositeOffscreen)
scissorY = m_currentRenderSurface->m_contentRect.height() - (scissorRect.maxY() - m_currentRenderSurface->m_contentRect.y());
else
scissorY = scissorRect.y() - contentRect.y();
GLC(m_context.get(), m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height()));
}
bool LayerRendererChromium::makeContextCurrent()
{
m_context->makeContextCurrent();
return true;
}
bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize)
{
if (textureSize.width() > m_maxTextureSize || textureSize.height() > m_maxTextureSize)
return false;
return true;
}
void LayerRendererChromium::setDrawViewportRect(const IntRect& drawRect, bool flipY)
{
if (flipY)
m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.maxY(), drawRect.y());
else
m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.y(), drawRect.maxY());
GLC(m_context.get(), m_context->viewport(0, 0, drawRect.width(), drawRect.height()));
}
void LayerRendererChromium::resizeOnscreenContent(const IntSize& size)
{
if (m_context)
m_context->reshape(size.width(), size.height());
}
bool LayerRendererChromium::initializeSharedObjects()
{
makeContextCurrent();
m_maxTextureSize = 0;
GLC(m_context.get(), m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize));
GLC(m_context.get(), m_offscreenFramebufferId = m_context->createFramebuffer());
m_sharedGeometry = adoptPtr(new GeometryBinding(m_context.get()));
m_borderProgram = adoptPtr(new LayerChromium::BorderProgram(m_context.get()));
m_headsUpDisplayProgram = adoptPtr(new CCHeadsUpDisplay::Program(m_context.get()));
m_canvasLayerProgram = adoptPtr(new CCCanvasLayerImpl::Program(m_context.get()));
m_videoLayerRGBAProgram = adoptPtr(new CCVideoLayerImpl::RGBAProgram(m_context.get()));
m_videoLayerYUVProgram = adoptPtr(new CCVideoLayerImpl::YUVProgram(m_context.get()));
m_pluginLayerProgram = adoptPtr(new CCPluginLayerImpl::Program(m_context.get()));
m_renderSurfaceProgram = adoptPtr(new RenderSurfaceChromium::Program(m_context.get()));
m_renderSurfaceMaskProgram = adoptPtr(new RenderSurfaceChromium::MaskProgram(m_context.get()));
m_tilerProgram = adoptPtr(new LayerTilerChromium::Program(m_context.get()));
if (!m_sharedGeometry->initialized() || !m_borderProgram->initialized()
|| !m_canvasLayerProgram->initialized()
|| !m_headsUpDisplayProgram->initialized()
|| !m_videoLayerRGBAProgram->initialized() || !m_videoLayerYUVProgram->initialized()
|| !m_pluginLayerProgram->initialized() || !m_renderSurfaceProgram->initialized()
|| !m_renderSurfaceMaskProgram->initialized() || !m_tilerProgram->initialized()) {
LOG_ERROR("Compositor failed to initialize shaders. Falling back to software.");
cleanupSharedObjects();
return false;
}
m_textureManager = TextureManager::create(m_context.get(), textureMemoryLimitBytes, m_maxTextureSize);
return true;
}
void LayerRendererChromium::cleanupSharedObjects()
{
makeContextCurrent();
m_sharedGeometry.clear();
m_borderProgram.clear();
m_canvasLayerProgram.clear();
m_headsUpDisplayProgram.clear();
m_videoLayerRGBAProgram.clear();
m_videoLayerYUVProgram.clear();
m_pluginLayerProgram.clear();
m_renderSurfaceProgram.clear();
m_renderSurfaceMaskProgram.clear();
m_tilerProgram.clear();
if (m_offscreenFramebufferId)
GLC(m_context.get(), m_context->deleteFramebuffer(m_offscreenFramebufferId));
m_rootLayerContentTiler.clear();
m_textureManager.clear();
}
String LayerRendererChromium::layerTreeAsText() const
{
TextStream ts;
if (m_rootLayer.get()) {
ts << m_rootLayer->layerTreeAsText();
ts << "RenderSurfaces:\n";
dumpRenderSurfaces(ts, 1, m_rootLayer.get());
}
return ts.release();
}
void LayerRendererChromium::addChildContext(GraphicsContext3D* ctx)
{
if (!ctx->getExtensions()->supports("GL_CHROMIUM_latch"))
return;
std::pair<ChildContextMap::iterator, bool> insert_result = m_childContexts.add(ctx, 1);
if (!insert_result.second) {
++insert_result.first->second;
} else {
}
}
void LayerRendererChromium::removeChildContext(GraphicsContext3D* ctx)
{
if (!ctx->getExtensions()->supports("GL_CHROMIUM_latch"))
return;
ChildContextMap::iterator i = m_childContexts.find(ctx);
if (i != m_childContexts.end()) {
if (--i->second <= 0) {
m_childContexts.remove(i);
}
} else {
ASSERT(0 && "m_childContexts map has mismatched add/remove calls");
}
}
void LayerRendererChromium::dumpRenderSurfaces(TextStream& ts, int indent, LayerChromium* layer) const
{
if (layer->ccLayerImpl()->renderSurface())
layer->ccLayerImpl()->renderSurface()->dumpSurface(ts, indent);
for (size_t i = 0; i < layer->children().size(); ++i)
dumpRenderSurfaces(ts, indent, layer->children()[i].get());
}
}
#endif // USE(ACCELERATED_COMPOSITING)