Remove separate cache for clip mask textures
Review URL: https://codereview.chromium.org/1377943003
This commit is contained in:
parent
399dd05962
commit
473addf176
@ -78,8 +78,6 @@
|
||||
'<(skia_src_path)/gpu/GrBufferAllocPool.h',
|
||||
'<(skia_src_path)/gpu/GrCaps.cpp',
|
||||
'<(skia_src_path)/gpu/GrClip.cpp',
|
||||
'<(skia_src_path)/gpu/GrClipMaskCache.h',
|
||||
'<(skia_src_path)/gpu/GrClipMaskCache.cpp',
|
||||
'<(skia_src_path)/gpu/GrClipMaskManager.h',
|
||||
'<(skia_src_path)/gpu/GrClipMaskManager.cpp',
|
||||
'<(skia_src_path)/gpu/GrContext.cpp',
|
||||
|
@ -430,7 +430,6 @@ private:
|
||||
void abandon();
|
||||
bool abandoned() const { return NULL == fDrawTarget; }
|
||||
|
||||
void purgeResources();
|
||||
void reset();
|
||||
void flush();
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrClipMaskCache.h"
|
||||
|
||||
GrClipMaskCache::GrClipMaskCache(GrResourceProvider* resourceProvider)
|
||||
: fStack(sizeof(GrClipStackFrame))
|
||||
, fResourceProvider(resourceProvider) {
|
||||
// We need an initial frame to capture the clip state prior to
|
||||
// any pushes
|
||||
new (fStack.push_back()) GrClipStackFrame;
|
||||
}
|
||||
|
||||
void GrClipMaskCache::push() { new (fStack.push_back()) GrClipStackFrame; }
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrClipMaskCache_DEFINED
|
||||
#define GrClipMaskCache_DEFINED
|
||||
|
||||
#include "GrResourceProvider.h"
|
||||
#include "SkClipStack.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
class GrTexture;
|
||||
|
||||
/**
|
||||
* The stencil buffer stores the last clip path - providing a single entry
|
||||
* "cache". This class provides similar functionality for AA clip paths
|
||||
*/
|
||||
class GrClipMaskCache : SkNoncopyable {
|
||||
public:
|
||||
GrClipMaskCache(GrResourceProvider*);
|
||||
|
||||
~GrClipMaskCache() {
|
||||
while (!fStack.empty()) {
|
||||
GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
|
||||
temp->~GrClipStackFrame();
|
||||
fStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool canReuse(int32_t clipGenID, const SkIRect& bounds) {
|
||||
|
||||
SkASSERT(clipGenID != SkClipStack::kWideOpenGenID);
|
||||
SkASSERT(clipGenID != SkClipStack::kEmptyGenID);
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
// We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
|
||||
// an offset to the caller.
|
||||
if (back->fLastMask &&
|
||||
!back->fLastMask->wasDestroyed() &&
|
||||
back->fLastBound == bounds &&
|
||||
back->fLastClipGenID == clipGenID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (fStack.empty()) {
|
||||
// SkASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
back->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* After a "push" the clip state is entirely open. Currently, the
|
||||
* entire clip stack will be re-rendered into a new clip mask.
|
||||
* TODO: can we take advantage of the nested nature of the clips to
|
||||
* reduce the mask creation cost?
|
||||
*/
|
||||
void push();
|
||||
|
||||
void pop() {
|
||||
//SkASSERT(!fStack.empty());
|
||||
|
||||
if (!fStack.empty()) {
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
back->~GrClipStackFrame();
|
||||
fStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t getLastClipGenID() const {
|
||||
|
||||
if (fStack.empty()) {
|
||||
return SkClipStack::kInvalidGenID;
|
||||
}
|
||||
|
||||
return ((GrClipStackFrame*) fStack.back())->fLastClipGenID;
|
||||
}
|
||||
|
||||
GrTexture* getLastMask() {
|
||||
|
||||
if (fStack.empty()) {
|
||||
SkASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
return back->fLastMask;
|
||||
}
|
||||
|
||||
const GrTexture* getLastMask() const {
|
||||
|
||||
if (fStack.empty()) {
|
||||
SkASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
return back->fLastMask;
|
||||
}
|
||||
|
||||
void acquireMask(int32_t clipGenID,
|
||||
const GrSurfaceDesc& desc,
|
||||
const SkIRect& bound) {
|
||||
|
||||
if (fStack.empty()) {
|
||||
SkASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
back->acquireMask(fResourceProvider, clipGenID, desc, bound);
|
||||
}
|
||||
|
||||
int getLastMaskWidth() const {
|
||||
|
||||
if (fStack.empty()) {
|
||||
SkASSERT(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
if (nullptr == back->fLastMask) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return back->fLastMask->width();
|
||||
}
|
||||
|
||||
int getLastMaskHeight() const {
|
||||
|
||||
if (fStack.empty()) {
|
||||
SkASSERT(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
if (nullptr == back->fLastMask) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return back->fLastMask->height();
|
||||
}
|
||||
|
||||
void getLastBound(SkIRect* bound) const {
|
||||
|
||||
if (fStack.empty()) {
|
||||
SkASSERT(false);
|
||||
bound->setEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
|
||||
|
||||
*bound = back->fLastBound;
|
||||
}
|
||||
|
||||
// TODO: Remove this when we hold cache keys instead of refs to textures.
|
||||
void purgeResources() {
|
||||
SkDeque::F2BIter iter(fStack);
|
||||
for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
|
||||
frame != nullptr;
|
||||
frame = (GrClipStackFrame*) iter.next()) {
|
||||
frame->reset();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct GrClipStackFrame {
|
||||
|
||||
GrClipStackFrame() {
|
||||
this->reset();
|
||||
}
|
||||
|
||||
void acquireMask(GrResourceProvider* resourceProvider,
|
||||
int32_t clipGenID,
|
||||
const GrSurfaceDesc& desc,
|
||||
const SkIRect& bound) {
|
||||
|
||||
fLastClipGenID = clipGenID;
|
||||
|
||||
// TODO: Determine if we really need the NoPendingIO flag anymore.
|
||||
// (http://skbug.com/4156)
|
||||
static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag;
|
||||
fLastMask.reset(resourceProvider->createApproxTexture(desc, kFlags));
|
||||
|
||||
fLastBound = bound;
|
||||
}
|
||||
|
||||
void reset () {
|
||||
fLastClipGenID = SkClipStack::kInvalidGenID;
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
|
||||
fLastMask.reset(nullptr);
|
||||
fLastBound.setEmpty();
|
||||
}
|
||||
|
||||
int32_t fLastClipGenID;
|
||||
// The mask's width & height values are used by GrClipMaskManager to correctly scale the
|
||||
// texture coords for the geometry drawn with this mask. TODO: This should be a cache key
|
||||
// and not a hard ref to a texture.
|
||||
SkAutoTUnref<GrTexture> fLastMask;
|
||||
// fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
|
||||
// used by GrClipMaskManager to position a rect and compute texture coords for the mask.
|
||||
SkIRect fLastBound;
|
||||
};
|
||||
|
||||
SkDeque fStack;
|
||||
GrResourceProvider* fResourceProvider;
|
||||
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
|
||||
#endif // GrClipMaskCache_DEFINED
|
@ -9,10 +9,12 @@
|
||||
#include "GrCaps.h"
|
||||
#include "GrDrawContext.h"
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrPaint.h"
|
||||
#include "GrPathRenderer.h"
|
||||
#include "GrRenderTarget.h"
|
||||
#include "GrRenderTargetPriv.h"
|
||||
#include "GrResourceProvider.h"
|
||||
#include "GrStencilAttachment.h"
|
||||
#include "GrSWMaskHelper.h"
|
||||
#include "SkRasterClip.h"
|
||||
@ -78,7 +80,6 @@ bool path_needs_SW_renderer(GrContext* context,
|
||||
|
||||
GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget)
|
||||
: fCurrClipMaskType(kNone_ClipMaskType)
|
||||
, fAACache(drawTarget->cmmAccess().resourceProvider())
|
||||
, fDrawTarget(drawTarget)
|
||||
, fClipMode(kIgnoreClip_StencilClipMode) {
|
||||
}
|
||||
@ -344,13 +345,6 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
// if alpha clip mask creation fails fall through to the non-AA code paths
|
||||
}
|
||||
|
||||
// Either a hard (stencil buffer) clip was explicitly requested or an anti-aliased clip couldn't
|
||||
// be created. In either case, free up the texture in the anti-aliased mask cache.
|
||||
// TODO: this may require more investigation. Ganesh performs a lot of utility draws (e.g.,
|
||||
// clears, GrBufferedDrawTarget playbacks) that hit the stencil buffer path. These may be
|
||||
// "incorrectly" clearing the AA cache.
|
||||
fAACache.reset();
|
||||
|
||||
// use the stencil clip if we can't represent the clip as a rectangle.
|
||||
SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin();
|
||||
this->createStencilClipMask(rt,
|
||||
@ -516,62 +510,55 @@ GrTexture* GrClipMaskManager::createTempMask(int width, int height) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Return the texture currently in the cache if it exists. Otherwise, return nullptr
|
||||
GrTexture* GrClipMaskManager::getCachedMaskTexture(int32_t elementsGenID,
|
||||
const SkIRect& clipSpaceIBounds) {
|
||||
bool cached = fAACache.canReuse(elementsGenID, clipSpaceIBounds);
|
||||
if (!cached) {
|
||||
// Create a 8-bit clip mask in alpha
|
||||
|
||||
static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(key, kDomain, 3);
|
||||
builder[0] = clipGenID;
|
||||
builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16);
|
||||
builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16);
|
||||
}
|
||||
|
||||
GrTexture* GrClipMaskManager::createCachedMask(int width, int height, const GrUniqueKey& key,
|
||||
bool renderTarget) {
|
||||
GrSurfaceDesc desc;
|
||||
desc.fWidth = width;
|
||||
desc.fHeight = height;
|
||||
desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
|
||||
if (!renderTarget || fDrawTarget->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
|
||||
desc.fConfig = kAlpha_8_GrPixelConfig;
|
||||
} else {
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
}
|
||||
|
||||
GrTexture* texture = fDrawTarget->cmmAccess().resourceProvider()->createApproxTexture(desc, 0);
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return fAACache.getLastMask();
|
||||
texture->resourcePriv().setUniqueKey(key);
|
||||
return texture;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Allocate a texture in the texture cache. This function returns the texture
|
||||
// allocated (or nullptr on error).
|
||||
GrTexture* GrClipMaskManager::allocMaskTexture(int32_t elementsGenID,
|
||||
const SkIRect& clipSpaceIBounds,
|
||||
bool willUpload) {
|
||||
// Since we are setting up the cache we should free up the
|
||||
// currently cached mask so it can be reused.
|
||||
fAACache.reset();
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = willUpload ? kNone_GrSurfaceFlags : kRenderTarget_GrSurfaceFlag;
|
||||
desc.fWidth = clipSpaceIBounds.width();
|
||||
desc.fHeight = clipSpaceIBounds.height();
|
||||
desc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
if (willUpload ||
|
||||
this->getContext()->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
|
||||
// We would always like A8 but it isn't supported on all platforms
|
||||
desc.fConfig = kAlpha_8_GrPixelConfig;
|
||||
}
|
||||
|
||||
fAACache.acquireMask(elementsGenID, desc, clipSpaceIBounds);
|
||||
return fAACache.getLastMask();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Create a 8-bit clip mask in alpha
|
||||
GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
GrReducedClip::InitialState initialState,
|
||||
const GrReducedClip::ElementList& elements,
|
||||
const SkVector& clipToMaskOffset,
|
||||
const SkIRect& clipSpaceIBounds) {
|
||||
SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
|
||||
|
||||
// First, check for cached texture
|
||||
GrTexture* result = this->getCachedMaskTexture(elementsGenID, clipSpaceIBounds);
|
||||
if (result) {
|
||||
GrResourceProvider* resourceProvider = fDrawTarget->cmmAccess().resourceProvider();
|
||||
GrUniqueKey key;
|
||||
GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
|
||||
if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
|
||||
fCurrClipMaskType = kAlpha_ClipMaskType;
|
||||
return result;
|
||||
return texture;
|
||||
}
|
||||
|
||||
SkAutoTUnref<GrTexture> texture(this->createCachedMask(
|
||||
clipSpaceIBounds.width(), clipSpaceIBounds.height(), key, true));
|
||||
|
||||
// There's no texture in the cache. Let's try to allocate it then.
|
||||
result = this->allocMaskTexture(elementsGenID, clipSpaceIBounds, false);
|
||||
if (nullptr == result) {
|
||||
fAACache.reset();
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -589,7 +576,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
fDrawTarget->clear(&maskSpaceIBounds,
|
||||
GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
|
||||
true,
|
||||
result->asRenderTarget());
|
||||
texture->asRenderTarget());
|
||||
|
||||
// When we use the stencil in the below loop it is important to have this clip installed.
|
||||
// The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first
|
||||
@ -608,7 +595,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
|
||||
pipelineBuilder.setClip(clip);
|
||||
GrPathRenderer* pr = nullptr;
|
||||
bool useTemp = !this->canStencilAndDrawElement(&pipelineBuilder, result, &pr, element);
|
||||
bool useTemp = !this->canStencilAndDrawElement(&pipelineBuilder, texture, &pr, element);
|
||||
GrTexture* dst;
|
||||
// This is the bounds of the clip element in the space of the alpha-mask. The temporary
|
||||
// mask buffer can be substantially larger than the actually clip stack element. We
|
||||
@ -629,7 +616,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
temp.reset(this->createTempMask(maskSpaceIBounds.fRight,
|
||||
maskSpaceIBounds.fBottom));
|
||||
if (!temp) {
|
||||
fAACache.reset();
|
||||
texture->resourcePriv().removeUniqueKey();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -643,7 +630,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
} else {
|
||||
// draw directly into the result with the stencil set to make the pixels affected
|
||||
// by the clip shape be non-zero.
|
||||
dst = result;
|
||||
dst = texture;
|
||||
GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
|
||||
kReplace_StencilOp,
|
||||
kReplace_StencilOp,
|
||||
@ -656,25 +643,25 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
}
|
||||
|
||||
if (!this->drawElement(&pipelineBuilder, translate, dst, element, pr)) {
|
||||
fAACache.reset();
|
||||
texture->resourcePriv().removeUniqueKey();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (useTemp) {
|
||||
GrPipelineBuilder backgroundPipelineBuilder;
|
||||
backgroundPipelineBuilder.setRenderTarget(result->asRenderTarget());
|
||||
backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarget());
|
||||
|
||||
// Now draw into the accumulator using the real operation and the temp buffer as a
|
||||
// texture
|
||||
this->mergeMask(&backgroundPipelineBuilder,
|
||||
result,
|
||||
texture,
|
||||
temp,
|
||||
op,
|
||||
maskSpaceIBounds,
|
||||
maskSpaceElementIBounds);
|
||||
} else {
|
||||
GrPipelineBuilder backgroundPipelineBuilder;
|
||||
backgroundPipelineBuilder.setRenderTarget(result->asRenderTarget());
|
||||
backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarget());
|
||||
|
||||
set_coverage_drawing_xpf(op, !invert, &backgroundPipelineBuilder);
|
||||
// Draw to the exterior pixels (those with a zero stencil value).
|
||||
@ -697,12 +684,12 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
|
||||
// all the remaining ops can just be directly draw into the accumulation buffer
|
||||
set_coverage_drawing_xpf(op, false, &pipelineBuilder);
|
||||
// The color passed in here does not matter since the coverageSetOpXP won't read it.
|
||||
this->drawElement(&pipelineBuilder, translate, result, element);
|
||||
this->drawElement(&pipelineBuilder, translate, texture, element);
|
||||
}
|
||||
}
|
||||
|
||||
fCurrClipMaskType = kAlpha_ClipMaskType;
|
||||
return result;
|
||||
return texture.detach();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1079,10 +1066,11 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
||||
const SkVector& clipToMaskOffset,
|
||||
const SkIRect& clipSpaceIBounds) {
|
||||
SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
|
||||
|
||||
GrTexture* result = this->getCachedMaskTexture(elementsGenID, clipSpaceIBounds);
|
||||
if (result) {
|
||||
return result;
|
||||
GrUniqueKey key;
|
||||
GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
|
||||
GrResourceProvider* resourceProvider = fDrawTarget->cmmAccess().resourceProvider();
|
||||
if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
// The mask texture may be larger than necessary. We round out the clip space bounds and pin
|
||||
@ -1133,9 +1121,9 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
||||
}
|
||||
|
||||
// Allocate clip mask texture
|
||||
result = this->allocMaskTexture(elementsGenID, clipSpaceIBounds, true);
|
||||
GrTexture* result = this->createCachedMask(clipSpaceIBounds.width(), clipSpaceIBounds.height(),
|
||||
key, false);
|
||||
if (nullptr == result) {
|
||||
fAACache.reset();
|
||||
return nullptr;
|
||||
}
|
||||
helper.toTexture(result);
|
||||
@ -1145,9 +1133,6 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void GrClipMaskManager::purgeResources() {
|
||||
fAACache.purgeResources();
|
||||
}
|
||||
|
||||
void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stencilAttachment,
|
||||
GrStencilSettings* settings) {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#ifndef GrClipMaskManager_DEFINED
|
||||
#define GrClipMaskManager_DEFINED
|
||||
|
||||
#include "GrClipMaskCache.h"
|
||||
#include "GrPipelineBuilder.h"
|
||||
#include "GrReducedClip.h"
|
||||
#include "GrStencil.h"
|
||||
@ -49,12 +48,6 @@ public:
|
||||
GrScissorState*,
|
||||
const SkRect* devBounds);
|
||||
|
||||
/**
|
||||
* Purge resources to free up memory. TODO: This class shouldn't hold any long lived refs
|
||||
* which will allow GrResourceCache to automatically purge anything this class has created.
|
||||
*/
|
||||
void purgeResources();
|
||||
|
||||
bool isClipInStencil() const {
|
||||
return kStencil_ClipMaskType == fCurrClipMaskType;
|
||||
}
|
||||
@ -113,17 +106,7 @@ private:
|
||||
const SkVector& clipToMaskOffset,
|
||||
const SkIRect& clipSpaceIBounds);
|
||||
|
||||
// Returns the cached mask texture if it matches the elementsGenID and the clipSpaceIBounds.
|
||||
// Returns nullptr if not found.
|
||||
GrTexture* getCachedMaskTexture(int32_t elementsGenID, const SkIRect& clipSpaceIBounds);
|
||||
|
||||
// Handles allocation (if needed) of a clip alpha-mask texture for both the sw-upload
|
||||
// or gpu-rendered cases.
|
||||
GrTexture* allocMaskTexture(int32_t elementsGenID,
|
||||
const SkIRect& clipSpaceIBounds,
|
||||
bool willUpload);
|
||||
|
||||
bool useSWOnlyPath(const GrPipelineBuilder&,
|
||||
bool useSWOnlyPath(const GrPipelineBuilder&,
|
||||
const SkVector& clipToMaskOffset,
|
||||
const GrReducedClip::ElementList& elements);
|
||||
|
||||
@ -153,8 +136,6 @@ private:
|
||||
|
||||
GrTexture* createTempMask(int width, int height);
|
||||
|
||||
void setupCache(const SkClipStack& clip,
|
||||
const SkIRect& bounds);
|
||||
/**
|
||||
* Called prior to return control back the GrGpu in setupClipping. It updates the
|
||||
* GrPipelineBuilder with stencil settings that account for stencil-based clipping.
|
||||
@ -170,6 +151,8 @@ private:
|
||||
StencilClipMode mode,
|
||||
int stencilBitCnt);
|
||||
|
||||
GrTexture* createCachedMask(int width, int height, const GrUniqueKey& key, bool renderTarget);
|
||||
|
||||
/**
|
||||
* We may represent the clip as a mask in the stencil buffer or as an alpha
|
||||
* texture. It may be neither because the scissor rect suffices or we
|
||||
@ -181,7 +164,6 @@ private:
|
||||
kAlpha_ClipMaskType,
|
||||
} fCurrClipMaskType;
|
||||
|
||||
GrClipMaskCache fAACache; // cache for the AA path
|
||||
GrDrawTarget* fDrawTarget; // This is our owning draw target.
|
||||
StencilClipMode fClipMode;
|
||||
|
||||
|
@ -87,12 +87,6 @@ void GrContext::DrawingMgr::abandon() {
|
||||
}
|
||||
}
|
||||
|
||||
void GrContext::DrawingMgr::purgeResources() {
|
||||
if (fDrawTarget) {
|
||||
fDrawTarget->purgeResources();
|
||||
}
|
||||
}
|
||||
|
||||
void GrContext::DrawingMgr::reset() {
|
||||
if (fDrawTarget) {
|
||||
fDrawTarget->reset();
|
||||
@ -243,8 +237,6 @@ void GrContext::resetContext(uint32_t state) {
|
||||
void GrContext::freeGpuResources() {
|
||||
this->flush();
|
||||
|
||||
fDrawingMgr.purgeResources();
|
||||
|
||||
fBatchFontCache->freeAll();
|
||||
fLayerCache->freeAll();
|
||||
// a path renderer may be holding onto resources
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "GrPathRenderer.h"
|
||||
#include "GrRenderTarget.h"
|
||||
#include "GrRenderTargetPriv.h"
|
||||
#include "GrResourceProvider.h"
|
||||
#include "GrStencilAndCoverTextContext.h"
|
||||
|
||||
#include "batches/GrBatch.h"
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "GrVertexBuffer.h"
|
||||
#include "GrXferProcessor.h"
|
||||
|
||||
#include "batches/GrDrawBatch.h"
|
||||
|
||||
#include "SkClipStack.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkPath.h"
|
||||
@ -34,7 +36,6 @@ class GrBatch;
|
||||
class GrClip;
|
||||
class GrCaps;
|
||||
class GrPath;
|
||||
class GrDrawBatch;
|
||||
class GrDrawPathBatchBase;
|
||||
class GrPathRangeDraw;
|
||||
|
||||
@ -170,15 +171,6 @@ public:
|
||||
GrSurface* src,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint);
|
||||
/**
|
||||
* Release any resources that are cached but not currently in use. This
|
||||
* is intended to give an application some recourse when resources are low.
|
||||
* TODO: Stop holding on to resources.
|
||||
*/
|
||||
virtual void purgeResources() {
|
||||
// The clip mask manager can rebuild all its clip masks so just get rid of them all.
|
||||
fClipMaskManager->purgeResources();
|
||||
};
|
||||
|
||||
bool programUnitTest(GrContext* owner, int maxStages);
|
||||
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
|
||||
using GrTextureProvider::assignUniqueKeyToResource;
|
||||
using GrTextureProvider::findAndRefResourceByUniqueKey;
|
||||
using GrTextureProvider::findAndRefTextureByUniqueKey;
|
||||
using GrTextureProvider::abandon;
|
||||
|
||||
enum Flags {
|
||||
@ -142,6 +143,8 @@ public:
|
||||
*/
|
||||
GrStencilAttachment* attachStencilAttachment(GrRenderTarget* rt);
|
||||
|
||||
const GrCaps* caps() { return this->gpu()->caps(); }
|
||||
|
||||
private:
|
||||
const GrIndexBuffer* createInstancedIndexBuffer(const uint16_t* pattern,
|
||||
int patternSize,
|
||||
|
85
tests/ClipBoundsTest.cpp
Normal file
85
tests/ClipBoundsTest.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Test.h"
|
||||
// This is a GR test
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrClipMaskManager.h"
|
||||
#include "GrContextFactory.h"
|
||||
#include "SkGpuDevice.h"
|
||||
|
||||
// Ensure that the 'getConservativeBounds' calls are returning bounds clamped
|
||||
// to the render target
|
||||
static void test_clip_bounds(skiatest::Reporter* reporter, GrContext* context) {
|
||||
|
||||
static const int kXSize = 100;
|
||||
static const int kYSize = 100;
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fConfig = kAlpha_8_GrPixelConfig;
|
||||
desc.fWidth = kXSize;
|
||||
desc.fHeight = kYSize;
|
||||
|
||||
SkAutoTUnref<GrTexture> texture(
|
||||
context->textureProvider()->createTexture(desc, false, nullptr, 0));
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkIRect intScreen = SkIRect::MakeWH(kXSize, kYSize);
|
||||
SkRect screen = SkRect::Make(intScreen);
|
||||
|
||||
SkRect clipRect(screen);
|
||||
clipRect.outset(10, 10);
|
||||
|
||||
// create a clip stack that will (trivially) reduce to a single rect that
|
||||
// is larger than the screen
|
||||
SkClipStack stack;
|
||||
stack.clipDevRect(clipRect, SkRegion::kReplace_Op, false);
|
||||
|
||||
bool isIntersectionOfRects = true;
|
||||
SkRect devStackBounds;
|
||||
|
||||
stack.getConservativeBounds(0, 0, kXSize, kYSize,
|
||||
&devStackBounds,
|
||||
&isIntersectionOfRects);
|
||||
|
||||
// make sure that the SkClipStack is behaving itself
|
||||
REPORTER_ASSERT(reporter, screen == devStackBounds);
|
||||
REPORTER_ASSERT(reporter, isIntersectionOfRects);
|
||||
|
||||
// wrap the SkClipStack in a GrClip
|
||||
GrClip clipData;
|
||||
clipData.setClipStack(&stack);
|
||||
|
||||
SkIRect devGrClipBound;
|
||||
clipData.getConservativeBounds(texture,
|
||||
&devGrClipBound,
|
||||
&isIntersectionOfRects);
|
||||
|
||||
// make sure that GrClip is behaving itself
|
||||
REPORTER_ASSERT(reporter, intScreen == devGrClipBound);
|
||||
REPORTER_ASSERT(reporter, isIntersectionOfRects);
|
||||
}
|
||||
|
||||
DEF_GPUTEST(GrClipBounds, reporter, factory) {
|
||||
for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
|
||||
GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
|
||||
if (!GrContextFactory::IsRenderingGLContext(glType)) {
|
||||
continue;
|
||||
}
|
||||
GrContext* context = factory->get(glType);
|
||||
if (nullptr == context) {
|
||||
continue;
|
||||
}
|
||||
test_clip_bounds(reporter, context);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Test.h"
|
||||
// This is a GR test
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrClipMaskManager.h"
|
||||
#include "GrContextFactory.h"
|
||||
#include "SkGpuDevice.h"
|
||||
|
||||
static const int X_SIZE = 12;
|
||||
static const int Y_SIZE = 12;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// note: this is unused
|
||||
static GrTexture* create_texture(GrContext* context) {
|
||||
unsigned char textureData[X_SIZE][Y_SIZE][4];
|
||||
|
||||
memset(textureData, 0, 4* X_SIZE * Y_SIZE);
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
|
||||
// let Skia know we will be using this texture as a render target
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
desc.fWidth = X_SIZE;
|
||||
desc.fHeight = Y_SIZE;
|
||||
|
||||
// We are initializing the texture with zeros here
|
||||
GrTexture* texture = context->textureProvider()->createTexture(desc, false, textureData, 0);
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Ensure that the 'getConservativeBounds' calls are returning bounds clamped
|
||||
// to the render target
|
||||
static void test_clip_bounds(skiatest::Reporter* reporter, GrContext* context) {
|
||||
|
||||
static const int kXSize = 100;
|
||||
static const int kYSize = 100;
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fConfig = kAlpha_8_GrPixelConfig;
|
||||
desc.fWidth = kXSize;
|
||||
desc.fHeight = kYSize;
|
||||
|
||||
GrTexture* texture = context->textureProvider()->createTexture(desc, false, nullptr, 0);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkAutoTUnref<GrTexture> au(texture);
|
||||
|
||||
SkIRect intScreen = SkIRect::MakeWH(kXSize, kYSize);
|
||||
SkRect screen;
|
||||
|
||||
screen = SkRect::MakeWH(SkIntToScalar(kXSize),
|
||||
SkIntToScalar(kYSize));
|
||||
|
||||
SkRect clipRect(screen);
|
||||
clipRect.outset(10, 10);
|
||||
|
||||
// create a clip stack that will (trivially) reduce to a single rect that
|
||||
// is larger than the screen
|
||||
SkClipStack stack;
|
||||
stack.clipDevRect(clipRect, SkRegion::kReplace_Op, false);
|
||||
|
||||
bool isIntersectionOfRects = true;
|
||||
SkRect devStackBounds;
|
||||
|
||||
stack.getConservativeBounds(0, 0, kXSize, kYSize,
|
||||
&devStackBounds,
|
||||
&isIntersectionOfRects);
|
||||
|
||||
// make sure that the SkClipStack is behaving itself
|
||||
REPORTER_ASSERT(reporter, screen == devStackBounds);
|
||||
REPORTER_ASSERT(reporter, isIntersectionOfRects);
|
||||
|
||||
// wrap the SkClipStack in a GrClip
|
||||
GrClip clipData;
|
||||
clipData.setClipStack(&stack);
|
||||
|
||||
SkIRect devGrClipBound;
|
||||
clipData.getConservativeBounds(texture,
|
||||
&devGrClipBound,
|
||||
&isIntersectionOfRects);
|
||||
|
||||
// make sure that GrClip is behaving itself
|
||||
REPORTER_ASSERT(reporter, intScreen == devGrClipBound);
|
||||
REPORTER_ASSERT(reporter, isIntersectionOfRects);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// verify that the top state of the stack matches the passed in state
|
||||
static void check_state(skiatest::Reporter* reporter,
|
||||
const GrClipMaskCache& cache,
|
||||
const SkClipStack& clip,
|
||||
GrTexture* mask,
|
||||
const SkIRect& bound) {
|
||||
REPORTER_ASSERT(reporter, clip.getTopmostGenID() == cache.getLastClipGenID());
|
||||
|
||||
REPORTER_ASSERT(reporter, mask == cache.getLastMask());
|
||||
|
||||
SkIRect cacheBound;
|
||||
cache.getLastBound(&cacheBound);
|
||||
REPORTER_ASSERT(reporter, bound == cacheBound);
|
||||
}
|
||||
|
||||
static void check_empty_state(skiatest::Reporter* reporter,
|
||||
const GrClipMaskCache& cache) {
|
||||
REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID == cache.getLastClipGenID());
|
||||
REPORTER_ASSERT(reporter, nullptr == cache.getLastMask());
|
||||
|
||||
SkIRect emptyBound;
|
||||
emptyBound.setEmpty();
|
||||
|
||||
SkIRect cacheBound;
|
||||
cache.getLastBound(&cacheBound);
|
||||
REPORTER_ASSERT(reporter, emptyBound == cacheBound);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// basic test of the cache's base functionality:
|
||||
// push, pop, set, canReuse & getters
|
||||
static void test_cache(skiatest::Reporter* reporter, GrContext* context) {
|
||||
|
||||
if (false) { // avoid bit rot, suppress warning
|
||||
create_texture(context);
|
||||
}
|
||||
GrClipMaskCache cache(context->resourceProvider());
|
||||
|
||||
// check initial state
|
||||
check_empty_state(reporter, cache);
|
||||
|
||||
// set the current state
|
||||
SkIRect bound1;
|
||||
bound1.set(0, 0, 100, 100);
|
||||
|
||||
SkClipStack clip1(bound1);
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fWidth = X_SIZE;
|
||||
desc.fHeight = Y_SIZE;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
cache.acquireMask(clip1.getTopmostGenID(), desc, bound1);
|
||||
|
||||
GrTexture* texture1 = cache.getLastMask();
|
||||
REPORTER_ASSERT(reporter, texture1);
|
||||
if (nullptr == texture1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check that the set took
|
||||
check_state(reporter, cache, clip1, texture1, bound1);
|
||||
|
||||
// push the state
|
||||
cache.push();
|
||||
|
||||
// verify that the pushed state is initially empty
|
||||
check_empty_state(reporter, cache);
|
||||
|
||||
// modify the new state
|
||||
SkIRect bound2;
|
||||
bound2.set(-10, -10, 10, 10);
|
||||
|
||||
SkClipStack clip2(bound2);
|
||||
|
||||
cache.acquireMask(clip2.getTopmostGenID(), desc, bound2);
|
||||
|
||||
GrTexture* texture2 = cache.getLastMask();
|
||||
REPORTER_ASSERT(reporter, texture2);
|
||||
if (nullptr == texture2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check that the changes took
|
||||
check_state(reporter, cache, clip2, texture2, bound2);
|
||||
|
||||
// check to make sure canReuse works
|
||||
REPORTER_ASSERT(reporter, cache.canReuse(clip2.getTopmostGenID(), bound2));
|
||||
REPORTER_ASSERT(reporter, !cache.canReuse(clip1.getTopmostGenID(), bound1));
|
||||
|
||||
// pop the state
|
||||
cache.pop();
|
||||
|
||||
// verify that the old state is restored
|
||||
check_state(reporter, cache, clip1, texture1, bound1);
|
||||
|
||||
// manually clear the state
|
||||
cache.reset();
|
||||
|
||||
// verify it is now empty
|
||||
check_empty_state(reporter, cache);
|
||||
|
||||
// pop again - so there is no state
|
||||
cache.pop();
|
||||
|
||||
#if !defined(SK_DEBUG)
|
||||
// verify that the getters don't crash
|
||||
// only do in release since it generates asserts in debug
|
||||
check_empty_state(reporter, cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
DEF_GPUTEST(ClipCache, reporter, factory) {
|
||||
for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
|
||||
GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
|
||||
if (!GrContextFactory::IsRenderingGLContext(glType)) {
|
||||
continue;
|
||||
}
|
||||
GrContext* context = factory->get(glType);
|
||||
if (nullptr == context) {
|
||||
continue;
|
||||
}
|
||||
|
||||
test_cache(reporter, context);
|
||||
test_clip_bounds(reporter, context);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@
|
||||
#include "GrRenderTarget.h"
|
||||
#include "GrRenderTargetPriv.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrResourceProvider.h"
|
||||
#include "GrTest.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkGr.h"
|
||||
|
Loading…
Reference in New Issue
Block a user