Added instancing example.

This commit is contained in:
bkaradzic 2012-10-08 23:24:10 -07:00
parent 772c671752
commit f5295b951d
21 changed files with 432 additions and 32 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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",
}

View file

@ -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"

View file

@ -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

View file

@ -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;

Binary file not shown.

View file

@ -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);
}