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 17:51:10 +0300
committerMike Erwin <significant.bit@gmail.com>2016-09-15 17:51:10 +0300
commit39f7a8117692da3a6645ccb7ae2080077f9e5980 (patch)
tree0062f4acb59e8afa5ebb8e9e811e107b9de9c04f
parent0d54d32dd608be5d87d3d57131ede33a8f19aa37 (diff)
Gawain: batch rendering API
Follow-up to rBddb1d5648dbd API is nearly complete but untested. 1) create batch with vertex buffer & optional index buffer 2) choose shader program 3) draw!
-rw-r--r--source/blender/gpu/CMakeLists.txt3
-rw-r--r--source/blender/gpu/gawain/batch.c108
-rw-r--r--source/blender/gpu/gawain/batch.h130
-rw-r--r--source/blender/gpu/gawain/element.c42
-rw-r--r--source/blender/gpu/gawain/element.h7
-rw-r--r--source/blender/gpu/gawain/vertex_buffer.c34
-rw-r--r--source/blender/gpu/gawain/vertex_buffer.h8
7 files changed, 209 insertions, 123 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 50c2db2544c..63ae58dad59 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -62,6 +62,8 @@ set(SRC
gawain/attrib_binding.c
gawain/attrib_binding.h
+ gawain/batch.c
+ gawain/batch.h
gawain/common.h
gawain/element.c
gawain/element.h
@@ -95,6 +97,7 @@ set(SRC
shaders/gpu_shader_smoke_vert.glsl
GPU_basic_shader.h
+ GPU_batch.h
GPU_buffers.h
GPU_compositing.h
GPU_debug.h
diff --git a/source/blender/gpu/gawain/batch.c b/source/blender/gpu/gawain/batch.c
index 3934d35df06..96bf6dd1b5a 100644
--- a/source/blender/gpu/gawain/batch.c
+++ b/source/blender/gpu/gawain/batch.c
@@ -10,9 +10,107 @@
// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
#include "batch.h"
+#include <stdlib.h>
-// BasicBatches
-// Vertex buffer with 3D pos only
-// Index buffer for edges (lines)
-// Index buffer for surface (triangles)
-// glGenBuffers(3,xxx)
+Batch* Batch_create(GLenum prim_type, VertexBuffer* verts, ElementList* elem)
+ {
+#if TRUST_NO_ONE
+ assert(verts != NULL);
+ assert(prim_type == GL_POINTS || prim_type == GL_LINES || prim_type == GL_TRIANGLES);
+ // we will allow other primitive types in a future update
+#endif
+
+ Batch* batch = calloc(1, sizeof(Batch));
+
+ batch->verts = verts;
+ batch->elem = elem;
+ batch->prim_type = prim_type;
+
+ return batch;
+ }
+
+void Batch_set_program(Batch* batch, GLuint program)
+ {
+ batch->program = program;
+ batch->program_dirty = true;
+ }
+
+static void Batch_update_program_bindings(Batch* batch)
+ {
+#if TRUST_NO_ONE
+ assert(glIsProgram(program));
+#endif
+
+ const VertexFormat* format = &batch->verts->format;
+
+ const unsigned attrib_ct = format->attrib_ct;
+ const unsigned stride = format->stride;
+
+ for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx)
+ {
+ const Attrib* a = format->attribs + a_idx;
+
+ const GLvoid* pointer = (const GLubyte*)0 + a->offset;
+
+ const unsigned loc = glGetAttribLocation(batch->program, a->name);
+
+ glEnableVertexAttribArray(loc);
+
+ switch (a->fetch_mode)
+ {
+ case KEEP_FLOAT:
+ case CONVERT_INT_TO_FLOAT:
+ glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_FALSE, stride, pointer);
+ break;
+ case NORMALIZE_INT_TO_FLOAT:
+ glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_TRUE, stride, pointer);
+ break;
+ case KEEP_INT:
+ glVertexAttribIPointer(loc, a->comp_ct, a->comp_type, stride, pointer);
+ }
+ }
+
+ batch->program_dirty = false;
+ }
+
+static void Batch_prime(Batch* batch)
+ {
+ glGenVertexArrays(1, &batch->vao_id);
+ glBindVertexArray(batch->vao_id);
+
+ VertexBuffer_use(batch->verts);
+
+ if (batch->elem)
+ ElementList_use(batch->elem);
+
+ // vertex attribs and element list remain bound to this VAO
+ }
+
+void Batch_draw(Batch* batch)
+ {
+ if (batch->vao_id)
+ glBindVertexArray(batch->vao_id);
+ else
+ Batch_prime(batch);
+
+ if (batch->program_dirty)
+ Batch_update_program_bindings(batch);
+
+ if (batch->elem)
+ {
+ const ElementList* el = batch->elem;
+
+#if TRACK_INDEX_RANGE
+ if (el->base_index)
+ glDrawRangeElementsBaseVertex(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0, el->base_index);
+ else
+ glDrawRangeElements(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0);
+#else
+ glDrawElements(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0);
+#endif
+ }
+ else
+ glDrawArrays(batch->prim_type, 0, batch->verts->vertex_ct);
+
+ glBindVertexArray(0);
+ }
diff --git a/source/blender/gpu/gawain/batch.h b/source/blender/gpu/gawain/batch.h
index 9625d666a41..8387b0144a3 100644
--- a/source/blender/gpu/gawain/batch.h
+++ b/source/blender/gpu/gawain/batch.h
@@ -13,34 +13,53 @@
#include "vertex_buffer.h"
#include "element.h"
-#include "attrib_binding.h"
-
-// How will this API be used?
-// create batch
-// ...
-// profit!
-
-// TODO: finalize Batch struct design & usage, pare down this file
-
-typedef struct {
- VertexBuffer; // format is fixed at "vec3 pos"
- ElementList line_elem;
- ElementList triangle_elem;
- GLuint vao_id;
- GLenum prev_prim; // did most recent draw use GL_POINTS, GL_LINES or GL_TRIANGLES?
-} BasicBatch;
-
-// How to do this without replicating code?
typedef struct {
+ // geometry
VertexBuffer* verts;
- ElementList* elem; // <-- NULL if element list not needed
+ ElementList* elem; // NULL if element list not needed
GLenum prim_type;
- GLuint vao_id;
- GLuint bound_program;
- AttribBinding attrib_binding;
+
+ // book-keeping
+ GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer)
+ bool program_dirty;
+
+ // state
+ GLuint program;
} Batch;
+Batch* Batch_create(GLenum prim_type, VertexBuffer*, ElementList*);
+
+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.
+
+void Batch_draw(Batch*);
+
+
+
+
+
+
+#if 0 // future plans
+
+// 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.
@@ -67,69 +86,4 @@ Batch* create_BatchWithOwnVertexBufferAndElementList(GLenum prim_type, VertexFor
// elem: none, shared, own
Batch* create_BatchInGeneral(GLenum prim_type, VertexBufferStuff, ElementListStuff);
-typedef struct {
- // geometry
- GLenum prim_type;
- VertexBuffer verts;
- ElementList elem; // <-- elem.index_ct = 0 if element list not needed
-
- // book-keeping
- GLuint vao_id; // <-- remembers all vertex state (array buffer, element buffer, attrib bindings)
- // wait a sec... I thought VAO held attrib bindings but not currently bound array buffer.
- // That's fine but verify that VAO holds *element* buffer binding.
- // Verified: ELEMENT_ARRAY_BUFFER_BINDING is part of VAO state.
- // VERTEX_ATTRIB_ARRAY_BUFFER_BINDING is too, per vertex attrib. Currently bound ARRAY_BUFFER is not.
- // Does APPLE_vertex_array_object also include ELEMENT_ARRAY_BUFFER_BINDING?
- // The extension spec refers only to APPLE_element_array, so.. maybe, maybe not?
- // Will have to test during development, maybe alter behavior for APPLE_LEGACY. Can strip out this
- // platform-specific cruft for Blender, keep it for legacy Gawain.
-
- // state
- GLuint bound_program;
- AttribBinding attrib_binding;
-} Batch;
-
-typedef struct {
- Batch* batch;
-} BatchBuilder;
-
-// One batch can be drawn with multiple shaders, as long as those shaders' inputs
-// are compatible with the batch's vertex format.
-
-// Can multiple batches share a VertexBuffer? Use ref count?
-
-// BasicBatch
-// Create one VertexBuffer from an object's verts (3D position only)
-// Shader must depend only on position + uniforms: uniform color, depth only, or object ID.
-// - draw verts via DrawArrays
-// - draw lines via DrawElements (can have 2 element lists: true face edges, triangulated edges)
-// - draw faces via DrawElements (raw triangles, not polygon faces)
-// This is very 3D-mesh-modeling specific. I'm investigating what Gawain needs to allow/expose
-// to meet Blender's needs, possibly other programs' needs.
-
-Batch* BatchPlease(GLenum prim_type, unsigned prim_ct, unsigned v_ct);
-// GL_TRIANGLES 12 triangles that share 8 vertices
-
-// Is there ever a reason to index GL_POINTS? nothing comes to mind...
-// (later) ok now that I'm thinking straight, *of course* you can draw
-// indexed POINTS. Only some verts from the buffer will be drawn. I was
-// just limiting my thinking to immediate needs. Batched needs.
-
-Batch* batch = BatchPlease(GL_TRIANGLES, 12, 8);
-unsigned pos = add_attrib(batch->verts.format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
-pack(batch->verts->format); // or ...
-finalize(batch); // <-- packs vertex format, allocates vertex buffer
-
-Batch* create_Batch(GLenum prim_type, VertexBuffer*, ElementList*);
-
-// and don't forget
-Batch* immBeginBatch(GLenum prim_type, unsigned v_ct);
-// use standard immFunctions after this. immEnd will finalize the batch instead
-// of drawing.
-
-typedef enum {
- READY_TO_FORMAT,
- READY_TO_BUILD,
- BUILDING, BUILDING_IMM, // choose one
- READY_TO_DRAW
-} BatchPhase;
+#endif // future plans
diff --git a/source/blender/gpu/gawain/element.c b/source/blender/gpu/gawain/element.c
index 0ec31f6a45a..385705c71c6 100644
--- a/source/blender/gpu/gawain/element.c
+++ b/source/blender/gpu/gawain/element.c
@@ -16,43 +16,47 @@
unsigned ElementList_size(const ElementList* elem)
{
+#if TRACK_INDEX_RANGE
switch (elem->index_type)
{
case GL_UNSIGNED_BYTE: return elem->index_ct * sizeof(GLubyte);
case GL_UNSIGNED_SHORT: return elem->index_ct * sizeof(GLushort);
case GL_UNSIGNED_INT: return elem->index_ct * sizeof(GLuint);
+ default:
+ assert(false);
+ return 0;
}
- return 0;
+#else
+ return elem->index_ct * sizeof(GLuint);
+#endif
}
-void ElementList_use(ElementList* elem)
+static void ElementList_prime(ElementList* elem)
{
- if (elem->vbo_id)
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
- else
- {
- glGenBuffers(1, &elem->vbo_id);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
- // fill with delicious data & send to GPU the first time only
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementList_size(elem), elem->data, GL_STATIC_DRAW);
+ glGenBuffers(1, &elem->vbo_id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+ // fill with delicious data & send to GPU the first time only
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementList_size(elem), elem->data, GL_STATIC_DRAW);
#if KEEP_SINGLE_COPY
- // now that GL has a copy, discard original
- free(elem->data);
- elem->data = NULL;
+ // now that GL has a copy, discard original
+ free(elem->data);
+ elem->data = NULL;
#endif
- }
}
-void ElementList_done_using()
+void ElementList_use(ElementList* elem)
{
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ if (elem->vbo_id)
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+ else
+ ElementList_prime(elem);
}
-void init_ElementListBuilder(ElementListBuilder* builder, GLenum prim_type, unsigned prim_ct, unsigned vertex_ct)
+void ElementListBuilder_init(ElementListBuilder* builder, GLenum prim_type, unsigned prim_ct, unsigned vertex_ct)
{
- unsigned verts_per_prim;
+ unsigned verts_per_prim = 0;
switch (prim_type)
{
case GL_POINTS:
@@ -195,7 +199,7 @@ static void squeeze_indices_short(const unsigned values[], ElementList* elem)
#endif // TRACK_INDEX_RANGE
-void build_ElementList(ElementListBuilder* builder, ElementList* elem)
+void ElementList_build(ElementListBuilder* builder, ElementList* elem)
{
#if TRUST_NO_ONE
assert(builder->data != NULL);
diff --git a/source/blender/gpu/gawain/element.h b/source/blender/gpu/gawain/element.h
index c092dba721f..9ba2ed2a5b1 100644
--- a/source/blender/gpu/gawain/element.h
+++ b/source/blender/gpu/gawain/element.h
@@ -28,7 +28,6 @@ typedef struct {
} ElementList;
void ElementList_use(ElementList*);
-void ElementList_done_using(void);
unsigned ElementList_size(const ElementList*);
typedef struct {
@@ -44,8 +43,8 @@ typedef struct {
// GL_LINES
// GL_TRIANGLES
-void init_ElementListBuilder(ElementListBuilder*, GLenum prim_type, unsigned prim_ct, unsigned vertex_ct);
-//void init_CustomElementListBuilder(ElementListBuilder*, GLenum prim_type, unsigned index_ct, unsigned vertex_ct);
+void ElementListBuilder_init(ElementListBuilder*, GLenum prim_type, unsigned prim_ct, unsigned vertex_ct);
+//void ElementListBuilder_init_custom(ElementListBuilder*, GLenum prim_type, unsigned index_ct, unsigned vertex_ct);
void add_generic_vertex(ElementListBuilder*, unsigned v);
@@ -53,4 +52,4 @@ void add_point_vertex(ElementListBuilder*, unsigned v);
void add_line_vertices(ElementListBuilder*, unsigned v1, unsigned v2);
void add_triangle_vertices(ElementListBuilder*, unsigned v1, unsigned v2, unsigned v3);
-void build_ElementList(ElementListBuilder*, ElementList*);
+void ElementList_build(ElementListBuilder*, ElementList*);
diff --git a/source/blender/gpu/gawain/vertex_buffer.c b/source/blender/gpu/gawain/vertex_buffer.c
index 054148403f3..9ceec5c0ca4 100644
--- a/source/blender/gpu/gawain/vertex_buffer.c
+++ b/source/blender/gpu/gawain/vertex_buffer.c
@@ -13,19 +13,21 @@
#include <stdlib.h>
#include <string.h>
-VertexBuffer* create_VertexBuffer()
+#define KEEP_SINGLE_COPY 1
+
+VertexBuffer* VertexBuffer_create()
{
VertexBuffer* verts = malloc(sizeof(VertexBuffer));
- init_VertexBuffer(verts);
+ VertexBuffer_init(verts);
return verts;
}
-void init_VertexBuffer(VertexBuffer* verts)
+void VertexBuffer_init(VertexBuffer* verts)
{
memset(verts, 0, sizeof(VertexBuffer));
}
-void allocate_vertex_data(VertexBuffer* verts, unsigned v_ct)
+void VertexBuffer_allocate_data(VertexBuffer* verts, unsigned v_ct)
{
VertexFormat* format = &verts->format;
if (!format->packed)
@@ -89,3 +91,27 @@ void fillAttribStride(VertexBuffer* verts, unsigned a_idx, unsigned stride, cons
memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz);
}
}
+
+static void VertexBuffer_prime(VertexBuffer* verts)
+ {
+ const VertexFormat* format = &verts->format;
+
+ glGenBuffers(1, &verts->vbo_id);
+ glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
+ // fill with delicious data & send to GPU the first time only
+ glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size(format, verts->vertex_ct), verts->data, GL_STATIC_DRAW);
+
+#if KEEP_SINGLE_COPY
+ // now that GL has a copy, discard original
+ free(verts->data);
+ verts->data = NULL;
+#endif
+ }
+
+void VertexBuffer_use(VertexBuffer* verts)
+ {
+ if (verts->vbo_id)
+ glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
+ else
+ VertexBuffer_prime(verts);
+ }
diff --git a/source/blender/gpu/gawain/vertex_buffer.h b/source/blender/gpu/gawain/vertex_buffer.h
index 631b6652d92..a26a7306656 100644
--- a/source/blender/gpu/gawain/vertex_buffer.h
+++ b/source/blender/gpu/gawain/vertex_buffer.h
@@ -29,13 +29,13 @@ typedef struct {
GLuint vbo_id; // 0 indicates not yet sent to VRAM
} VertexBuffer;
-VertexBuffer* create_VertexBuffer(void); // create means allocate, then init
-void init_VertexBuffer(VertexBuffer*);
+VertexBuffer* VertexBuffer_create(void); // create means allocate, then init
+void VertexBuffer_init(VertexBuffer*);
// TODO: use copy of existing format
// void init_VertexBuffer_with_format(VertexBuffer*, VertexFormat*);
-void allocate_vertex_data(VertexBuffer*, unsigned v_ct);
+void VertexBuffer_allocate_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
@@ -56,3 +56,5 @@ void fillAttribStride(VertexBuffer*, unsigned a_idx, unsigned stride, const void
//
// void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b);
// void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+void VertexBuffer_use(VertexBuffer*);