diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index b44f1d7818..e67d4355e4 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -2,6 +2,7 @@ #include "SamplePipeControllers.h" #include "SkCommonFlags.h" #include "SkDocument.h" +#include "SkError.h" #include "SkMultiPictureDraw.h" #include "SkNullCanvas.h" #include "SkOSFile.h" @@ -157,6 +158,8 @@ int GPUSink::enclave() const { return fThreaded ? kAnyThread_Enclave : kGPU_Enclave; } +void PreAbandonGpuContextErrorHandler(SkError, void*) {} + Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const { GrContextFactory factory; const SkISize size = src.size(); @@ -167,6 +170,10 @@ Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) co if (!surface) { return "Could not create a surface."; } + if (FLAGS_preAbandonGpuContext) { + SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, NULL); + factory.abandonContexts(); + } SkCanvas* canvas = surface->getCanvas(); Error err = src.draw(canvas); if (!err.isEmpty()) { @@ -178,7 +185,7 @@ Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) co canvas->getGrContext()->dumpGpuStats(log); } dst->allocPixels(info); - canvas->readPixels(dst, 0,0); + canvas->readPixels(dst, 0, 0); if (FLAGS_abandonGpuContext) { factory.abandonContexts(); } diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 221ed93ac8..c10d390f56 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -13,6 +13,7 @@ #include "SkDrawable.h" #include "SkDrawFilter.h" #include "SkDrawLooper.h" +#include "SkErrorInternals.h" #include "SkImage.h" #include "SkMetaData.h" #include "SkPathOps.h" @@ -947,7 +948,8 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage, fProps.pixelGeometry())); if (NULL == device) { - SkDebugf("Unable to create device for layer."); + SkErrorInternals::SetError( kInternalError_SkError, + "Unable to create device for layer."); return; } diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp index 32609b8b79..4dcc05e904 100644 --- a/src/effects/SkBlurImageFilter.cpp +++ b/src/effects/SkBlurImageFilter.cpp @@ -280,6 +280,9 @@ bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const true, sigma.x(), sigma.y())); + if (!tex) { + return false; + } WrapTexture(tex, rect.width(), rect.height(), result); return true; #else diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index d7c874cfda..491f5983d8 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -965,6 +965,9 @@ GrFragmentProcessor* GrRRectBlurEffect::Create(GrContext* context, float sigma, texDesc.fConfig = kAlpha_8_GrPixelConfig; blurNinePatchTexture = context->createTexture(texDesc, true, blurred_mask.fImage, 0); + if (!blurNinePatchTexture) { + return NULL; + } context->addResourceToCache(key, blurNinePatchTexture); SkMask::FreeImage(blurred_mask.fImage); diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index d2b8bc30f8..0f6599dc9a 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -1130,6 +1130,9 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx, fTextureAccess.reset(fAtlas->getTexture(), params); } else { SkAutoTUnref texture(GrRefCachedBitmapTexture(ctx, bitmap, ¶ms)); + if (!texture) { + return; + } fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode()); fTextureAccess.reset(texture, params); fYCoord = SK_ScalarHalf; diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index b574614eb0..85ea9cab28 100755 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -52,6 +52,9 @@ static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11; static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4; #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) +#define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; } +#define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; } +#define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; } class GrContext::AutoCheckFlush { public: @@ -240,6 +243,7 @@ bool GrContext::npotTextureTileSupport() const { GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData, size_t rowBytes) { + RETURN_NULL_IF_ABANDONED if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) && !this->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { return NULL; @@ -263,6 +267,7 @@ GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, bool budgeted, co GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match, bool calledDuringFlush) { + RETURN_NULL_IF_ABANDONED // Currently we don't recycle compressed textures as scratch. if (GrPixelConfigIsCompressed(desc.fConfig)) { return NULL; @@ -344,10 +349,12 @@ int GrContext::getMaxSampleCount() const { /////////////////////////////////////////////////////////////////////////////// GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) { + RETURN_NULL_IF_ABANDONED return fGpu->wrapBackendTexture(desc); } GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { + RETURN_NULL_IF_ABANDONED return fGpu->wrapBackendRenderTarget(desc); } @@ -357,6 +364,7 @@ void GrContext::clear(const SkIRect* rect, const GrColor color, bool canIgnoreRect, GrRenderTarget* renderTarget) { + RETURN_IF_ABANDONED ASSERT_OWNED_RESOURCE(renderTarget); SkASSERT(renderTarget); @@ -373,6 +381,7 @@ void GrContext::drawPaint(GrRenderTarget* rt, const GrClip& clip, const GrPaint& origPaint, const SkMatrix& viewMatrix) { + RETURN_IF_ABANDONED // set rect to be big enough to fill the space, but not super-huge, so we // don't overflow fixed-point implementations SkRect r; @@ -507,6 +516,7 @@ void GrContext::drawRect(GrRenderTarget* rt, const SkMatrix& viewMatrix, const SkRect& rect, const GrStrokeInfo* strokeInfo) { + RETURN_IF_ABANDONED if (strokeInfo && strokeInfo->isDashed()) { SkPath path; path.addRect(rect); @@ -641,6 +651,7 @@ void GrContext::drawNonAARectToRect(GrRenderTarget* rt, const SkRect& rectToDraw, const SkRect& localRect, const SkMatrix* localMatrix) { + RETURN_IF_ABANDONED AutoCheckFlush acf(this); GrPipelineBuilder pipelineBuilder; GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf); @@ -693,6 +704,7 @@ void GrContext::drawVertices(GrRenderTarget* rt, const GrColor colors[], const uint16_t indices[], int indexCount) { + RETURN_IF_ABANDONED AutoCheckFlush acf(this); GrPipelineBuilder pipelineBuilder; GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope @@ -751,6 +763,7 @@ void GrContext::drawRRect(GrRenderTarget*rt, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrStrokeInfo& strokeInfo) { + RETURN_IF_ABANDONED if (rrect.isEmpty()) { return; } @@ -796,6 +809,7 @@ void GrContext::drawDRRect(GrRenderTarget* rt, const SkMatrix& viewMatrix, const SkRRect& outer, const SkRRect& inner) { + RETURN_IF_ABANDONED if (outer.isEmpty()) { return; } @@ -833,6 +847,7 @@ void GrContext::drawOval(GrRenderTarget* rt, const SkMatrix& viewMatrix, const SkRect& oval, const GrStrokeInfo& strokeInfo) { + RETURN_IF_ABANDONED if (oval.isEmpty()) { return; } @@ -929,7 +944,7 @@ void GrContext::drawPath(GrRenderTarget* rt, const SkMatrix& viewMatrix, const SkPath& path, const GrStrokeInfo& strokeInfo) { - + RETURN_IF_ABANDONED if (path.isEmpty()) { if (path.isInverseFillType()) { this->drawPaint(rt, clip, paint, viewMatrix); @@ -1020,6 +1035,7 @@ void GrContext::internalDrawPath(GrDrawTarget* target, bool useAA, const SkPath& path, const GrStrokeInfo& strokeInfo) { + RETURN_IF_ABANDONED SkASSERT(!path.isEmpty()); GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target); @@ -1110,7 +1126,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, uint32_t pixelOpsFlags) { - + RETURN_FALSE_IF_ABANDONED { GrTexture* texture = NULL; if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) && @@ -1240,6 +1256,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig dstConfig, void* buffer, size_t rowBytes, uint32_t flags) { + RETURN_FALSE_IF_ABANDONED ASSERT_OWNED_RESOURCE(target); SkASSERT(target); @@ -1378,6 +1395,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, } void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) { + RETURN_IF_ABANDONED SkASSERT(surface); ASSERT_OWNED_RESOURCE(surface); if (surface->surfacePriv().hasPendingIO()) { @@ -1390,6 +1408,7 @@ void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) { } void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) { + RETURN_IF_ABANDONED SkASSERT(renderTarget); ASSERT_OWNED_RESOURCE(renderTarget); AutoCheckFlush acf(this); @@ -1402,6 +1421,7 @@ void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) { void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { + RETURN_IF_ABANDONED if (NULL == src || NULL == dst) { return; } @@ -1423,6 +1443,7 @@ void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe } void GrContext::flushSurfaceWrites(GrSurface* surface) { + RETURN_IF_ABANDONED if (surface->surfacePriv().hasPendingWrite()) { this->flush(); } @@ -1433,7 +1454,7 @@ GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder, const GrClip& clip, const GrPaint* paint, const AutoCheckFlush* acf) { - if (NULL == fGpu) { + if (NULL == fGpu || NULL == fDrawBuffer) { return NULL; } diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp index cef99c6c45..ad5e7c0aa5 100644 --- a/src/gpu/GrTextContext.cpp +++ b/src/gpu/GrTextContext.cpp @@ -40,6 +40,9 @@ bool GrTextContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPai const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y) { + if (!fContext->getTextTarget()) { + return false; + } GrTextContext* textContext = this; do { @@ -58,6 +61,9 @@ bool GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const Gr const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset) { + if (!fContext->getTextTarget()) { + return false; + } GrTextContext* textContext = this; do { diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index edbb82e167..fb5fa7cc7a 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1494,6 +1494,9 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, GrTexture* texture; // draw sprite uses the default texture params AutoBitmapTexture abt(fContext, bitmap, NULL, &texture); + if (!texture) { + return; + } SkImageFilter* filter = paint.getImageFilter(); // This bitmap will own the filtered result as a texture. @@ -1882,8 +1885,9 @@ SkBaseDevice* SkGpuDevice::onCreateCompatibleDevice(const CreateInfo& cinfo) { SkSurfaceProps props(fSurfaceProps.flags(), cinfo.fPixelGeometry); return SkGpuDevice::Create(texture->asRenderTarget(), &props, flags); } else { - SkDebugf("---- failed to create compatible device texture [%d %d]\n", - cinfo.fInfo.width(), cinfo.fInfo.height()); + SkErrorInternals::SetError( kInternalError_SkError, + "---- failed to create compatible device texture [%d %d]\n", + cinfo.fInfo.width(), cinfo.fInfo.height()); return NULL; } } diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 8dafcfcb34..6b520e7174 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -57,7 +57,7 @@ public: return static_cast(dev); } - GrContext* context() const { return fRenderTarget->getContext(); } + GrContext* context() const { return fContext; } // set all pixels to 0 void clearAll(); diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index b0814af1de..401a50eca8 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -11,6 +11,7 @@ #include "SkColorFilter.h" #include "SkConfig8888.h" #include "SkData.h" +#include "SkErrorInternals.h" #include "SkMessageBus.h" #include "SkPixelRef.h" #include "SkResourceCache.h" @@ -560,8 +561,9 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, return result; } - SkDebugf("---- failed to create texture for cache [%d %d]\n", - bitmap.width(), bitmap.height()); + SkErrorInternals::SetError( kInternalError_SkError, + "---- failed to create texture for cache [%d %d]\n", + bitmap.width(), bitmap.height()); return NULL; } diff --git a/src/gpu/effects/GrTextureStripAtlas.cpp b/src/gpu/effects/GrTextureStripAtlas.cpp index 51aaf53540..65096bf650 100644 --- a/src/gpu/effects/GrTextureStripAtlas.cpp +++ b/src/gpu/effects/GrTextureStripAtlas.cpp @@ -92,6 +92,9 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& data) { VALIDATE; if (0 == fLockedRows) { this->lockTexture(); + if (!fTexture) { + return -1; + } } int key = data.getGenerationID(); @@ -204,6 +207,9 @@ void GrTextureStripAtlas::lockTexture() { fTexture = fDesc.fContext->findAndRefCachedTexture(key); if (NULL == fTexture) { fTexture = fDesc.fContext->createTexture(texDesc, true, NULL, 0); + if (!fTexture) { + return; + } fDesc.fContext->addResourceToCache(key, fTexture); // This is a new texture, so all of our cache info is now invalid this->initLRU(); diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp index fa54a18979..d05f76439b 100644 --- a/tools/flags/SkCommonFlags.cpp +++ b/tools/flags/SkCommonFlags.cpp @@ -39,6 +39,8 @@ DEFINE_string2(match, m, NULL, DEFINE_bool2(quiet, q, false, "if true, don't print status updates."); +DEFINE_bool(preAbandonGpuContext, false, "Abandons the GrContext before running the test."); + DEFINE_bool(abandonGpuContext, false, "Abandon the GrContext after running each test."); DEFINE_string(skps, "skps", "Directory to read skps from."); diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h index 69b835800c..6a5ff58f4f 100644 --- a/tools/flags/SkCommonFlags.h +++ b/tools/flags/SkCommonFlags.h @@ -20,6 +20,7 @@ DECLARE_bool(leaks); DECLARE_string(match); DECLARE_bool(quiet); DECLARE_bool(resetGpuContext); +DECLARE_bool(preAbandonGpuContext); DECLARE_bool(abandonGpuContext); DECLARE_string(skps); DECLARE_int32(threads);