Răsfoiți Sursa

Initial Transient Vertex/Index Buffer implementation

Daniele Bartolini 12 ani în urmă
părinte
comite
27c79a2958

+ 2 - 2
engine/gui/GuiImage.h

@@ -50,8 +50,8 @@ struct GuiImage
 		MaterialResource* mat = (MaterialResource*) device()->resource_manager()->data(material);
 		m_material = m_render_world.create_material(mat);
 
-		m_vb = m_r.create_vertex_buffer(4, VertexFormat::P2_T2, m_vertices);
-		m_ib = m_r.create_index_buffer(6, m_indices);
+		m_vb = m_r.create_vertex_buffer(4 * Vertex::bytes_per_vertex(VertexFormat::P2_T2), m_vertices, VertexFormat::P2_T2);
+		m_ib = m_r.create_index_buffer(6 * sizeof(uint16_t), m_indices);
 	}
 
 	//-------------------------------------------------------------------------

+ 2 - 2
engine/gui/GuiRect.h

@@ -45,8 +45,8 @@ struct GuiRect
 	{
 		update(pos, size, color);
 
-		m_vb = m_r.create_vertex_buffer(4, VertexFormat::P2_C4, m_vertices);
-		m_ib = m_r.create_index_buffer(8, m_indices);
+		m_vb = m_r.create_vertex_buffer(4 * Vertex::bytes_per_vertex(VertexFormat::P2_C4), m_vertices, VertexFormat::P2_C4);
+		m_ib = m_r.create_index_buffer(8 * sizeof(uint16_t), m_indices);
 	}
 
 	//-------------------------------------------------------------------------

+ 2 - 2
engine/gui/GuiTriangle.h

@@ -40,8 +40,8 @@ struct GuiTriangle
 	{
 		update(p1, p2, p3, color);
 
-		m_vb = m_r.create_vertex_buffer(3, VertexFormat::P2_C4, m_vertices);
-		m_ib = m_r.create_index_buffer(6, m_indices);
+		m_vb = m_r.create_vertex_buffer(3 * Vertex::bytes_per_vertex(VertexFormat::P2_C4), m_vertices, VertexFormat::P2_C4);
+		m_ib = m_r.create_index_buffer(6 * sizeof(uint16_t), m_indices);
 	}
 
 	//-------------------------------------------------------------------------

+ 67 - 1
engine/renderers/backend/RenderContext.h

@@ -175,6 +175,11 @@ struct RenderState
 		program.id = INVALID_ID;
 		vb.id = INVALID_ID;
 		ib.id = INVALID_ID;
+		start_vertex = 0;
+		num_vertices = 0xFFFFFFFF;
+		start_index = 0;
+		num_indices = 0xFFFFFFFF;
+		vertex_format = VertexFormat::COUNT;
 
 		for (uint32_t i = 0; i < STATE_MAX_TEXTURES; i++)
 		{
@@ -191,8 +196,11 @@ public:
 	GPUProgramId	program;
 	VertexBufferId	vb;
 	IndexBufferId	ib;
+	uint32_t		start_vertex;
+	uint32_t		num_vertices;
 	uint32_t		start_index;
 	uint32_t		num_indices;
+	VertexFormat::Enum vertex_format;
 	Sampler			samplers[STATE_MAX_TEXTURES];
 };
 
@@ -218,6 +226,25 @@ public:
 	uint8_t m_layer;
 };
 
+/// A vertex buffer valid for one frame only
+struct TransientVertexBuffer
+{
+	VertexBufferId vb;
+	VertexFormat::Enum format;
+	uint32_t start_vertex;
+	size_t size;
+	char* data;
+};
+
+/// An index buffer valid for one frame only
+struct TransientIndexBuffer
+{
+	IndexBufferId ib;
+	uint32_t start_index;
+	size_t size;
+	char* data;
+};
+
 struct RenderContext
 {
 	RenderContext()
@@ -225,6 +252,20 @@ struct RenderContext
 		clear();
 	}
 
+	uint32_t reserve_transient_vertex_buffer(uint32_t num, VertexFormat::Enum format)
+	{
+		const uint32_t offset = m_tvb_offset;
+		m_tvb_offset = offset + Vertex::bytes_per_vertex(format) * num;
+		return offset;
+	}
+
+	uint32_t reserve_transient_index_buffer(uint32_t num)
+	{
+		const uint32_t offset = m_tib_offset;
+		m_tib_offset = offset + sizeof(uint16_t) * num;
+		return offset;
+	}
+
 	void set_state(uint64_t flags)
 	{
 		m_state.m_flags = flags;
@@ -240,9 +281,19 @@ struct RenderContext
 		m_state.program = program;
 	}
 
-	void set_vertex_buffer(VertexBufferId vb)
+	void set_vertex_buffer(VertexBufferId vb, uint32_t num_vertices)
 	{
 		m_state.vb = vb;
+		m_state.start_vertex = 0;
+		m_state.num_vertices = num_vertices;
+	}
+
+	void set_vertex_buffer(const TransientVertexBuffer& tvb, uint32_t num_vertices)
+	{
+		m_state.vb = tvb.vb;
+		m_state.start_vertex = tvb.start_vertex;
+		m_state.num_vertices = math::min((uint32_t) tvb.size / (uint32_t) Vertex::bytes_per_vertex(tvb.format), num_vertices);
+		m_state.vertex_format = tvb.format;
 	}
 
 	void set_index_buffer(IndexBufferId ib, uint32_t start_index, uint32_t num_indices)
@@ -252,6 +303,13 @@ struct RenderContext
 		m_state.num_indices = num_indices;
 	}
 
+	void set_index_buffer(const TransientIndexBuffer& tib, uint32_t num_indices)
+	{
+		m_state.ib = tib.ib;
+		m_state.start_index = tib.start_index;
+		m_state.num_indices = math::min((uint32_t) tib.size / (uint32_t) sizeof(uint16_t), num_indices);
+	}
+
 	void set_uniform(UniformId id, UniformType::Enum type, const void* value, uint8_t num)
 	{
 		m_constants.write_constant(id, type, value, num);
@@ -339,6 +397,9 @@ struct RenderContext
 
 		m_num_states = 0;
 		m_state.clear();
+
+		m_tvb_offset = 0;
+		m_tib_offset = 0;
 	}
 
 	void push()
@@ -373,6 +434,11 @@ public:
 
 	CommandBuffer m_commands;
 	ConstantBuffer m_constants;
+
+	uint32_t m_tvb_offset;
+	uint32_t m_tib_offset;
+	TransientVertexBuffer* m_transient_vb;
+	TransientIndexBuffer* m_transient_ib;
 };
 
 } // namespace crown

+ 177 - 64
engine/renderers/backend/Renderer.h

@@ -53,14 +53,14 @@ public:
 	void shutdown_impl();
 	void render_impl();
 
-	void create_vertex_buffer_impl(VertexBufferId id, size_t count, VertexFormat::Enum format, const void* vertices);
-	void create_dynamic_vertex_buffer_impl(VertexBufferId id, size_t count, VertexFormat::Enum format);
-	void update_vertex_buffer_impl(VertexBufferId id, size_t offset, size_t count, const void* vertices);
+	void create_vertex_buffer_impl(VertexBufferId id, size_t size, const void* data, VertexFormat::Enum format);
+	void create_dynamic_vertex_buffer_impl(VertexBufferId id, size_t size);
+	void update_vertex_buffer_impl(VertexBufferId id, size_t offset, size_t size, const void* data);
 	void destroy_vertex_buffer_impl(VertexBufferId id);
 
-	void create_index_buffer_impl(IndexBufferId id, size_t count, const void* indices);
-	void create_dynamic_index_buffer_impl(IndexBufferId id, size_t count);
-	void update_index_buffer_impl(IndexBufferId id, size_t offset, size_t count, const void* indices);
+	void create_index_buffer_impl(IndexBufferId id, size_t size, const void* data);
+	void create_dynamic_index_buffer_impl(IndexBufferId id, size_t size);
+	void update_index_buffer_impl(IndexBufferId id, size_t offset, size_t size, const void* data);
 	void destroy_index_buffer_impl(IndexBufferId id);
 
 	void create_texture_impl(TextureId id, uint32_t width, uint32_t height, PixelFormat::Enum format, const void* data);
@@ -85,10 +85,17 @@ public:
 	void init()
 	{
 		m_should_run = true;
-		m_thread.start(render_thread, this);
+		// m_thread.start(render_thread, this);
 
 		m_submit->m_commands.write(CommandType::INIT_RENDERER);
 		frame();
+
+		m_submit->m_transient_vb = create_transient_vertex_buffer(2 * 1024);
+		m_submit->m_transient_ib = create_transient_index_buffer(2 * 1024);
+		frame();
+		m_submit->m_transient_vb = create_transient_vertex_buffer(2 * 1024);
+		m_submit->m_transient_ib = create_transient_index_buffer(2 * 1024);
+		frame();
 	}
 
 	/// Shutdowns the renderer.
@@ -97,24 +104,32 @@ public:
 	{
 		if (m_should_run)
 		{
+			destroy_transient_index_buffer(m_submit->m_transient_ib);
+			destroy_transient_vertex_buffer(m_submit->m_transient_vb);
+			frame();
+
+			destroy_transient_index_buffer(m_submit->m_transient_ib);
+			destroy_transient_vertex_buffer(m_submit->m_transient_vb);
+			frame();
+
 			m_submit->m_commands.write(CommandType::SHUTDOWN_RENDERER);
 			frame();
 
-			m_thread.stop();		
+			//m_thread.stop();		
 		}
 	}
 
 	/// Creates a new vertex buffer optimized for rendering static vertex data.
 	/// @a vertices is the array containig @a count vertex data elements, each of the given @a format.
-	VertexBufferId create_vertex_buffer(size_t count, VertexFormat::Enum format, const void* vertices)
+	VertexBufferId create_vertex_buffer(size_t size, const void* data, VertexFormat::Enum format)
 	{
 		const VertexBufferId id = m_vertex_buffers.create();
 
 		m_submit->m_commands.write(CommandType::CREATE_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
-		m_submit->m_commands.write(count);
+		m_submit->m_commands.write(size);
+		m_submit->m_commands.write(data);
 		m_submit->m_commands.write(format);
-		m_submit->m_commands.write(vertices);
 
 		return id;
 	}
@@ -122,32 +137,68 @@ public:
 	/// Creates a new vertex buffer optimized for renderering dynamic vertex data.
 	/// This function only allocates storage for @a count vertices, each of the given @a format;
 	/// use Renderer::update_vertex_buffer() to fill the buffer with actual data.
-	VertexBufferId create_dynamic_vertex_buffer(size_t count, VertexFormat::Enum format)
+	VertexBufferId create_dynamic_vertex_buffer(size_t size)
 	{
 		const VertexBufferId id = m_vertex_buffers.create();
 
 		m_submit->m_commands.write(CommandType::CREATE_DYNAMIC_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
-		m_submit->m_commands.write(count);
-		m_submit->m_commands.write(format);
+		m_submit->m_commands.write(size);
 
 		return id;
 	}
 
+	/// Creates a new transient vertex buffer with storage for exactly @a size bytes.
+	/// Transient vertex buffers are useful when you have to render highly dynamic vertex data, such as font glyphs.
+	/// @note
+	/// This call is tipically only performed by the backend to allocate a common large generic transient buffer
+	/// that can be used to carve out smaller transient buffers by calling Renderer::reserve_transient_vertex_buffer().
+	TransientVertexBuffer* create_transient_vertex_buffer(size_t size)
+	{
+		VertexBufferId vb = create_dynamic_vertex_buffer(size);
+		TransientVertexBuffer* tvb = NULL;
+
+		tvb = (TransientVertexBuffer*) default_allocator().allocate(sizeof(TransientVertexBuffer) + size);
+		tvb->vb = vb;
+		tvb->data = (char*) &tvb[1]; // Nice trick
+		tvb->size = size;
+
+		return tvb;
+	}
+
+	/// Reserves a portion of the common transient vertex buffer for exactly @a num vertices
+	/// of the given @a format.
+	/// @note
+	/// The returned @a tvb transient buffer is valid for one frame only!
+	void reserve_transient_vertex_buffer(TransientVertexBuffer* tvb, uint32_t num, VertexFormat::Enum format)
+	{
+		CE_ASSERT(tvb != NULL, "Transient buffer must be != NULL");
+
+		TransientVertexBuffer& tvb_shared = *m_submit->m_transient_vb;
+
+		const uint32_t offset = m_submit->reserve_transient_vertex_buffer(num, format);
+
+		tvb->vb = tvb_shared.vb;
+		tvb->data = &tvb_shared.data[offset];
+		tvb->start_vertex = offset / Vertex::bytes_per_vertex(format);
+		tvb->size = Vertex::bytes_per_vertex(format) * num;
+		tvb->format = format;
+	}
+
 	/// Updates the vertex buffer data of @a id with @a count @a vertices starting
 	/// at the given @a offset. The @a vertices have to match the format specified at creation time.
 	/// @note
 	/// @a count and @a offset together do not have to exceed the number of elements
 	/// originally specified to Renderer::create_vertex_buffer() (or Renderer::create_dynamic_vertex_buffer())
-	void update_vertex_buffer(VertexBufferId id, size_t offset, size_t count, const void* vertices)
+	void update_vertex_buffer(VertexBufferId id, size_t offset, size_t size, const void* data)
 	{
 		CE_ASSERT(m_vertex_buffers.has(id), "Vertex buffer does not exist");
 
 		m_submit->m_commands.write(CommandType::UPDATE_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);
 		m_submit->m_commands.write(offset);
-		m_submit->m_commands.write(count);
-		m_submit->m_commands.write(vertices);			
+		m_submit->m_commands.write(size);
+		m_submit->m_commands.write(data);	
 	}
 
 	/// Destroys the given vertex buffer @a id.
@@ -159,16 +210,25 @@ public:
 		m_submit->m_commands.write(id);
 	}
 
+	/// Destroys the given @a tvb transient buffer
+	void destroy_transient_vertex_buffer(TransientVertexBuffer* tvb)
+	{
+		CE_ASSERT(tvb != NULL, "Transient buffer must be != NULL");
+
+		destroy_vertex_buffer(tvb->vb);
+		default_allocator().deallocate(tvb);
+	}
+
 	/// Creates a new index buffer optimized for rendering static index buffers.
 	/// @a indices is the array containing @a count index data elements.
-	IndexBufferId create_index_buffer(size_t count, const void* indices)
+	IndexBufferId create_index_buffer(size_t size, const void* data)
 	{
 		const IndexBufferId id = m_index_buffers.create();
 
 		m_submit->m_commands.write(CommandType::CREATE_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
-		m_submit->m_commands.write(count);
-		m_submit->m_commands.write(indices);
+		m_submit->m_commands.write(size);
+		m_submit->m_commands.write(data);
 
 		return id;
 	}
@@ -176,31 +236,66 @@ public:
 	/// Creates a new index buffer optimized for rendering dynamic index buffers.
 	/// This function only allocates storage for @a count indices;
 	/// use Renderer::update_index_buffer() to fill the buffer with actual data.
-	IndexBufferId create_dynamic_index_buffer(size_t count)
+	IndexBufferId create_dynamic_index_buffer(size_t size)
 	{
 		const IndexBufferId id = m_index_buffers.create();
 
 		m_submit->m_commands.write(CommandType::CREATE_DYNAMIC_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
-		m_submit->m_commands.write(count);
+		m_submit->m_commands.write(size);
 
 		return id;
 	}
 
+	/// Creates a new transient index buffer with storage for exactly @a size bytes.
+	/// Transient index buffers are useful when you have to render highly dynamic index data, such as font glyphs.
+	/// @note
+	/// This call is tipically only performed by the backend to allocate a common large generic transient buffer
+	/// that can be used to carve out smaller transient buffers by calling Renderer::reserve_transient_index_buffer().
+	TransientIndexBuffer* create_transient_index_buffer(size_t size)
+	{
+		IndexBufferId ib = create_dynamic_index_buffer(size);
+		TransientIndexBuffer* tib = NULL;
+
+		tib = (TransientIndexBuffer*) default_allocator().allocate(sizeof(TransientIndexBuffer) + size);
+		tib->ib = ib;
+		tib->data = (char*) &tib[1]; // Same as before
+		tib->size = size;
+
+		return tib;
+	}
+
+	/// Reserves a portion of the common transient index buffer for exactly @a num indices.
+	/// @note
+	/// The returned @a tvb transient buffer is valid for one frame only!
+	void reserve_transient_index_buffer(TransientIndexBuffer* tib, uint32_t num)
+	{
+		CE_ASSERT(tib != NULL, "Transient buffer must be != NULL");
+
+		TransientIndexBuffer& tib_shared = *m_submit->m_transient_ib;
+
+		const uint32_t offset = m_submit->reserve_transient_index_buffer(num);
+
+		tib->ib = tib_shared.ib;
+		tib->data = &tib_shared.data[offset];
+		tib->start_index = offset / sizeof(uint16_t);
+		tib->size = sizeof(uint16_t) * num;
+	}
+
 	/// Updates the index buffer data of @a id with @a count @a indices starting
 	/// at the given @a offset.
 	/// @note
 	/// @a count and @a offset together do not have to exceed the number of elements
 	/// originally specified to Renderer::create_index_buffer() (or Renderer::create_dynamic_index_buffer())
-	void update_index_buffer(IndexBufferId id, size_t offset, size_t count, const void* indices)
+	void update_index_buffer(IndexBufferId id, size_t offset, size_t size, const void* data)
 	{
 		CE_ASSERT(m_index_buffers.has(id), "Index buffer does not exist");
 
 		m_submit->m_commands.write(CommandType::UPDATE_INDEX_BUFFER);
 		m_submit->m_commands.write(id);
 		m_submit->m_commands.write(offset);
-		m_submit->m_commands.write(count);
-		m_submit->m_commands.write(indices);
+		m_submit->m_commands.write(size);
+		m_submit->m_commands.write(data);
 	}
 
 	/// Destroys the @a id index buffer.
@@ -212,6 +307,15 @@ public:
 		m_submit->m_commands.write(id);
 	}
 
+	/// Destroys the given @a tvi transient buffer
+	void destroy_transient_index_buffer(TransientIndexBuffer* tib)
+	{
+		CE_ASSERT(tib != NULL, "Transient buffer must be != NULL");
+
+		destroy_vertex_buffer(tib->ib);
+		default_allocator().deallocate(tib);
+	}
+
 	/// Creates a new texture of size @a width and @height.
 	/// The array @a data should contain @a width * @a height elements of the given @a format.
 	TextureId create_texture(uint32_t width, uint32_t height, PixelFormat::Enum format, const void* data)
@@ -365,44 +469,42 @@ public:
 				case CommandType::CREATE_VERTEX_BUFFER:
 				{
 					VertexBufferId id;
-					size_t count;
+					size_t size;
+					const void* data;
 					VertexFormat::Enum format;
-					void* vertices;
 
 					cmds.read(id);
-					cmds.read(count);
+					cmds.read(size);
+					cmds.read(data);
 					cmds.read(format);
-					cmds.read(vertices);
 
-					create_vertex_buffer_impl(id, count, format, vertices);
+					create_vertex_buffer_impl(id, size, data, format);
 					break;
 				}
 				case CommandType::CREATE_DYNAMIC_VERTEX_BUFFER:
 				{
 					VertexBufferId id;
-					size_t count;
-					VertexFormat::Enum format;
+					size_t size;
 
 					cmds.read(id);
-					cmds.read(count);
-					cmds.read(format);
+					cmds.read(size);
 
-					create_dynamic_vertex_buffer_impl(id, count, format);
+					create_dynamic_vertex_buffer_impl(id, size);
 					break;
 				}
 				case CommandType::UPDATE_VERTEX_BUFFER:
 				{
 					VertexBufferId id;
 					size_t offset;
-					size_t count;
-					void* vertices;
+					size_t size;
+					void* data;
 
 					cmds.read(id);
 					cmds.read(offset);
-					cmds.read(count);
-					cmds.read(vertices);
+					cmds.read(size);
+					cmds.read(data);
 
-					update_vertex_buffer_impl(id, offset, count, vertices);			
+					update_vertex_buffer_impl(id, offset, size, data);			
 					break;
 				}
 				case CommandType::DESTROY_VERTEX_BUFFER:
@@ -416,40 +518,40 @@ public:
 				case CommandType::CREATE_INDEX_BUFFER:
 				{
 					IndexBufferId id;
-					size_t count;
-					void* indices;
+					size_t size;
+					void* data;
 
 					cmds.read(id);
-					cmds.read(count);
-					cmds.read(indices);
+					cmds.read(size);
+					cmds.read(data);
 
-					create_index_buffer_impl(id, count, indices);
+					create_index_buffer_impl(id, size, data);
 					break;
 				}
 				case CommandType::CREATE_DYNAMIC_INDEX_BUFFER:
 				{
 					IndexBufferId id;
-					size_t count;
+					size_t size;
 
 					cmds.read(id);
-					cmds.read(count);
+					cmds.read(size);
 
-					create_dynamic_index_buffer_impl(id, count);
+					create_dynamic_index_buffer_impl(id, size);
 					break;
 				}
 				case CommandType::UPDATE_INDEX_BUFFER:
 				{
 					IndexBufferId id;
 					size_t offset;
-					size_t count;
-					void* indices;
+					size_t size;
+					void* data;
 
 					cmds.read(id);
 					cmds.read(offset);
-					cmds.read(count);
-					cmds.read(indices);
+					cmds.read(size);
+					cmds.read(data);
 
-					update_index_buffer_impl(id, offset, count, indices);
+					update_index_buffer_impl(id, offset, size, data);
 					break;
 				}
 				case CommandType::DESTROY_INDEX_BUFFER:
@@ -626,10 +728,15 @@ public:
 		m_submit->set_program(id);
 	}
 
-	void set_vertex_buffer(VertexBufferId id)
+	void set_vertex_buffer(VertexBufferId id, uint32_t num_vertices = 0xFFFFFFFF)
 	{
 		CE_ASSERT(m_vertex_buffers.has(id), "Vertex buffer does not exist");
-		m_submit->set_vertex_buffer(id);
+		m_submit->set_vertex_buffer(id, num_vertices);
+	}
+
+	void set_vertex_buffer(const TransientVertexBuffer& tvb, uint32_t num_vertices = 0xFFFFFFFF)
+	{
+		m_submit->set_vertex_buffer(tvb, num_vertices);
 	}
 
 	void set_index_buffer(IndexBufferId id, uint32_t start_index = 0, uint32_t num_indices = 0xFFFFFFFF)
@@ -638,6 +745,11 @@ public:
 		m_submit->set_index_buffer(id, start_index, num_indices);
 	}
 
+	void set_index_buffer(const TransientIndexBuffer& tib, uint32_t num_indices = 0xFFFFFFFF)
+	{
+		m_submit->set_index_buffer(tib, num_indices);
+	}
+
 	void set_uniform(UniformId id, UniformType::Enum type, const void* value, uint8_t num)
 	{
 		CE_ASSERT(m_uniforms.has(id), "Uniform does not exist");
@@ -690,11 +802,11 @@ public:
 
 	static int32_t render_thread(void* thiz)
 	{
-		Renderer* renderer = (Renderer*)thiz;
-		while (renderer->m_should_run)
-		{
-			renderer->render_all();
-		}
+		// Renderer* renderer = (Renderer*)thiz;
+		// while (renderer->m_should_run)
+		// {
+		// 	renderer->render_all();
+		// }
 
 		return 0;
 	}
@@ -712,15 +824,16 @@ public:
 	void frame()
 	{
 		// Signal main thread finished updating
-		m_render_wait.post();
-		m_main_wait.wait();
+		// m_render_wait.post();
+		// m_main_wait.wait();
+		render_all();
 	}
 
 	// Do all the processing needed to render a frame
 	void render_all()
 	{
 		// Waits for main thread to finish update
-		m_render_wait.wait();
+		// m_render_wait.wait();
 
 		swap_contexts();
 
@@ -732,7 +845,7 @@ public:
 			render_impl();
 		}
 
-		m_main_wait.post();
+		// m_main_wait.post();
 	}
 
 protected:

+ 25 - 14
engine/renderers/backend/gl/GLRenderer.cpp

@@ -262,6 +262,16 @@ public:
 		// Sort render keys
 		context.sort();
 
+		// Update transient buffers
+		if (context.m_tvb_offset)
+		{
+			m_vertex_buffers[context.m_transient_vb->vb.index].update(0, context.m_tvb_offset, context.m_transient_vb->data);
+		}
+		if (context.m_tib_offset)
+		{
+			m_index_buffers[context.m_transient_ib->ib.index].update(0, context.m_tib_offset, context.m_transient_ib->data);
+		}
+
 		for (uint32_t s = 0; s < context.m_num_states; s++)
 		{
 			const uint64_t key_s = context.m_keys[s];
@@ -462,7 +472,8 @@ public:
 				GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer.m_id));
 
 				const GPUProgram& gpu_program = m_gpu_programs[cur_state.program.index];
-				gpu_program.bind_attributes(vertex_buffer.m_format);
+				const VertexFormat::Enum format = vertex_buffer.m_format == VertexFormat::COUNT ? cur_state.vertex_format : vertex_buffer.m_format;
+				gpu_program.bind_attributes(format, cur_state.start_vertex);
 			}
 			else
 			{
@@ -475,7 +486,7 @@ public:
 				const IndexBuffer& index_buffer = m_index_buffers[ib.index];
 				const uint32_t prim_type = (flags & STATE_PRIMITIVE_MASK) >> STATE_PRIMITIVE_SHIFT;
 				const GLenum gl_prim_type = PRIMITIVE_TYPE_TABLE[prim_type];
-				const uint32_t num_indices = cur_state.num_indices == 0xFFFFFFFF ? index_buffer.m_index_count : cur_state.num_indices;
+				const uint32_t num_indices = cur_state.num_indices == 0xFFFFFFFF ? index_buffer.m_size : cur_state.num_indices;
 
 				GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer.m_id));
 				GL_CHECK(glDrawElements(gl_prim_type, num_indices, GL_UNSIGNED_SHORT, (void*) (uintptr_t) (cur_state.start_index * sizeof(uint16_t))));
@@ -561,21 +572,21 @@ void Renderer::render_impl()
 }
 
 //-----------------------------------------------------------------------------
-void Renderer::create_vertex_buffer_impl(VertexBufferId id, size_t count, VertexFormat::Enum format, const void* vertices)
+void Renderer::create_vertex_buffer_impl(VertexBufferId id, size_t size, const void* data, VertexFormat::Enum format)
 {
-	m_impl->m_vertex_buffers[id.index].create(count, format, vertices);
+	m_impl->m_vertex_buffers[id.index].create(size, data, format);
 }
 
 //-----------------------------------------------------------------------------
-void Renderer::create_dynamic_vertex_buffer_impl(VertexBufferId id, size_t count, VertexFormat::Enum format)
+void Renderer::create_dynamic_vertex_buffer_impl(VertexBufferId id, size_t size)
 {
-	m_impl->m_vertex_buffers[id.index].create(count, format, NULL);
+	m_impl->m_vertex_buffers[id.index].create(size, NULL, VertexFormat::COUNT);
 }
 
 //-----------------------------------------------------------------------------
-void Renderer::update_vertex_buffer_impl(VertexBufferId id, size_t offset, size_t count, const void* vertices)
+void Renderer::update_vertex_buffer_impl(VertexBufferId id, size_t offset, size_t size, const void* data)
 {
-	m_impl->m_vertex_buffers[id.index].update(offset, count, vertices);
+	m_impl->m_vertex_buffers[id.index].update(offset, size, data);
 }
 
 //-----------------------------------------------------------------------------
@@ -586,21 +597,21 @@ void Renderer::destroy_vertex_buffer_impl(VertexBufferId id)
 }
 
 //-----------------------------------------------------------------------------
-void Renderer::create_index_buffer_impl(IndexBufferId id, size_t count, const void* indices)
+void Renderer::create_index_buffer_impl(IndexBufferId id, size_t size, const void* data)
 {
-	m_impl->m_index_buffers[id.index].create(count, indices);
+	m_impl->m_index_buffers[id.index].create(size, data);
 }
 
 //-----------------------------------------------------------------------------
-void Renderer::create_dynamic_index_buffer_impl(IndexBufferId id, size_t count)
+void Renderer::create_dynamic_index_buffer_impl(IndexBufferId id, size_t size)
 {
-	m_impl->m_index_buffers[id.index].create(count, NULL);
+	m_impl->m_index_buffers[id.index].create(size, NULL);
 }
 
 //-----------------------------------------------------------------------------
-void Renderer::update_index_buffer_impl(IndexBufferId id, size_t offset, size_t count, const void* indices)
+void Renderer::update_index_buffer_impl(IndexBufferId id, size_t offset, size_t size, const void* data)
 {
-	m_impl->m_index_buffers[id.index].update(offset, count, indices);	
+	m_impl->m_index_buffers[id.index].update(offset, size, data);
 }
 
 //-----------------------------------------------------------------------------

+ 19 - 20
engine/renderers/backend/gl/GLRenderer.h

@@ -90,24 +90,23 @@ static const char* gl_error_to_string(GLenum error)
 struct VertexBuffer
 {
 	//-----------------------------------------------------------------------------
-	void create(size_t count, VertexFormat::Enum format, const void* vertices)
+	void create(size_t size, const void* data, VertexFormat::Enum format)
 	{
 		GL_CHECK(glGenBuffers(1, &m_id));
+		CE_ASSERT(m_id != 0, "Failed to create buffer");
 		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferData(GL_ARRAY_BUFFER, count * Vertex::bytes_per_vertex(format), vertices,
-			(vertices == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
+		GL_CHECK(glBufferData(GL_ARRAY_BUFFER, size, data, (data == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
 		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
 
-		m_count = count;
+		m_size = size;
 		m_format = format;
 	}
 
 	//-----------------------------------------------------------------------------
-	void update(size_t offset, size_t count, const void* vertices)
+	void update(size_t offset, size_t size, const void* data)
 	{
 		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, offset * Vertex::bytes_per_vertex(m_format),
-									count * Vertex::bytes_per_vertex(m_format), vertices));
+		GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, offset, size, data));
 		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
 	}
 
@@ -120,32 +119,31 @@ struct VertexBuffer
 
 public:
 
-	GLuint			m_id;
-	size_t			m_count;
-	VertexFormat::Enum	m_format;
+	GLuint m_id;
+	size_t m_size;
+	VertexFormat::Enum m_format;
 };
 
 //-----------------------------------------------------------------------------
 struct IndexBuffer
 {
 	//-----------------------------------------------------------------------------
-	void create(size_t count, const void* indices)
+	void create(size_t size, const void* data)
 	{
 		GL_CHECK(glGenBuffers(1, &m_id));
+		CE_ASSERT(m_id != 0, "Failed to create buffer");
 		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(GLushort), indices,
-					(indices == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
+		GL_CHECK(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, (data == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
 		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
 
-		m_index_count = count;
+		m_size = size;
 	}
 
 	//-----------------------------------------------------------------------------
-	void update(size_t offset, size_t count, const void* indices)
+	void update(size_t offset, size_t size, const void* data)
 	{
 		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(uint16_t),
-									count * sizeof(uint16_t), indices));
+		GL_CHECK(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data));
 		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
 	}
 
@@ -159,7 +157,7 @@ struct IndexBuffer
 public:
 
 	GLuint		m_id;
-	uint32_t	m_index_count;
+	uint32_t	m_size;
 };
 
 //-----------------------------------------------------------------------------
@@ -421,7 +419,7 @@ struct GPUProgram
 	}
 
 	//-----------------------------------------------------------------------------
-	void bind_attributes(VertexFormat::Enum format) const
+	void bind_attributes(VertexFormat::Enum format, uint32_t start_vertex) const
 	{
 		// Bind all active attributes
 		for (uint8_t i = 0; i < m_num_active_attribs; i++)
@@ -434,8 +432,9 @@ struct GPUProgram
 			if (loc != -1 && info.has_attrib(attrib))
 			{
 				GL_CHECK(glEnableVertexAttribArray(loc));
+				uint32_t base_vertex = start_vertex * info.attrib_stride(attrib) + info.attrib_offset(attrib);
 				GL_CHECK(glVertexAttribPointer(loc, info.num_components(attrib), GL_FLOAT, GL_FALSE, info.attrib_stride(attrib),
-										(GLvoid*)(uintptr_t) info.attrib_offset(attrib)));
+										(GLvoid*)(uintptr_t) base_vertex));
 			}
 		}
 	}

+ 2 - 2
engine/resource/MeshResource.h

@@ -94,8 +94,8 @@ public:
 		MeshResource* m = (MeshResource*) resource;
 		MeshHeader* h = (MeshHeader*) m;
 
-		h->vbuffer = device()->renderer()->create_vertex_buffer(m->num_vertices(), m->vertex_format(), m->vertices());
-		h->ibuffer = device()->renderer()->create_index_buffer(m->num_indices(), m->indices());
+		h->vbuffer = device()->renderer()->create_vertex_buffer(m->num_vertices() * Vertex::bytes_per_vertex(m->vertex_format()), m->vertices(), m->vertex_format());
+		h->ibuffer = device()->renderer()->create_index_buffer(m->num_indices() * sizeof(uint16_t), m->indices());
 	}
 
 	//-----------------------------------------------------------------------------

+ 2 - 2
engine/resource/SpriteResource.h

@@ -87,8 +87,8 @@ struct SpriteResource
 		const float* vertices = (float*) (((char*) resource) + h->vertices_offset);
 		const uint16_t* indices = (uint16_t*) (((char*) resource) + h->indices_offset);
 
-		h->vb = device()->renderer()->create_vertex_buffer(h->num_vertices, VertexFormat::P2_T2, vertices);
-		h->ib = device()->renderer()->create_index_buffer(h->num_indices, indices);
+		h->vb = device()->renderer()->create_vertex_buffer(h->num_vertices * Vertex::bytes_per_vertex(VertexFormat::P2_T2), vertices, VertexFormat::P2_T2);
+		h->ib = device()->renderer()->create_index_buffer(h->num_indices * sizeof(uint16_t), indices);
 	}
 
 	//-----------------------------------------------------------------------------