Created
December 1, 2019 08:03
-
-
Save jdryg/fc8d573d78ff832c169fa450bb275243 to your computer and use it in GitHub Desktop.
Minimal bgfx example to show D3D11 IB warning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2011-2019 Branimir Karadzic. All rights reserved. | |
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause | |
*/ | |
#include "common.h" | |
#include "bgfx_utils.h" | |
#include "imgui/imgui.h" | |
namespace | |
{ | |
// Copied from debugdraw.cpp | |
uint32_t genSphere(uint8_t _subdiv0, void* _pos0 = NULL, uint16_t _posStride0 = 0, void* _normals0 = NULL, uint16_t _normalStride0 = 0) | |
{ | |
if (NULL != _pos0) { | |
struct Gen | |
{ | |
Gen(void* _pos, uint16_t _posStride, void* _normals, uint16_t _normalStride, uint8_t _subdiv) | |
: m_pos((uint8_t*)_pos) | |
, m_normals((uint8_t*)_normals) | |
, m_posStride(_posStride) | |
, m_normalStride(_normalStride) | |
{ | |
static const float scale = 1.0f; | |
static const float golden = 1.6180339887f; | |
static const float len = bx::sqrt(golden*golden + 1.0f); | |
static const float ss = 1.0f / len * scale; | |
static const float ll = ss * golden; | |
static const bx::Vec3 vv[] = | |
{ | |
{ -ll, 0.0f, -ss }, | |
{ ll, 0.0f, -ss }, | |
{ ll, 0.0f, ss }, | |
{ -ll, 0.0f, ss }, | |
{ -ss, ll, 0.0f }, | |
{ ss, ll, 0.0f }, | |
{ ss, -ll, 0.0f }, | |
{ -ss, -ll, 0.0f }, | |
{ 0.0f, -ss, ll }, | |
{ 0.0f, ss, ll }, | |
{ 0.0f, ss, -ll }, | |
{ 0.0f, -ss, -ll }, | |
}; | |
m_numVertices = 0; | |
triangle(vv[0], vv[4], vv[3], scale, _subdiv); | |
triangle(vv[0], vv[10], vv[4], scale, _subdiv); | |
triangle(vv[4], vv[10], vv[5], scale, _subdiv); | |
triangle(vv[5], vv[10], vv[1], scale, _subdiv); | |
triangle(vv[5], vv[1], vv[2], scale, _subdiv); | |
triangle(vv[5], vv[2], vv[9], scale, _subdiv); | |
triangle(vv[5], vv[9], vv[4], scale, _subdiv); | |
triangle(vv[3], vv[4], vv[9], scale, _subdiv); | |
triangle(vv[0], vv[3], vv[7], scale, _subdiv); | |
triangle(vv[0], vv[7], vv[11], scale, _subdiv); | |
triangle(vv[11], vv[7], vv[6], scale, _subdiv); | |
triangle(vv[11], vv[6], vv[1], scale, _subdiv); | |
triangle(vv[1], vv[6], vv[2], scale, _subdiv); | |
triangle(vv[2], vv[6], vv[8], scale, _subdiv); | |
triangle(vv[8], vv[6], vv[7], scale, _subdiv); | |
triangle(vv[8], vv[7], vv[3], scale, _subdiv); | |
triangle(vv[0], vv[11], vv[10], scale, _subdiv); | |
triangle(vv[1], vv[10], vv[11], scale, _subdiv); | |
triangle(vv[2], vv[8], vv[9], scale, _subdiv); | |
triangle(vv[3], vv[9], vv[8], scale, _subdiv); | |
} | |
void addVert(const bx::Vec3& _v) | |
{ | |
bx::store(m_pos, _v); | |
m_pos += m_posStride; | |
if (NULL != m_normals) { | |
const bx::Vec3 normal = bx::normalize(_v); | |
bx::store(m_normals, normal); | |
m_normals += m_normalStride; | |
} | |
m_numVertices++; | |
} | |
void triangle(const bx::Vec3& _v0, const bx::Vec3& _v1, const bx::Vec3& _v2, float _scale, uint8_t _subdiv) | |
{ | |
if (0 == _subdiv) { | |
addVert(_v0); | |
addVert(_v1); | |
addVert(_v2); | |
} else { | |
const bx::Vec3 v01 = bx::mul(bx::normalize(bx::add(_v0, _v1)), _scale); | |
const bx::Vec3 v12 = bx::mul(bx::normalize(bx::add(_v1, _v2)), _scale); | |
const bx::Vec3 v20 = bx::mul(bx::normalize(bx::add(_v2, _v0)), _scale); | |
--_subdiv; | |
triangle(_v0, v01, v20, _scale, _subdiv); | |
triangle(_v1, v12, v01, _scale, _subdiv); | |
triangle(_v2, v20, v12, _scale, _subdiv); | |
triangle(v01, v12, v20, _scale, _subdiv); | |
} | |
} | |
uint8_t* m_pos; | |
uint8_t* m_normals; | |
uint16_t m_posStride; | |
uint16_t m_normalStride; | |
uint32_t m_numVertices; | |
} gen(_pos0, _posStride0, _normals0, _normalStride0, _subdiv0); | |
} | |
uint32_t numVertices = 20 * 3 * bx::uint32_max(1, (uint32_t)bx::pow(4.0f, _subdiv0)); | |
return numVertices; | |
} | |
struct PosColorVertex | |
{ | |
float m_x; | |
float m_y; | |
float m_z; | |
uint32_t m_abgr; | |
static void init() | |
{ | |
ms_layout | |
.begin() | |
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) | |
.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) | |
.end(); | |
}; | |
static bgfx::VertexLayout ms_layout; | |
}; | |
bgfx::VertexLayout PosColorVertex::ms_layout; | |
static PosColorVertex s_cubeVertices[] = | |
{ | |
{-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_cubeTriList[] = | |
{ | |
0, 1, 2, // 0 | |
1, 3, 2, | |
4, 6, 5, // 2 | |
5, 6, 7, | |
0, 2, 4, // 4 | |
4, 2, 6, | |
1, 5, 3, // 6 | |
5, 7, 3, | |
0, 4, 1, // 8 | |
4, 5, 1, | |
2, 3, 6, // 10 | |
6, 3, 7, | |
}; | |
static const uint32_t s_colors[] = { | |
0xffff0000, | |
0xff00ff00, | |
0xff0000ff, | |
0xffff00ff | |
}; | |
class ExampleCubes : public entry::AppI | |
{ | |
public: | |
ExampleCubes(const char* _name, const char* _description, const char* _url) | |
: entry::AppI(_name, _description, _url) | |
, m_pt(0) | |
, m_r(true) | |
, m_g(true) | |
, m_b(true) | |
, m_a(true) | |
{ | |
} | |
void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override | |
{ | |
Args args(_argc, _argv); | |
m_width = _width; | |
m_height = _height; | |
m_debug = BGFX_DEBUG_NONE; | |
m_reset = BGFX_RESET_VSYNC; | |
bgfx::Init init; | |
init.type = args.m_type; | |
init.vendorId = args.m_pciId; | |
init.resolution.width = m_width; | |
init.resolution.height = m_height; | |
init.resolution.reset = m_reset; | |
bgfx::init(init); | |
// Enable debug text. | |
bgfx::setDebug(m_debug); | |
// Set view 0 clear state. | |
bgfx::setViewClear(0 | |
, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH | |
, 0x303030ff | |
, 1.0f | |
, 0 | |
); | |
// Create vertex stream declaration. | |
PosColorVertex::init(); | |
// JD: Generate vertex and index buffer data. In my case, the data are generated | |
// every frame. | |
{ | |
bx::DefaultAllocator allocator; | |
const uint8_t subdiv = 4; | |
const uint32_t numSphereVertices = genSphere(subdiv); | |
bx::Vec3* sphereVertices = (bx::Vec3*)BX_ALLOC(&allocator, sizeof(bx::Vec3) * numSphereVertices); | |
genSphere(subdiv, sphereVertices, sizeof(bx::Vec3)); | |
const uint32_t numSphereIndices = numSphereVertices; | |
// Fit as many spheres as we can in a single VB with 16-bit indices. | |
const uint32_t numSpheres = 65536 / numSphereVertices; | |
m_vbDataSize = sizeof(PosColorVertex) * numSphereVertices * numSpheres; | |
m_vbData = (PosColorVertex*)BX_ALLOC(&allocator, m_vbDataSize); | |
PosColorVertex* vbDataPtr = m_vbData; | |
for (uint32_t i = 0; i < numSpheres; ++i) { | |
const float posx = -15.0f + i * 8.0f; | |
const float posy = 0.0f; | |
const float posz = 0.0f; | |
const uint32_t color = s_colors[i % BX_COUNTOF(s_colors)]; | |
for (uint32_t j = 0; j < numSphereVertices; j++) { | |
vbDataPtr[j].m_x = posx + sphereVertices[j].x; | |
vbDataPtr[j].m_y = posy + sphereVertices[j].y; | |
vbDataPtr[j].m_z = posz + sphereVertices[j].z; | |
vbDataPtr[j].m_abgr = color; | |
} | |
vbDataPtr += numSphereVertices; | |
} | |
// Generate a large enough IB to trigger the warning | |
const uint32_t targetIBSize = 4 << 20; // This should be larger than BGFX_CONFIG_DYNAMIC_INDEX_BUFFER_SIZE | |
m_instanceIndices = numSphereIndices * numSpheres; | |
const uint32_t instanceIBMem = sizeof(uint16_t) * m_instanceIndices; | |
m_numInstances = targetIBSize / instanceIBMem; | |
m_ibDataSize = instanceIBMem * m_numInstances; | |
m_ibData = (uint16_t*)BX_ALLOC(&allocator, m_ibDataSize); | |
uint16_t* ibDataPtr = m_ibData; | |
for (uint32_t i = 0; i < m_numInstances; ++i) { | |
for (uint32_t j = 0; j < numSpheres; ++j) { | |
const uint16_t baseVertex = (uint16_t)(j * numSphereVertices); | |
for (uint32_t k = 0; k < numSphereIndices; ++k) { | |
ibDataPtr[k] = (uint16_t)(baseVertex + k); | |
} | |
ibDataPtr += numSphereIndices; | |
} | |
} | |
// Emulate a real-world scenario by preallocating both buffers to predefined values | |
// even though, in this case, we know the exact numbers. | |
// Note that setting the initial IB size to 256 will force all draw commands of the | |
// initial couple of frames to be partially rendered (only 256 indices will be submitted) | |
m_vbh = bgfx::createDynamicVertexBuffer(65536, PosColorVertex::ms_layout); | |
m_ibh = bgfx::createDynamicIndexBuffer(256, BGFX_BUFFER_ALLOW_RESIZE); | |
} | |
// Create program from shaders. | |
m_program = loadProgram("vs_cubes", "fs_cubes"); | |
m_timeOffset = bx::getHPCounter(); | |
imguiCreate(); | |
} | |
virtual int shutdown() override | |
{ | |
imguiDestroy(); | |
// Cleanup. | |
bgfx::destroy(m_ibh); | |
bgfx::destroy(m_vbh); | |
bgfx::destroy(m_program); | |
// Shutdown bgfx. | |
bgfx::shutdown(); | |
return 0; | |
} | |
bool update() override | |
{ | |
if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) ) | |
{ | |
imguiBeginFrame(m_mouseState.m_mx | |
, m_mouseState.m_my | |
, (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0) | |
| (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0) | |
| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0) | |
, m_mouseState.m_mz | |
, uint16_t(m_width) | |
, uint16_t(m_height) | |
); | |
showExampleDialog(this); | |
imguiEndFrame(); | |
const bx::Vec3 at = { 0.0f, 0.0f, 0.0f }; | |
const bx::Vec3 eye = { 0.0f, 0.0f, -35.0f }; | |
// Set view and projection matrix for view 0. | |
{ | |
float view[16]; | |
bx::mtxLookAt(view, eye, at); | |
float proj[16]; | |
bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth); | |
bgfx::setViewTransform(0, view, proj); | |
// Set view 0 default viewport. | |
bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) ); | |
} | |
// 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::touch(0); | |
uint64_t state = 0 | |
| (m_r ? BGFX_STATE_WRITE_R : 0) | |
| (m_g ? BGFX_STATE_WRITE_G : 0) | |
| (m_b ? BGFX_STATE_WRITE_B : 0) | |
| (m_a ? BGFX_STATE_WRITE_A : 0) | |
| BGFX_STATE_WRITE_Z | |
| BGFX_STATE_DEPTH_TEST_LESS | |
| BGFX_STATE_CULL_CW | |
| BGFX_STATE_MSAA | |
; | |
// JD: Submit all draw commands before updating the buffers. | |
for (uint32_t i = 0; i < m_numInstances; ++i) { | |
float mtx[16]; | |
bx::mtxIdentity(mtx); | |
mtx[12] = -15.0f + (i % 2) * 32.0f; | |
mtx[13] = -15.0f + (i / 2) * 2.0f; | |
mtx[14] = 0.0f; | |
bgfx::setTransform(mtx); | |
bgfx::setVertexBuffer(0, m_vbh); | |
bgfx::setIndexBuffer(m_ibh, m_instanceIndices * i, m_instanceIndices); | |
bgfx::setState(state); | |
bgfx::submit(0, m_program); | |
} | |
bgfx::update(m_vbh, 0, bgfx::makeRef(m_vbData, m_vbDataSize)); | |
bgfx::update(m_ibh, 0, bgfx::makeRef(m_ibData, m_ibDataSize)); | |
// Advance to next frame. Rendering thread will be kicked to | |
// process submitted rendering primitives. | |
bgfx::frame(); | |
return true; | |
} | |
return false; | |
} | |
entry::MouseState m_mouseState; | |
uint32_t m_width; | |
uint32_t m_height; | |
uint32_t m_debug; | |
uint32_t m_reset; | |
bgfx::DynamicVertexBufferHandle m_vbh; | |
bgfx::DynamicIndexBufferHandle m_ibh; | |
bgfx::ProgramHandle m_program; | |
int64_t m_timeOffset; | |
int32_t m_pt; | |
PosColorVertex* m_vbData; | |
uint16_t* m_ibData; | |
uint32_t m_vbDataSize; | |
uint32_t m_ibDataSize; | |
uint32_t m_numInstances; | |
uint32_t m_instanceIndices; | |
bool m_r; | |
bool m_g; | |
bool m_b; | |
bool m_a; | |
}; | |
} // namespace | |
ENTRY_IMPLEMENT_MAIN( | |
ExampleCubes | |
, "01-cubes" | |
, "Rendering simple static mesh." | |
, "https://bkaradzic.github.io/bgfx/examples.html#cubes" | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment