Improve null gpu's memory handling
https://codereview.chromium.org/19678010/
git-svn-id: http://skia.googlecode.com/svn/trunk@10148 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 0cf7a18..98525a5 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -1258,6 +1258,11 @@
/* The gpudebug context does not generate meaningful images, so don't record
* the images it generates! We only run it to look for asserts. */
{ SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kDebug_GLContextType, 0, kNone_ConfigFlag, "gpudebug", GR_DEBUG},
+ /* The gpunull context does the least amount of work possible and doesn't
+ generate meaninful images, so don't record them!. It can be run to
+ isolate the CPU-side processing expense from the GPU-side.
+ */
+ { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kNull_GLContextType, 0, kNone_ConfigFlag, "gpunull", GR_DEBUG},
#if SK_ANGLE
{ SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 0, kRW_ConfigFlag, "angle", true },
{ SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 16, kRW_ConfigFlag, "anglemsaa16", true },
diff --git a/src/gpu/gl/GrGLCreateNullInterface.cpp b/src/gpu/gl/GrGLCreateNullInterface.cpp
index 1c2e1cd..0fa2b9e 100644
--- a/src/gpu/gl/GrGLCreateNullInterface.cpp
+++ b/src/gpu/gl/GrGLCreateNullInterface.cpp
@@ -15,13 +15,124 @@
namespace { // added to suppress 'no previous prototype' warning
+class GrBufferObj {
+public:
+ GrBufferObj(GrGLuint id) : fID(id), fDataPtr(NULL), fSize(0), fMapped(false) {
+ }
+ ~GrBufferObj() { SkDELETE_ARRAY(fDataPtr); }
+
+ void allocate(GrGLint size, const GrGLchar* dataPtr) {
+ if (NULL != fDataPtr) {
+ GrAssert(0 != fSize);
+ SkDELETE_ARRAY(fDataPtr);
+ }
+
+ fSize = size;
+ fDataPtr = SkNEW_ARRAY(char, size);
+ }
+
+ GrGLuint id() const { return fID; }
+ GrGLchar* dataPtr() { return fDataPtr; }
+ GrGLint size() const { return fSize; }
+
+ void setMapped(bool mapped) { fMapped = mapped; }
+ bool mapped() const { return fMapped; }
+
+private:
+ GrGLuint fID;
+ GrGLchar* fDataPtr;
+ GrGLint fSize; // size in bytes
+ bool fMapped;
+};
+
+// In debug builds we do asserts that ensure we agree with GL about when a buffer
+// is mapped.
+static SkTDArray<GrBufferObj*> gBuffers; // slot 0 is reserved for head of free list
+static GrGLuint gCurrArrayBuffer;
+static GrGLuint gCurrElementArrayBuffer;
+
+static GrBufferObj* look_up(GrGLuint id) {
+ GrBufferObj* buffer = gBuffers[id];
+ GrAssert(NULL != buffer && buffer->id() == id);
+ return buffer;
+}
+
+static GrBufferObj* create_buffer() {
+ if (0 == gBuffers.count()) {
+ // slot zero is reserved for the head of the free list
+ *gBuffers.append() = NULL;
+ }
+
+ GrGLuint id;
+ GrBufferObj* buffer;
+
+ if (NULL == gBuffers[0]) {
+ // no free slots - create a new one
+ id = gBuffers.count();
+ buffer = SkNEW_ARGS(GrBufferObj, (id));
+ gBuffers.append(1, &buffer);
+ } else {
+ // recycle a slot from the free list
+ id = (GrGLuint) gBuffers[0];
+ gBuffers[0] = gBuffers[id];
+
+ buffer = SkNEW_ARGS(GrBufferObj, (id));
+ gBuffers[id] = buffer;
+ }
+
+ return buffer;
+}
+
+static void delete_buffer(GrBufferObj* buffer) {
+ GrAssert(gBuffers.count() > 0);
+
+ GrGLuint id = buffer->id();
+ SkDELETE(buffer);
+
+ // Add this slot to the free list
+ gBuffers[id] = gBuffers[0];
+ gBuffers[0] = (GrBufferObj*) id;
+}
+
GrGLvoid GR_GL_FUNCTION_TYPE nullGLActiveTexture(GrGLenum texture) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLAttachShader(GrGLuint program, GrGLuint shader) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBeginQuery(GrGLenum target, GrGLuint id) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindAttribLocation(GrGLuint program, GrGLuint index, const char* name) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindTexture(GrGLenum target, GrGLuint texture) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindVertexArray(GrGLuint id) {}
-GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage) {}
+
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenBuffers(GrGLsizei n, GrGLuint* ids) {
+
+ for (int i = 0; i < n; ++i) {
+ GrBufferObj* buffer = create_buffer();
+ ids[i] = buffer->id();
+ }
+}
+
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target,
+ GrGLsizeiptr size,
+ const GrGLvoid* data,
+ GrGLenum usage) {
+ GrGLuint id = 0;
+
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ id = gCurrArrayBuffer;
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ id = gCurrElementArrayBuffer;
+ break;
+ default:
+ GrCrash("Unexpected target to nullGLBufferData");
+ break;
+ }
+
+ if (id > 0) {
+ GrBufferObj* buffer = look_up(id);
+ buffer->allocate(size, (const GrGLchar*) data);
+ }
+}
+
GrGLvoid GR_GL_FUNCTION_TYPE nullGLPixelStorei(GrGLenum pname, GrGLint param) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLReadPixels(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLUseProgram(GrGLuint program) {}
@@ -34,12 +145,12 @@
GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) {}
GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateProgram() {
- static int gCurrID = 0;
+ static GrGLuint gCurrID = 0;
return ++gCurrID;
}
GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateShader(GrGLenum type) {
- static int gCurrID = 0;
+ static GrGLuint gCurrID = 0;
return ++gCurrID;
}
@@ -47,12 +158,6 @@
GrGLvoid GR_GL_FUNCTION_TYPE nullGLDelete(GrGLuint program) {
}
-// In debug builds we do asserts that ensure we agree with GL about when a buffer
-// is mapped.
-static SkTDArray<GrGLuint> gMappedBuffers;
-static GrGLuint gCurrArrayBuffer;
-static GrGLuint gCurrElementArrayBuffer;
-
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindBuffer(GrGLenum target, GrGLuint buffer) {
switch (target) {
case GR_GL_ARRAY_BUFFER:
@@ -73,75 +178,73 @@
if (ids[i] == gCurrElementArrayBuffer) {
gCurrElementArrayBuffer = 0;
}
- for (int j = 0; j < gMappedBuffers.count(); ++j) {
- if (gMappedBuffers[j] == ids[i]) {
- gMappedBuffers.remove(j);
- // don't break b/c we didn't check for dupes on insert
- --j;
- }
- }
+
+ GrBufferObj* buffer = look_up(ids[i]);
+ delete_buffer(buffer);
}
}
GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBuffer(GrGLenum target, GrGLenum access) {
- // We just reserve 32MB of RAM for all locks and hope its big enough
- static SkAutoMalloc gBufferData(32 * (1 << 20));
- GrGLuint buf = 0;
+
+ GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- buf = gCurrArrayBuffer;
+ id = gCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- buf = gCurrElementArrayBuffer;
+ id = gCurrElementArrayBuffer;
break;
}
- if (buf) {
- *gMappedBuffers.append() = buf;
+
+ if (id > 0) {
+ GrBufferObj* buffer = look_up(id);
+ GrAssert(!buffer->mapped());
+ buffer->setMapped(true);
+ return buffer->dataPtr();
}
- return gBufferData.get();
+
+ GrAssert(false);
+ return NULL; // no buffer bound to target
}
GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) {
- GrGLuint buf = 0;
+ GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- buf = gCurrArrayBuffer;
+ id = gCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- buf = gCurrElementArrayBuffer;
+ id = gCurrElementArrayBuffer;
break;
}
- if (buf) {
- for (int i = 0; i < gMappedBuffers.count(); ++i) {
- if (gMappedBuffers[i] == buf) {
- gMappedBuffers.remove(i);
- // don't break b/c we didn't check for dupes on insert
- --i;
- }
- }
+ if (id > 0) {
+ GrBufferObj* buffer = look_up(id);
+ GrAssert(buffer->mapped());
+ buffer->setMapped(false);
+ return GR_GL_TRUE;
}
- return GR_GL_TRUE;
+
+ GrAlwaysAssert(false);
+ return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) {
switch (pname) {
case GR_GL_BUFFER_MAPPED: {
*params = GR_GL_FALSE;
- GrGLuint buf = 0;
+ GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- buf = gCurrArrayBuffer;
+ id = gCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- buf = gCurrElementArrayBuffer;
+ id = gCurrElementArrayBuffer;
break;
}
- if (buf) {
- for (int i = 0; i < gMappedBuffers.count(); ++i) {
- if (gMappedBuffers[i] == buf) {
- *params = GR_GL_TRUE;
- break;
- }
+ if (id > 0) {
+ GrBufferObj* buffer = look_up(id);
+ if (buffer->mapped()) {
+ *params = GR_GL_TRUE;
}
}
break; }
@@ -202,7 +305,7 @@
interface->fFinish = noOpGLFinish;
interface->fFlush = noOpGLFlush;
interface->fFrontFace = noOpGLFrontFace;
- interface->fGenBuffers = noOpGLGenIds;
+ interface->fGenBuffers = nullGLGenBuffers;
interface->fGenQueries = noOpGLGenIds;
interface->fGenTextures = noOpGLGenIds;
interface->fGenVertexArrays = noOpGLGenIds;