Add GrContext::releaseAndAbandonContext()
Like abandonContext() this disconnects the GrContext from the underlying 3D API. However, unlike abandonContext it first frees all allocated GPU resources. BUG=skia:5142 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1852733002 Review URL: https://codereview.chromium.org/1852733002
This commit is contained in:
parent
895f3f0544
commit
6e2aad4e9f
@ -84,6 +84,8 @@ public:
|
||||
void destroyContexts() {}
|
||||
|
||||
void abandonContexts() {}
|
||||
|
||||
void releaseResourcesAndAbandonContexts() {}
|
||||
};
|
||||
} // namespace sk_gpu_test
|
||||
|
||||
|
@ -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 "";
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -51,7 +51,7 @@ GrGpu::GrGpu(GrContext* context)
|
||||
|
||||
GrGpu::~GrGpu() {}
|
||||
|
||||
void GrGpu::contextAbandoned() {}
|
||||
void GrGpu::disconnect(DisconnectType) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
GrContext* context);
|
||||
~GrGLGpu() override;
|
||||
|
||||
void contextAbandoned() override;
|
||||
void disconnect(DisconnectType) override;
|
||||
|
||||
const GrGLContext& glContext() const { return *fGLContext; }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
53
tests/GrContextAbandonTest.cpp
Normal file
53
tests/GrContextAbandonTest.cpp
Normal file
@ -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
|
@ -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.");
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
|
||||
void destroyContexts();
|
||||
void abandonContexts();
|
||||
void releaseResourcesAndAbandonContexts();
|
||||
|
||||
struct ContextInfo {
|
||||
ContextInfo()
|
||||
|
Loading…
Reference in New Issue
Block a user