Bug 939276 - Use a single GLContext for all SkiaGL canvases r=bjacob,gwright,dglastonbury

--HG--
rename : gfx/gl/GLContextSkia.cpp => gfx/gl/SkiaGLGlue.cpp
This commit is contained in:
James Willcox 2014-02-14 15:55:58 -06:00
parent 5457deea05
commit ee9a1556e5
26 changed files with 348 additions and 294 deletions

128
content/canvas/src/CanvasRenderingContext2D.cpp Normal file → Executable file
View File

@ -97,11 +97,13 @@
#ifdef USE_SKIA_GPU
#undef free // apparently defined by some windows header, clashing with a free()
// method in SkTypes.h
#include "GLContextSkia.h"
#include "SkiaGLGlue.h"
#include "SurfaceStream.h"
#include "SurfaceTypes.h"
#include "nsIGfxInfo.h"
#endif
using mozilla::gl::GLContext;
using mozilla::gl::SkiaGLGlue;
using mozilla::gl::GLContextProvider;
#ifdef XP_WIN
@ -430,28 +432,18 @@ public:
}
}
#ifdef USE_SKIA_GPU
static void PreTransactionCallback(void* aData)
{
CanvasRenderingContext2DUserData* self =
static_cast<CanvasRenderingContext2DUserData*>(aData);
CanvasRenderingContext2D* context = self->mContext;
if (!context)
if (!context || !context->mStream || !context->mTarget)
return;
GLContext* glContext = static_cast<GLContext*>(context->mTarget->GetGLContext());
if (!glContext)
return;
if (context->mTarget) {
// Since SkiaGL default to store drawing command until flush
// We will have to flush it before present.
context->mTarget->Flush();
}
glContext->MakeCurrent();
glContext->PublishFrame();
// Since SkiaGL default to store drawing command until flush
// We will have to flush it before present.
context->mTarget->Flush();
}
#endif
static void DidTransactionCallback(void* aData)
{
@ -542,18 +534,15 @@ DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
CanvasRenderingContext2D::CanvasRenderingContext2D()
: mZero(false), mOpaque(false), mResetLayer(true)
: mForceSoftware(false), mZero(false), mOpaque(false), mResetLayer(true)
, mIPC(false)
, mStream(nullptr)
, mIsEntireFrameInvalid(false)
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
, mInvalidateCount(0)
{
sNumLivingContexts++;
SetIsDOMBinding();
#ifdef USE_SKIA_GPU
mForceSoftware = false;
#endif
}
CanvasRenderingContext2D::~CanvasRenderingContext2D()
@ -568,9 +557,7 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D()
NS_IF_RELEASE(sErrorTarget);
}
#ifdef USE_SKIA_GPU
RemoveDemotableContext(this);
#endif
}
JSObject*
@ -629,6 +616,7 @@ CanvasRenderingContext2D::Reset()
}
mTarget = nullptr;
mStream = nullptr;
// Since the target changes the backing texture will change, and this will
// no longer be valid.
@ -750,8 +738,7 @@ CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
void CanvasRenderingContext2D::Demote()
{
#ifdef USE_SKIA_GPU
if (!IsTargetValid() || mForceSoftware || !mTarget->GetGLContext())
if (!IsTargetValid() || mForceSoftware || !mStream)
return;
RemoveDemotableContext(this);
@ -759,6 +746,7 @@ void CanvasRenderingContext2D::Demote()
RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
RefPtr<DrawTarget> oldTarget = mTarget;
mTarget = nullptr;
mStream = nullptr;
mResetLayer = true;
mForceSoftware = true;
@ -777,11 +765,8 @@ void CanvasRenderingContext2D::Demote()
}
mTarget->SetTransform(oldTarget->GetTransform());
#endif
}
#ifdef USE_SKIA_GPU
std::vector<CanvasRenderingContext2D*>&
CanvasRenderingContext2D::DemotableContexts()
{
@ -792,11 +777,7 @@ CanvasRenderingContext2D::DemotableContexts()
void
CanvasRenderingContext2D::DemoteOldestContextIfNecessary()
{
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
const size_t kMaxContexts = 2;
#else
const size_t kMaxContexts = 16;
#endif
const size_t kMaxContexts = 64;
std::vector<CanvasRenderingContext2D*>& contexts = DemotableContexts();
if (contexts.size() < kMaxContexts)
@ -830,8 +811,6 @@ CheckSizeForSkiaGL(IntSize size) {
return size.width >= minsize && size.height >= minsize;
}
#endif
void
CanvasRenderingContext2D::EnsureTarget()
{
@ -857,42 +836,29 @@ CanvasRenderingContext2D::EnsureTarget()
}
if (layerManager) {
#ifdef USE_SKIA_GPU
if (gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) {
SurfaceCaps caps = SurfaceCaps::ForRGBA();
caps.preserve = true;
#ifdef MOZ_WIDGET_GONK
layers::ShadowLayerForwarder *forwarder = layerManager->AsShadowForwarder();
if (forwarder) {
caps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
}
#endif
if (gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas() &&
!mForceSoftware &&
CheckSizeForSkiaGL(size)) {
DemoteOldestContextIfNecessary();
nsRefPtr<GLContext> glContext;
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
nsString vendor;
#ifdef USE_SKIA_GPU
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (!mForceSoftware && CheckSizeForSkiaGL(size))
{
glContext = GLContextProvider::CreateOffscreen(gfxIntSize(size.width, size.height),
caps);
}
if (glue) {
mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
MOZ_ASSERT(mTarget, "Failed to create SkiaGL DrawTarget");
if (glContext) {
SkAutoTUnref<GrGLInterface> i(CreateGrGLInterfaceFromGLContext(glContext));
mTarget = Factory::CreateDrawTargetSkiaWithGLContextAndGrGLInterface(glContext, i, size, format);
mStream = gfx::SurfaceStream::CreateForType(SurfaceStreamType::TripleBuffer, glue->GetGLContext());
AddDemotableContext(this);
} else {
} else
#endif
{
mTarget = layerManager->CreateDrawTarget(size, format);
}
} else
#endif
mTarget = layerManager->CreateDrawTarget(size, format);
mTarget = layerManager->CreateDrawTarget(size, format);
} else {
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
}
}
@ -1077,12 +1043,10 @@ CanvasRenderingContext2D::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value
ContextAttributes2D attributes;
NS_ENSURE_TRUE(attributes.Init(aCx, aOptions), NS_ERROR_UNEXPECTED);
#ifdef USE_SKIA_GPU
if (Preferences::GetBool("gfx.canvas.willReadFrequently.enable", false)) {
// Use software when there is going to be a lot of readback
mForceSoftware = attributes.mWillReadFrequently;
}
#endif
return NS_OK;
}
@ -3246,7 +3210,6 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
NS_ENSURE_SUCCESS_VOID(rv);
}
#ifdef USE_SKIA_GPU
static bool
IsStandardCompositeOp(CompositionOp op)
{
@ -3262,7 +3225,6 @@ IsStandardCompositeOp(CompositionOp op)
op == CompositionOp::OP_ADD ||
op == CompositionOp::OP_XOR);
}
#endif
void
CanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op,
@ -3303,11 +3265,9 @@ CanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op,
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
else return;
#ifdef USE_SKIA_GPU
if (!IsStandardCompositeOp(comp_op)) {
Demote();
}
#endif
#undef CANVAS_OP_TO_GFX_OP
CurrentState().op = comp_op;
@ -3353,11 +3313,9 @@ CanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op,
error.Throw(NS_ERROR_FAILURE);
}
#ifdef USE_SKIA_GPU
if (!IsStandardCompositeOp(comp_op)) {
Demote();
}
#endif
#undef CANVAS_OP_TO_GFX_OP
}
@ -4057,7 +4015,20 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
aOldLayer->GetUserData(&g2DContextLayerUserData));
CanvasLayer::Data data;
data.mGLContext = static_cast<GLContext*>(mTarget->GetGLContext());
#ifdef USE_SKIA_GPU
if (mStream) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (glue) {
data.mGLContext = glue->GetGLContext();
data.mStream = mStream.get();
}
} else
#endif
{
data.mDrawTarget = mTarget;
}
if (userData && userData->IsForContext(this) && aOldLayer->IsDataValid(data)) {
nsRefPtr<CanvasLayer> ret = aOldLayer;
return ret.forget();
@ -4091,11 +4062,16 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
CanvasLayer::Data data;
#ifdef USE_SKIA_GPU
GLContext* glContext = static_cast<GLContext*>(mTarget->GetGLContext());
if (glContext) {
canvasLayer->SetPreTransactionCallback(
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
data.mGLContext = glContext;
if (mStream) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (glue) {
canvasLayer->SetPreTransactionCallback(
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
data.mGLContext = glue->GetGLContext();
data.mStream = mStream.get();
data.mTexID = mTarget->GetTextureID();
}
} else
#endif
{

View File

@ -31,6 +31,7 @@ class nsXULElement;
namespace mozilla {
namespace gfx {
class SourceSurface;
class SurfaceStream;
}
namespace dom {
@ -593,7 +594,6 @@ protected:
return CurrentState().font;
}
#if USE_SKIA_GPU
static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
static void DemoteOldestContextIfNecessary();
@ -602,7 +602,6 @@ protected:
// Do not use GL
bool mForceSoftware;
#endif
// Member vars
int32_t mWidth, mHeight;
@ -629,6 +628,8 @@ protected:
// sErrorTarget.
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
RefPtr<gfx::SurfaceStream> mStream;
/**
* Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
* Redraw is called, reset to false when Render is called.

View File

@ -962,18 +962,17 @@ public:
return mPermitSubpixelAA;
}
virtual GenericRefCountedBase* GetGLContext() const {
return nullptr;
}
#ifdef USE_SKIA_GPU
virtual void InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
GrGLInterface* aGrGLInterface,
const IntSize &aSize,
SurfaceFormat aFormat)
virtual void InitWithGrContext(GrContext* aGrContext,
const IntSize &aSize,
SurfaceFormat aFormat)
{
MOZ_CRASH();
}
virtual uint32_t GetTextureID() const {
return 0;
}
#endif
protected:
@ -1075,13 +1074,9 @@ public:
#ifdef USE_SKIA_GPU
static TemporaryRef<DrawTarget>
CreateDrawTargetSkiaWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
GrGLInterface* aGrGLInterface,
const IntSize &aSize,
SurfaceFormat aFormat);
static void
SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes);
CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
const IntSize &aSize,
SurfaceFormat aFormat);
#endif
static void PurgeAllCaches();

View File

@ -77,80 +77,6 @@ public:
ExtendMode mExtendMode;
};
#ifdef USE_SKIA_GPU
int DrawTargetSkia::sTextureCacheCount = 256;
int DrawTargetSkia::sTextureCacheSizeInBytes = 96*1024*1024;
static std::vector<DrawTargetSkia*>&
GLDrawTargets()
{
static std::vector<DrawTargetSkia*> targets;
return targets;
}
void
DrawTargetSkia::RebalanceCacheLimits()
{
// Divide the global cache limits equally between all currently active GL-backed
// Skia DrawTargets.
std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
uint32_t targetCount = targets.size();
if (targetCount == 0)
return;
int individualCacheSize = sTextureCacheSizeInBytes / targetCount;
for (uint32_t i = 0; i < targetCount; i++) {
targets[i]->SetCacheLimits(sTextureCacheCount, individualCacheSize);
}
}
static void
AddGLDrawTarget(DrawTargetSkia* target)
{
GLDrawTargets().push_back(target);
DrawTargetSkia::RebalanceCacheLimits();
}
static void
RemoveGLDrawTarget(DrawTargetSkia* target)
{
std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
std::vector<DrawTargetSkia*>::iterator it = std::find(targets.begin(), targets.end(), target);
if (it != targets.end()) {
targets.erase(it);
DrawTargetSkia::RebalanceCacheLimits();
}
}
void
DrawTargetSkia::SetGlobalCacheLimits(int aCount, int aSizeInBytes)
{
sTextureCacheCount = aCount;
sTextureCacheSizeInBytes = aSizeInBytes;
DrawTargetSkia::RebalanceCacheLimits();
}
void
DrawTargetSkia::PurgeCaches()
{
if (mGrContext) {
mGrContext->freeGpuResources();
}
}
/* static */ void
DrawTargetSkia::PurgeAllCaches()
{
std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
uint32_t targetCount = targets.size();
for (uint32_t i = 0; i < targetCount; i++) {
targets[i]->PurgeCaches();
}
}
#endif
/**
* When constructing a temporary SkBitmap via GetBitmapForSurface, we may also
* have to construct a temporary DataSourceSurface, which must live as long as
@ -187,15 +113,12 @@ GetBitmapForSurface(SourceSurface* aSurface)
}
DrawTargetSkia::DrawTargetSkia()
: mSnapshot(nullptr)
: mTexture(0), mSnapshot(nullptr)
{
}
DrawTargetSkia::~DrawTargetSkia()
{
#ifdef USE_SKIA_GPU
RemoveGLDrawTarget(this);
#endif
}
TemporaryRef<SourceSurface>
@ -768,45 +691,33 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
#ifdef USE_SKIA_GPU
void
DrawTargetSkia::InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
GrGLInterface* aGrGLInterface,
const IntSize &aSize,
SurfaceFormat aFormat)
DrawTargetSkia::InitWithGrContext(GrContext* aGrContext,
const IntSize &aSize,
SurfaceFormat aFormat)
{
mGLContext = aGLContext;
mGrContext = aGrContext;
mSize = aSize;
mFormat = aFormat;
mGrGLInterface = aGrGLInterface;
mGrGLInterface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
GrBackendContext backendContext = reinterpret_cast<GrBackendContext>(aGrGLInterface);
SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, backendContext));
mGrContext = gr.get();
GrBackendRenderTargetDesc targetDescriptor;
GrTextureDesc targetDescriptor;
targetDescriptor.fFlags = kRenderTarget_GrTextureFlagBit;
targetDescriptor.fWidth = mSize.width;
targetDescriptor.fHeight = mSize.height;
targetDescriptor.fConfig = GfxFormatToGrConfig(mFormat);
targetDescriptor.fOrigin = kBottomLeft_GrSurfaceOrigin;
targetDescriptor.fSampleCnt = 0;
targetDescriptor.fRenderTargetHandle = 0; // GLContext always exposes the right framebuffer as id 0
SkAutoTUnref<GrRenderTarget> target(mGrContext->wrapBackendRenderTarget(targetDescriptor));
SkAutoTUnref<SkDevice> device(new SkGpuDevice(mGrContext.get(), target.get()));
SkAutoTUnref<GrTexture> skiaTexture(mGrContext->createUncachedTexture(targetDescriptor, NULL, 0));
mTexture = (uint32_t)skiaTexture->getTextureHandle();
SkAutoTUnref<SkDevice> device(new SkGpuDevice(mGrContext.get(), skiaTexture->asRenderTarget()));
SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
mCanvas = canvas.get();
AddGLDrawTarget(this);
}
void
DrawTargetSkia::SetCacheLimits(int aCount, int aSizeInBytes)
{
MOZ_ASSERT(mGrContext, "No GrContext!");
mGrContext->setTextureCacheLimits(aCount, aSizeInBytes);
}
#endif
void

View File

@ -104,18 +104,10 @@ public:
void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
#ifdef USE_SKIA_GPU
virtual GenericRefCountedBase* GetGLContext() const MOZ_OVERRIDE { return mGLContext; }
void InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
GrGLInterface* aGrGLInterface,
const IntSize &aSize,
SurfaceFormat aFormat) MOZ_OVERRIDE;
void SetCacheLimits(int aCount, int aSizeInBytes);
void PurgeCaches();
static void SetGlobalCacheLimits(int aCount, int aSizeInBytes);
static void RebalanceCacheLimits();
static void PurgeAllCaches();
void InitWithGrContext(GrContext* aGrContext,
const IntSize &aSize,
SurfaceFormat aFormat) MOZ_OVERRIDE;
uint32_t GetTextureID() const { return mTexture; }
#endif
operator std::string() const {
@ -133,18 +125,8 @@ private:
SkRect SkRectCoveringWholeSurface() const;
#ifdef USE_SKIA_GPU
/*
* These members have inter-dependencies, but do not keep each other alive, so
* destruction order is very important here: mGrContext uses mGrGLInterface, and
* through it, uses mGLContext, so it is important that they be declared in the
* present order.
*/
RefPtr<GenericRefCountedBase> mGLContext;
SkRefPtr<GrGLInterface> mGrGLInterface;
SkRefPtr<GrContext> mGrContext;
static int sTextureCacheCount;
static int sTextureCacheSizeInBytes;
uint32_t mTexture;
#endif
IntSize mSize;

View File

@ -585,30 +585,21 @@ Factory::D2DCleanup()
#ifdef USE_SKIA_GPU
TemporaryRef<DrawTarget>
Factory::CreateDrawTargetSkiaWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
GrGLInterface* aGrGLInterface,
const IntSize &aSize,
SurfaceFormat aFormat)
Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
const IntSize &aSize,
SurfaceFormat aFormat)
{
DrawTargetSkia* newDrawTargetSkia = new DrawTargetSkia();
newDrawTargetSkia->InitWithGLContextAndGrGLInterface(aGLContext, aGrGLInterface, aSize, aFormat);
newDrawTargetSkia->InitWithGrContext(aGrContext, aSize, aFormat);
RefPtr<DrawTarget> newTarget = newDrawTargetSkia;
return newTarget;
}
void
Factory::SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes)
{
DrawTargetSkia::SetGlobalCacheLimits(aCount, aSizeInBytes);
}
#endif // USE_SKIA_GPU
void
Factory::PurgeAllCaches()
{
#ifdef USE_SKIA_GPU
DrawTargetSkia::PurgeAllCaches();
#endif
}
#ifdef USE_SKIA_FREETYPE

View File

@ -1,8 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "skia/GrGLInterface.h"
GrGLInterface* CreateGrGLInterfaceFromGLContext(mozilla::gl::GLContext* context);

3
gfx/gl/GLScreenBuffer.cpp Normal file → Executable file
View File

@ -43,6 +43,7 @@ GLScreenBuffer::Create(GLContext* gl,
#ifdef MOZ_WIDGET_GONK
/* On B2G, we want a Gralloc factory, and we want one right at the start */
if (!factory &&
caps.surfaceAllocator &&
XRE_GetProcessType() != GeckoProcessType_Default)
{
factory = new SurfaceFactory_Gralloc(gl, caps);
@ -70,7 +71,6 @@ GLScreenBuffer::Create(GLContext* gl,
GLScreenBuffer::~GLScreenBuffer()
{
delete mStream;
delete mDraw;
delete mRead;
@ -378,7 +378,6 @@ GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamTyp
SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mGL, mStream);
MOZ_ASSERT(newStream);
delete mStream;
mStream = newStream;
}

View File

@ -16,6 +16,7 @@
#define SCREEN_BUFFER_H_
#include "SurfaceTypes.h"
#include "SurfaceStream.h"
#include "GLContextTypes.h"
#include "GLDefs.h"
#include "mozilla/gfx/2D.h"
@ -156,7 +157,7 @@ protected:
GLContext* const mGL; // Owns us.
SurfaceCaps mCaps;
SurfaceFactory_GL* mFactory; // Owned by us.
SurfaceStream* mStream; // Owned by us.
RefPtr<SurfaceStream> mStream;
DrawBuffer* mDraw; // Owned by us.
ReadBuffer* mRead; // Owned by us.

View File

@ -284,6 +284,7 @@ SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
size,
hasAlpha)
, mTex(tex)
, mFB(gl, tex)
{
mData = Factory::CreateDataSourceSurfaceWithStride(size, format,
GetAlignedStride<4>(size.width * BytesPerPixel(format)));
@ -300,10 +301,10 @@ SharedSurface_Basic::~SharedSurface_Basic()
void
SharedSurface_Basic::Fence()
{
MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize());
mGL->MakeCurrent();
ScopedBindFramebuffer autoFB(mGL, mFB.FB());
DataSourceSurface::MappedSurface map;
mData->Map(DataSourceSurface::MapType::WRITE, &map);
nsRefPtr<gfxImageSurface> wrappedData =
@ -311,7 +312,7 @@ SharedSurface_Basic::Fence()
ThebesIntSize(mData->GetSize()),
map.mStride,
SurfaceFormatToImageFormat(mData->GetFormat()));
ReadScreenIntoImageSurface(mGL, wrappedData);
ReadPixelsIntoImageSurface(mGL, wrappedData);
mData->Unmap();
}
@ -322,15 +323,24 @@ SharedSurface_GLTexture::Create(GLContext* prodGL,
GLContext* consGL,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha)
bool hasAlpha,
GLuint texture)
{
MOZ_ASSERT(prodGL);
MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL));
prodGL->MakeCurrent();
GLuint tex = CreateTextureForOffscreen(prodGL, formats, size);
return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex);
GLuint tex = texture;
bool ownsTex = false;
if (!tex) {
tex = CreateTextureForOffscreen(prodGL, formats, size);
ownsTex = true;
}
return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex, ownsTex);
}
SharedSurface_GLTexture::~SharedSurface_GLTexture()
@ -338,7 +348,10 @@ SharedSurface_GLTexture::~SharedSurface_GLTexture()
if (!mGL->MakeCurrent())
return;
mGL->fDeleteTextures(1, &mTex);
if (mOwnsTex) {
GLuint tex = mTex;
mGL->fDeleteTextures(1, &mTex);
}
if (mSync) {
mGL->fDeleteSync(mSync);

View File

@ -6,6 +6,7 @@
#ifndef SHARED_SURFACE_GL_H_
#define SHARED_SURFACE_GL_H_
#include "ScopedGLHelpers.h"
#include "SharedSurface.h"
#include "SurfaceFactory.h"
#include "SurfaceTypes.h"
@ -136,6 +137,7 @@ public:
protected:
const GLuint mTex;
RefPtr<gfx::DataSourceSurface> mData;
ScopedFramebufferForTexture mFB;
SharedSurface_Basic(GLContext* gl,
const gfx::IntSize& size,
@ -192,7 +194,8 @@ public:
GLContext* consGL,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha);
bool hasAlpha,
GLuint texture = 0);
static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->Type() == SharedSurfaceType::GLTextureShare);
@ -203,6 +206,7 @@ public:
protected:
GLContext* mConsGL;
const GLuint mTex;
const bool mOwnsTex;
GLsync mSync;
mutable Mutex mMutex;
@ -210,7 +214,8 @@ protected:
GLContext* consGL,
const gfx::IntSize& size,
bool hasAlpha,
GLuint tex)
GLuint tex,
bool ownsTex)
: SharedSurface_GL(SharedSurfaceType::GLTextureShare,
AttachmentType::GLTexture,
prodGL,
@ -218,6 +223,7 @@ protected:
hasAlpha)
, mConsGL(consGL)
, mTex(tex)
, mOwnsTex(ownsTex)
, mSync(0)
, mMutex("SharedSurface_GLTexture mutex")
{

19
gfx/gl/GLContextSkia.cpp → gfx/gl/SkiaGLGlue.cpp Normal file → Executable file
View File

@ -16,9 +16,11 @@
#endif
#include "GLContext.h"
#include "SkiaGLGlue.h"
using mozilla::gl::GLContext;
using mozilla::gl::GLFeature;
using mozilla::gl::SkiaGLGlue;
using mozilla::gfx::DrawTarget;
static mozilla::ThreadLocal<GLContext*> sGLContext;
@ -27,8 +29,8 @@ extern "C" {
void EnsureGLContext(const GrGLInterface* i)
{
const DrawTarget* drawTarget = reinterpret_cast<const DrawTarget*>(i->fCallbackData);
GLContext* gl = static_cast<GLContext*>(drawTarget->GetGLContext());
const SkiaGLGlue* contextSkia = reinterpret_cast<const SkiaGLGlue*>(i->fCallbackData);
GLContext* gl = contextSkia->GetGLContext();
gl->MakeCurrent();
if (!sGLContext.initialized()) {
@ -713,7 +715,7 @@ GrGLvoid glGenVertexArrays_mozilla(GrGLsizei n, GrGLuint *arrays) {
} // extern "C"
GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
{
GrGLInterface* i = new GrGLInterface();
i->fCallback = EnsureGLContext;
@ -858,3 +860,14 @@ GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
return i;
}
SkiaGLGlue::SkiaGLGlue(GLContext* context)
: mGLContext(context)
{
SkAutoTUnref<GrGLInterface> i(CreateGrGLInterfaceFromGLContext(mGLContext));
i->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
mGrGLInterface = i;
SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)mGrGLInterface.get()));
mGrContext = gr;
}

34
gfx/gl/SkiaGLGlue.h Executable file
View File

@ -0,0 +1,34 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/RefPtr.h"
#include "skia/GrGLInterface.h"
#include "skia/GrContext.h"
namespace mozilla {
namespace gl {
class GLContext;
class SkiaGLGlue : public GenericAtomicRefCounted
{
public:
SkiaGLGlue(GLContext* context);
GLContext* GetGLContext() const { return mGLContext.get(); }
GrContext* GetGrContext() const { return mGrContext.get(); }
private:
/*
* These members have inter-dependencies, but do not keep each other alive, so
* destruction order is very important here: mGrContext uses mGrGLInterface, and
* through it, uses mGLContext, so it is important that they be declared in the
* present order.
*/
RefPtr<GLContext> mGLContext;
SkRefPtr<GrGLInterface> mGrGLInterface;
SkRefPtr<GrContext> mGrContext;
};
}
}

View File

@ -7,6 +7,7 @@
#include "gfxPoint.h"
#include "SharedSurface.h"
#include "SharedSurfaceGL.h"
#include "SurfaceFactory.h"
#include "GeckoProfiler.h"
@ -56,6 +57,20 @@ SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glC
return result;
}
void
SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory)
{
if (!mProducer) {
New(factory, src->Size(), mProducer);
}
MOZ_ASSERT(mProducer);
mProducer->LockProd();
SharedSurface::Copy(src, mProducer, factory);
mProducer->UnlockProd();
}
void
SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size,
SharedSurface*& surf)

View File

@ -11,6 +11,7 @@
#include "mozilla/Monitor.h"
#include "mozilla/Attributes.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/GenericRefCounted.h"
#include "SurfaceTypes.h"
namespace mozilla {
@ -24,7 +25,7 @@ class SharedSurface;
class SurfaceFactory;
// Owned by: ScreenBuffer
class SurfaceStream
class SurfaceStream : public GenericAtomicRefCounted
{
public:
typedef enum {
@ -50,6 +51,8 @@ public:
const SurfaceStreamType mType;
mozilla::gl::GLContext* GLContext() const { return mGLContext; }
protected:
// |mProd| is owned by us, but can be ripped away when
// creating a new GLStream from this one.
@ -121,6 +124,8 @@ public:
virtual SharedSurface* Resize(SurfaceFactory* factory, const gfx::IntSize& size);
virtual void CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory) { MOZ_ASSERT(0); }
protected:
// SwapCons will return the same surface more than once,
// if nothing new has been published.
@ -192,6 +197,7 @@ protected:
public:
SurfaceStream_TripleBuffer(SurfaceStream* prevStream);
virtual ~SurfaceStream_TripleBuffer();
virtual void CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory);
private:
// Common constructor code.

View File

@ -75,9 +75,9 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
'SharedSurfaceANGLE.cpp',
]
if CONFIG['MOZ_ENABLE_SKIA_GPU']:
EXPORTS += ['GLContextSkia.h']
EXPORTS += ['SkiaGLGlue.h']
UNIFIED_SOURCES += [
'GLContextSkia.cpp',
'SkiaGLGlue.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':

View File

@ -32,6 +32,7 @@ namespace layers {
CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
CanvasLayer(aLayerManager, aImplData)
, mStream(nullptr)
{
MOZ_COUNT_CTOR(CopyableCanvasLayer);
mForceReadback = Preferences::GetBool("webgl.force-layers-readback", false);
@ -49,6 +50,7 @@ CopyableCanvasLayer::Initialize(const Data& aData)
if (aData.mGLContext) {
mGLContext = aData.mGLContext;
mStream = aData.mStream;
mIsGLAlphaPremult = aData.mIsGLAlphaPremult;
mNeedsYFlip = true;
MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
@ -71,7 +73,7 @@ CopyableCanvasLayer::Initialize(const Data& aData)
bool
CopyableCanvasLayer::IsDataValid(const Data& aData)
{
return mGLContext == aData.mGLContext;
return mGLContext == aData.mGLContext && mStream == aData.mStream;
}
void

View File

@ -22,6 +22,13 @@
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
namespace mozilla {
namespace gfx {
class SurfaceStream;
class SharedSurface;
class SurfaceFactory;
}
namespace layers {
class CanvasClientWebGL;
@ -54,6 +61,8 @@ protected:
nsRefPtr<mozilla::gl::GLContext> mGLContext;
mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
gfx::SurfaceStream* mStream;
uint32_t mCanvasFramebuffer;
bool mIsGLAlphaPremult;

View File

@ -63,6 +63,7 @@ class GLContext;
namespace gfx {
class DrawTarget;
class SurfaceStream;
}
namespace css {
@ -1790,6 +1791,8 @@ public:
Data()
: mDrawTarget(nullptr)
, mGLContext(nullptr)
, mStream(nullptr)
, mTexID(0)
, mSize(0,0)
, mIsGLAlphaPremult(false)
{ }
@ -1798,6 +1801,14 @@ public:
mozilla::gfx::DrawTarget *mDrawTarget; // a DrawTarget for the canvas contents
mozilla::gl::GLContext* mGLContext; // or this, for GL.
#ifdef USE_SKIA_GPU
// Canvas/SkiaGL uses this
mozilla::gfx::SurfaceStream* mStream;
// ID of the texture backing the canvas layer (defaults to 0)
uint32_t mTexID;
#endif
// The size of the canvas content
nsIntSize mSize;

View File

@ -112,7 +112,15 @@ void
CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
SurfaceStream* stream = screen->Stream();
SurfaceStream* stream = nullptr;
if (aLayer->mStream) {
stream = aLayer->mStream;
stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
} else {
stream = screen->Stream();
}
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
bool bufferCreated = false;
@ -251,7 +259,15 @@ DeprecatedCanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLaye
mDeprecatedTextureClient->EnsureAllocated(aSize, gfxContentType::COLOR);
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
SurfaceStream* stream = screen->Stream();
SurfaceStream* stream = nullptr;
if (aLayer->mStream) {
stream = aLayer->mStream;
stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
} else {
stream = screen->Stream();
}
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
if (isCrossProcess) {

View File

@ -36,27 +36,34 @@ void
ClientCanvasLayer::Initialize(const Data& aData)
{
CopyableCanvasLayer::Initialize(aData);
mCanvasClient = nullptr;
if (mGLContext) {
GLScreenBuffer* screen = mGLContext->Screen();
SurfaceCaps caps = screen->Caps();
if (mStream) {
// The screen caps are irrelevant if we're using a separate stream
caps = GetContentFlags() & CONTENT_OPAQUE ? SurfaceCaps::ForRGB() : SurfaceCaps::ForRGBA();
}
SurfaceStreamType streamType =
SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread,
screen->PreserveBuffer());
SurfaceFactory_GL* factory = nullptr;
if (!mForceReadback) {
if (ClientManager()->AsShadowForwarder()->GetCompositorBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) {
if (ClientManager()->AsShadowForwarder()->GetCompositorBackendType() == mozilla::layers::LAYERS_OPENGL) {
if (mGLContext->GetContextType() == GLContextType::EGL) {
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
if (!isCrossProcess) {
// [Basic/OGL Layers, OMTC] WebGL layer init.
factory = SurfaceFactory_EGLImage::Create(mGLContext, screen->Caps());
factory = SurfaceFactory_EGLImage::Create(mGLContext, caps);
} else {
// [Basic/OGL Layers, OOPC] WebGL layer init. (Out Of Process Compositing)
#ifdef MOZ_WIDGET_GONK
factory = new SurfaceFactory_Gralloc(mGLContext, screen->Caps(), ClientManager()->AsShadowForwarder());
factory = new SurfaceFactory_Gralloc(mGLContext, caps, ClientManager()->AsShadowForwarder());
#else
// we could do readback here maybe
NS_NOTREACHED("isCrossProcess but not on native B2G!");
@ -66,16 +73,34 @@ ClientCanvasLayer::Initialize(const Data& aData)
// [Basic Layers, OMTC] WebGL layer init.
// Well, this *should* work...
#ifdef XP_MACOSX
factory = new SurfaceFactory_IOSurface(mGLContext, screen->Caps());
factory = new SurfaceFactory_IOSurface(mGLContext, caps);
#else
factory = new SurfaceFactory_GLTexture(mGLContext, nullptr, screen->Caps());
factory = new SurfaceFactory_GLTexture(mGLContext, nullptr, caps);
#endif
}
}
}
if (factory) {
screen->Morph(factory, streamType);
if (mStream) {
// We're using a stream other than the one in the default screen
mFactory = factory;
gfx::IntSize size = gfx::IntSize(aData.mSize.width, aData.mSize.height);
mTextureSurface = SharedSurface_GLTexture::Create(mGLContext, mGLContext,
mGLContext->GetGLFormats(),
size, caps.alpha, aData.mTexID);
SharedSurface* producer = mStream->SwapProducer(mFactory, size);
if (!producer) {
// Fallback to basic factory
delete mFactory;
mFactory = new SurfaceFactory_Basic(mGLContext, caps);
producer = mStream->SwapProducer(mFactory, size);
MOZ_ASSERT(producer, "Failed to create initial canvas surface with basic factory");
}
} else {
screen->Morph(factory, streamType);
}
}
}
}

View File

@ -33,6 +33,8 @@ public:
ClientCanvasLayer(ClientLayerManager* aLayerManager) :
CopyableCanvasLayer(aLayerManager,
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
, mTextureSurface(nullptr)
, mFactory(nullptr)
{
MOZ_COUNT_CTOR(ClientCanvasLayer);
}
@ -90,6 +92,9 @@ protected:
RefPtr<CanvasClient> mCanvasClient;
gfx::SharedSurface* mTextureSurface;
gfx::SurfaceFactory* mFactory;
friend class DeprecatedCanvasClient2D;
friend class CanvasClient2D;
friend class DeprecatedCanvasClientSurfaceStream;

View File

@ -86,7 +86,6 @@ SharedTextureClientOGL::IsAllocated() const
StreamTextureClientOGL::StreamTextureClientOGL(TextureFlags aFlags)
: TextureClient(aFlags)
, mStream(0)
, mIsLocked(false)
{
}
@ -131,6 +130,7 @@ StreamTextureClientOGL::InitWith(gfx::SurfaceStream* aStream)
{
MOZ_ASSERT(!IsAllocated());
mStream = aStream;
mGL = mStream->GLContext();
}
bool

View File

@ -97,8 +97,9 @@ public:
virtual gfx::IntSize GetSize() const { return gfx::IntSize(); }
protected:
gfx::SurfaceStream* mStream;
bool mIsLocked;
RefPtr<gfx::SurfaceStream> mStream;
RefPtr<gl::GLContext> mGL;
};
} // namespace

View File

@ -76,6 +76,11 @@
#ifdef USE_SKIA
#include "mozilla/Hal.h"
#include "skia/SkGraphics.h"
#ifdef USE_SKIA_GPU
#include "SkiaGLGlue.h"
#endif
#endif
#include "mozilla/Preferences.h"
@ -231,6 +236,11 @@ MemoryPressureObserver::Observe(nsISupports *aSubject,
{
NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
Factory::PurgeAllCaches();
#if USE_SKIA_GPU
gfxPlatform::GetPlatform()->PurgeSkiaCache();
#endif
return NS_OK;
}
@ -298,6 +308,10 @@ gfxPlatform::gfxPlatform()
mLayersUseDeprecated = false;
#endif
#ifdef USE_SKIA_GPU
mSkiaGlue = nullptr;
#endif
Preferences::AddBoolVarCache(&mDrawLayerBorders,
"layers.draw-borders",
false);
@ -482,10 +496,6 @@ gfxPlatform::Init()
CreateCMSOutputProfile();
#ifdef USE_SKIA
gPlatform->InitializeSkiaCaches();
#endif
// Listen to memory pressure event so we can purge DrawTarget caches
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -892,39 +902,68 @@ gfxPlatform::UseAcceleratedSkiaCanvas()
mPreferredCanvasBackend == BackendType::SKIA;
}
void
gfxPlatform::InitializeSkiaCaches()
static void
InitializeSkiaCacheLimits(GrContext* context)
{
#ifdef USE_SKIA_GPU
if (UseAcceleratedSkiaCanvas()) {
bool usingDynamicCache = Preferences::GetBool("gfx.canvas.skiagl.dynamic-cache", false);
bool usingDynamicCache = Preferences::GetBool("gfx.canvas.skiagl.dynamic-cache", false);
int cacheItemLimit = Preferences::GetInt("gfx.canvas.skiagl.cache-items", 256);
int cacheSizeLimit = Preferences::GetInt("gfx.canvas.skiagl.cache-size", 96);
int cacheItemLimit = Preferences::GetInt("gfx.canvas.skiagl.cache-items", 256);
int cacheSizeLimit = Preferences::GetInt("gfx.canvas.skiagl.cache-size", 96);
// Prefs are in megabytes, but we want the sizes in bytes
cacheSizeLimit *= 1024*1024;
// Prefs are in megabytes, but we want the sizes in bytes
cacheSizeLimit *= 1024*1024;
if (usingDynamicCache) {
uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
if (usingDynamicCache) {
uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
if (totalMemory <= 256*1024*1024) {
// We need a very minimal cache on 256 meg devices
cacheSizeLimit = 2*1024*1024;
} else if (totalMemory > 0) {
cacheSizeLimit = totalMemory / 16;
}
if (totalMemory <= 256*1024*1024) {
// We need a very minimal cache on 256 meg devices
cacheSizeLimit = 2*1024*1024;
} else if (totalMemory > 0) {
cacheSizeLimit = totalMemory / 16;
}
}
#ifdef DEBUG
printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
#endif
Factory::SetGlobalSkiaCacheLimits(cacheItemLimit, cacheSizeLimit);
}
context->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit);
#endif
}
#ifdef USE_SKIA_GPU
mozilla::gl::SkiaGLGlue*
gfxPlatform::GetSkiaGLGlue()
{
if (!mSkiaGlue) {
// Dummy context. We always draw into a FBO.
// FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
// stands, this only works on the main thread.
mozilla::gfx::SurfaceCaps caps = mozilla::gfx::SurfaceCaps::ForRGBA();
nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
if (!glContext) {
printf_stderr("Failed to create GLContext for SkiaGL!\n");
return nullptr;
}
mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext);
InitializeSkiaCacheLimits(mSkiaGlue->GetGrContext());
}
return mSkiaGlue;
}
void
gfxPlatform::PurgeSkiaCache()
{
if (!mSkiaGlue)
return;
mSkiaGlue->GetGrContext()->freeGpuResources();
}
#endif
already_AddRefed<gfxASurface>
gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{

View File

@ -40,6 +40,10 @@ struct gfxRGBA;
namespace mozilla {
namespace gl {
class GLContext;
#if USE_SKIA_GPU
class SkiaGLGlue;
#endif
}
namespace gfx {
class DrawTarget;
@ -284,8 +288,6 @@ public:
virtual bool UseAcceleratedSkiaCanvas();
virtual void InitializeSkiaCaches();
void GetAzureBackendInfo(mozilla::widget::InfoObject &aObj) {
aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
aObj.DefineProperty("AzureSkiaAccelerated", UseAcceleratedSkiaCanvas());
@ -632,6 +634,11 @@ public:
bool PreferMemoryOverShmem() const;
bool UseDeprecatedTextures() const { return mLayersUseDeprecated; }
#ifdef USE_SKIA_GPU
mozilla::gl::SkiaGLGlue* GetSkiaGLGlue();
void PurgeSkiaCache();
#endif
protected:
gfxPlatform();
virtual ~gfxPlatform();
@ -752,6 +759,10 @@ private:
bool mDrawLayerBorders;
bool mDrawTileBorders;
bool mDrawBigImageBorders;
#ifdef USE_SKIA_GPU
mozilla::RefPtr<mozilla::gl::SkiaGLGlue> mSkiaGlue;
#endif
};
#endif /* GFX_PLATFORM_H */