Diff
Modified: trunk/Source/WebCore/ChangeLog (122251 => 122252)
--- trunk/Source/WebCore/ChangeLog 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebCore/ChangeLog 2012-07-10 20:14:36 UTC (rev 122252)
@@ -1,3 +1,45 @@
+2012-07-10 Dana Jansens <[email protected]>
+
+ [chromium] Avoid allocating render pass textures that have no content
+ https://bugs.webkit.org/show_bug.cgi?id=90702
+
+ Reviewed by Adrienne Walker.
+
+ When OOM conditions are hit, textures are not allocated for some layers
+ which can prevent any quads from being present for a render surface.
+ This is used as a signal to prevent the RenderPass from allocating a
+ texture.
+
+ Replace the CCLayerTreeHostImpl::removePassesWithCachedTextures() method
+ with a general removeRenderPasses() which takes a culling control object
+ and will remove passes based on the inputs from the control object.
+
+ This new method is used for the old purpose of removing passes with cached
+ textures, as well as to remove passes that do not have any quad inputs.
+
+ Test: CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
+
+ * platform/graphics/chromium/LayerRendererChromium.cpp:
+ (WebCore::LayerRendererChromium::drawRenderPassQuad):
+ * platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
+ (WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
+ (WebCore):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRenderPass):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass):
+ (WebCore::CCLayerTreeHostImpl::removeRenderPasses):
+ * platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
+ (WebCore):
+ (CullRenderPassesWithCachedTextures):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::renderPassListBegin):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::renderPassListEnd):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::renderPassListNext):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::CullRenderPassesWithCachedTextures):
+ (CCLayerTreeHostImpl):
+ (CullRenderPassesWithNoQuads):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::renderPassListBegin):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::renderPassListEnd):
+ (WebCore::CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::renderPassListNext):
+
2012-07-10 Joshua Netterfield <[email protected]>
Make GC3D and E3D more maintainable for GLES platforms
https://bugs.webkit.org/show_bug.cgi?id=90567
Modified: trunk/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp (122251 => 122252)
--- trunk/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp 2012-07-10 20:14:36 UTC (rev 122252)
@@ -612,6 +612,10 @@
void LayerRendererChromium::drawRenderPassQuad(const CCRenderPassDrawQuad* quad)
{
+ ManagedTexture* contentsTexture = m_renderPassTextures.get(quad->renderPassId());
+ if (!contentsTexture || !contentsTexture->textureId())
+ return;
+
WebTransformationMatrix renderTransform = quad->layerTransform();
// Apply a scaling factor to size the quad from 1x1 to its intended size.
renderTransform.scale3d(quad->quadRect().width(), quad->quadRect().height(), 1);
@@ -621,9 +625,6 @@
if (!contentsDeviceTransform.isInvertible())
return;
- ManagedTexture* contentsTexture = m_renderPassTextures.get(quad->renderPassId());
- ASSERT(contentsTexture && contentsTexture->textureId());
-
OwnPtr<ManagedTexture> backgroundTexture = drawBackgroundFilters(quad, contentsDeviceTransform);
// FIXME: Cache this value so that we don't have to do it for both the surface and its replica.
Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp (122251 => 122252)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp 2012-07-10 20:14:36 UTC (rev 122252)
@@ -353,8 +353,9 @@
if (drawFrame)
occlusionTracker.overdrawMetrics().recordMetrics(this);
+ removeRenderPasses(CullRenderPassesWithNoQuads(), frame);
m_layerRenderer->decideRenderPassAllocationsForFrame(frame.renderPasses);
- removePassesWithCachedTextures(frame.renderPasses, frame.skippedPasses, m_layerRenderer.get());
+ removeRenderPasses(CullRenderPassesWithCachedTextures(*m_layerRenderer), frame);
return drawFrame;
}
@@ -405,6 +406,7 @@
return m_rootScrollLayerImpl->children()[0]->contentBounds();
}
+// static
void CCLayerTreeHostImpl::removeRenderPassesRecursive(CCRenderPassList& passes, size_t bottomPass, const CCRenderPass* firstToRemove, CCRenderPassList& skippedPasses)
{
size_t removeIndex = passes.find(firstToRemove);
@@ -434,10 +436,41 @@
skippedPasses.append(removedPass.release());
}
-void CCLayerTreeHostImpl::removePassesWithCachedTextures(CCRenderPassList& passes, CCRenderPassList& skippedPasses, const CCRenderer* renderer)
+bool CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRenderPass(const CCRenderPassList&, const CCRenderPassDrawQuad& quad) const
{
- for (int passIndex = passes.size() - 1; passIndex >= 0; --passIndex) {
- CCRenderPass* currentPass = passes[passIndex].get();
+ return quad.contentsChangedSinceLastFrame().isEmpty() && m_renderer.haveCachedResourcesForRenderPassId(quad.renderPassId());
+}
+
+bool CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(const CCRenderPassList& passList, const CCRenderPassDrawQuad& quad) const
+{
+ size_t passIndex = passList.find(quad.renderPass());
+ ASSERT(passIndex != notFound);
+
+ // If any quad or RenderPass draws into this RenderPass, then keep it.
+ const CCQuadList& quadList = passList[passIndex]->quadList();
+ for (CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
+ CCDrawQuad* currentQuad = quadListIterator->get();
+
+ if (currentQuad->material() != CCDrawQuad::RenderPass)
+ return false;
+
+ const CCRenderPassDrawQuad* quadInPass = static_cast<CCRenderPassDrawQuad*>(currentQuad);
+ if (passList.contains(quadInPass->renderPass()))
+ return false;
+ }
+ return true;
+}
+
+// Defined for linking tests.
+template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&);
+template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullRenderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&);
+
+// static
+template<typename RenderPassCuller>
+void CCLayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData& frame)
+{
+ for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culler.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) {
+ CCRenderPass* currentPass = frame.renderPasses[it].get();
const CCQuadList& quadList = currentPass->quadList();
CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
@@ -448,18 +481,18 @@
continue;
CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQuad*>(currentQuad);
- if (!renderPassQuad->contentsChangedSinceLastFrame().isEmpty())
+ if (!culler.shouldRemoveRenderPass(frame.renderPasses, *renderPassQuad))
continue;
- if (!renderer->haveCachedResourcesForRenderPassId(renderPassQuad->renderPassId()))
- continue;
- // We are changing the vector in the middle of reverse iteration.
- // We are guaranteed that any data from iterator to the end will not change.
- // Capture the iterator position from the end, and restore it after the change.
- int positionFromEnd = passes.size() - passIndex;
- removeRenderPassesRecursive(passes, passIndex, renderPassQuad->renderPass(), skippedPasses);
- passIndex = passes.size() - positionFromEnd;
- ASSERT(passIndex >= 0);
+ // We are changing the vector in the middle of iteration. Because we
+ // delete render passes that draw into the current pass, we are
+ // guaranteed that any data from the iterator to the end will not
+ // change. So, capture the iterator position from the end of the
+ // list, and restore it after the change.
+ int positionFromEnd = frame.renderPasses.size() - it;
+ removeRenderPassesRecursive(frame.renderPasses, it, renderPassQuad->renderPass(), frame.skippedPasses);
+ it = frame.renderPasses.size() - positionFromEnd;
+ ASSERT(it >= 0);
}
}
}
Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h (122251 => 122252)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h 2012-07-10 20:14:36 UTC (rev 122252)
@@ -42,9 +42,10 @@
class CCFontAtlas;
class CCFrameRateCounter;
class CCHeadsUpDisplay;
-class CCPageScaleAnimation;
class CCLayerImpl;
class CCLayerTreeHostImplTimeSourceAdapter;
+class CCPageScaleAnimation;
+class CCRenderPassDrawQuad;
class LayerRendererChromium;
class TextureAllocator;
struct LayerRendererCapabilities;
@@ -177,9 +178,36 @@
CCFrameRateCounter* fpsCounter() const { return m_fpsCounter.get(); }
CCDebugRectHistory* debugRectHistory() const { return m_debugRectHistory.get(); }
- // Removes all render passes for which we have cached textures, and which did not change their content.
- static void removePassesWithCachedTextures(CCRenderPassList& passes, CCRenderPassList& skippedPasses, const CCRenderer*);
+ class CullRenderPassesWithCachedTextures {
+ public:
+ bool shouldRemoveRenderPass(const CCRenderPassList&, const CCRenderPassDrawQuad&) const;
+ // Iterates from the root first, in order to remove the surfaces closest
+ // to the root with cached textures, and all surfaces that draw into
+ // them.
+ size_t renderPassListBegin(const CCRenderPassList& list) const { return list.size() - 1; }
+ size_t renderPassListEnd(const CCRenderPassList&) const { return 0 - 1; }
+ size_t renderPassListNext(size_t it) const { return it - 1; }
+
+ CullRenderPassesWithCachedTextures(CCRenderer& renderer) : m_renderer(renderer) { }
+ private:
+ CCRenderer& m_renderer;
+ };
+
+ class CullRenderPassesWithNoQuads {
+ public:
+ bool shouldRemoveRenderPass(const CCRenderPassList&, const CCRenderPassDrawQuad&) const;
+
+ // Iterates in draw order, so that when a surface is removed, and its
+ // target becomes empty, then its target can be removed also.
+ size_t renderPassListBegin(const CCRenderPassList&) const { return 0; }
+ size_t renderPassListEnd(const CCRenderPassList& list) const { return list.size(); }
+ size_t renderPassListNext(size_t it) const { return it + 1; }
+ };
+
+ template<typename RenderPassCuller>
+ static void removeRenderPasses(RenderPassCuller, FrameData&);
+
protected:
CCLayerTreeHostImpl(const CCLayerTreeSettings&, CCLayerTreeHostImplClient*);
Modified: trunk/Source/WebKit/chromium/ChangeLog (122251 => 122252)
--- trunk/Source/WebKit/chromium/ChangeLog 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebKit/chromium/ChangeLog 2012-07-10 20:14:36 UTC (rev 122252)
@@ -1,3 +1,21 @@
+2012-07-10 Dana Jansens <[email protected]>
+
+ [chromium] Avoid allocating render pass textures that have no content
+ https://bugs.webkit.org/show_bug.cgi?id=90702
+
+ Reviewed by Adrienne Walker.
+
+ * tests/CCLayerTreeHostImplTest.cpp:
+ * tests/CCLayerTreeHostTest.cpp:
+ (WTF::ContentLayerChromiumWithUpdateTracking::ContentLayerChromiumWithUpdateTracking):
+ (CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit):
+ (WTF::CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit::CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit):
+ (WTF::CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit::beginTest):
+ (WTF::CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit::didCommit):
+ (WTF::CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit::drawLayersOnCCThread):
+ (WTF::CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit::afterTest):
+ (WTF):
+
2012-07-10 Leandro Gracia Gil <[email protected]>
Unreviewed Chromium build fix for mac-release.
Modified: trunk/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp (122251 => 122252)
--- trunk/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp 2012-07-10 20:14:36 UTC (rev 122252)
@@ -2877,8 +2877,7 @@
}
};
-struct RenderPassRemovalTestData {
- CCRenderPassList renderPassList;
+struct RenderPassRemovalTestData : public CCLayerTreeHostImpl::FrameData {
std::map<char, RenderPassCacheEntry> renderPassCache;
std::map<const CCRenderPass*, char> renderPassId;
Vector<OwnPtr<CCRenderSurface> > renderSurfaceStore;
@@ -3019,7 +3018,7 @@
static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.release());
}
}
- testData.renderPassList.insert(0, renderPass.release());
+ testData.renderPasses.insert(0, renderPass.release());
if (*currentChar)
currentChar++;
}
@@ -3028,8 +3027,7 @@
void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buffer)
{
char* pos = buffer;
- CCRenderPassList::const_reverse_iterator it = testData.renderPassList.rbegin();
- while (it != testData.renderPassList.rend()) {
+ for (CCRenderPassList::const_reverse_iterator it = testData.renderPasses.rbegin(); it != testData.renderPasses.rend(); ++it) {
CCRenderPass* currentPass = it->get();
char passId = testData.renderPassId.find(currentPass)->second;
*pos = passId;
@@ -3061,7 +3059,6 @@
}
*pos = '\n';
pos++;
- it++;
}
*pos = '\0';
}
@@ -3224,9 +3221,8 @@
int testCaseIndex = 0;
while (removeRenderPassesCases[testCaseIndex].name) {
RenderPassRemovalTestData testData;
- CCRenderPassList skippedPasses;
configureRenderPassTestData(removeRenderPassesCases[testCaseIndex].initScript, testData, renderer.get());
- CCLayerTreeHostImpl::removePassesWithCachedTextures(testData.renderPassList, skippedPasses, renderer.get());
+ CCLayerTreeHostImpl::removeRenderPasses(CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures(*renderer), testData);
verifyRenderPassTestData(removeRenderPassesCases[testCaseIndex], testData);
testCaseIndex++;
}
Modified: trunk/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp (122251 => 122252)
--- trunk/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp 2012-07-10 19:56:37 UTC (rev 122251)
+++ trunk/Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp 2012-07-10 20:14:36 UTC (rev 122252)
@@ -1171,6 +1171,7 @@
: ContentLayerChromium(delegate)
, m_paintContentsCount(0)
{
+ setAnchorPoint(FloatPoint(0, 0));
setBounds(IntSize(10, 10));
setIsDrawable(true);
}
@@ -2261,4 +2262,75 @@
SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestCompositeAndReadbackCleanup)
+class CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit : public CCLayerTreeHostTest {
+public:
+ CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit()
+ : m_rootLayer(ContentLayerChromiumWithUpdateTracking::create(&m_mockDelegate))
+ , m_surfaceLayer1(ContentLayerChromiumWithUpdateTracking::create(&m_mockDelegate))
+ , m_surfaceLayer2(ContentLayerChromiumWithUpdateTracking::create(&m_mockDelegate))
+ {
+ }
+
+ virtual void beginTest()
+ {
+ m_layerTreeHost->setViewportSize(IntSize(100, 100));
+
+ m_rootLayer->setBounds(IntSize(100, 100));
+ m_surfaceLayer1->setBounds(IntSize(100, 100));
+ m_surfaceLayer1->setForceRenderSurface(true);
+ m_surfaceLayer1->setOpacity(0.5);
+ m_surfaceLayer2->setBounds(IntSize(100, 100));
+ m_surfaceLayer2->setForceRenderSurface(true);
+ m_surfaceLayer2->setOpacity(0.5);
+
+ m_rootLayer->addChild(m_surfaceLayer1);
+ m_surfaceLayer1->addChild(m_surfaceLayer2);
+ m_layerTreeHost->setRootLayer(m_rootLayer);
+ }
+
+ virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* hostImpl)
+ {
+ CCRenderer* renderer = hostImpl->layerRenderer();
+ unsigned surface1RenderPassId = hostImpl->rootLayer()->children()[0]->id();
+ unsigned surface2RenderPassId = hostImpl->rootLayer()->children()[0]->children()[0]->id();
+
+ switch (hostImpl->sourceFrameNumber()) {
+ case 0:
+ EXPECT_TRUE(renderer->haveCachedResourcesForRenderPassId(surface1RenderPassId));
+ EXPECT_TRUE(renderer->haveCachedResourcesForRenderPassId(surface2RenderPassId));
+
+ // Reduce the memory limit to only fit the root layer and one render surface. This
+ // prevents any contents drawing into surfaces from being allocated.
+ hostImpl->setMemoryAllocationLimitBytes(100 * 100 * 4 * 2);
+ break;
+ case 1:
+ EXPECT_FALSE(renderer->haveCachedResourcesForRenderPassId(surface1RenderPassId));
+ EXPECT_FALSE(renderer->haveCachedResourcesForRenderPassId(surface2RenderPassId));
+
+ endTest();
+ break;
+ }
+ }
+
+ virtual void afterTest()
+ {
+ EXPECT_EQ(2, m_rootLayer->paintContentsCount());
+ EXPECT_EQ(2, m_surfaceLayer1->paintContentsCount());
+ EXPECT_EQ(2, m_surfaceLayer2->paintContentsCount());
+
+ // Clear layer references so CCLayerTreeHost dies.
+ m_rootLayer.clear();
+ m_surfaceLayer1.clear();
+ m_surfaceLayer2.clear();
+ }
+
+private:
+ MockContentLayerDelegate m_mockDelegate;
+ RefPtr<ContentLayerChromiumWithUpdateTracking> m_rootLayer;
+ RefPtr<ContentLayerChromiumWithUpdateTracking> m_surfaceLayer1;
+ RefPtr<ContentLayerChromiumWithUpdateTracking> m_surfaceLayer2;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit)
+
} // namespace