aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dm/DMGpuSupport.h2
-rw-r--r--dm/DMSrcSink.cpp2
-rw-r--r--include/gpu/GrContext.h32
-rw-r--r--src/gpu/GrContext.cpp21
-rw-r--r--src/gpu/GrGpu.cpp2
-rw-r--r--src/gpu/GrGpu.h16
-rw-r--r--src/gpu/gl/GrGLGpu.cpp52
-rw-r--r--src/gpu/gl/GrGLGpu.h2
-rw-r--r--src/gpu/gl/GrGLPathRendering.cpp5
-rw-r--r--src/gpu/gl/GrGLPathRendering.h6
-rw-r--r--tests/GrContextAbandonTest.cpp53
-rw-r--r--tools/flags/SkCommonFlags.cpp8
-rw-r--r--tools/flags/SkCommonFlags.h1
-rwxr-xr-xtools/gpu/GrContextFactory.cpp11
-rw-r--r--tools/gpu/GrContextFactory.h1
15 files changed, 184 insertions, 30 deletions
diff --git a/dm/DMGpuSupport.h b/dm/DMGpuSupport.h
index c713244e9d..490737f41e 100644
--- a/dm/DMGpuSupport.h
+++ b/dm/DMGpuSupport.h
@@ -84,6 +84,8 @@ public:
void destroyContexts() {}
void abandonContexts() {}
+
+ void releaseResourcesAndAbandonContexts() {}
};
} // namespace sk_gpu_test
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index e704f74d03..6584789a0b 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1011,6 +1011,8 @@ Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) co
canvas->readPixels(dst, 0, 0);
if (FLAGS_abandonGpuContext) {
factory.abandonContexts();
+ } else if (FLAGS_releaseAndAbandonGpuContext) {
+ factory.releaseResourcesAndAbandonContexts();
}
return "";
}
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 6d67d3ebb3..d59b2a28f0 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -93,21 +93,29 @@ public:
}
/**
- * Abandons all GPU resources and assumes the underlying backend 3D API
- * context is not longer usable. Call this if you have lost the associated
- * GPU context, and thus internal texture, buffer, etc. references/IDs are
- * now invalid. Should be called even when GrContext is no longer going to
- * be used for two reasons:
- * 1) ~GrContext will not try to free the objects in the 3D API.
- * 2) Any GrGpuResources created by this GrContext that outlive
- * will be marked as invalid (GrGpuResource::wasDestroyed()) and
- * when they're destroyed no 3D API calls will be made.
- * Content drawn since the last GrContext::flush() may be lost. After this
- * function is called the only valid action on the GrContext or
- * GrGpuResources it created is to destroy them.
+ * Abandons all GPU resources and assumes the underlying backend 3D API context is not longer
+ * usable. Call this if you have lost the associated GPU context, and thus internal texture,
+ * buffer, etc. references/IDs are now invalid. Calling this ensures that the destructors of the
+ * GrContext and any of its created resource objects will not make backend 3D API calls. Content
+ * rendered but not previously flushed may be lost. After this function is called all subsequent
+ * calls on the GrContext will fail or be no-ops.
+ *
+ * The typical use case for this function is that the underlying 3D context was lost and further
+ * API calls may crash.
*/
void abandonContext();
+ /**
+ * This is similar to abandonContext() however the underlying 3D context is not yet lost and
+ * the GrContext will cleanup all allocated resources before returning. After returning it will
+ * assume that the underlying context may no longer be valid.
+ *
+ * The typical use case for this function is that the client is going to destroy the 3D context
+ * but can't guarantee that GrContext will be destroyed first (perhaps because it may be ref'ed
+ * elsewhere by either the client or Skia objects).
+ */
+ void releaseResourcesAndAbandonContext();
+
///////////////////////////////////////////////////////////////////////////
// Resource Cache
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 1f6934d441..1d6bb32142 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -148,7 +148,26 @@ void GrContext::abandonContext() {
// don't try to free the resources in the API.
fResourceCache->abandonAll();
- fGpu->contextAbandoned();
+ fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
+
+ fBatchFontCache->freeAll();
+ fLayerCache->freeAll();
+ fTextBlobCache->freeAll();
+}
+
+void GrContext::releaseResourcesAndAbandonContext() {
+ ASSERT_SINGLE_OWNER
+
+ fResourceProvider->abandon();
+
+ // Need to abandon the drawing manager first so all the render targets
+ // will be released/forgotten before they too are abandoned.
+ fDrawingManager->abandon();
+
+ // Release all resources in the backend 3D API.
+ fResourceCache->releaseAll();
+
+ fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
fBatchFontCache->freeAll();
fLayerCache->freeAll();
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 960526635e..bc11b4b9c6 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -51,7 +51,7 @@ GrGpu::GrGpu(GrContext* context)
GrGpu::~GrGpu() {}
-void GrGpu::contextAbandoned() {}
+void GrGpu::disconnect(DisconnectType) {}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 0da1aa6399..b3251dc14f 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -61,11 +61,17 @@ public:
GrPathRendering* pathRendering() { return fPathRendering.get(); }
- // Called by GrContext when the underlying backend context has been destroyed.
- // GrGpu should use this to ensure that no backend API calls will be made from
- // here onward, including in its destructor. Subclasses should call
- // INHERITED::contextAbandoned() if they override this.
- virtual void contextAbandoned();
+ enum class DisconnectType {
+ // No cleanup should be attempted, immediately cease making backend API calls
+ kAbandon,
+ // Free allocated resources (not known by GrResourceCache) before returning and
+ // ensure no backend backend 3D API calls will be made after disconnect() returns.
+ kCleanup,
+ };
+
+ // Called by GrContext when the underlying backend context is already or will be destroyed
+ // before GrContext.
+ virtual void disconnect(DisconnectType);
/**
* The GrGpu object normally assumes that no outsider is setting state
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 34223f1cc8..c8c12a388d 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -386,9 +386,51 @@ void GrGLGpu::createPLSSetupProgram() {
GR_GL_STATIC_DRAW));
}
-void GrGLGpu::contextAbandoned() {
- INHERITED::contextAbandoned();
- fProgramCache->abandon();
+void GrGLGpu::disconnect(DisconnectType type) {
+ INHERITED::disconnect(type);
+ if (DisconnectType::kCleanup == type) {
+ if (fHWProgramID) {
+ GL_CALL(UseProgram(0));
+ }
+ if (fTempSrcFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID));
+ }
+ if (fTempDstFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID));
+ }
+ if (fStencilClearFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID));
+ }
+ if (fCopyProgramArrayBuffer) {
+ GL_CALL(DeleteBuffers(1, &fCopyProgramArrayBuffer));
+ }
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
+ if (fCopyPrograms[i].fProgram) {
+ GL_CALL(DeleteProgram(fCopyPrograms[i].fProgram));
+ }
+ }
+ if (fWireRectProgram.fProgram) {
+ GL_CALL(DeleteProgram(fWireRectProgram.fProgram));
+ }
+ if (fWireRectArrayBuffer) {
+ GL_CALL(DeleteBuffers(1, &fWireRectArrayBuffer));
+ }
+
+ if (fPLSSetupProgram.fProgram) {
+ GL_CALL(DeleteProgram(fPLSSetupProgram.fProgram));
+ }
+ if (fPLSSetupProgram.fArrayBuffer) {
+ GL_CALL(DeleteBuffers(1, &fPLSSetupProgram.fArrayBuffer));
+ }
+ } else {
+ if (fProgramCache) {
+ fProgramCache->abandon();
+ }
+ }
+
+ delete fProgramCache;
+ fProgramCache = nullptr;
+
fHWProgramID = 0;
fTempSrcFBOID = 0;
fTempDstFBOID = 0;
@@ -399,8 +441,10 @@ void GrGLGpu::contextAbandoned() {
}
fWireRectProgram.fProgram = 0;
fWireRectArrayBuffer = 0;
+ fPLSSetupProgram.fProgram = 0;
+ fPLSSetupProgram.fArrayBuffer = 0;
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
- this->glPathRendering()->abandonGpuResources();
+ this->glPathRendering()->disconnect(type);
}
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 6d851ee1dd..c77076fc51 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -38,7 +38,7 @@ public:
GrContext* context);
~GrGLGpu() override;
- void contextAbandoned() override;
+ void disconnect(DisconnectType) override;
const GrGLContext& glContext() const { return *fGLContext; }
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 47274f9d69..0ecf58a8e1 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -91,7 +91,10 @@ GrGLPathRendering::~GrGLPathRendering() {
}
}
-void GrGLPathRendering::abandonGpuResources() {
+void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
+ if (GrGpu::DisconnectType::kCleanup == type) {
+ this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
+ };
fPreallocatedPathCount = 0;
}
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index cd4668fc88..b39c866c6f 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -41,10 +41,10 @@ public:
void resetContext();
/**
- * Called when the GPU resources have been lost and need to be abandoned
- * (for example after a context loss).
+ * Called when the context either is about to be lost or is lost. DisconnectType indicates
+ * whether GPU resources should be cleaned up or abandoned when this is called.
*/
- void abandonGpuResources();
+ void disconnect(GrGpu::DisconnectType);
bool shouldBindFragmentInputs() const {
return fCaps.bindFragmentInputSupport;
diff --git a/tests/GrContextAbandonTest.cpp b/tests/GrContextAbandonTest.cpp
new file mode 100644
index 0000000000..c62973f4da
--- /dev/null
+++ b/tests/GrContextAbandonTest.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrContextFactory.h"
+#include "Test.h"
+
+using sk_gpu_test::GrContextFactory;
+
+DEF_GPUTEST(GrContext_abandonContext, reporter, /*factory*/) {
+ for (int testType = 0; testType < 6; ++testType) {
+ for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+ GrContextFactory testFactory;
+ GrContextFactory::GLContextType ctxType = (GrContextFactory::GLContextType) i;
+ GrContextFactory::ContextInfo info = testFactory.getContextInfo(ctxType);
+ if (GrContext* context = info.fGrContext) {
+ switch (testType) {
+ case 0:
+ context->abandonContext();
+ break;
+ case 1:
+ context->releaseResourcesAndAbandonContext();
+ break;
+ case 2:
+ context->abandonContext();
+ context->abandonContext();
+ break;
+ case 3:
+ context->abandonContext();
+ context->releaseResourcesAndAbandonContext();
+ break;
+ case 4:
+ context->releaseResourcesAndAbandonContext();
+ context->abandonContext();
+ break;
+ case 5:
+ context->releaseResourcesAndAbandonContext();
+ context->releaseResourcesAndAbandonContext();
+ break;
+ }
+ }
+ }
+ }
+}
+
+#endif
diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp
index e6d269b9e2..eb2075c58a 100644
--- a/tools/flags/SkCommonFlags.cpp
+++ b/tools/flags/SkCommonFlags.cpp
@@ -30,9 +30,13 @@ DEFINE_string2(match, m, nullptr,
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(preAbandonGpuContext, false, "Test abandoning the GrContext before running the test.");
-DEFINE_bool(abandonGpuContext, false, "Abandon the GrContext after running each test.");
+DEFINE_bool(abandonGpuContext, false, "Test abandoning the GrContext after running each test.");
+
+DEFINE_bool(releaseAndAbandonGpuContext, false,
+ "Test releasing all gpu resources and abandoning 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 1f7bbffe6e..c6cbde45ca 100644
--- a/tools/flags/SkCommonFlags.h
+++ b/tools/flags/SkCommonFlags.h
@@ -21,6 +21,7 @@ DECLARE_bool(quiet);
DECLARE_bool(resetGpuContext);
DECLARE_bool(preAbandonGpuContext);
DECLARE_bool(abandonGpuContext);
+DECLARE_bool(releaseAndAbandonGpuContext);
DECLARE_string(skps);
DECLARE_int32(threads);
DECLARE_string(resourcePath);
diff --git a/tools/gpu/GrContextFactory.cpp b/tools/gpu/GrContextFactory.cpp
index bae73a4e19..c232121332 100755
--- a/tools/gpu/GrContextFactory.cpp
+++ b/tools/gpu/GrContextFactory.cpp
@@ -63,6 +63,17 @@ void GrContextFactory::abandonContexts() {
}
}
+void GrContextFactory::releaseResourcesAndAbandonContexts() {
+ for (Context& context : fContexts) {
+ if (context.fGLContext) {
+ context.fGLContext->makeCurrent();
+ context.fGrContext->releaseResourcesAndAbandonContext();
+ delete(context.fGLContext);
+ context.fGLContext = nullptr;
+ }
+ }
+}
+
GrContextFactory::ContextInfo GrContextFactory::getContextInfo(GLContextType type,
GLContextOptions options) {
for (int i = 0; i < fContexts.count(); ++i) {
diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h
index 14a2739815..16f6fb23ff 100644
--- a/tools/gpu/GrContextFactory.h
+++ b/tools/gpu/GrContextFactory.h
@@ -107,6 +107,7 @@ public:
void destroyContexts();
void abandonContexts();
+ void releaseResourcesAndAbandonContexts();
struct ContextInfo {
ContextInfo()