Skip to content

Commit 9a31e45

Browse files
committed
Implement drawArraysInstanced and make instanced draw more common use
1 parent d514187 commit 9a31e45

17 files changed

+225
-116
lines changed

core/3d/Mesh.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ void Mesh::draw(Renderer* renderer,
537537
command.setWireframe(wireframe);
538538
if (_instancing && _instances.size() > 0)
539539
{
540-
command.setDrawType(CustomCommand::DrawType::ELEMENT_INSTANCE);
540+
command.setDrawType(CustomCommand::DrawType::ELEMENT_INSTANCED);
541541
command.setInstanceBuffer(_instanceTransformBuffer, _instances.size());
542542
}
543543
else if (_instancing)

core/renderer/CustomCommand.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ CustomCommand::CustomCommand()
4040
CustomCommand::~CustomCommand()
4141
{
4242
AX_SAFE_RELEASE(_vertexBuffer);
43+
AX_SAFE_RELEASE(_instanceBuffer);
4344
AX_SAFE_RELEASE(_indexBuffer);
4445
}
4546

@@ -145,6 +146,24 @@ void CustomCommand::createVertexBuffer(std::size_t vertexSize, std::size_t capac
145146
_vertexBuffer = backend::DriverBase::getInstance()->newBuffer(vertexSize * capacity, backend::BufferType::VERTEX, usage);
146147
}
147148

149+
void CustomCommand::createInstanceBuffer(std::size_t vertexSize, std::size_t capacity, BufferUsage usage)
150+
{
151+
AX_SAFE_RELEASE(_instanceBuffer);
152+
_instanceBuffer = backend::DriverBase::getInstance()->newBuffer(vertexSize * capacity, backend::BufferType::VERTEX, usage);
153+
_instanceCount = capacity;
154+
}
155+
156+
void CustomCommand::setInstanceBuffer(backend::Buffer* instanceBuffer, int count)
157+
{
158+
if (_instanceBuffer != instanceBuffer)
159+
{
160+
AX_SAFE_RELEASE(_instanceBuffer);
161+
_instanceBuffer = instanceBuffer;
162+
_instanceCount = count;
163+
AX_SAFE_RETAIN(_instanceBuffer);
164+
}
165+
}
166+
148167
void CustomCommand::createIndexBuffer(IndexFormat format, std::size_t capacity, BufferUsage usage)
149168
{
150169
AX_SAFE_RELEASE(_indexBuffer);

core/renderer/CustomCommand.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ class AX_DLL CustomCommand : public RenderCommand
4949
enum class DrawType
5050
{
5151
ARRAY,
52+
ARRAY_INSTANCED,
5253
ELEMENT,
53-
ELEMENT_INSTANCE
54+
ELEMENT_INSTANCED
5455
};
5556

5657
using PrimitiveType = backend::PrimitiveType;
@@ -112,6 +113,8 @@ TODO: should remove it.
112113
every frame, otherwise use DYNAMIC.
113114
*/
114115
void createVertexBuffer(std::size_t vertexSize, std::size_t capacity, BufferUsage usage);
116+
void createInstanceBuffer(std::size_t vertexSize, std::size_t capacity, BufferUsage usage);
117+
115118
/**
116119
Create an index buffer of the custom command. The buffer size is (indexSize * capacity).
117120
Index size is determined by format. If the buffer already exists, then it will delete the
@@ -221,11 +224,8 @@ TODO: should remove it.
221224
*/
222225
void setAfterCallback(const CallBackFunc& after) { _afterCallback = after; }
223226

224-
void setInstanceBuffer(backend::Buffer* transformBuffer, int count)
225-
{
226-
_InstanceTransformBuffer = transformBuffer, _instanceCount = count;
227-
}
228-
backend::Buffer* getInstanceBuffer() const { return _InstanceTransformBuffer; }
227+
void setInstanceBuffer(backend::Buffer* instanceBuffer, int count);
228+
backend::Buffer* getInstanceBuffer() const { return _instanceBuffer; }
229229
int getInstanceCount() const { return _instanceCount; }
230230

231231
const CallBackFunc& getBeforeCallback() { return _beforeCallback; }
@@ -238,7 +238,7 @@ TODO: should remove it.
238238
backend::Buffer* _vertexBuffer = nullptr;
239239
backend::Buffer* _indexBuffer = nullptr;
240240

241-
backend::Buffer* _InstanceTransformBuffer = nullptr;
241+
backend::Buffer* _instanceBuffer = nullptr;
242242
int _instanceCount = 0;
243243

244244
std::size_t _vertexDrawStart = 0;

core/renderer/Renderer.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -729,26 +729,34 @@ void Renderer::drawCustomCommand(RenderCommand* command)
729729
_commandBuffer->setProgramState(cmd->getPipelineDescriptor().programState);
730730

731731
auto drawType = cmd->getDrawType();
732-
if (CustomCommand::DrawType::ELEMENT == drawType)
732+
switch (drawType)
733733
{
734+
case CustomCommand::DrawType::ELEMENT:
734735
_commandBuffer->setIndexBuffer(cmd->getIndexBuffer());
735736
_commandBuffer->drawElements(cmd->getPrimitiveType(), cmd->getIndexFormat(), cmd->getIndexDrawCount(),
736737
cmd->getIndexDrawOffset(), cmd->isWireframe());
737738
_drawnVertices += cmd->getIndexDrawCount();
738-
}
739-
else if (CustomCommand::DrawType::ELEMENT_INSTANCE == drawType)
740-
{
739+
break;
740+
case CustomCommand::DrawType::ELEMENT_INSTANCED:
741741
_commandBuffer->setIndexBuffer(cmd->getIndexBuffer());
742742
_commandBuffer->setInstanceBuffer(cmd->getInstanceBuffer());
743743
_commandBuffer->drawElementsInstanced(cmd->getPrimitiveType(), cmd->getIndexFormat(), cmd->getIndexDrawCount(),
744744
cmd->getIndexDrawOffset(), cmd->getInstanceCount(), cmd->isWireframe());
745745
_drawnVertices += cmd->getIndexDrawCount() * cmd->getInstanceCount();
746-
}
747-
else
748-
{
746+
break;
747+
case CustomCommand::DrawType::ARRAY:
749748
_commandBuffer->drawArrays(cmd->getPrimitiveType(), cmd->getVertexDrawStart(), cmd->getVertexDrawCount(),
750749
cmd->isWireframe());
751750
_drawnVertices += cmd->getVertexDrawCount();
751+
break;
752+
case CustomCommand::DrawType::ARRAY_INSTANCED:
753+
_commandBuffer->setInstanceBuffer(cmd->getInstanceBuffer());
754+
_commandBuffer->drawArraysInstanced(cmd->getPrimitiveType(), cmd->getVertexDrawStart(),
755+
cmd->getVertexDrawCount(), cmd->getInstanceCount(),
756+
cmd->isWireframe());
757+
_drawnVertices += cmd->getVertexDrawCount() * cmd->getInstanceCount();
758+
break;
759+
default:;
752760
}
753761
_drawnBatches++;
754762
endRenderPass();

core/renderer/backend/CommandBuffer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ class CommandBuffer : public ax::Object
165165
std::size_t count,
166166
bool wireframe = false) = 0;
167167

168+
virtual void drawArraysInstanced(PrimitiveType primitiveType,
169+
std::size_t start,
170+
std::size_t count,
171+
int instanceCount,
172+
bool wireframe = false) = 0;
173+
168174
/**
169175
* Draw primitives with an index list.
170176
* @param primitiveType The type of primitives that elements are assembled into.

core/renderer/backend/Enums.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ enum class VertexFormat : uint32_t
7171
INT,
7272
USHORT4,
7373
USHORT2,
74-
UBYTE4
74+
UBYTE4,
75+
MAT4,
7576
};
7677
/** @typedef backend::PixelFormat
7778
Possible texture pixel formats

core/renderer/backend/Program.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,20 +163,32 @@ struct VertexLayoutHelper
163163
backend::VertexFormat::FLOAT3, offsetof(V3F_T2F_N3F, normal), false);
164164
vertexLayout->setStride(sizeof(V3F_T2F_N3F));
165165
}
166+
167+
static void setupInstanced(Program* program)
168+
{
169+
auto vertexLayout = program->getVertexLayout(true);
170+
vertexLayout->setAttrib(backend::ATTRIBUTE_NAME_INSTANCE,
171+
program->getAttributeLocation(backend::Attribute::INSTANCE),
172+
backend::VertexFormat::MAT4, 0, false);
173+
vertexLayout->setStride(sizeof(Mat4));
174+
}
166175
};
167176
std::function<void(Program*)> Program::s_vertexLayoutSetupList[static_cast<int>(VertexLayoutType::Count)] = {
168177
VertexLayoutHelper::setupDummy, VertexLayoutHelper::setupPos, VertexLayoutHelper::setupTexture,
169178
VertexLayoutHelper::setupSprite, VertexLayoutHelper::setupDrawNode, VertexLayoutHelper::setupDrawNode3D,
170179
VertexLayoutHelper::setupSkyBox, VertexLayoutHelper::setupPU3D, VertexLayoutHelper::setupPosColor,
171-
VertexLayoutHelper::setupTerrain3D};
180+
VertexLayoutHelper::setupTerrain3D, VertexLayoutHelper::setupInstanced};
172181

173-
Program::Program(std::string_view vs, std::string_view fs)
174-
: _vertexShader(vs), _fragmentShader(fs), _vertexLayout(new VertexLayout())
175-
{}
182+
Program::Program(std::string_view vs, std::string_view fs) : _vertexShader(vs), _fragmentShader(fs)
183+
{
184+
_vertexLayout[0] = new VertexLayout();
185+
_vertexLayout[1] = new VertexLayout(); // instanced draw
186+
}
176187

177188
Program::~Program()
178189
{
179-
delete _vertexLayout;
190+
delete _vertexLayout[0];
191+
delete _vertexLayout[1];
180192
}
181193

182194
void Program::setupVertexLayout(VertexLayoutType vlt)

core/renderer/backend/Program.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ enum class VertexLayoutType
5858
PU3D, // V3F_C4B_T2F // same with sprite, TODO: reuse spriete
5959
posColor, // V3F_C4B
6060
Terrain3D, // V3F_T2F_V3F
61+
Instanced, // builtin instanced vertex format for 3D transform
6162
Count
6263
};
6364

@@ -167,7 +168,7 @@ class AX_DLL Program : public Object
167168
*/
168169
virtual const hlookup::string_map<UniformInfo>& getAllActiveUniformInfo(ShaderStage stage) const = 0;
169170

170-
inline VertexLayout* getVertexLayout() const { return _vertexLayout; }
171+
inline VertexLayout* getVertexLayout(bool instanced = false) const { return !instanced ? _vertexLayout[0] : _vertexLayout[1]; }
171172

172173
protected:
173174

@@ -211,7 +212,7 @@ class AX_DLL Program : public Object
211212

212213
std::string _vertexShader; ///< Vertex shader.
213214
std::string _fragmentShader; ///< Fragment shader.
214-
VertexLayout* _vertexLayout = nullptr;
215+
VertexLayout* _vertexLayout[2] = {};
215216
uint32_t _programType = ProgramType::CUSTOM_PROGRAM; ///< built-in program type, initial value is CUSTOM_PROGRAM.
216217
uint64_t _programId = 0;
217218

core/renderer/backend/ProgramManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ bool ProgramManager::init()
131131
registerProgram(ProgramType::POSITION_TEXTURE_3D, positionTexture3D_vert, colorTexture_frag,
132132
VertexLayoutType::Unspec);
133133
registerProgram(ProgramType::POSITION_TEXTURE_3D_INSTANCE, positionTextureInstance_vert, colorTexture_frag,
134-
VertexLayoutType::Unspec);
134+
VertexLayoutType::Instanced);
135135
registerProgram(ProgramType::POSITION_3D, position_vert, color_frag, VertexLayoutType::Unspec);
136136
registerProgram(ProgramType::POSITION_NORMAL_3D, positionNormalTexture_vert, colorNormal_frag,
137137
VertexLayoutType::Unspec);

core/renderer/backend/ProgramState.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,11 @@ bool ProgramState::init(Program* program)
157157
AX_SAFE_RETAIN(program);
158158
_program = program;
159159

160-
_vertexLayout = program->getVertexLayout();
161-
_ownVertexLayout = false;
162-
_vertexUniformBufferSize = _program->getUniformBufferSize(ShaderStage::VERTEX);
160+
_vertexLayout = program->getVertexLayout();
161+
_vertexLayoutInstanced = program->getVertexLayout(true);
162+
_ownVertexLayout = false;
163+
_ownVertexLayoutInstanced = false;
164+
_vertexUniformBufferSize = _program->getUniformBufferSize(ShaderStage::VERTEX);
163165

164166
#ifdef AX_USE_METAL
165167
_fragmentUniformBufferSize = _program->getUniformBufferSize(ShaderStage::FRAGMENT);
@@ -216,6 +218,9 @@ ProgramState::~ProgramState()
216218

217219
if (_ownVertexLayout)
218220
AX_SAFE_DELETE(_vertexLayout);
221+
222+
if (_ownVertexLayoutInstanced)
223+
AX_SAFE_DELETE(_vertexLayoutInstanced);
219224
}
220225

221226
ProgramState* ProgramState::clone() const
@@ -228,6 +233,9 @@ ProgramState* ProgramState::clone() const
228233
cp->_ownVertexLayout = _ownVertexLayout;
229234
cp->_vertexLayout = !_ownVertexLayout ? _vertexLayout : new VertexLayout(*_vertexLayout);
230235

236+
cp->_ownVertexLayoutInstanced = _ownVertexLayout;
237+
cp->_vertexLayoutInstanced = !_ownVertexLayout ? _vertexLayoutInstanced : new VertexLayout(*_vertexLayoutInstanced);
238+
231239
cp->_batchId = this->_batchId;
232240
return cp;
233241
}
@@ -295,13 +303,24 @@ void ProgramState::ensureVertexLayoutMutable()
295303
}
296304
}
297305

298-
VertexLayout* ProgramState::getMutableVertexLayout()
306+
VertexLayout* ProgramState::getMutableVertexLayout(bool instanced)
299307
{
300-
if (_ownVertexLayout || !_vertexLayout->isValid())
301-
return _vertexLayout;
308+
if (!instanced)
309+
{
310+
if (_ownVertexLayout || !_vertexLayout->isValid())
311+
return _vertexLayout;
302312

303-
_ownVertexLayout = true;
304-
return _vertexLayout = new VertexLayout();
313+
_ownVertexLayout = true;
314+
return _vertexLayout = new VertexLayout();
315+
}
316+
else
317+
{
318+
if (_ownVertexLayoutInstanced || !_vertexLayoutInstanced->isValid())
319+
return _vertexLayoutInstanced;
320+
321+
_ownVertexLayoutInstanced = true;
322+
return _vertexLayoutInstanced = new VertexLayout();
323+
}
305324
}
306325

307326
void ProgramState::setSharedVertexLayout(VertexLayout* vertexLayout)
@@ -349,7 +368,8 @@ void ProgramState::setTextureArray(const backend::UniformLocation& uniformLocati
349368
setTextureArray(uniformLocation.vertStage.location, std::move(slots), std::move(textures), _vertexTextureInfos);
350369
#ifdef AX_USE_METAL
351370
if (uniformLocation.fragStage)
352-
setTextureArray(uniformLocation.fragStage.location, std::move(slots), std::move(textures), _fragmentTextureInfos);
371+
setTextureArray(uniformLocation.fragStage.location, std::move(slots), std::move(textures),
372+
_fragmentTextureInfos);
353373
#endif
354374
}
355375

core/renderer/backend/ProgramState.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,21 +290,24 @@ class AX_DLL ProgramState : public Object
290290
*/
291291
void setParameterAutoBinding(std::string_view uniformName, std::string_view autoBinding);
292292

293-
inline const VertexLayout* getVertexLayout() const { return _vertexLayout; }
293+
inline const VertexLayout* getVertexLayout(bool instanced = false) const
294+
{
295+
return !instanced ? _vertexLayout : _vertexLayoutInstanced;
296+
}
294297

295-
VertexLayout* getMutableVertexLayout();
298+
VertexLayout* getMutableVertexLayout(bool instanced = false);
296299

297300
void setSharedVertexLayout(VertexLayout* vertexLayout);
298301

299302
/*
300-
* Gets batch id of current program state, part of batch draw materialID
301-
*/
303+
* Gets batch id of current program state, part of batch draw materialID
304+
*/
302305
uint64_t getBatchId() const { return _batchId; };
303306

304307
/*
305-
* Update batchID of current program state, by default, custom program was traits with mutable uniforms
306-
* so batch ID was set to -1 indicate batch was disabled
307-
*/
308+
* Update batchID of current program state, by default, custom program was traits with mutable uniforms
309+
* so batch ID was set to -1 indicate batch was disabled
310+
*/
308311
void updateBatchId();
309312

310313
/** Custom shader program's vertex layout maybe not setup
@@ -386,8 +389,10 @@ class AX_DLL ProgramState : public Object
386389
std::unordered_map<std::string, std::string> _autoBindings;
387390

388391
static std::vector<AutoBindingResolver*> _customAutoBindingResolvers;
389-
VertexLayout* _vertexLayout = nullptr;
390-
bool _ownVertexLayout = false;
392+
VertexLayout* _vertexLayout = nullptr;
393+
VertexLayout* _vertexLayoutInstanced = nullptr;
394+
bool _ownVertexLayout = false;
395+
bool _ownVertexLayoutInstanced = false;
391396

392397
uint64_t _batchId = -1;
393398

core/renderer/backend/metal/CommandBufferMTL.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ class CommandBufferMTL : public CommandBuffer
150150
* TODO: Implement a wireframe mode for METAL devices. Refer to: https://forums.ogre3d.org/viewtopic.php?t=95089
151151
*/
152152
void drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count, bool wireframe) override;
153+
void drawArraysInstanced(PrimitiveType primitiveType,
154+
std::size_t start,
155+
std::size_t count,
156+
int instanceCount,
157+
bool wireframe = false) override;
153158

154159
/**
155160
* Draw primitives with an index list.

core/renderer/backend/metal/CommandBufferMTL.mm

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,12 @@ inline int clamp(int value, int min, int max)
300300
[_mtlRenderEncoder drawPrimitives:toMTLPrimitive(primitiveType) vertexStart:start vertexCount:count];
301301
}
302302

303+
void CommandBufferMTL::drawArraysInstanced(PrimitiveType primitiveType, std::size_t start, std::size_t count, int instanceCount, bool wireframe /* unused */)
304+
{
305+
prepareDrawing();
306+
[_mtlRenderEncoder drawPrimitives:toMTLPrimitive(primitiveType) vertexStart:start vertexCount:count instanceCount:instanceCount];
307+
}
308+
303309
void CommandBufferMTL::drawElements(PrimitiveType primitiveType,
304310
IndexFormat indexType,
305311
std::size_t count,
@@ -308,10 +314,10 @@ inline int clamp(int value, int min, int max)
308314
{
309315
prepareDrawing();
310316
[_mtlRenderEncoder drawIndexedPrimitives:toMTLPrimitive(primitiveType)
311-
indexCount:count
312-
indexType:toMTLIndexType(indexType)
313-
indexBuffer:_mtlIndexBuffer
314-
indexBufferOffset:offset];
317+
indexCount:count
318+
indexType:toMTLIndexType(indexType)
319+
indexBuffer:_mtlIndexBuffer
320+
indexBufferOffset:offset];
315321
}
316322

317323
void CommandBufferMTL::drawElementsInstanced(PrimitiveType primitiveType,
@@ -323,11 +329,11 @@ inline int clamp(int value, int min, int max)
323329
{
324330
prepareDrawing();
325331
[_mtlRenderEncoder drawIndexedPrimitives:toMTLPrimitive(primitiveType)
326-
indexCount:count
327-
indexType:toMTLIndexType(indexType)
328-
indexBuffer:_mtlIndexBuffer
329-
indexBufferOffset:offset
330-
instanceCount:instanceCount];
332+
indexCount:count
333+
indexType:toMTLIndexType(indexType)
334+
indexBuffer:_mtlIndexBuffer
335+
indexBufferOffset:offset
336+
instanceCount:instanceCount];
331337
}
332338

333339
void CommandBufferMTL::endRenderPass()

0 commit comments

Comments
 (0)