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
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)
{
OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque;
......@@ -486,25 +527,20 @@ PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const
// FIXME: Actually, avoid setting m_accelerationDisabled at all when
// doing GPU-based rasterization.
if (m_accelerationDisabled)
return adoptPtr(new UnacceleratedImageBufferSurface(size(), opacityMode));
return adoptPtr(new WebGLImageBufferSurface(size(), opacityMode));
return adoptPtr(new UnacceleratedImageBufferSurface(deviceSize, opacityMode));
return adoptPtr(new WebGLImageBufferSurface(deviceSize, opacityMode));
}
if (RuntimeEnabledFeatures::displayList2dCanvasEnabled()) {
OwnPtr<ImageBufferSurface> surface = adoptPtr(new RecordingImageBufferSurface(size(), opacityMode));
if (surface->isValid())
return surface.release();
}
OwnPtr<RecordingImageBufferFallbackSurfaceFactory> surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount);
if (shouldAccelerate(deviceSize)) {
if (document().settings())
*msaaSampleCount = document().settings()->accelerated2dCanvasMSAASampleCount();
OwnPtr<ImageBufferSurface> surface = adoptPtr(new Canvas2DImageBufferSurface(size(), opacityMode, *msaaSampleCount));
if (RuntimeEnabledFeatures::displayList2dCanvasEnabled()) {
OwnPtr<ImageBufferSurface> surface = adoptPtr(new RecordingImageBufferSurface(deviceSize, surfaceFactory.release(), opacityMode));
if (surface->isValid())
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()
......
......@@ -55,6 +55,7 @@ class ImageData;
class ImageBuffer;
class ImageBufferSurface;
class IntSize;
class RecordingImageBufferFallbackSurfaceFactory;
class CanvasObserver : public WillBeGarbageCollectedMixin {
DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver);
......@@ -174,6 +175,7 @@ private:
void reset();
PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> createSurfaceFactory(const IntSize& deviceSize, int* msaaSampleCount) const;
PassOwnPtr<ImageBufferSurface> createImageBufferSurface(const IntSize& deviceSize, int* msaaSampleCount);
void createImageBuffer();
void createImageBufferInternal();
......
......@@ -16,11 +16,12 @@
namespace blink {
RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize& size, OpacityMode opacityMode)
RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize& size, PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> fallbackFactory, OpacityMode opacityMode)
: ImageBufferSurface(size, opacityMode)
, m_imageBuffer(0)
, m_initialSaveCount(0)
, m_frameWasCleared(true)
, m_fallbackFactory(fallbackFactory)
{
initializeCurrentFrame();
}
......@@ -60,42 +61,49 @@ void RecordingImageBufferSurface::setImageBuffer(ImageBuffer* imageBuffer)
m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
}
if (m_fallbackSurface) {
m_fallbackSurface->setImageBuffer(imageBuffer);
}
}
void RecordingImageBufferSurface::willAccessPixels()
{
fallBackToRasterCanvas();
if (m_fallbackSurface)
m_fallbackSurface->willAccessPixels();
else
fallBackToRasterCanvas();
}
void RecordingImageBufferSurface::fallBackToRasterCanvas()
{
if (m_rasterCanvas) {
if (m_fallbackSurface) {
ASSERT(!m_currentFrame);
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) {
m_previousFrame->draw(m_rasterCanvas.get());
m_previousFrame->draw(m_fallbackSurface->canvas());
m_previousFrame.clear();
}
if (m_currentFrame) {
RefPtr<SkPicture> currentPicture = adoptRef(m_currentFrame->endRecording());
currentPicture->draw(m_rasterCanvas.get());
currentPicture->draw(m_fallbackSurface->canvas());
m_currentFrame.clear();
}
if (m_imageBuffer) {
m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingDisabled);
m_imageBuffer->context()->resetCanvas(m_rasterCanvas.get());
m_imageBuffer->context()->resetCanvas(m_fallbackSurface->canvas());
}
}
SkCanvas* RecordingImageBufferSurface::canvas() const
{
if (m_rasterCanvas)
return m_rasterCanvas.get();
if (m_fallbackSurface)
return m_fallbackSurface->canvas();
ASSERT(m_currentFrame->getRecordingCanvas());
return m_currentFrame->getRecordingCanvas();
......@@ -103,6 +111,9 @@ SkCanvas* RecordingImageBufferSurface::canvas() const
PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
{
if (m_fallbackSurface)
return nullptr;
bool canUsePicture = finalizeFrameInternal();
m_imageBuffer->didFinalizeFrame();
......@@ -110,25 +121,35 @@ PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
return m_previousFrame;
}
if (!m_rasterCanvas)
if (!m_fallbackSurface)
fallBackToRasterCanvas();
return nullptr;
}
void RecordingImageBufferSurface::finalizeFrame(const FloatRect &)
void RecordingImageBufferSurface::finalizeFrame(const FloatRect &dirtyRect)
{
if (!finalizeFrameInternal() && !m_rasterCanvas) {
fallBackToRasterCanvas();
if (m_fallbackSurface) {
m_fallbackSurface->finalizeFrame(dirtyRect);
return;
}
if (!finalizeFrameInternal())
fallBackToRasterCanvas();
}
void RecordingImageBufferSurface::didClearCanvas()
{
if (m_fallbackSurface) {
m_fallbackSurface->didClearCanvas();
return;
}
m_frameWasCleared = true;
}
bool RecordingImageBufferSurface::finalizeFrameInternal()
{
ASSERT(!m_fallbackSurface);
if (!m_imageBuffer->isDirty()) {
if (m_currentFrame && !m_previousFrame) {
// Create an initial blank frame
......@@ -138,10 +159,6 @@ bool RecordingImageBufferSurface::finalizeFrameInternal()
return m_currentFrame;
}
if (!m_currentFrame) {
return false;
}
IntRect canvasRect(IntPoint(0, 0), size());
if (!m_frameWasCleared && !m_imageBuffer->context()->opaqueRegion().asRect().contains(canvasRect)) {
return false;
......@@ -194,4 +211,79 @@ void RecordingImageBufferSurface::setCurrentState(SkCanvas* dstCanvas, StateStac
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
......@@ -20,10 +20,16 @@ namespace blink {
class ImageBuffer;
class RecordingImageBufferFallbackSurfaceFactory {
public:
virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize&, OpacityMode) = 0;
virtual ~RecordingImageBufferFallbackSurfaceFactory() { }
};
class PLATFORM_EXPORT RecordingImageBufferSurface : public ImageBufferSurface {
WTF_MAKE_NONCOPYABLE(RecordingImageBufferSurface); WTF_MAKE_FAST_ALLOCATED;
public:
RecordingImageBufferSurface(const IntSize&, OpacityMode = NonOpaque);
RecordingImageBufferSurface(const IntSize&, PassOwnPtr<RecordingImageBufferFallbackSurfaceFactory> fallbackFactory, OpacityMode = NonOpaque);
virtual ~RecordingImageBufferSurface();
// Implementation of ImageBufferSurface interfaces
......@@ -35,6 +41,18 @@ public:
virtual void didClearCanvas() 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:
struct StateRec {
public:
......@@ -55,10 +73,11 @@ private:
OwnPtr<SkPictureRecorder> m_currentFrame;
RefPtr<SkPicture> m_previousFrame;
OwnPtr<SkCanvas> m_rasterCanvas;
OwnPtr<ImageBufferSurface> m_fallbackSurface;
ImageBuffer* m_imageBuffer;
int m_initialSaveCount;
bool m_frameWasCleared;
OwnPtr<RecordingImageBufferFallbackSurfaceFactory> m_fallbackFactory;
};
} // namespace blink
......
......@@ -9,6 +9,7 @@
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/ImageBufferClient.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "public/platform/Platform.h"
#include "public/platform/WebThread.h"
#include "third_party/skia/include/core/SkCanvas.h"
......@@ -73,13 +74,33 @@ private:
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
class RecordingImageBufferSurfaceTest : public Test {
protected:
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();
// We create an ImageBuffer in order for the testSurface to be
// properly initialized with a GraphicsContext
......@@ -125,6 +146,7 @@ public:
m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
EXPECT_EQ(0, m_surfaceFactory->createSurfaceCount());
expectDisplayListEnabled(true); // first frame has an implicit clear
m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture();
......@@ -155,10 +177,10 @@ public:
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
m_testSurface->getPicture();
EXPECT_EQ(4, m_fakeImageBufferClient->frameCount());
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(4, m_fakeImageBufferClient->frameCount());
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
}
......@@ -196,10 +218,13 @@ public:
void expectDisplayListEnabled(bool displayListEnabled)
{
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:
MockSurfaceFactory* m_surfaceFactory;
RecordingImageBufferSurface* m_testSurface;
OwnPtr<FakeImageBufferClient> m_fakeImageBufferClient;
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