Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Erwin <significant.bit@gmail.com>2016-09-15 22:45:10 +0300
committerMike Erwin <significant.bit@gmail.com>2016-09-15 22:45:10 +0300
commit76c99f361f58752eff8054f5cff52cad9ce57145 (patch)
treee70fd4f33c9eee9e83a2641784ad4436c429b449
parent5eddb8051382aa4406f6fb33b3eb0f748c6d1911 (diff)
Gawain improvements
Fixed compile error in debug build (thanks mont29) Renamed some functions for consistency. New features: Create a Batch with immediate mode! Just use immBeginBatch instead of immBegin. You can keep the result and draw it as many times as you like. This partially replaces the need for display lists. Copy a VertexFormat, and create a VertexBuffer using an existing format. Resize a VertexBuffer to a different number of vertices. (can only resize BEFORE using it to draw)
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/gpu/gawain/batch.c7
-rw-r--r--source/blender/gpu/gawain/batch.h25
-rw-r--r--source/blender/gpu/gawain/immediate.c142
-rw-r--r--source/blender/gpu/gawain/immediate.h13
-rw-r--r--source/blender/gpu/gawain/vertex_buffer.c43
-rw-r--r--source/blender/gpu/gawain/vertex_buffer.h10
-rw-r--r--source/blender/gpu/gawain/vertex_format.c18
-rw-r--r--source/blender/gpu/gawain/vertex_format.h6
9 files changed, 199 insertions, 67 deletions
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 77f19d353e9..cb07dd8135c 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -740,7 +740,7 @@ static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
immUnbindProgram();
- clear_VertexFormat(format);
+ VertexFormat_clear(format);
pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/gpu/gawain/batch.c b/source/blender/gpu/gawain/batch.c
index 96bf6dd1b5a..f8183abc6f0 100644
--- a/source/blender/gpu/gawain/batch.c
+++ b/source/blender/gpu/gawain/batch.c
@@ -25,6 +25,7 @@ Batch* Batch_create(GLenum prim_type, VertexBuffer* verts, ElementList* elem)
batch->verts = verts;
batch->elem = elem;
batch->prim_type = prim_type;
+ batch->phase = READY_TO_DRAW;
return batch;
}
@@ -38,7 +39,7 @@ void Batch_set_program(Batch* batch, GLuint program)
static void Batch_update_program_bindings(Batch* batch)
{
#if TRUST_NO_ONE
- assert(glIsProgram(program));
+ assert(glIsProgram(batch->program));
#endif
const VertexFormat* format = &batch->verts->format;
@@ -88,6 +89,10 @@ static void Batch_prime(Batch* batch)
void Batch_draw(Batch* batch)
{
+#if TRUST_NO_ONE
+ assert(batch->phase == READY_TO_DRAW);
+#endif
+
if (batch->vao_id)
glBindVertexArray(batch->vao_id);
else
diff --git a/source/blender/gpu/gawain/batch.h b/source/blender/gpu/gawain/batch.h
index 8387b0144a3..8b132aa3c02 100644
--- a/source/blender/gpu/gawain/batch.h
+++ b/source/blender/gpu/gawain/batch.h
@@ -14,6 +14,13 @@
#include "vertex_buffer.h"
#include "element.h"
+typedef enum {
+ READY_TO_FORMAT,
+ READY_TO_BUILD,
+ BUILDING,
+ READY_TO_DRAW
+} BatchPhase;
+
typedef struct {
// geometry
VertexBuffer* verts;
@@ -22,6 +29,7 @@ typedef struct {
// book-keeping
GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer)
+ BatchPhase phase;
bool program_dirty;
// state
@@ -30,6 +38,9 @@ typedef struct {
Batch* Batch_create(GLenum prim_type, VertexBuffer*, ElementList*);
+// TODO: void Batch_discard(Batch*);
+// must first decide how sharing of vertex buffers & index buffers should work
+
void Batch_set_program(Batch*, GLuint program);
// Entire batch draws with one shader program, but can be redrawn later with another program.
// Vertex shader's inputs must be compatible with the batch's vertex format.
@@ -46,20 +57,6 @@ void Batch_draw(Batch*);
// Can multiple batches share a VertexBuffer? Use ref count?
-// for multithreaded batch building:
-typedef enum {
- READY_TO_FORMAT,
- READY_TO_BUILD,
- BUILDING, BUILDING_IMM, // choose one
- READY_TO_DRAW
-} BatchPhase;
-
-
-Batch* immBeginBatch(GLenum prim_type, unsigned v_ct);
-// use standard immFunctions after this. immEnd will finalize the batch instead
-// of drawing.
-
-
// We often need a batch with its own data, to be created and discarded together.
// WithOwn variants reduce number of system allocations.
diff --git a/source/blender/gpu/gawain/immediate.c b/source/blender/gpu/gawain/immediate.c
index 90a67dff014..650bccb9248 100644
--- a/source/blender/gpu/gawain/immediate.c
+++ b/source/blender/gpu/gawain/immediate.c
@@ -16,6 +16,10 @@
typedef struct {
// TODO: organize this struct by frequency of change (run-time)
+#if IMM_BATCH_COMBO
+ Batch* batch;
+#endif
+
// current draw call
GLubyte* buffer_data;
unsigned buffer_offset;
@@ -79,7 +83,7 @@ void immDestroy()
assert(imm.primitive == PRIM_NONE); // make sure we're not between a Begin/End pair
#endif
- clear_VertexFormat(&imm.vertex_format);
+ VertexFormat_clear(&imm.vertex_format);
glDeleteVertexArrays(1, &imm.vao_id);
glDeleteBuffers(1, &imm.vbo_id);
initialized = false;
@@ -87,7 +91,7 @@ void immDestroy()
VertexFormat* immVertexFormat()
{
- clear_VertexFormat(&imm.vertex_format);
+ VertexFormat_clear(&imm.vertex_format);
return &imm.vertex_format;
}
@@ -98,7 +102,7 @@ void immBindProgram(GLuint program)
#endif
if (!imm.vertex_format.packed)
- pack(&imm.vertex_format);
+ VertexFormat_pack(&imm.vertex_format);
glUseProgram(program);
get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, program);
@@ -151,8 +155,6 @@ void immBegin(GLenum primitive, unsigned vertex_ct)
imm.primitive = primitive;
imm.vertex_ct = vertex_ct;
- imm.vertex_idx = 0;
- imm.attrib_value_bits = 0;
// how many bytes do we need for this draw call?
const unsigned bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_ct);
@@ -206,40 +208,43 @@ void immBeginAtMost(GLenum primitive, unsigned vertex_ct)
immBegin(primitive, vertex_ct);
}
-void immEnd()
+#if IMM_BATCH_COMBO
+
+Batch* immBeginBatch(GLenum prim_type, unsigned vertex_ct)
{
#if TRUST_NO_ONE
- assert(imm.primitive != PRIM_NONE); // make sure we're between a Begin/End pair
+ assert(initialized);
+ assert(imm.primitive == PRIM_NONE); // make sure we haven't already begun
+ assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type));
#endif
- unsigned buffer_bytes_used;
- if (imm.strict_vertex_ct)
- {
-#if TRUST_NO_ONE
- assert(imm.vertex_idx == imm.vertex_ct); // with all vertices defined
-#endif
- buffer_bytes_used = imm.buffer_bytes_mapped;
- }
- else
- {
-#if TRUST_NO_ONE
- assert(imm.vertex_idx <= imm.vertex_ct);
- assert(vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.primitive));
-#endif
- // printf("used %u of %u verts,", imm.vertex_idx, imm.vertex_ct);
- imm.vertex_ct = imm.vertex_idx;
- buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_ct);
- // unused buffer bytes are available to the next immBegin
- // printf(" %u of %u bytes\n", buffer_bytes_used, imm.buffer_bytes_mapped);
- }
+ imm.primitive = prim_type;
+ imm.vertex_ct = vertex_ct;
-#if APPLE_LEGACY
- // tell OpenGL what range was modified so it doesn't copy the whole buffer
- glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER, imm.buffer_offset, buffer_bytes_used);
-// printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1);
-#endif
- glUnmapBuffer(GL_ARRAY_BUFFER);
+ VertexBuffer* verts = VertexBuffer_create_with_format(&imm.vertex_format);
+ VertexBuffer_allocate_data(verts, vertex_ct);
+
+ imm.buffer_bytes_mapped = VertexBuffer_size(verts);
+ imm.vertex_data = verts->data;
+
+ imm.batch = Batch_create(prim_type, verts, NULL);
+ imm.batch->phase = BUILDING;
+ Batch_set_program(imm.batch, imm.bound_program);
+
+ return imm.batch;
+ }
+
+Batch* immBeginBatchAtMost(GLenum prim_type, unsigned vertex_ct)
+ {
+ imm.strict_vertex_ct = false;
+ return immBeginBatch(prim_type, vertex_ct);
+ }
+
+#endif // IMM_BATCH_COMBO
+
+static void immDrawSetup()
+ {
// set up VAO -- can be done during Begin or End really
glBindVertexArray(imm.vao_id);
@@ -292,21 +297,78 @@ void immEnd()
glVertexAttribIPointer(loc, a->comp_ct, a->comp_type, stride, pointer);
}
}
+ }
- glDrawArrays(imm.primitive, 0, imm.vertex_ct);
+void immEnd()
+ {
+#if TRUST_NO_ONE
+ assert(imm.primitive != PRIM_NONE); // make sure we're between a Begin/End pair
+#endif
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
+ unsigned buffer_bytes_used;
+ if (imm.strict_vertex_ct)
+ {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx == imm.vertex_ct); // with all vertices defined
+#endif
+ buffer_bytes_used = imm.buffer_bytes_mapped;
+ }
+ else
+ {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx <= imm.vertex_ct);
+ assert(vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.primitive));
+#endif
+ // printf("used %u of %u verts,", imm.vertex_idx, imm.vertex_ct);
+ imm.vertex_ct = imm.vertex_idx;
+ buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_ct);
+ // unused buffer bytes are available to the next immBegin
+ // printf(" %u of %u bytes\n", buffer_bytes_used, imm.buffer_bytes_mapped);
+ }
+
+#if IMM_BATCH_COMBO
+ if (imm.batch)
+ {
+ if (buffer_bytes_used != imm.buffer_bytes_mapped)
+ {
+ VertexBuffer_resize_data(imm.batch->verts, imm.vertex_ct);
+ // TODO: resize only if vertex count is much smaller
+ }
+
+ imm.batch->phase = READY_TO_DRAW;
+ imm.batch = NULL; // don't free, batch belongs to caller
+ }
+ else
+#endif
+ {
+#if APPLE_LEGACY
+ // tell OpenGL what range was modified so it doesn't copy the whole buffer
+ glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER, imm.buffer_offset, buffer_bytes_used);
+// printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1);
+#endif
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ immDrawSetup();
+
+ glDrawArrays(imm.primitive, 0, imm.vertex_ct);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+
+ // prep for next immBegin
+ imm.buffer_offset += buffer_bytes_used;
+ }
// prep for next immBegin
- imm.buffer_offset += buffer_bytes_used;
imm.primitive = PRIM_NONE;
imm.strict_vertex_ct = true;
+ imm.vertex_idx = 0;
+ imm.attrib_value_bits = 0;
// further optional cleanup
- imm.buffer_bytes_mapped = 0;
- imm.buffer_data = NULL;
- imm.vertex_data = NULL;
+// imm.buffer_bytes_mapped = 0;
+// imm.buffer_data = NULL;
+// imm.vertex_data = NULL;
}
static void setAttribValueBit(unsigned attrib_id)
diff --git a/source/blender/gpu/gawain/immediate.h b/source/blender/gpu/gawain/immediate.h
index 9a013528aa8..1854819cca2 100644
--- a/source/blender/gpu/gawain/immediate.h
+++ b/source/blender/gpu/gawain/immediate.h
@@ -13,6 +13,8 @@
#include "vertex_format.h"
+#define IMM_BATCH_COMBO 1
+
void immInit(void);
void immDestroy(void);
@@ -23,7 +25,16 @@ void immUnbindProgram(void);
void immBegin(GLenum primitive, unsigned vertex_ct); // must supply exactly vertex_ct vertices
void immBeginAtMost(GLenum primitive, unsigned max_vertex_ct); // can supply fewer vertices
-void immEnd(void);
+void immEnd(void); // finishes and draws
+
+#if IMM_BATCH_COMBO
+#include "gawain/batch.h"
+// immBegin a batch, then use standard immFunctions as usual.
+// immEnd will finalize the batch instead of drawing.
+// Then you can draw it as many times as you like! Partially replaces the need for display lists.
+Batch* immBeginBatch(GLenum prim_type, unsigned vertex_ct);
+Batch* immBeginBatchAtMost(GLenum prim_type, unsigned vertex_ct);
+#endif
void immAttrib1f(unsigned attrib_id, float x);
void immAttrib2f(unsigned attrib_id, float x, float y);
diff --git a/source/blender/gpu/gawain/vertex_buffer.c b/source/blender/gpu/gawain/vertex_buffer.c
index 9ceec5c0ca4..93d0facdf7c 100644
--- a/source/blender/gpu/gawain/vertex_buffer.c
+++ b/source/blender/gpu/gawain/vertex_buffer.c
@@ -22,21 +22,60 @@ VertexBuffer* VertexBuffer_create()
return verts;
}
+VertexBuffer* VertexBuffer_create_with_format(const VertexFormat* format)
+ {
+ VertexBuffer* verts = VertexBuffer_create();
+ VertexFormat_copy(&verts->format, format);
+ if (!format->packed)
+ VertexFormat_pack(&verts->format);
+ return verts;
+
+ // this function might seem redundant, but there is potential for memory savings here...
+ // TODO: implement those memory savings
+ }
+
void VertexBuffer_init(VertexBuffer* verts)
{
memset(verts, 0, sizeof(VertexBuffer));
}
+void VertexBuffer_init_with_format(VertexBuffer* verts, const VertexFormat* format)
+ {
+ VertexBuffer_init(verts);
+ VertexFormat_copy(&verts->format, format);
+ if (!format->packed)
+ VertexFormat_pack(&verts->format);
+ }
+
+unsigned VertexBuffer_size(const VertexBuffer* verts)
+ {
+ return vertex_buffer_size(&verts->format, verts->vertex_ct);
+ }
+
void VertexBuffer_allocate_data(VertexBuffer* verts, unsigned v_ct)
{
VertexFormat* format = &verts->format;
if (!format->packed)
- pack(format);
+ VertexFormat_pack(format);
verts->vertex_ct = v_ct;
// Data initially lives in main memory. Will be transferred to VRAM when we "prime" it.
- verts->data = malloc(vertex_buffer_size(format, v_ct));
+ verts->data = malloc(VertexBuffer_size(verts));
+ }
+
+void VertexBuffer_resize_data(VertexBuffer* verts, unsigned v_ct)
+ {
+#if TRUST_NO_ONE
+ assert(verts->vertex_ct != v_ct); // allow this?
+ assert(verts->data != NULL); // has already been allocated
+ assert(verts->vbo_id == 0); // has not been sent to VRAM
+#endif
+
+ verts->vertex_ct = v_ct;
+ verts->data = realloc(verts->data, VertexBuffer_size(verts));
+ // TODO: skip realloc if v_ct < existing vertex count
+ // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime)
}
void setAttrib(VertexBuffer* verts, unsigned a_idx, unsigned v_idx, const void* data)
diff --git a/source/blender/gpu/gawain/vertex_buffer.h b/source/blender/gpu/gawain/vertex_buffer.h
index a26a7306656..7128ec4b1af 100644
--- a/source/blender/gpu/gawain/vertex_buffer.h
+++ b/source/blender/gpu/gawain/vertex_buffer.h
@@ -29,13 +29,15 @@ typedef struct {
GLuint vbo_id; // 0 indicates not yet sent to VRAM
} VertexBuffer;
-VertexBuffer* VertexBuffer_create(void); // create means allocate, then init
-void VertexBuffer_init(VertexBuffer*);
+VertexBuffer* VertexBuffer_create(void);
+VertexBuffer* VertexBuffer_create_with_format(const VertexFormat*);
-// TODO: use copy of existing format
-// void init_VertexBuffer_with_format(VertexBuffer*, VertexFormat*);
+void VertexBuffer_init(VertexBuffer*);
+void VertexBuffer_init_with_format(VertexBuffer*, const VertexFormat*);
+unsigned VertexBuffer_size(const VertexBuffer*);
void VertexBuffer_allocate_data(VertexBuffer*, unsigned v_ct);
+void VertexBuffer_resize_data(VertexBuffer*, unsigned v_ct);
// The most important setAttrib variant is the untyped one. Get it right first.
// It takes a void* so the app developer is responsible for matching their app data types
diff --git a/source/blender/gpu/gawain/vertex_format.c b/source/blender/gpu/gawain/vertex_format.c
index 3f373b2feae..522200134ad 100644
--- a/source/blender/gpu/gawain/vertex_format.c
+++ b/source/blender/gpu/gawain/vertex_format.c
@@ -19,7 +19,7 @@
#include <stdio.h>
#endif
-void clear_VertexFormat(VertexFormat* format)
+void VertexFormat_clear(VertexFormat* format)
{
for (unsigned a = 0; a < format->attrib_ct; ++a)
free(format->attribs[a].name);
@@ -32,6 +32,20 @@ void clear_VertexFormat(VertexFormat* format)
#endif
}
+void VertexFormat_copy(VertexFormat* dest, const VertexFormat* src)
+ {
+ // discard dest format's old name strings
+ for (unsigned a = 0; a < dest->attrib_ct; ++a)
+ free(dest->attribs[a].name);
+
+ // copy regular struct fields
+ memcpy(dest, src, sizeof(VertexFormat));
+
+ // give dest attribs their own copy of name strings
+ for (unsigned i = 0; i < src->attrib_ct; ++i)
+ dest->attribs[i].name = strdup(src->attribs[i].name);
+ }
+
static unsigned comp_sz(GLenum type)
{
#if TRUST_NO_ONE
@@ -102,7 +116,7 @@ static void show_pack(unsigned a_idx, unsigned sz, unsigned pad)
}
#endif
-void pack(VertexFormat* format)
+void VertexFormat_pack(VertexFormat* format)
{
// for now, attributes are packed in the order they were added,
// making sure each attrib is naturally aligned (add padding where necessary)
diff --git a/source/blender/gpu/gawain/vertex_format.h b/source/blender/gpu/gawain/vertex_format.h
index 7921a47079f..b58e70fe70a 100644
--- a/source/blender/gpu/gawain/vertex_format.h
+++ b/source/blender/gpu/gawain/vertex_format.h
@@ -38,10 +38,12 @@ typedef struct {
Attrib attribs[MAX_VERTEX_ATTRIBS]; // TODO: variable-size attribs array
} VertexFormat;
-void clear_VertexFormat(VertexFormat*);
+void VertexFormat_clear(VertexFormat*);
+void VertexFormat_copy(VertexFormat* dest, const VertexFormat* src);
+
unsigned add_attrib(VertexFormat*, const char* name, GLenum comp_type, unsigned comp_ct, VertexFetchMode);
// for internal use
-void pack(VertexFormat*);
+void VertexFormat_pack(VertexFormat*);
unsigned padding(unsigned offset, unsigned alignment);
unsigned vertex_buffer_size(const VertexFormat*, unsigned vertex_ct);