From: David Steele Date: Thu, 13 Apr 2023 19:02:27 +0000 (+0100) Subject: VertexBuffer instancing X-Git-Tag: dali_2.2.23~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-core.git;a=commitdiff_plain;h=526085088ce0ee6ee14ceb57a5f9191c65d8a2e6 VertexBuffer instancing Added a SetDivisor() API to Vertex buffer. This will enable instancing on that buffer - when this is drawn, it will use DrawArraysInstanced or DrawElementsInstanced, with all the attributes in this vertex buffer having the same input rate. Currently, only an input rate of 1 is supported - this will be changed in a future patch. Requires an update to dali-adaptor too. Change-Id: I5c7461cc3e2cb72c6257d3093afa95116a6dc6c1 --- diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h b/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h index 7ba7834..834ae6f 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h +++ b/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h @@ -2,7 +2,7 @@ #define TEST_GL_ABSTRACTION_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1893,10 +1893,26 @@ public: inline void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) override { + std::stringstream out; + out << mode << ", " << first << ", " << count << ", " << instanceCount; + TraceCallStack::NamedParams namedParams; + namedParams["mode"] << std::hex << mode; + namedParams["first"] << first; + namedParams["count"] << count; + namedParams["instanceCount"] << instanceCount; + mDrawTrace.PushCall("DrawArraysInstanced", out.str(), namedParams); } inline void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) override { + std::stringstream out; + out << mode << ", " << count << ", " << type << ", " << instanceCount; + TraceCallStack::NamedParams namedParams; + namedParams["mode"] << std::hex << mode; + namedParams["count"] << count; + namedParams["type"] << std::hex << type; + namedParams["indexCount"] << instanceCount; + mDrawTrace.PushCall("DrawElementsInstanced", out.str(), namedParams); } inline GLsync FenceSync(GLenum condition, GLbitfield flags) override @@ -1981,6 +1997,12 @@ public: inline void VertexAttribDivisor(GLuint index, GLuint divisor) override { + std::stringstream out; + out << index << ", " << divisor; + TraceCallStack::NamedParams namedParams; + namedParams["index"] << index; + namedParams["divisor"] << divisor; + mBufferTrace.PushCall("VertexAttribDivisor", out.str(), namedParams); } inline void BindTransformFeedback(GLenum target, GLuint id) override diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.cpp b/automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.cpp index 319ec67..3cc464c 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.cpp +++ b/automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.cpp @@ -712,9 +712,19 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com { if(currentPipeline) { - mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology), - 0, - cmd.data.draw.draw.vertexCount); + if(cmd.data.draw.draw.instanceCount == 0) + { + mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology), + 0, + cmd.data.draw.draw.vertexCount); + } + else + { + mGl.DrawArraysInstanced(GetTopology(currentPipeline->inputAssemblyState.topology), + 0, + cmd.data.draw.draw.vertexCount, + cmd.data.draw.draw.instanceCount); + } } break; } @@ -722,10 +732,21 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com { if(currentPipeline) { - mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology), - static_cast(cmd.data.draw.drawIndexed.indexCount), - GL_UNSIGNED_SHORT, - reinterpret_cast(cmd.data.draw.drawIndexed.firstIndex)); + if(cmd.data.draw.draw.instanceCount == 0) + { + mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology), + static_cast(cmd.data.draw.drawIndexed.indexCount), + GL_UNSIGNED_SHORT, + reinterpret_cast(cmd.data.draw.drawIndexed.firstIndex)); + } + else + { + mGl.DrawElementsInstanced(GetTopology(currentPipeline->inputAssemblyState.topology), + static_cast(cmd.data.draw.drawIndexed.indexCount), + GL_UNSIGNED_SHORT, + reinterpret_cast(cmd.data.draw.drawIndexed.firstIndex), + cmd.data.draw.drawIndexed.instanceCount); + } } break; } @@ -983,12 +1004,22 @@ void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline) uint32_t attributeOffset = attribute.offset; GLsizei stride = vi.bufferBindings[attribute.binding].stride; + auto rate = vi.bufferBindings[attribute.binding].inputRate; + mGl.VertexAttribPointer(attribute.location, GetNumComponents(attribute.format), GetGlType(attribute.format), GL_FALSE, // Not normalized stride, reinterpret_cast(attributeOffset)); + if(rate == Graphics::VertexInputRate::PER_VERTEX) + { + mGl.VertexAttribDivisor(attribute.location, 0); + } + else if(rate == Graphics::VertexInputRate::PER_INSTANCE) + { + mGl.VertexAttribDivisor(attribute.location, 1); + } } // Cull face setup diff --git a/automated-tests/src/dali/utc-Dali-VertexBuffer.cpp b/automated-tests/src/dali/utc-Dali-VertexBuffer.cpp index 6efe695..b03d938 100644 --- a/automated-tests/src/dali/utc-Dali-VertexBuffer.cpp +++ b/automated-tests/src/dali/utc-Dali-VertexBuffer.cpp @@ -183,6 +183,9 @@ int UtcDaliVertexBufferSetData01(void) actor.AddRenderer(renderer); application.GetScene().Add(actor); + auto& drawTrace = application.GetGlAbstraction().GetDrawTrace(); + drawTrace.Enable(true); + application.SendNotification(); application.Render(0); application.Render(); @@ -191,6 +194,8 @@ int UtcDaliVertexBufferSetData01(void) const TestGlAbstraction::BufferDataCalls& bufferDataCalls = application.GetGlAbstraction().GetBufferDataCalls(); + DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays")); + DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION); DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION); @@ -260,23 +265,6 @@ int UtcDaliVertexBufferSetData02(void) application.SendNotification(); application.Render(0); - { - const TestGlAbstraction::BufferSubDataCalls& bufferSubDataCalls = - application.GetGlAbstraction().GetBufferSubDataCalls(); - - const TestGlAbstraction::BufferDataCalls& bufferDataCalls = - application.GetGlAbstraction().GetBufferDataCalls(); - - // Should be 3 (2 Render + 1 vertexBuffer reload) - DALI_TEST_EQUALS(bufferSubDataCalls.size(), 3u, TEST_LOCATION); - DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION); - - if(bufferSubDataCalls.size() >= 2) - { - DALI_TEST_EQUALS(bufferSubDataCalls[1], sizeof(texturedQuadVertexData), TEST_LOCATION); - } - } - END_TEST; } @@ -374,3 +362,87 @@ int UtcDaliVertexBufferGetSizeNegative(void) } END_TEST; } + +int UtcDaliVertexBufferSetDivisor(void) +{ + TestApplication application; + + Property::Map texturedQuadVertexFormat; + texturedQuadVertexFormat["aPosition"] = Property::VECTOR2; + texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2; + + Property::Map instanceFormat{{"aTranslate", Property::VECTOR2}, {"aColor", Property::VECTOR4}}; + + VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat); + DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION); + + DALI_TEST_EQUALS(0, vertexBuffer.GetDivisor(), TEST_LOCATION); + + VertexBuffer instanceBuffer = VertexBuffer::New(instanceFormat); + DALI_TEST_EQUALS((bool)instanceBuffer, true, TEST_LOCATION); + + const float halfQuadSize = .5f; + struct TexturedQuadVertex + { + Vector2 position; + Vector2 textureCoordinates; + }; + TexturedQuadVertex texturedQuadVertexData[4] = { + {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)}, + {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)}, + {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)}, + {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}}; + + vertexBuffer.SetData(texturedQuadVertexData, 4); + + struct InstanceData + { + Vector2 translate; + Vector4 color; + }; + + InstanceData instanceData[] = {{Vector2(12, 33), Color::WHITE}, + {Vector2(-2000, 43), Color::BLUE}, + {Vector2(200, 43), Color::GREEN}, + {Vector2(-243, 43), Color::TURQUOISE}, + {Vector2(192, 43), Color::CYAN}, + {Vector2(-2000, 43), Color::MAGENTA}, + {Vector2(-292, 393), Color::BLUE}, + {Vector2(-499, 128), Color::BLUE}, + {Vector2(328, 43), Color::BLUE}, + {Vector2(726, 43), Color::BLUE}}; + instanceBuffer.SetData(instanceData, sizeof(instanceData) / sizeof(InstanceData)); + instanceBuffer.SetDivisor(1); + DALI_TEST_EQUALS(1, instanceBuffer.GetDivisor(), TEST_LOCATION); + + Geometry geometry = Geometry::New(); + geometry.AddVertexBuffer(vertexBuffer); + geometry.AddVertexBuffer(instanceBuffer); + + Shader shader = CreateShader(); + Renderer renderer = Renderer::New(geometry, shader); + Actor actor = Actor::New(); + actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f); + actor.AddRenderer(renderer); + application.GetScene().Add(actor); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + auto& bufferTrace = gl.GetBufferTrace(); + auto& drawTrace = gl.GetDrawTrace(); + bufferTrace.Enable(true); + drawTrace.Enable(true); + + application.SendNotification(); + application.Render(); + + TraceCallStack::NamedParams params; + params["divisor"] << "1"; + DALI_TEST_CHECK(bufferTrace.FindMethodAndParams("VertexAttribDivisor", params)); + + TraceCallStack::NamedParams params2; + DALI_TEST_CHECK(drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params2)); + std::ostringstream oss; + oss << sizeof(instanceData) / sizeof(InstanceData); + DALI_TEST_EQUALS(params2["instanceCount"].str(), oss.str(), TEST_LOCATION); + END_TEST; +} diff --git a/dali/graphics-api/graphics-types.h b/dali/graphics-api/graphics-types.h index 3d0f0f5..6d6eb40 100644 --- a/dali/graphics-api/graphics-types.h +++ b/dali/graphics-api/graphics-types.h @@ -630,6 +630,7 @@ struct VertexInputState } uint32_t stride; VertexInputRate inputRate; + //@todo Add actual rate... }; /** diff --git a/dali/internal/event/rendering/vertex-buffer-impl.cpp b/dali/internal/event/rendering/vertex-buffer-impl.cpp index b6bbf32..547d60d 100644 --- a/dali/internal/event/rendering/vertex-buffer-impl.cpp +++ b/dali/internal/event/rendering/vertex-buffer-impl.cpp @@ -171,6 +171,17 @@ uint32_t VertexBuffer::GetSize() const return mSize; } +void VertexBuffer::SetDivisor(uint32_t divisor) +{ + SceneGraph::SetVertexBufferDivisorMessage(mEventThreadServices.GetUpdateManager(), *mRenderObject, divisor); + mDivisor = divisor; +} + +uint32_t VertexBuffer::GetDivisor() const +{ + return mDivisor; +} + const Render::VertexBuffer* VertexBuffer::GetRenderObject() const { return mRenderObject; diff --git a/dali/internal/event/rendering/vertex-buffer-impl.h b/dali/internal/event/rendering/vertex-buffer-impl.h index dcba098..a10a886 100644 --- a/dali/internal/event/rendering/vertex-buffer-impl.h +++ b/dali/internal/event/rendering/vertex-buffer-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_VERTEX_BUFFER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,20 +44,30 @@ class VertexBuffer : public BaseObject { public: /** - * @copydoc PropertBuffer::New() + * @copydoc Dali::VertexBuffer::New() */ static VertexBufferPtr New(Dali::Property::Map& format); /** - * @copydoc PropertBuffer::SetData() + * @copydoc Dali::VertexBuffer::SetData() */ void SetData(const void* data, uint32_t size); /** - * @copydoc PropertBuffer::GetSize() + * @copydoc Dali::VertexBuffer::GetSize() */ uint32_t GetSize() const; + /** + * @copydoc Dali::VertexBuffer::SetDivisor() + */ + void SetDivisor(uint32_t divisor); + + /** + * @copydoc Dali::VertexBuffer::GetDivisor() + */ + uint32_t GetDivisor() const; + public: // Default property extensions from Object /** * @brief Get the render thread side of the VertexBuffer @@ -87,11 +97,12 @@ private: // unimplemented methods VertexBuffer(const VertexBuffer&); VertexBuffer& operator=(const VertexBuffer&); -private: // data - EventThreadServices& mEventThreadServices; ///GetFormat(); + uint32_t divisor = vertexBuffer->GetDivisor(); + Graphics::VertexInputRate vertexInputRate = (divisor == 0 + ? Graphics::VertexInputRate::PER_VERTEX + : Graphics::VertexInputRate::PER_INSTANCE); + vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride - Graphics::VertexInputRate::PER_VERTEX); + vertexInputRate); + //@todo Add the actual rate to the graphics struct const uint32_t attributeCount = vertexBuffer->GetAttributeCount(); uint32_t lastBoundAttributeIndex = 0; diff --git a/dali/internal/render/renderers/render-geometry.cpp b/dali/internal/render/renderers/render-geometry.cpp index b407b6f..83be141 100644 --- a/dali/internal/render/renderers/render-geometry.cpp +++ b/dali/internal/render/renderers/render-geometry.cpp @@ -93,6 +93,7 @@ void Geometry::SetIndexBuffer(Uint32ContainerType& indices) void Geometry::RemoveVertexBuffer(const Render::VertexBuffer* vertexBuffer) { const auto&& end = mVertexBuffers.End(); + // @todo if this buffer is the only instance buffer, reduce instance count to 1. for(auto&& iter = mVertexBuffers.Begin(); iter != end; ++iter) { if(*iter == vertexBuffer) @@ -159,6 +160,11 @@ bool Geometry::BindVertexAttributes(Graphics::CommandBuffer& commandBuffer) for(uint32_t i = 0; i < vertexBufferCount; ++i) { + if(mVertexBuffers[i]->GetDivisor() > 0) + { + mInstanceCount = mVertexBuffers[i]->GetElementCount(); + } + const GpuBuffer* gpuBuffer = mVertexBuffers[i]->GetGpuBuffer(); if(gpuBuffer) { @@ -219,7 +225,7 @@ bool Geometry::Draw( commandBuffer.BindIndexBuffer(*ibo, 0, mIndexType); } - commandBuffer.DrawIndexed(numIndices, 1, firstIndexOffset, 0, 0); + commandBuffer.DrawIndexed(numIndices, mInstanceCount, firstIndexOffset, 0, 0); } else { @@ -232,7 +238,7 @@ bool Geometry::Draw( numVertices = static_cast(mVertexBuffers[0]->GetElementCount()); } - commandBuffer.Draw(numVertices, 1, 0, 0); + commandBuffer.Draw(numVertices, mInstanceCount, 0, 0); } return true; } diff --git a/dali/internal/render/renderers/render-geometry.h b/dali/internal/render/renderers/render-geometry.h index 2f04c97..0af4faa 100644 --- a/dali/internal/render/renderers/render-geometry.h +++ b/dali/internal/render/renderers/render-geometry.h @@ -151,6 +151,7 @@ private: OwnerPointer mIndexBuffer; IndexType mIndexType; Type mGeometryType; + uint32_t mInstanceCount{0}; // Booleans bool mIndicesChanged : 1; diff --git a/dali/internal/render/renderers/render-vertex-buffer.cpp b/dali/internal/render/renderers/render-vertex-buffer.cpp index 1a881d1..b140cef 100644 --- a/dali/internal/render/renderers/render-vertex-buffer.cpp +++ b/dali/internal/render/renderers/render-vertex-buffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,6 +78,16 @@ bool VertexBuffer::Update(Graphics::Controller& graphicsController) return true; } +void VertexBuffer::SetDivisor(uint32_t divisor) +{ + mDivisor = divisor; +} + +uint32_t VertexBuffer::GetDivisor() +{ + return mDivisor; +} + } // namespace Render } // namespace Internal } // namespace Dali diff --git a/dali/internal/render/renderers/render-vertex-buffer.h b/dali/internal/render/renderers/render-vertex-buffer.h index b7074ef..a8b86c1 100644 --- a/dali/internal/render/renderers/render-vertex-buffer.h +++ b/dali/internal/render/renderers/render-vertex-buffer.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_RENDER_VERTEX_BUFFER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,6 +87,17 @@ public: bool Update(Graphics::Controller& graphicsController); /** + * @brief Set the divisor of the buffer for instanced drawing + * @param[in] divisor The divisor (0 = not instanced, >=1 = instanced) + */ + void SetDivisor(uint32_t divisor); + + /** + * Get the divisor for the vertex buffer + */ + [[nodiscard]] uint32_t GetDivisor(); + + /** * Get the number of attributes present in the buffer * @return The number of attributes stored in this buffer */ @@ -152,6 +163,7 @@ private: OwnerPointer mGpuBuffer; ///< Pointer to the GpuBuffer associated with this RenderVertexBuffer uint32_t mSize; ///< Number of Elements in the buffer + uint32_t mDivisor{0}; ///< The divisor (0:not instanced, >=1:instanced) bool mDataChanged; ///< Flag to know if data has changed in a frame }; diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 4a2f1bb..985bcbd 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -42,6 +42,7 @@ #include #include +#include // Un-comment to enable node tree debug logging //#define NODE_TREE_LOGGING 1 @@ -1375,6 +1376,13 @@ void UpdateManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, Owne new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferData, vertexBuffer, data, size); } +void UpdateManager::SetVertexBufferDivisor(Render::VertexBuffer* vertexBuffer, uint32_t divisor) +{ + using LocalType = MessageValue1; + uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(LocalType)); + new(slot) LocalType(vertexBuffer, &Render::VertexBuffer::SetDivisor, divisor); +} + void UpdateManager::AddGeometry(OwnerPointer& geometry) { // Message has ownership of format while in transit from update -> render diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 908f827..dabe08f 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -477,6 +477,14 @@ public: void SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer>& data, uint32_t size); /** + * Sets the divisor of a vertex buffer. This is used by the GPU to provide + * instanced drawing. + * @param[in] vertexBuffer The property buffer. + * @param[in] divisor The instance divisor. 0 to turn instancing off. + */ + void SetVertexBufferDivisor(Render::VertexBuffer* vertexBuffer, uint32_t divisor); + + /** * Adds a geometry to the RenderManager * @param[in] geometry The geometry to add * @post Sends a message to RenderManager to add the Geometry @@ -1263,6 +1271,13 @@ inline void SetVertexBufferData(UpdateManager& manager, Render::VertexBuffer& ve new(slot) LocalType(&manager, &UpdateManager::SetVertexBufferData, &vertexBuffer, data, size); } +inline void SetVertexBufferDivisorMessage(UpdateManager& manager, Render::VertexBuffer& vertexBuffer, uint32_t divisor) +{ + using LocalType = MessageValue2; + uint32_t* slot = manager.ReserveMessageSlot(sizeof(LocalType)); + new(slot) LocalType(&manager, &UpdateManager::SetVertexBufferDivisor, &vertexBuffer, divisor); +} + inline void AddGeometry(UpdateManager& manager, OwnerPointer& geometry) { // Message has ownership of Geometry while in transit from event -> update diff --git a/dali/public-api/rendering/vertex-buffer.cpp b/dali/public-api/rendering/vertex-buffer.cpp index c2351c4..85b8bb3 100644 --- a/dali/public-api/rendering/vertex-buffer.cpp +++ b/dali/public-api/rendering/vertex-buffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,6 +58,16 @@ std::size_t VertexBuffer::GetSize() const return GetImplementation(*this).GetSize(); } +void VertexBuffer::SetDivisor(uint32_t divisor) +{ + GetImplementation(*this).SetDivisor(divisor); +} + +uint32_t VertexBuffer::GetDivisor() const +{ + return GetImplementation(*this).GetDivisor(); +} + VertexBuffer::VertexBuffer(Internal::VertexBuffer* pointer) : BaseHandle(pointer) { diff --git a/dali/public-api/rendering/vertex-buffer.h b/dali/public-api/rendering/vertex-buffer.h index 6c80284..7300a38 100644 --- a/dali/public-api/rendering/vertex-buffer.h +++ b/dali/public-api/rendering/vertex-buffer.h @@ -2,7 +2,7 @@ #define DALI_VERTEX_BUFFER_H /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -171,6 +171,27 @@ public: */ std::size_t GetSize() const; + /** + * @brief Sets vertex divisor for all attributes + * + * If instancing isn't supported, the function has no effect. + * It's responsibility of developer to make sure the feature is supported. + * A divisor of 0 will turn off instanced drawing. + * Currently, a divisor > 1 will turn on instanced draw, but will have an + * actual rate of 1. + * + * @param[in] divisor Sets vertex buffer divisor for an instanced draw + */ + void SetDivisor(uint32_t divisor); + + /** + * @brief Get the divisor for the given attribute. A return value of 0 means that + * instancing is turned off. + * + * @return either 0 (not instanced), or > 0 (instanced) + */ + uint32_t GetDivisor() const; + public: /** * @brief The constructor.