[Bf-blender-cvs] [39f7a81] blender2.8: Gawain: batch rendering API
Mike Erwin
noreply at git.blender.org
Thu Sep 15 16:51:41 CEST 2016
Commit: 39f7a8117692da3a6645ccb7ae2080077f9e5980
Author: Mike Erwin
Date: Thu Sep 15 16:51:10 2016 +0200
Branches: blender2.8
https://developer.blender.org/rB39f7a8117692da3a6645ccb7ae2080077f9e5980
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!
===================================================================
M source/blender/gpu/CMakeLists.txt
M source/blender/gpu/gawain/batch.c
M source/blender/gpu/gawain/batch.h
M source/blender/gpu/gawain/element.c
M source/blender/gpu/gawain/element.h
M source/blender/gpu/gawain/vertex_buffer.c
M source/blender/gpu/gawain/vertex_buffer.h
===================================================================
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 50c2db2..63ae58d 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 3934d35..96bf6dd 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 9625d66..8387b01 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 0ec31f6..385705c 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 origina
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list