Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(775)

Unified Diff: src/gpu/gl/GrGLCreateNullInterface.cpp

Issue 470993002: Make null gpu context threadsafe(r) and make sure buffer objects are destroyed. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: cast back to int when used as tdarray index Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/gl/GrGLCreateNullInterface.cpp
diff --git a/src/gpu/gl/GrGLCreateNullInterface.cpp b/src/gpu/gl/GrGLCreateNullInterface.cpp
index d047e730f71a4cdb2db77abea8a412b89c4abad3..f852e30da5b8ab713d75eeb0a4d8c419d6176481 100644
--- a/src/gpu/gl/GrGLCreateNullInterface.cpp
+++ b/src/gpu/gl/GrGLCreateNullInterface.cpp
@@ -10,16 +10,15 @@
#include "GrGLDefines.h"
#include "SkTDArray.h"
#include "GrGLNoOpInterface.h"
+#include "SkTLS.h"
-// Functions not declared in GrGLBogusInterface.h (not common with the Debug GL interface).
-
-namespace { // added to suppress 'no previous prototype' warning
-
-class GrBufferObj {
+class BufferObj {
public:
- GrBufferObj(GrGLuint id) : fID(id), fDataPtr(NULL), fSize(0), fMapped(false) {
+ SK_DECLARE_INST_COUNT_ROOT(BufferObj);
+
+ BufferObj(GrGLuint id) : fID(id), fDataPtr(NULL), fSize(0), fMapped(false) {
}
- ~GrBufferObj() { SkDELETE_ARRAY(fDataPtr); }
+ ~BufferObj() { SkDELETE_ARRAY(fDataPtr); }
void allocate(GrGLsizeiptr size, const GrGLchar* dataPtr) {
if (NULL != fDataPtr) {
@@ -45,54 +44,104 @@ private:
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;
+// This class maintains a sparsely populated array of buffer pointers.
+class BufferManager {
+public:
+ SK_DECLARE_INST_COUNT_ROOT(BufferManager);
-static GrBufferObj* look_up(GrGLuint id) {
- GrBufferObj* buffer = gBuffers[id];
- SkASSERT(NULL != buffer && buffer->id() == id);
- return buffer;
-}
+ BufferManager() : fFreeListHead(kFreeListEnd) {}
+
+ ~BufferManager() {
+ // NULL out the entries that are really free list links rather than ptrs before deleting.
+ intptr_t curr = fFreeListHead;
+ while (kFreeListEnd != curr) {
+ intptr_t next = reinterpret_cast<intptr_t>(fBuffers[SkToS32(curr)]);
+ fBuffers[SkToS32(curr)] = NULL;
+ curr = next;
+ }
-static GrBufferObj* create_buffer() {
- if (0 == gBuffers.count()) {
- // slot zero is reserved for the head of the free list
- *gBuffers.append() = NULL;
+ fBuffers.deleteAll();
}
- 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 = SkTCast<GrGLuint>(gBuffers[0]);
- gBuffers[0] = gBuffers[id];
-
- buffer = SkNEW_ARGS(GrBufferObj, (id));
- gBuffers[id] = buffer;
+ BufferObj* lookUp(GrGLuint id) {
+ BufferObj* buffer = fBuffers[id];
+ SkASSERT(NULL != buffer && buffer->id() == id);
+ return buffer;
}
- return buffer;
-}
+ BufferObj* create() {
+ GrGLuint id;
+ BufferObj* buffer;
+
+ if (kFreeListEnd == fFreeListHead) {
+ // no free slots - create a new one
+ id = fBuffers.count();
+ buffer = SkNEW_ARGS(BufferObj, (id));
+ *fBuffers.append() = buffer;
+ } else {
+ // grab the head of the free list and advance the head to the next free slot.
+ id = static_cast<GrGLuint>(fFreeListHead);
+ fFreeListHead = reinterpret_cast<intptr_t>(fBuffers[id]);
+
+ buffer = SkNEW_ARGS(BufferObj, (id));
+ fBuffers[id] = buffer;
+ }
-static void delete_buffer(GrBufferObj* buffer) {
- SkASSERT(gBuffers.count() > 0);
+ return buffer;
+ }
- GrGLuint id = buffer->id();
- SkDELETE(buffer);
+ void free(BufferObj* buffer) {
+ SkASSERT(fBuffers.count() > 0);
- // Add this slot to the free list
- gBuffers[id] = gBuffers[0];
- gBuffers[0] = SkTCast<GrBufferObj*>((const void*)(intptr_t)id);
-}
+ GrGLuint id = buffer->id();
+ SkDELETE(buffer);
+
+ fBuffers[id] = reinterpret_cast<BufferObj*>(fFreeListHead);
+ fFreeListHead = id;
+ }
+
+private:
+ static const intptr_t kFreeListEnd = -1;
+ // Index of the first entry of fBuffers in the free list. Free slots in fBuffers are indices to
+ // the next free slot. The last free slot has a value of kFreeListEnd.
+ intptr_t fFreeListHead;
+ SkTDArray<BufferObj*> fBuffers;
+};
+
+/**
+ * The global-to-thread state object for the null interface. All null interfaces on the
+ * same thread currently share one of these. This means two null contexts on the same thread
+ * can interfere with each other. It may make sense to more integrate this into SkNullGLContext
+ * and use it's makeCurrent mechanism.
+ */
+struct ThreadContext {
+public:
+ SK_DECLARE_INST_COUNT_ROOT(ThreadContext);
+
+ BufferManager fBufferManager;
+ GrGLuint fCurrArrayBuffer;
+ GrGLuint fCurrElementArrayBuffer;
+ GrGLuint fCurrProgramID;
+ GrGLuint fCurrShaderID;
+
+ static ThreadContext* Get() {
+ return reinterpret_cast<ThreadContext*>(SkTLS::Get(Create, Delete));
+ }
+
+ ThreadContext()
+ : fCurrArrayBuffer(0)
+ , fCurrElementArrayBuffer(0)
+ , fCurrProgramID(0)
+ , fCurrShaderID(0) {}
+
+private:
+ static void* Create() { return SkNEW(ThreadContext ); }
+ static void Delete(void* context) { SkDELETE(reinterpret_cast<ThreadContext *>(context)); }
+};
+
+// Functions not declared in GrGLBogusInterface.h (not common with the Debug GL interface).
+
+namespace { // added to suppress 'no previous prototype' warning
GrGLvoid GR_GL_FUNCTION_TYPE nullGLActiveTexture(GrGLenum texture) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLAttachShader(GrGLuint program, GrGLuint shader) {}
@@ -102,9 +151,9 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindTexture(GrGLenum target, GrGLuint texture
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindVertexArray(GrGLuint id) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenBuffers(GrGLsizei n, GrGLuint* ids) {
-
+ ThreadContext* ctx = ThreadContext::Get();
for (int i = 0; i < n; ++i) {
- GrBufferObj* buffer = create_buffer();
+ BufferObj* buffer = ctx->fBufferManager.create();
ids[i] = buffer->id();
}
}
@@ -115,14 +164,15 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target,
GrGLsizeiptr size,
const GrGLvoid* data,
GrGLenum usage) {
+ ThreadContext* ctx = ThreadContext::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- id = gCurrArrayBuffer;
+ id = ctx->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- id = gCurrElementArrayBuffer;
+ id = ctx->fCurrElementArrayBuffer;
break;
default:
SkFAIL("Unexpected target to nullGLBufferData");
@@ -130,7 +180,7 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target,
}
if (id > 0) {
- GrBufferObj* buffer = look_up(id);
+ BufferObj* buffer = ctx->fBufferManager.lookUp(id);
buffer->allocate(size, (const GrGLchar*) data);
}
}
@@ -147,13 +197,11 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferRenderbuffer(GrGLenum target, GrGL
GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) {}
GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateProgram() {
- static GrGLuint gCurrID = 0;
- return ++gCurrID;
+ return ++ThreadContext::Get()->fCurrProgramID;
}
GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateShader(GrGLenum type) {
- static GrGLuint gCurrID = 0;
- return ++gCurrID;
+ return ++ThreadContext::Get()->fCurrShaderID;
}
// same delete used for shaders and programs
@@ -161,46 +209,49 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLDelete(GrGLuint program) {
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindBuffer(GrGLenum target, GrGLuint buffer) {
+ ThreadContext* ctx = ThreadContext::Get();
switch (target) {
case GR_GL_ARRAY_BUFFER:
- gCurrArrayBuffer = buffer;
+ ctx->fCurrArrayBuffer = buffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- gCurrElementArrayBuffer = buffer;
+ ctx->fCurrElementArrayBuffer = buffer;
break;
}
}
// deleting a bound buffer has the side effect of binding 0
GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteBuffers(GrGLsizei n, const GrGLuint* ids) {
+ ThreadContext* ctx = ThreadContext::Get();
for (int i = 0; i < n; ++i) {
- if (ids[i] == gCurrArrayBuffer) {
- gCurrArrayBuffer = 0;
+ if (ids[i] == ctx->fCurrArrayBuffer) {
+ ctx->fCurrArrayBuffer = 0;
}
- if (ids[i] == gCurrElementArrayBuffer) {
- gCurrElementArrayBuffer = 0;
+ if (ids[i] == ctx->fCurrElementArrayBuffer) {
+ ctx->fCurrElementArrayBuffer = 0;
}
- GrBufferObj* buffer = look_up(ids[i]);
- delete_buffer(buffer);
+ BufferObj* buffer = ctx->fBufferManager.lookUp(ids[i]);
+ ctx->fBufferManager.free(buffer);
}
}
GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBufferRange(GrGLenum target, GrGLintptr offset,
GrGLsizeiptr length, GrGLbitfield access) {
+ ThreadContext* ctx = ThreadContext::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- id = gCurrArrayBuffer;
+ id = ctx->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- id = gCurrElementArrayBuffer;
+ id = ctx->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
// We just ignore the offset and length here.
- GrBufferObj* buffer = look_up(id);
+ BufferObj* buffer = ctx->fBufferManager.lookUp(id);
SkASSERT(!buffer->mapped());
buffer->setMapped(true);
return buffer->dataPtr();
@@ -209,18 +260,19 @@ GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBufferRange(GrGLenum target, GrGLintptr o
}
GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBuffer(GrGLenum target, GrGLenum access) {
+ ThreadContext* ctx = ThreadContext::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- id = gCurrArrayBuffer;
+ id = ctx->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- id = gCurrElementArrayBuffer;
+ id = ctx->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
- GrBufferObj* buffer = look_up(id);
+ BufferObj* buffer = ctx->fBufferManager.lookUp(id);
SkASSERT(!buffer->mapped());
buffer->setMapped(true);
return buffer->dataPtr();
@@ -236,17 +288,18 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLFlushMappedBufferRange(GrGLenum target,
GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) {
+ ThreadContext* ctx = ThreadContext::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- id = gCurrArrayBuffer;
+ id = ctx->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- id = gCurrElementArrayBuffer;
+ id = ctx->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
- GrBufferObj* buffer = look_up(id);
+ BufferObj* buffer = ctx->fBufferManager.lookUp(id);
SkASSERT(buffer->mapped());
buffer->setMapped(false);
return GR_GL_TRUE;
@@ -257,20 +310,21 @@ GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) {
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) {
+ ThreadContext* ctx = ThreadContext::Get();
switch (pname) {
case GR_GL_BUFFER_MAPPED: {
*params = GR_GL_FALSE;
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
- id = gCurrArrayBuffer;
+ id = ctx->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- id = gCurrElementArrayBuffer;
+ id = ctx->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
- GrBufferObj* buffer = look_up(id);
+ BufferObj* buffer = ctx->fBufferManager.lookUp(id);
if (buffer->mapped()) {
*params = GR_GL_TRUE;
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698