Skip duplicated vertex binding
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-geometry.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // CLASS HEADER
18 #include <dali/internal/render/renderers/render-geometry.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/internal/common/buffer-index.h>
22 #include <dali/internal/render/renderers/render-vertex-buffer.h>
23 #include <dali/internal/render/shaders/program.h>
24
25 namespace Dali
26 {
27 namespace Internal
28 {
29 namespace Render
30 {
31 namespace
32 {
33 inline constexpr size_t GetSizeOfIndexFromIndexType(Dali::Graphics::Format graphicsFormat)
34 {
35   switch(graphicsFormat)
36   {
37     case Dali::Graphics::Format::R16_UINT:
38     {
39       return sizeof(uint16_t);
40     }
41     case Dali::Graphics::Format::R32_UINT:
42     {
43       return sizeof(uint32_t);
44     }
45     default:
46     {
47       // TODO : Not implmeneted.
48       return sizeof(uint16_t);
49     }
50   }
51 }
52 } // unnamed namespace
53 Geometry::Geometry()
54 : mIndices(),
55   mIndexBuffer(nullptr),
56   mIndexType(Dali::Graphics::Format::R16_UINT),
57   mGeometryType(Dali::Geometry::TRIANGLES),
58   mIndicesChanged(false),
59   mHasBeenUpdated(false),
60   mAttributesChanged(true)
61 {
62 }
63
64 Geometry::~Geometry() = default;
65
66 void Geometry::AddVertexBuffer(Render::VertexBuffer* vertexBuffer)
67 {
68   mVertexBuffers.PushBack(vertexBuffer);
69   mAttributesChanged = true;
70 }
71
72 const Vector<Render::VertexBuffer*>& Geometry::GetVertexBuffers() const
73 {
74   return mVertexBuffers;
75 }
76
77 void Geometry::SetIndexBuffer(Uint16ContainerType& indices)
78 {
79   mIndices.Swap(indices);
80   mIndicesChanged = true;
81   mIndexType      = Graphics::Format::R16_UINT;
82 }
83
84 void Geometry::SetIndexBuffer(Uint32ContainerType& indices)
85 {
86   // mIndices type is not matched with indices. Copy memory hardly.
87   mIndices.ResizeUninitialized(indices.Count() * 2);
88   memcpy(mIndices.Begin(), indices.Begin(), indices.Count() * sizeof(uint32_t));
89   mIndicesChanged = true;
90   mIndexType      = Graphics::Format::R32_UINT;
91 }
92
93 void Geometry::RemoveVertexBuffer(const Render::VertexBuffer* vertexBuffer)
94 {
95   const auto&& end = mVertexBuffers.End();
96   for(auto&& iter = mVertexBuffers.Begin(); iter != end; ++iter)
97   {
98     if(*iter == vertexBuffer)
99     {
100       //This will delete the gpu buffer associated to the RenderVertexBuffer if there is one
101       mVertexBuffers.Remove(iter);
102       mAttributesChanged = true;
103       break;
104     }
105   }
106 }
107
108 void Geometry::OnRenderFinished()
109 {
110   mHasBeenUpdated    = false;
111   mAttributesChanged = false;
112 }
113
114 void Geometry::Upload(Graphics::Controller& graphicsController)
115 {
116   if(!mHasBeenUpdated)
117   {
118     // Update buffers
119     if(mIndicesChanged)
120     {
121       if(mIndices.Empty())
122       {
123         mIndexBuffer = nullptr;
124       }
125       else
126       {
127         if(mIndexBuffer == nullptr)
128         {
129           mIndexBuffer = new GpuBuffer(graphicsController, 0 | Graphics::BufferUsage::INDEX_BUFFER);
130         }
131
132         uint32_t bufferSize = static_cast<uint32_t>(sizeof(uint16_t) * mIndices.Size());
133         mIndexBuffer->UpdateDataBuffer(graphicsController, bufferSize, &mIndices[0]);
134       }
135
136       mIndicesChanged = false;
137     }
138
139     for(auto&& buffer : mVertexBuffers)
140     {
141       if(!buffer->Update(graphicsController))
142       {
143         //Vertex buffer is not ready ( Size, data or format has not been specified yet )
144         return;
145       }
146     }
147
148     mHasBeenUpdated = true;
149   }
150 }
151
152 bool Geometry::BindVertexAttributes(Graphics::CommandBuffer& commandBuffer)
153 {
154   //Bind buffers to attribute locations
155   const auto vertexBufferCount = static_cast<uint32_t>(mVertexBuffers.Count());
156
157   std::vector<const Graphics::Buffer*> buffers;
158   std::vector<uint32_t>                offsets;
159
160   for(uint32_t i = 0; i < vertexBufferCount; ++i)
161   {
162     const GpuBuffer* gpuBuffer = mVertexBuffers[i]->GetGpuBuffer();
163     if(gpuBuffer)
164     {
165       const Graphics::Buffer* buffer = gpuBuffer->GetGraphicsObject();
166
167       if(buffer)
168       {
169         buffers.push_back(buffer);
170         offsets.push_back(0u);
171       }
172     }
173     //@todo Figure out why this is being drawn without geometry having been uploaded
174   }
175   if(buffers.empty())
176   {
177     return false;
178   }
179
180   commandBuffer.BindVertexBuffers(0, buffers, offsets);
181
182   return true;
183 }
184
185 bool Geometry::Draw(
186   Graphics::Controller&    graphicsController,
187   Graphics::CommandBuffer& commandBuffer,
188   uint32_t                 elementBufferOffset,
189   uint32_t                 elementBufferCount)
190 {
191   uint32_t numIndices(0u);
192   intptr_t firstIndexOffset(0u);
193   if(mIndexBuffer)
194   {
195     std::size_t sizeOfIndex = GetSizeOfIndexFromIndexType(mIndexType);
196
197     numIndices = static_cast<uint32_t>(mIndices.Size() * sizeof(uint16_t) / sizeOfIndex);
198
199     if(elementBufferOffset != 0u)
200     {
201       elementBufferOffset = (elementBufferOffset >= numIndices) ? numIndices - 1 : elementBufferOffset;
202       firstIndexOffset    = intptr_t(elementBufferOffset * sizeOfIndex);
203       numIndices -= elementBufferOffset;
204     }
205
206     if(elementBufferCount != 0u)
207     {
208       numIndices = std::min(elementBufferCount, numIndices);
209     }
210   }
211
212   //Draw call
213   if(mIndexBuffer && mGeometryType != Dali::Geometry::POINTS)
214   {
215     //Indexed draw call
216     const Graphics::Buffer* ibo = mIndexBuffer->GetGraphicsObject();
217     if(ibo)
218     {
219       commandBuffer.BindIndexBuffer(*ibo, 0, mIndexType);
220     }
221
222     commandBuffer.DrawIndexed(numIndices, 1, firstIndexOffset, 0, 0);
223   }
224   else
225   {
226     // Un-indexed draw call
227     uint32_t numVertices(0u);
228
229     if(mVertexBuffers.Count() > 0)
230     {
231       // truncated, no value loss happening in practice
232       numVertices = static_cast<uint32_t>(mVertexBuffers[0]->GetElementCount());
233     }
234
235     commandBuffer.Draw(numVertices, 1, 0, 0);
236   }
237   return true;
238 }
239
240 Graphics::PrimitiveTopology Geometry::GetTopology() const
241 {
242   Graphics::PrimitiveTopology topology = Graphics::PrimitiveTopology::TRIANGLE_LIST;
243
244   switch(mGeometryType)
245   {
246     case Dali::Geometry::TRIANGLES:
247     {
248       topology = Graphics::PrimitiveTopology::TRIANGLE_LIST;
249       break;
250     }
251     case Dali::Geometry::LINES:
252     {
253       topology = Graphics::PrimitiveTopology::LINE_LIST;
254       break;
255     }
256     case Dali::Geometry::POINTS:
257     {
258       topology = Graphics::PrimitiveTopology::POINT_LIST;
259       break;
260     }
261     case Dali::Geometry::TRIANGLE_STRIP:
262     {
263       topology = Graphics::PrimitiveTopology::TRIANGLE_STRIP;
264       break;
265     }
266     case Dali::Geometry::TRIANGLE_FAN:
267     {
268       topology = Graphics::PrimitiveTopology::TRIANGLE_FAN;
269       break;
270     }
271     case Dali::Geometry::LINE_LOOP:
272     {
273       topology = Graphics::PrimitiveTopology::LINE_LOOP;
274       break;
275     }
276     case Dali::Geometry::LINE_STRIP:
277     {
278       topology = Graphics::PrimitiveTopology::LINE_STRIP;
279       break;
280     }
281   }
282   return topology;
283 }
284
285 } // namespace Render
286 } // namespace Internal
287 } // namespace Dali