[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