// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "config.h" #include "CCDirectRenderer.h" #include "CCMathUtil.h" #include using WebKit::WebTransformationMatrix; static WebTransformationMatrix orthoProjectionMatrix(float left, float right, float bottom, float top) { // Use the standard formula to map the clipping frustum to the cube from // [-1, -1, -1] to [1, 1, 1]. float deltaX = right - left; float deltaY = top - bottom; WebTransformationMatrix proj; if (!deltaX || !deltaY) return proj; proj.setM11(2.0f / deltaX); proj.setM41(-(right + left) / deltaX); proj.setM22(2.0f / deltaY); proj.setM42(-(top + bottom) / deltaY); // Z component of vertices is always set to zero as we don't use the depth buffer // while drawing. proj.setM33(0); return proj; } static WebTransformationMatrix windowMatrix(int x, int y, int width, int height) { WebTransformationMatrix canvas; // Map to window position and scale up to pixel coordinates. canvas.translate3d(x, y, 0); canvas.scale3d(width, height, 0); // Map from ([-1, -1] to [1, 1]) -> ([0, 0] to [1, 1]) canvas.translate3d(0.5, 0.5, 0.5); canvas.scale3d(0.5, 0.5, 0.5); return canvas; } namespace cc { // // static FloatRect CCDirectRenderer::quadVertexRect() { return FloatRect(-0.5, -0.5, 1, 1); } // static void CCDirectRenderer::quadRectTransform(WebKit::WebTransformationMatrix* quadRectTransform, const WebKit::WebTransformationMatrix& quadTransform, const FloatRect& quadRect) { *quadRectTransform = quadTransform; quadRectTransform->translate(0.5 * quadRect.width() + quadRect.x(), 0.5 * quadRect.height() + quadRect.y()); quadRectTransform->scaleNonUniform(quadRect.width(), quadRect.height()); } // static void CCDirectRenderer::initializeMatrices(DrawingFrame& frame, const IntRect& drawRect, bool flipY) { if (flipY) frame.projectionMatrix = orthoProjectionMatrix(drawRect.x(), drawRect.maxX(), drawRect.maxY(), drawRect.y()); else frame.projectionMatrix = orthoProjectionMatrix(drawRect.x(), drawRect.maxX(), drawRect.y(), drawRect.maxY()); frame.windowMatrix = windowMatrix(0, 0, drawRect.width(), drawRect.height()); frame.flippedY = flipY; } // static IntRect CCDirectRenderer::moveScissorToWindowSpace(const DrawingFrame& frame, FloatRect scissorRect) { IntRect scissorRectInCanvasSpace = enclosingIntRect(scissorRect); // The scissor coordinates must be supplied in viewport space so we need to offset // by the relative position of the top left corner of the current render pass. IntRect framebufferOutputRect = frame.currentRenderPass->outputRect(); scissorRectInCanvasSpace.setX(scissorRectInCanvasSpace.x() - framebufferOutputRect.x()); if (frame.flippedY && !frame.currentTexture) scissorRectInCanvasSpace.setY(framebufferOutputRect.height() - (scissorRectInCanvasSpace.maxY() - framebufferOutputRect.y())); else scissorRectInCanvasSpace.setY(scissorRectInCanvasSpace.y() - framebufferOutputRect.y()); return scissorRectInCanvasSpace; } void CCDirectRenderer::decideRenderPassAllocationsForFrame(const CCRenderPassList& renderPassesInDrawOrder) { HashMap renderPassesInFrame; for (size_t i = 0; i < renderPassesInDrawOrder.size(); ++i) renderPassesInFrame.set(renderPassesInDrawOrder[i]->id(), renderPassesInDrawOrder[i]); Vector passesToDelete; HashMap >::const_iterator passIterator; for (passIterator = m_renderPassTextures.begin(); passIterator != m_renderPassTextures.end(); ++passIterator) { #if WTF_NEW_HASHMAP_ITERATORS_INTERFACE const CCRenderPass* renderPassInFrame = renderPassesInFrame.get(passIterator->key); #else const CCRenderPass* renderPassInFrame = renderPassesInFrame.get(passIterator->first); #endif if (!renderPassInFrame) { #if WTF_NEW_HASHMAP_ITERATORS_INTERFACE passesToDelete.append(passIterator->key); #else passesToDelete.append(passIterator->first); #endif continue; } const IntSize& requiredSize = renderPassTextureSize(renderPassInFrame); GC3Denum requiredFormat = renderPassTextureFormat(renderPassInFrame); #if WTF_NEW_HASHMAP_ITERATORS_INTERFACE CachedTexture* texture = passIterator->value.get(); #else CachedTexture* texture = passIterator->second.get(); #endif ASSERT(texture); if (texture->id() && (texture->size() != requiredSize || texture->format() != requiredFormat)) texture->free(); } // Delete RenderPass textures from the previous frame that will not be used again. for (size_t i = 0; i < passesToDelete.size(); ++i) m_renderPassTextures.remove(passesToDelete[i]); for (size_t i = 0; i < renderPassesInDrawOrder.size(); ++i) { if (!m_renderPassTextures.contains(renderPassesInDrawOrder[i]->id())) { OwnPtr texture = CachedTexture::create(m_resourceProvider); m_renderPassTextures.set(renderPassesInDrawOrder[i]->id(), texture.release()); } } } void CCDirectRenderer::drawFrame(const CCRenderPassList& renderPassesInDrawOrder, const CCRenderPassIdHashMap& renderPassesById) { const CCRenderPass* rootRenderPass = renderPassesInDrawOrder.last(); ASSERT(rootRenderPass); DrawingFrame frame; frame.renderPassesById = &renderPassesById; frame.rootRenderPass = rootRenderPass; frame.rootDamageRect = capabilities().usingPartialSwap ? rootRenderPass->damageRect() : rootRenderPass->outputRect(); frame.rootDamageRect.intersect(IntRect(IntPoint::zero(), viewportSize())); beginDrawingFrame(frame); for (size_t i = 0; i < renderPassesInDrawOrder.size(); ++i) drawRenderPass(frame, renderPassesInDrawOrder[i]); finishDrawingFrame(frame); } void CCDirectRenderer::drawRenderPass(DrawingFrame& frame, const CCRenderPass* renderPass) { if (!useRenderPass(frame, renderPass)) return; frame.scissorRectInRenderPassSpace = frame.currentRenderPass->outputRect(); if (frame.rootDamageRect != frame.rootRenderPass->outputRect()) { WebTransformationMatrix inverseTransformToRoot = frame.currentRenderPass->transformToRootTarget().inverse(); frame.scissorRectInRenderPassSpace.intersect(CCMathUtil::projectClippedRect(inverseTransformToRoot, frame.rootDamageRect)); } enableScissorTestRect(moveScissorToWindowSpace(frame, frame.scissorRectInRenderPassSpace)); clearFramebuffer(frame); const CCQuadList& quadList = renderPass->quadList(); for (CCQuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it) { FloatRect quadScissorRect = frame.scissorRectInRenderPassSpace; quadScissorRect.intersect(it->get()->clippedRectInTarget()); if (!quadScissorRect.isEmpty()) { enableScissorTestRect(moveScissorToWindowSpace(frame, quadScissorRect)); drawQuad(frame, it->get()); } } CachedTexture* texture = m_renderPassTextures.get(renderPass->id()); if (texture) texture->setIsComplete(!renderPass->hasOcclusionFromOutsideTargetSurface()); } bool CCDirectRenderer::useRenderPass(DrawingFrame& frame, const CCRenderPass* renderPass) { frame.currentRenderPass = renderPass; frame.currentTexture = 0; if (renderPass == frame.rootRenderPass) { bindFramebufferToOutputSurface(frame); initializeMatrices(frame, renderPass->outputRect(), true); setDrawViewportSize(renderPass->outputRect().size()); return true; } CachedTexture* texture = m_renderPassTextures.get(renderPass->id()); ASSERT(texture); if (!texture->id() && !texture->allocate(CCRenderer::ImplPool, renderPassTextureSize(renderPass), renderPassTextureFormat(renderPass), CCResourceProvider::TextureUsageFramebuffer)) return false; return bindFramebufferToTexture(frame, texture, renderPass->outputRect()); } bool CCDirectRenderer::haveCachedResourcesForRenderPassId(CCRenderPass::Id id) const { CachedTexture* texture = m_renderPassTextures.get(id); return texture && texture->id() && texture->isComplete(); } // static IntSize CCDirectRenderer::renderPassTextureSize(const CCRenderPass* pass) { return pass->outputRect().size(); } // static GC3Denum CCDirectRenderer::renderPassTextureFormat(const CCRenderPass*) { return GraphicsContext3D::RGBA; } }