Commit 2cfc8956 authored by junov@chromium.org's avatar junov@chromium.org

Making display list canvases fall back to gpu-accelerated when appropriate

BUG=392606
TEST=RecordingImageBufferSurfaceTest

Review URL: https://codereview.chromium.org/659873002

git-svn-id: svn://svn.chromium.org/blink/trunk@183824 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent f7a8d843
...@@ -473,6 +473,47 @@ bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const ...@@ -473,6 +473,47 @@ bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const
return true; return true;
} }
class UnacceleratedSurfaceFactory : public RecordingImageBufferFallbackSurfaceFactory {
public:
virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize& size, OpacityMode opacityMode)
{
return adoptPtr(new UnacceleratedImageBufferSurface(size, opacityMode));
}
virtual ~UnacceleratedSurfaceFactory() { }
};
class Accelerated2dSurfaceFactory : public RecordingImageBufferFallbackSurfaceFactory {
public:
Accelerated2dSurfaceFactory(int msaaSampleCount) : m_msaaSampleCount(msaaSampleCount) { }
virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize& size, OpacityMode opacityMode)
{
OwnPtr<ImageBufferSurface> surface = adoptPtr(new Canvas2DImageBufferSurface(size, opacityMode, m_msaaSampleCount));
if (surface->isValid())
return surface.release();
return adoptPtr(new UnacceleratedImageBufferSurface(size, opacityMode));
}
virtual ~Accelerated2dSurfaceFactory() { }
private:
int m_msaaSampleCount;
};
PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> HTMLCanvasElement::createSurfaceFactory(const IntSize& deviceSize, int* msaaSampleCount) const
{
*msaaSampleCount = 0;
OwnPtr<RecordingImageBufferFallbackSurfaceFactory> surfaceFactory;
if (shouldAccelerate(deviceSize)) {
if (document().settings())
*msaaSampleCount = document().settings()->accelerated2dCanvasMSAASampleCount();
surfaceFactory = adoptPtr(new Accelerated2dSurfaceFactory(*msaaSampleCount));
} else {
surfaceFactory = adoptPtr(new UnacceleratedSurfaceFactory());
}
return surfaceFactory.release();
}
PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const IntSize& deviceSize, int* msaaSampleCount) PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const IntSize& deviceSize, int* msaaSampleCount)
{ {
OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque; OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque;
...@@ -486,25 +527,20 @@ PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const ...@@ -486,25 +527,20 @@ PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const
// FIXME: Actually, avoid setting m_accelerationDisabled at all when // FIXME: Actually, avoid setting m_accelerationDisabled at all when
// doing GPU-based rasterization. // doing GPU-based rasterization.
if (m_accelerationDisabled) if (m_accelerationDisabled)
return adoptPtr(new UnacceleratedImageBufferSurface(size(), opacityMode)); return adoptPtr(new UnacceleratedImageBufferSurface(deviceSize, opacityMode));
return adoptPtr(new WebGLImageBufferSurface(size(), opacityMode)); return adoptPtr(new WebGLImageBufferSurface(deviceSize, opacityMode));
} }
if (RuntimeEnabledFeatures::displayList2dCanvasEnabled()) { OwnPtr<RecordingImageBufferFallbackSurfaceFactory> surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount);
OwnPtr<ImageBufferSurface> surface = adoptPtr(new RecordingImageBufferSurface(size(), opacityMode));
if (surface->isValid())
return surface.release();
}
if (shouldAccelerate(deviceSize)) { if (RuntimeEnabledFeatures::displayList2dCanvasEnabled()) {
if (document().settings()) OwnPtr<ImageBufferSurface> surface = adoptPtr(new RecordingImageBufferSurface(deviceSize, surfaceFactory.release(), opacityMode));
*msaaSampleCount = document().settings()->accelerated2dCanvasMSAASampleCount();
OwnPtr<ImageBufferSurface> surface = adoptPtr(new Canvas2DImageBufferSurface(size(), opacityMode, *msaaSampleCount));
if (surface->isValid()) if (surface->isValid())
return surface.release(); return surface.release();
surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // recreate because old previous one was released
} }
return adoptPtr(new UnacceleratedImageBufferSurface(size(), opacityMode)); return surfaceFactory->createSurface(deviceSize, opacityMode);
} }
void HTMLCanvasElement::createImageBuffer() void HTMLCanvasElement::createImageBuffer()
......
...@@ -55,6 +55,7 @@ class ImageData; ...@@ -55,6 +55,7 @@ class ImageData;
class ImageBuffer; class ImageBuffer;
class ImageBufferSurface; class ImageBufferSurface;
class IntSize; class IntSize;
class RecordingImageBufferFallbackSurfaceFactory;
class CanvasObserver : public WillBeGarbageCollectedMixin { class CanvasObserver : public WillBeGarbageCollectedMixin {
DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver);
...@@ -174,6 +175,7 @@ private: ...@@ -174,6 +175,7 @@ private:
void reset(); void reset();
PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> createSurfaceFactory(const IntSize& deviceSize, int* msaaSampleCount) const;
PassOwnPtr<ImageBufferSurface> createImageBufferSurface(const IntSize& deviceSize, int* msaaSampleCount); PassOwnPtr<ImageBufferSurface> createImageBufferSurface(const IntSize& deviceSize, int* msaaSampleCount);
void createImageBuffer(); void createImageBuffer();
void createImageBufferInternal(); void createImageBufferInternal();
......
...@@ -16,11 +16,12 @@ ...@@ -16,11 +16,12 @@
namespace blink { namespace blink {
RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize& size, OpacityMode opacityMode) RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize& size, PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> fallbackFactory, OpacityMode opacityMode)
: ImageBufferSurface(size, opacityMode) : ImageBufferSurface(size, opacityMode)
, m_imageBuffer(0) , m_imageBuffer(0)
, m_initialSaveCount(0) , m_initialSaveCount(0)
, m_frameWasCleared(true) , m_frameWasCleared(true)
, m_fallbackFactory(fallbackFactory)
{ {
initializeCurrentFrame(); initializeCurrentFrame();
} }
...@@ -60,42 +61,49 @@ void RecordingImageBufferSurface::setImageBuffer(ImageBuffer* imageBuffer) ...@@ -60,42 +61,49 @@ void RecordingImageBufferSurface::setImageBuffer(ImageBuffer* imageBuffer)
m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite); m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas()); m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
} }
if (m_fallbackSurface) {
m_fallbackSurface->setImageBuffer(imageBuffer);
}
} }
void RecordingImageBufferSurface::willAccessPixels() void RecordingImageBufferSurface::willAccessPixels()
{ {
if (m_fallbackSurface)
m_fallbackSurface->willAccessPixels();
else
fallBackToRasterCanvas(); fallBackToRasterCanvas();
} }
void RecordingImageBufferSurface::fallBackToRasterCanvas() void RecordingImageBufferSurface::fallBackToRasterCanvas()
{ {
if (m_rasterCanvas) { if (m_fallbackSurface) {
ASSERT(!m_currentFrame); ASSERT(!m_currentFrame);
return; return;
} }
m_rasterCanvas = adoptPtr(SkCanvas::NewRasterN32(size().width(), size().height())); m_fallbackSurface = m_fallbackFactory->createSurface(size(), opacityMode());
m_fallbackSurface->setImageBuffer(m_imageBuffer);
if (m_previousFrame) { if (m_previousFrame) {
m_previousFrame->draw(m_rasterCanvas.get()); m_previousFrame->draw(m_fallbackSurface->canvas());
m_previousFrame.clear(); m_previousFrame.clear();
} }
if (m_currentFrame) { if (m_currentFrame) {
RefPtr<SkPicture> currentPicture = adoptRef(m_currentFrame->endRecording()); RefPtr<SkPicture> currentPicture = adoptRef(m_currentFrame->endRecording());
currentPicture->draw(m_rasterCanvas.get()); currentPicture->draw(m_fallbackSurface->canvas());
m_currentFrame.clear(); m_currentFrame.clear();
} }
if (m_imageBuffer) { if (m_imageBuffer) {
m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingDisabled); m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingDisabled);
m_imageBuffer->context()->resetCanvas(m_rasterCanvas.get()); m_imageBuffer->context()->resetCanvas(m_fallbackSurface->canvas());
} }
} }
SkCanvas* RecordingImageBufferSurface::canvas() const SkCanvas* RecordingImageBufferSurface::canvas() const
{ {
if (m_rasterCanvas) if (m_fallbackSurface)
return m_rasterCanvas.get(); return m_fallbackSurface->canvas();
ASSERT(m_currentFrame->getRecordingCanvas()); ASSERT(m_currentFrame->getRecordingCanvas());
return m_currentFrame->getRecordingCanvas(); return m_currentFrame->getRecordingCanvas();
...@@ -103,6 +111,9 @@ SkCanvas* RecordingImageBufferSurface::canvas() const ...@@ -103,6 +111,9 @@ SkCanvas* RecordingImageBufferSurface::canvas() const
PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture() PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
{ {
if (m_fallbackSurface)
return nullptr;
bool canUsePicture = finalizeFrameInternal(); bool canUsePicture = finalizeFrameInternal();
m_imageBuffer->didFinalizeFrame(); m_imageBuffer->didFinalizeFrame();
...@@ -110,25 +121,35 @@ PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture() ...@@ -110,25 +121,35 @@ PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
return m_previousFrame; return m_previousFrame;
} }
if (!m_rasterCanvas) if (!m_fallbackSurface)
fallBackToRasterCanvas(); fallBackToRasterCanvas();
return nullptr; return nullptr;
} }
void RecordingImageBufferSurface::finalizeFrame(const FloatRect &) void RecordingImageBufferSurface::finalizeFrame(const FloatRect &dirtyRect)
{ {
if (!finalizeFrameInternal() && !m_rasterCanvas) { if (m_fallbackSurface) {
fallBackToRasterCanvas(); m_fallbackSurface->finalizeFrame(dirtyRect);
return;
} }
if (!finalizeFrameInternal())
fallBackToRasterCanvas();
} }
void RecordingImageBufferSurface::didClearCanvas() void RecordingImageBufferSurface::didClearCanvas()
{ {
if (m_fallbackSurface) {
m_fallbackSurface->didClearCanvas();
return;
}
m_frameWasCleared = true; m_frameWasCleared = true;
} }
bool RecordingImageBufferSurface::finalizeFrameInternal() bool RecordingImageBufferSurface::finalizeFrameInternal()
{ {
ASSERT(!m_fallbackSurface);
if (!m_imageBuffer->isDirty()) { if (!m_imageBuffer->isDirty()) {
if (m_currentFrame && !m_previousFrame) { if (m_currentFrame && !m_previousFrame) {
// Create an initial blank frame // Create an initial blank frame
...@@ -138,10 +159,6 @@ bool RecordingImageBufferSurface::finalizeFrameInternal() ...@@ -138,10 +159,6 @@ bool RecordingImageBufferSurface::finalizeFrameInternal()
return m_currentFrame; return m_currentFrame;
} }
if (!m_currentFrame) {
return false;
}
IntRect canvasRect(IntPoint(0, 0), size()); IntRect canvasRect(IntPoint(0, 0), size());
if (!m_frameWasCleared && !m_imageBuffer->context()->opaqueRegion().asRect().contains(canvasRect)) { if (!m_frameWasCleared && !m_imageBuffer->context()->opaqueRegion().asRect().contains(canvasRect)) {
return false; return false;
...@@ -194,4 +211,79 @@ void RecordingImageBufferSurface::setCurrentState(SkCanvas* dstCanvas, StateStac ...@@ -194,4 +211,79 @@ void RecordingImageBufferSurface::setCurrentState(SkCanvas* dstCanvas, StateStac
dstCanvas->setMatrix(stateStack->peek().m_ctm); dstCanvas->setMatrix(stateStack->peek().m_ctm);
} }
// Fallback passthroughs
const SkBitmap& RecordingImageBufferSurface::bitmap()
{
if (m_fallbackSurface)
return m_fallbackSurface->bitmap();
return ImageBufferSurface::bitmap();
}
bool RecordingImageBufferSurface::restore()
{
if (m_fallbackSurface)
return m_fallbackSurface->restore();
return ImageBufferSurface::restore();
}
WebLayer* RecordingImageBufferSurface::layer() const
{
if (m_fallbackSurface)
return m_fallbackSurface->layer();
return ImageBufferSurface::layer();
}
bool RecordingImageBufferSurface::isAccelerated() const
{
if (m_fallbackSurface)
return m_fallbackSurface->isAccelerated();
return ImageBufferSurface::isAccelerated();
}
Platform3DObject RecordingImageBufferSurface::getBackingTexture() const
{
if (m_fallbackSurface)
return m_fallbackSurface->getBackingTexture();
return ImageBufferSurface::getBackingTexture();
}
bool RecordingImageBufferSurface::cachedBitmapEnabled() const
{
if (m_fallbackSurface)
return m_fallbackSurface->cachedBitmapEnabled();
return ImageBufferSurface::cachedBitmapEnabled();
}
const SkBitmap& RecordingImageBufferSurface::cachedBitmap() const
{
if (m_fallbackSurface)
return m_fallbackSurface->cachedBitmap();
return ImageBufferSurface::cachedBitmap();
}
void RecordingImageBufferSurface::invalidateCachedBitmap()
{
if (m_fallbackSurface)
m_fallbackSurface->invalidateCachedBitmap();
else
ImageBufferSurface::invalidateCachedBitmap();
}
void RecordingImageBufferSurface::updateCachedBitmapIfNeeded()
{
if (m_fallbackSurface)
m_fallbackSurface->updateCachedBitmapIfNeeded();
else
ImageBufferSurface::updateCachedBitmapIfNeeded();
}
void RecordingImageBufferSurface::setIsHidden(bool hidden)
{
if (m_fallbackSurface)
m_fallbackSurface->setIsHidden(hidden);
else
ImageBufferSurface::setIsHidden(hidden);
}
} // namespace blink } // namespace blink
...@@ -20,10 +20,16 @@ namespace blink { ...@@ -20,10 +20,16 @@ namespace blink {
class ImageBuffer; class ImageBuffer;
class RecordingImageBufferFallbackSurfaceFactory {
public:
virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize&, OpacityMode) = 0;
virtual ~RecordingImageBufferFallbackSurfaceFactory() { }
};
class PLATFORM_EXPORT RecordingImageBufferSurface : public ImageBufferSurface { class PLATFORM_EXPORT RecordingImageBufferSurface : public ImageBufferSurface {
WTF_MAKE_NONCOPYABLE(RecordingImageBufferSurface); WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(RecordingImageBufferSurface); WTF_MAKE_FAST_ALLOCATED;
public: public:
RecordingImageBufferSurface(const IntSize&, OpacityMode = NonOpaque); RecordingImageBufferSurface(const IntSize&, PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> fallbackFactory, OpacityMode = NonOpaque);
virtual ~RecordingImageBufferSurface(); virtual ~RecordingImageBufferSurface();
// Implementation of ImageBufferSurface interfaces // Implementation of ImageBufferSurface interfaces
...@@ -35,6 +41,18 @@ public: ...@@ -35,6 +41,18 @@ public:
virtual void didClearCanvas() override; virtual void didClearCanvas() override;
virtual void setImageBuffer(ImageBuffer*) override; virtual void setImageBuffer(ImageBuffer*) override;
// Passthroughs to fallback surface
virtual const SkBitmap& bitmap() override;
virtual bool restore() override;
virtual WebLayer* layer() const override;
virtual bool isAccelerated() const override;
virtual Platform3DObject getBackingTexture() const override;
virtual bool cachedBitmapEnabled() const override;
virtual const SkBitmap& cachedBitmap() const override;
virtual void invalidateCachedBitmap() override;
virtual void updateCachedBitmapIfNeeded() override;
virtual void setIsHidden(bool) override;
private: private:
struct StateRec { struct StateRec {
public: public:
...@@ -55,10 +73,11 @@ private: ...@@ -55,10 +73,11 @@ private:
OwnPtr<SkPictureRecorder> m_currentFrame; OwnPtr<SkPictureRecorder> m_currentFrame;
RefPtr<SkPicture> m_previousFrame; RefPtr<SkPicture> m_previousFrame;
OwnPtr<SkCanvas> m_rasterCanvas; OwnPtr<ImageBufferSurface> m_fallbackSurface;
ImageBuffer* m_imageBuffer; ImageBuffer* m_imageBuffer;
int m_initialSaveCount; int m_initialSaveCount;
bool m_frameWasCleared; bool m_frameWasCleared;
OwnPtr<RecordingImageBufferFallbackSurfaceFactory> m_fallbackFactory;
}; };
} // namespace blink } // namespace blink
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBuffer.h" #include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/ImageBufferClient.h" #include "platform/graphics/ImageBufferClient.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "public/platform/WebThread.h" #include "public/platform/WebThread.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
...@@ -73,13 +74,33 @@ private: ...@@ -73,13 +74,33 @@ private:
int m_frameCount; int m_frameCount;
}; };
class MockSurfaceFactory : public RecordingImageBufferFallbackSurfaceFactory {
public:
MockSurfaceFactory() : m_createSurfaceCount(0) { }
virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize& size, OpacityMode opacityMode)
{
m_createSurfaceCount++;
return adoptPtr(new UnacceleratedImageBufferSurface(size, opacityMode));
}
virtual ~MockSurfaceFactory() { }
int createSurfaceCount() { return m_createSurfaceCount; }
private:
int m_createSurfaceCount;
};
} // unnamed namespace } // unnamed namespace
class RecordingImageBufferSurfaceTest : public Test { class RecordingImageBufferSurfaceTest : public Test {
protected: protected:
RecordingImageBufferSurfaceTest() RecordingImageBufferSurfaceTest()
{ {
OwnPtr<RecordingImageBufferSurface> testSurface = adoptPtr(new RecordingImageBufferSurface(IntSize(10, 10))); OwnPtr<MockSurfaceFactory> surfaceFactory = adoptPtr(new MockSurfaceFactory());
m_surfaceFactory = surfaceFactory.get();
OwnPtr<RecordingImageBufferSurface> testSurface = adoptPtr(new RecordingImageBufferSurface(IntSize(10, 10), surfaceFactory.release()));
m_testSurface = testSurface.get(); m_testSurface = testSurface.get();
// We create an ImageBuffer in order for the testSurface to be // We create an ImageBuffer in order for the testSurface to be
// properly initialized with a GraphicsContext // properly initialized with a GraphicsContext
...@@ -125,6 +146,7 @@ public: ...@@ -125,6 +146,7 @@ public:
m_fakeImageBufferClient->fakeDraw(); m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture(); m_testSurface->getPicture();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
EXPECT_EQ(0, m_surfaceFactory->createSurfaceCount());
expectDisplayListEnabled(true); // first frame has an implicit clear expectDisplayListEnabled(true); // first frame has an implicit clear
m_fakeImageBufferClient->fakeDraw(); m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture(); m_testSurface->getPicture();
...@@ -155,10 +177,10 @@ public: ...@@ -155,10 +177,10 @@ public:
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false); expectDisplayListEnabled(false);
m_testSurface->getPicture(); m_testSurface->getPicture();
EXPECT_EQ(4, m_fakeImageBufferClient->frameCount()); EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false); expectDisplayListEnabled(false);
m_fakeImageBufferClient->fakeDraw(); m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(4, m_fakeImageBufferClient->frameCount()); EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false); expectDisplayListEnabled(false);
} }
...@@ -196,10 +218,13 @@ public: ...@@ -196,10 +218,13 @@ public:
void expectDisplayListEnabled(bool displayListEnabled) void expectDisplayListEnabled(bool displayListEnabled)
{ {
EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get()); EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get());
EXPECT_EQ(!displayListEnabled, (bool)m_testSurface->m_rasterCanvas.get()); EXPECT_EQ(!displayListEnabled, (bool)m_testSurface->m_fallbackSurface.get());
int expectedSurfaceCreationCount = displayListEnabled ? 0 : 1;
EXPECT_EQ(expectedSurfaceCreationCount, m_surfaceFactory->createSurfaceCount());
} }
private: private:
MockSurfaceFactory* m_surfaceFactory;
RecordingImageBufferSurface* m_testSurface; RecordingImageBufferSurface* m_testSurface;
OwnPtr<FakeImageBufferClient> m_fakeImageBufferClient; OwnPtr<FakeImageBufferClient> m_fakeImageBufferClient;
OwnPtr<ImageBuffer> m_imageBuffer; OwnPtr<ImageBuffer> m_imageBuffer;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment