Selaa lähdekoodia

Added instancing example.

bkaradzic 13 vuotta sitten
vanhempi
sitoutus
f5295b951d

+ 3 - 3
examples/01-cubes/cubes.cpp

@@ -205,10 +205,10 @@ int _main_(int _argc, char** _argv)
 
 		float time = (float)(bx::getHPCounter()/double(bx::getHPFrequency() ) );
 
-		// Submit 10x10 cubes.
-		for (uint32_t yy = 0; yy <= 10; ++yy)
+		// Submit 11x11 cubes.
+		for (uint32_t yy = 0; yy < 11; ++yy)
 		{
-			for (uint32_t xx = 0; xx <= 10; ++xx)
+			for (uint32_t xx = 0; xx < 11; ++xx)
 			{
 				float mtx[16];
 				mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f);

+ 8 - 10
examples/03-raymarch/raymarch.cpp

@@ -283,16 +283,14 @@ int _main_(int _argc, char** _argv)
 			, time*0.37f
 			); 
 
-		{
-			float mtxInv[16];
-			mtxInverse(mtxInv, mtx);
-			float lightDirModel[4] = { -0.4f, -0.5f, -1.0f, 0.0f };
-			float lightDirModelN[4];
-			vec3Norm(lightDirModelN, lightDirModel);
-			float lightDir[4];
-			vec4MulMtx(lightDir, lightDirModelN, mtxInv);
-			bgfx::setUniform(u_lightDir, lightDir);
-		}
+		float mtxInv[16];
+		mtxInverse(mtxInv, mtx);
+		float lightDirModel[4] = { -0.4f, -0.5f, -1.0f, 0.0f };
+		float lightDirModelN[4];
+		vec3Norm(lightDirModelN, lightDirModel);
+		float lightDir[4];
+		vec4MulMtx(lightDir, lightDirModelN, mtxInv);
+		bgfx::setUniform(u_lightDir, lightDir);
 
 		float mvp[16];
 		mtxMul(mvp, mtx, vp);

+ 13 - 0
examples/05-instancing/fs_instancing.sc

@@ -0,0 +1,13 @@
+$input v_color0
+
+/*
+ * Copyright 2011-2012 Branimir Karadzic. All rights reserved.
+ * License: http://www.opensource.org/licenses/BSD-2-Clause
+ */
+
+#include "../common/common.sh"
+
+void main()
+{
+	gl_FragColor = v_color0;
+}

+ 266 - 0
examples/05-instancing/instancing.cpp

@@ -0,0 +1,266 @@
+/*
+ * Copyright 2011-2012 Branimir Karadzic. All rights reserved.
+ * License: http://www.opensource.org/licenses/BSD-2-Clause
+ */
+
+#include <bgfx.h>
+#include <bx/bx.h>
+#include <bx/timer.h>
+#include "../common/dbg.h"
+#include "../common/math.h"
+
+#include <stdio.h>
+#include <string.h>
+
+void fatalCb(bgfx::Fatal::Enum _code, const char* _str)
+{
+	DBG("%x: %s", _code, _str);
+}
+
+struct PosColorVertex
+{
+	float m_x;
+	float m_y;
+	float m_z;
+	uint32_t m_abgr;
+};
+
+static bgfx::VertexDecl s_PosColorDecl;
+
+static PosColorVertex s_cubeVertices[8] =
+{
+	{-1.0f,  1.0f,  1.0f, 0xff000000 },
+	{ 1.0f,  1.0f,  1.0f, 0xff0000ff },
+	{-1.0f, -1.0f,  1.0f, 0xff00ff00 },
+	{ 1.0f, -1.0f,  1.0f, 0xff00ffff },
+	{-1.0f,  1.0f, -1.0f, 0xffff0000 },
+	{ 1.0f,  1.0f, -1.0f, 0xffff00ff },
+	{-1.0f, -1.0f, -1.0f, 0xffffff00 },
+	{ 1.0f, -1.0f, -1.0f, 0xffffffff },
+};
+
+static const uint16_t s_cubeIndices[36] =
+{
+	0, 2, 1, // 0
+	1, 2, 3,
+	4, 5, 6, // 2
+	5, 7, 6,
+	0, 4, 2, // 4
+	4, 6, 2,
+	1, 3, 5, // 6
+	5, 3, 7,
+	0, 1, 4, // 8
+	4, 1, 5,
+	2, 6, 3, // 10
+	6, 7, 3,
+};
+
+static const char* s_shaderPath = NULL;
+
+static void shaderFilePath(char* _out, const char* _name)
+{
+	strcpy(_out, s_shaderPath);
+	strcat(_out, _name);
+	strcat(_out, ".bin");
+}
+
+long int fsize(FILE* _file)
+{
+	long int pos = ftell(_file);
+	fseek(_file, 0L, SEEK_END);
+	long int size = ftell(_file);
+	fseek(_file, pos, SEEK_SET);
+	return size;
+}
+
+static const bgfx::Memory* load(const char* _filePath)
+{
+	FILE* file = fopen(_filePath, "rb");
+	if (NULL != file)
+	{
+		uint32_t size = (uint32_t)fsize(file);
+		const bgfx::Memory* mem = bgfx::alloc(size+1);
+		size_t ignore = fread(mem->data, 1, size, file);
+		BX_UNUSED(ignore);
+		fclose(file);
+		mem->data[mem->size-1] = '\0';
+		return mem;
+	}
+
+	return NULL;
+}
+
+static const bgfx::Memory* loadShader(const char* _name, const char* _default = NULL)
+{
+	char filePath[512];
+	shaderFilePath(filePath, _name);
+	BX_UNUSED(_default);
+	return load(filePath);
+}
+
+int _main_(int _argc, char** _argv)
+{
+	bgfx::init(BX_PLATFORM_WINDOWS, fatalCb);
+	bgfx::reset(1280, 720);
+
+	// Enable debug text.
+	bgfx::setDebug(BGFX_DEBUG_TEXT);
+
+	// Set view 0 default viewport.
+	bgfx::setViewRect(0, 0, 0, 1280, 720);
+
+	// Set view 0 clear state.
+	bgfx::setViewClear(0
+		, BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT
+		, 0x303030ff
+		, 1.0f
+		, 0
+		);
+
+	// Setup root path for binary shaders. Shader binaries are different 
+	// for each renderer.
+	switch (bgfx::getRendererType() )
+	{
+	case bgfx::RendererType::Null:
+	case bgfx::RendererType::Direct3D9:
+		s_shaderPath = "shaders/dx9/";
+		break;
+
+	case bgfx::RendererType::Direct3D11:
+		s_shaderPath = "shaders/dx11/";
+		break;
+
+	case bgfx::RendererType::OpenGL:
+		s_shaderPath = "shaders/glsl/";
+		break;
+
+	case bgfx::RendererType::OpenGLES2:
+		s_shaderPath = "shaders/gles/";
+		break;
+	}
+
+	// Create vertex stream declaration.
+	s_PosColorDecl.begin();
+	s_PosColorDecl.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);
+	s_PosColorDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
+	s_PosColorDecl.end();
+
+	const bgfx::Memory* mem;
+
+	// Create static vertex buffer.
+	mem = bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) );
+	bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer(mem, s_PosColorDecl);
+
+	// Create static index buffer.
+	mem = bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) );
+	bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer(mem);
+
+	// Load vertex shader.
+	mem = loadShader("vs_instancing");
+	bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem);
+
+	// Load fragment shader.
+	mem = loadShader("fs_instancing");
+	bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem);
+
+	// Create program from shaders.
+	bgfx::ProgramHandle program = bgfx::createProgram(vsh, fsh);
+
+	// We can destroy vertex and fragment shader here since
+	// their reference is kept inside bgfx after calling createProgram.
+	// Vertex and fragment shader will be destroyed once program is
+	// destroyed.
+	bgfx::destroyVertexShader(vsh);
+	bgfx::destroyFragmentShader(fsh);
+
+	while (true)
+	{
+		// This dummy draw call is here to make sure that view 0 is cleared
+		// if no other draw calls are submitted to view 0.
+		bgfx::submit(0);
+
+		int64_t now = bx::getHPCounter();
+		static int64_t last = now;
+		const int64_t frameTime = now - last;
+		last = now;
+		const double freq = double(bx::getHPFrequency() );
+		const double toMs = 1000.0/freq;
+
+		// Use debug font to print information about this example.
+		bgfx::dbgTextClear();
+		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/05-instancing");
+		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Geometry instancing.");
+		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);
+
+		float at[3] = { 0.0f, 0.0f, 0.0f };
+		float eye[3] = { 0.0f, 0.0f, -35.0f };
+		
+		float view[16];
+		float proj[16];
+		mtxLookAt(view, eye, at);
+		mtxProj(proj, 60.0f, 16.0f/9.0f, 0.1f, 100.0f);
+
+		// Set view and projection matrix for view 0.
+		bgfx::setViewTransform(0, view, proj);
+
+		float time = (float)(bx::getHPCounter()/double(bx::getHPFrequency() ) );
+
+		const uint16_t instanceStride = 80;
+		const bgfx::InstanceDataBuffer* idb = bgfx::allocInstanceDataBuffer(121, instanceStride);
+		uint8_t* data = idb->data;
+
+		// Write instance data for 11x11 cubes.
+		for (uint32_t yy = 0; yy < 11; ++yy)
+		{
+			for (uint32_t xx = 0; xx < 11; ++xx)
+			{
+				float* mtx = (float*)data;
+				mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f);
+				mtx[12] = -15.0f + float(xx)*3.0f;
+				mtx[13] = -15.0f + float(yy)*3.0f;
+				mtx[14] = 0.0f;
+
+				float* color = (float*)&data[64];
+				color[0] = sin(time+float(xx)/11.0f)*0.5f+0.5f;
+				color[1] = cos(time+float(yy)/11.0f)*0.5f+0.5f;
+				color[2] = sin(time*3.0f)*0.5f+0.5f;
+				color[3] = 1.0f;
+
+				data += instanceStride;
+			}
+		}
+
+		// Set vertex and fragment shaders.
+		bgfx::setProgram(program);
+
+		// Set vertex and index buffer.
+		bgfx::setVertexBuffer(vbh);
+		bgfx::setIndexBuffer(ibh);
+
+		// Set instance data buffer.
+		bgfx::setInstanceDataBuffer(idb);
+
+		// Set render states.
+		bgfx::setState(BGFX_STATE_RGB_WRITE
+			|BGFX_STATE_DEPTH_WRITE
+			|BGFX_STATE_DEPTH_TEST_LESS
+			);
+
+		// Submit primitive for rendering to view 0.
+		bgfx::submit(0);
+
+		// Advance to next frame. Rendering thread will be kicked to 
+		// process submitted rendering primitives.
+		bgfx::frame();
+	}
+
+	// Cleanup.
+	bgfx::destroyIndexBuffer(ibh);
+	bgfx::destroyVertexBuffer(vbh);
+	bgfx::destroyProgram(program);
+
+	// Shutdown bgfx.
+	bgfx::shutdown();
+
+	return 0;
+}

+ 9 - 0
examples/05-instancing/makefile

@@ -0,0 +1,9 @@
+#
+# Copyright 2011-2012 Branimir Karadzic. All rights reserved.
+# License: http://www.opensource.org/licenses/BSD-2-Clause
+#
+
+BGFX_DIR=../..
+RUNTIME_DIR=$(BGFX_DIR)/examples/runtime
+
+include $(BGFX_DIR)/premake/shader.mk

+ 9 - 0
examples/05-instancing/varying.def.sc

@@ -0,0 +1,9 @@
+vec4 v_color0    : COLOR0    = vec4(1.0, 0.0, 0.0, 1.0);
+
+vec3 a_position  : POSITION;
+vec4 a_color     : COLOR0;
+vec4 i_data0     : TEXCOORD3;
+vec4 i_data1     : TEXCOORD4;
+vec4 i_data2     : TEXCOORD5;
+vec4 i_data3     : TEXCOORD6;
+vec4 i_data4     : TEXCOORD7;

+ 22 - 0
examples/05-instancing/vs_instancing.sc

@@ -0,0 +1,22 @@
+$input a_position, a_color, i_data0, i_data1, i_data2, i_data3, i_data4
+$output v_color0
+
+/*
+ * Copyright 2011-2012 Branimir Karadzic. All rights reserved.
+ * License: http://www.opensource.org/licenses/BSD-2-Clause
+ */
+
+#include "../common/common.sh"
+
+void main()
+{
+	mat4 model;
+	model[0] = i_data0;
+	model[1] = i_data1;
+	model[2] = i_data2;
+	model[3] = i_data3;
+
+	vec4 worldPos = instMul(model, vec4(a_position, 1.0) );
+	gl_Position = mul(u_viewProj, worldPos);
+	v_color0 = a_color*i_data4;
+}

BIN
examples/runtime/shaders/dx11/fs_instancing.bin


BIN
examples/runtime/shaders/dx11/vs_instancing.bin


BIN
examples/runtime/shaders/dx9/fs_instancing.bin


BIN
examples/runtime/shaders/dx9/vs_instancing.bin


BIN
examples/runtime/shaders/gles/fs_instancing.bin


BIN
examples/runtime/shaders/gles/vs_instancing.bin


BIN
examples/runtime/shaders/glsl/fs_instancing.bin


BIN
examples/runtime/shaders/glsl/vs_instancing.bin


+ 43 - 0
premake/example-05-instancing.lua

@@ -0,0 +1,43 @@
+project "example-05-instancing"
+	uuid "5d3da660-1105-11e2-aece-71e4dd6a022f"
+	kind "WindowedApp"
+
+	debugdir (BGFX_DIR .. "examples/runtime/")
+
+	defines {
+		"OPENCTM_STATIC",
+		"OPENCTM_NO_CPP",
+	}
+
+	includedirs {
+		BGFX_DIR .. "../bx/include",
+		BGFX_DIR .. "include",
+		BGFX_DIR .. "3rdparty/openctm/lib",
+	}
+
+	files {
+		BGFX_DIR .. "examples/common/**.cpp",
+		BGFX_DIR .. "examples/common/**.h",
+		BGFX_DIR .. "examples/05-instancing/**.cpp",
+		BGFX_DIR .. "examples/05-instancing/**.h",
+	}
+
+	links {
+		"bgfx",
+		"openctm",
+	}
+
+	configuration { "nacl" }
+		targetextension ".nexe"
+
+	configuration { "nacl", "Release" }
+		postbuildcommands {
+			"@echo Stripping symbols.",
+			"@$(NACL)/bin/x86_64-nacl-strip -s \"$(TARGET)\""
+		}
+
+	configuration { "linux" }
+		links {
+			"GL",
+			"pthread",
+		}

+ 1 - 0
premake/premake4.lua

@@ -248,3 +248,4 @@ dofile "example-01-cubes.lua"
 dofile "example-02-metaballs.lua"
 dofile "example-03-raymarch.lua"
 dofile "example-04-mesh.lua"
+dofile "example-05-instancing.lua"

+ 10 - 0
src/bgfx_shader.sh

@@ -39,6 +39,11 @@
 #	define vec2_splat(_x) float2(_x, _x)
 #	define vec3_splat(_x) float3(_x, _x, _x)
 #	define vec4_splat(_x) float4(_x, _x, _x, _x)
+
+vec4 instMul(mat4 _mtx, vec4 _vec)
+{
+	return mul(_vec, _mtx);
+}
 #elif BGFX_SHADER_LANGUAGE_GLSL
 #	define frac fract
 #	define lerp mix
@@ -50,6 +55,11 @@
 #	define vec2_splat(_x) vec2(_x)
 #	define vec3_splat(_x) vec3(_x)
 #	define vec4_splat(_x) vec4(_x)
+
+vec4 instMul(mat4 _mtx, vec4 _vec)
+{
+	return mul(_mtx, _vec);
+}
 #endif // BGFX_SHADER_LANGUAGE_HLSL
 
 #endif // __cplusplus

+ 46 - 18
src/renderer_d3d11.cpp

@@ -541,9 +541,10 @@ namespace bgfx
 //			DX_CHECK(s_renderCtx.m_device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE) );
 		}
 
-		void setInputLayout(const VertexDecl& _vertexDecl, const Program& _program)
+		void setInputLayout(const VertexDecl& _vertexDecl, const Program& _program, uint8_t _numInstanceData)
 		{
 			uint64_t layoutHash = (uint64_t(_vertexDecl.m_hash)<<32) | _program.m_vsh->m_hash;
+			layoutHash ^= _numInstanceData;
 			ID3D11InputLayout* layout = m_inputLayoutCache.find(layoutHash);
 			if (NULL == layout)
 			{
@@ -560,8 +561,41 @@ namespace bgfx
 					decl.m_attributes[ii] = attr == 0 ? 0xff : attr == 0xff ? 0 : attr;
 				}
 
+
 				D3D11_INPUT_ELEMENT_DESC* elem = fillVertexDecl(vertexElements, Attrib::Count, decl);
 				ptrdiff_t num = elem-vertexElements;
+
+				const D3D11_INPUT_ELEMENT_DESC inst = { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 };
+
+				for (uint32_t ii = 0; ii < _numInstanceData; ++ii)
+				{
+					uint32_t index = 8-_numInstanceData+ii;
+
+					uint32_t jj;
+					D3D11_INPUT_ELEMENT_DESC* curr;
+					for (jj = 0; jj < (uint32_t)num; ++jj)
+					{
+						curr = &vertexElements[jj];
+						if (0 == strcmp(curr->SemanticName, "TEXCOORD")
+						&&  curr->SemanticIndex == index)
+						{
+							break;
+						}
+					}
+
+					if (jj == num)
+					{
+						curr = elem;
+						++elem;
+					}
+
+					memcpy(curr, &inst, sizeof(D3D11_INPUT_ELEMENT_DESC) );
+					curr->InputSlot = 1;
+					curr->SemanticIndex = index;
+					curr->AlignedByteOffset = ii*16;
+				}
+
+				num = elem-vertexElements;
 				DX_CHECK(m_device->CreateInputLayout(vertexElements
 					, uint32_t(num)
 					, _program.m_vsh->m_code->data
@@ -971,7 +1005,7 @@ namespace bgfx
 		uint32_t stride = vertexDecl.m_stride;
 		uint32_t offset = 0;
 		deviceCtx->IASetVertexBuffers(0, 1, &vb.m_ptr, &stride, &offset);
-		s_renderCtx.setInputLayout(vertexDecl, program);
+		s_renderCtx.setInputLayout(vertexDecl, program, 0);
 
 		IndexBuffer& ib = s_renderCtx.m_indexBuffers[m_ib->handle.idx];
 		deviceCtx->IASetIndexBuffer(ib.m_ptr, DXGI_FORMAT_R16_UINT, 0);
@@ -1070,7 +1104,7 @@ namespace bgfx
 
 			s_renderCtx.m_vertexBuffers[m_vb->handle.idx].update(0, 4*m_decl.m_stride, m_vb->data);
 			deviceCtx->IASetVertexBuffers(0, 1, &vb.m_ptr, &stride, &offset);
-			s_renderCtx.setInputLayout(vertexDecl, program);
+			s_renderCtx.setInputLayout(vertexDecl, program, 0);
 
 			IndexBuffer& ib = s_renderCtx.m_indexBuffers[m_ib.idx];
 			deviceCtx->IASetIndexBuffer(ib.m_ptr, DXGI_FORMAT_R16_UINT, 0);
@@ -2110,24 +2144,18 @@ namespace bgfx
 						uint32_t stride = vertexDecl.m_stride;
 						uint32_t offset = 0;
 						deviceCtx->IASetVertexBuffers(0, 1, &vb.m_ptr, &stride, &offset);
-						s_renderCtx.setInputLayout(vertexDecl, s_renderCtx.m_program[programIdx]);
 
 						if (invalidHandle != state.m_instanceDataBuffer.idx)
 						{
-// 							const VertexBuffer& inst = s_renderCtx.m_vertexBuffers[state.m_instanceDataBuffer.idx];
-// 							DX_CHECK(device->SetStreamSourceFreq(0, D3DSTREAMSOURCE_INDEXEDDATA|state.m_numInstances) );
-// 							DX_CHECK(device->SetStreamSourceFreq(1, D3DSTREAMSOURCE_INSTANCEDATA|1) );
-// 							DX_CHECK(device->SetStreamSource(1, inst.m_ptr, state.m_instanceDataOffset, state.m_instanceDataStride) );
-// 
-// 							IDirect3DVertexDeclaration9* ptr = createVertexDecl(vertexDecl.m_decl, state.m_instanceDataStride/16);
-// 							DX_CHECK(device->SetVertexDeclaration(ptr) );
-// 							DX_RELEASE(ptr, 0);
+ 							const VertexBuffer& inst = s_renderCtx.m_vertexBuffers[state.m_instanceDataBuffer.idx];
+							uint32_t instStride = state.m_instanceDataStride;
+							deviceCtx->IASetVertexBuffers(1, 1, &inst.m_ptr, &instStride, &state.m_instanceDataOffset);
+							s_renderCtx.setInputLayout(vertexDecl, s_renderCtx.m_program[programIdx], state.m_instanceDataStride/16);
 						}
 						else
 						{
-// 							DX_CHECK(device->SetStreamSourceFreq(0, 1) );
-// 							DX_CHECK(device->SetStreamSource(1, NULL, 0, 0) );
-// 							DX_CHECK(device->SetVertexDeclaration(vertexDecl.m_ptr) );
+							deviceCtx->IASetVertexBuffers(1, 0, NULL, NULL, NULL);
+							s_renderCtx.setInputLayout(vertexDecl, s_renderCtx.m_program[programIdx], 0);
 						}
 					}
 					else
@@ -2177,7 +2205,7 @@ namespace bgfx
 							numInstances = state.m_numInstances;
 							numPrimsRendered = numPrimsSubmitted*state.m_numInstances;
 
-							deviceCtx->DrawIndexed(numIndices, 0, state.m_startVertex);
+							deviceCtx->DrawIndexedInstanced(numIndices, state.m_numInstances, 0, state.m_startVertex, 0);
 						}
 						else if (primNumVerts <= state.m_numIndices)
 						{
@@ -2186,7 +2214,7 @@ namespace bgfx
 							numInstances = state.m_numInstances;
 							numPrimsRendered = numPrimsSubmitted*state.m_numInstances;
 
-							deviceCtx->DrawIndexed(numIndices, state.m_startIndex, state.m_startVertex);
+							deviceCtx->DrawIndexedInstanced(numIndices, state.m_numInstances, state.m_startIndex, state.m_startVertex, 0);
 						}
 					}
 					else
@@ -2195,7 +2223,7 @@ namespace bgfx
 						numInstances = state.m_numInstances;
 						numPrimsRendered = numPrimsSubmitted*state.m_numInstances;
 
-						deviceCtx->Draw(numVertices, state.m_startVertex);
+						deviceCtx->DrawInstanced(numVertices, state.m_numInstances, state.m_startVertex, 0);
 					}
 
 					statsNumPrimsSubmitted += numPrimsSubmitted;

BIN
tools/bin/shaderc.exe


+ 2 - 1
tools/shaderc.cpp

@@ -1571,7 +1571,8 @@ int main(int _argc, const char* _argv[])
 				{
 					const Varying& var = varyingIt->second;
 					const char* name = var.m_name.c_str();
-					if (0 == strncmp(name, "a_", 2) )
+					if (0 == strncmp(name, "a_", 2)
+					||  0 == strncmp(name, "i_", 2) )
 					{
 						preprocessor.writef("attribute %s %s;\n", var.m_type.c_str(), name);
 					}