[dali_2.3.33] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-geometry.cpp
1 /*
2  * Copyright (c) 2024 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
97   for(auto&& iter = mVertexBuffers.Begin(); iter != end; ++iter)
98   {
99     if(*iter == vertexBuffer)
100     {
101       //This will delete the gpu buffer associated to the RenderVertexBuffer if there is one
102       mVertexBuffers.Remove(iter);
103       mAttributesChanged = true;
104       break;
105     }
106   }
107 }
108
109 void Geometry::OnRenderFinished()
110 {
111   mHasBeenUpdated    = false;
112   mAttributesChanged = false;
113 }
114
115 void Geometry::Upload(Graphics::Controller& graphicsController)
116 {
117   if(!mHasBeenUpdated)
118   {
119     // Update buffers
120     if(mIndicesChanged)
121     {
122       if(mIndices.Empty())
123       {
124         mIndexBuffer = nullptr;
125       }
126       else
127       {
128         if(mIndexBuffer == nullptr)
129         {
130           // Currently we are unable to reuse index buffer so the write policy is to preserve current content
131           mIndexBuffer = new GpuBuffer(graphicsController, 0 | Graphics::BufferUsage::INDEX_BUFFER, GpuBuffer::WritePolicy::RETAIN);
132         }
133
134         uint32_t bufferSize = static_cast<uint32_t>(sizeof(uint16_t) * mIndices.Size());
135         mIndexBuffer->UpdateDataBuffer(graphicsController, bufferSize, &mIndices[0]);
136       }
137
138       mIndicesChanged = false;
139     }
140
141     for(auto&& buffer : mVertexBuffers)
142     {
143       if(!buffer->Update(graphicsController))
144       {
145         //Vertex buffer is not ready ( Size, data or format has not been specified yet )
146         return;
147       }
148     }
149
150     mHasBeenUpdated = true;
151   }
152 }
153
154 bool Geometry::BindVertexAttributes(Graphics::CommandBuffer& commandBuffer)
155 {
156   //Bind buffers to attribute locations
157   const auto vertexBufferCount = static_cast<uint32_t>(mVertexBuffers.Count());
158
159   std::vector<const Graphics::Buffer*> buffers;
160   std::vector<uint32_t>                offsets;
161
162   for(uint32_t i = 0; i < vertexBufferCount; ++i)
163   {
164     const GpuBuffer* gpuBuffer = mVertexBuffers[i]->GetGpuBuffer();
165     if(gpuBuffer)
166     {
167       const Graphics::Buffer* buffer = gpuBuffer->GetGraphicsObject();
168
169       if(buffer)
170       {
171         buffers.push_back(buffer);
172         offsets.push_back(0u);
173       }
174     }
175     //@todo Figure out why this is being drawn without geometry having been uploaded
176   }
177   if(buffers.empty() || buffers.size() != vertexBufferCount)
178   {
179     return false;
180   }
181
182   commandBuffer.BindVertexBuffers(0, buffers, offsets);
183
184   return true;
185 }
186
187 bool Geometry::Draw(
188   Graphics::Controller&    graphicsController,
189   Graphics::CommandBuffer& commandBuffer,
190   uint32_t                 elementBufferOffset,
191   uint32_t                 elementBufferCount,
192   uint32_t                 instanceCount)
193 {
194   uint32_t numIndices(0u);
195   intptr_t firstIndexOffset(0u);
196   if(mIndexBuffer)
197   {
198     std::size_t sizeOfIndex = GetSizeOfIndexFromIndexType(mIndexType);
199
200     numIndices = static_cast<uint32_t>(mIndices.Size() * sizeof(uint16_t) / sizeOfIndex);
201
202     if(elementBufferOffset != 0u)
203     {
204       elementBufferOffset = (elementBufferOffset >= numIndices) ? numIndices : elementBufferOffset;
205       firstIndexOffset    = intptr_t(elementBufferOffset * sizeOfIndex);
206       numIndices -= elementBufferOffset;
207     }
208
209     if(elementBufferCount != 0u)
210     {
211       numIndices = std::min(elementBufferCount, numIndices);
212     }
213   }
214
215   //Draw call
216   if(mIndexBuffer && mGeometryType != Dali::Geometry::POINTS)
217   {
218     // Issue draw call only if there's non-zero numIndices
219     if(numIndices)
220     {
221       //Indexed draw call
222       const Graphics::Buffer* ibo = mIndexBuffer->GetGraphicsObject();
223       if(ibo)
224       {
225         commandBuffer.BindIndexBuffer(*ibo, 0, mIndexType);
226       }
227
228       commandBuffer.DrawIndexed(numIndices, instanceCount, firstIndexOffset, 0, 0);
229     }
230   }
231   else
232   {
233     // Un-indexed draw call
234     uint32_t numVertices(0u);
235     uint32_t firstVertex(0u);
236
237     // Use element buffer count for drawing arrays (needs changing API, for workaround)
238     if(elementBufferCount)
239     {
240       numVertices = elementBufferCount;
241       firstVertex = elementBufferOffset;
242     }
243     else if(mVertexBuffers.Count() > 0)
244     {
245       // truncated, no value loss happening in practice
246       numVertices = static_cast<uint32_t>(mVertexBuffers[0]->GetRenderableElementCount());
247     }
248     // In case we have more buffers, we select buffer with less elements to render
249     // TODO: we may eventually support wrapping around buffers????
250     else if(mVertexBuffers.Count() > 1)
251     {
252       auto elementsCount = mVertexBuffers[0]->GetRenderableElementCount();
253       for(auto& vertexBuffer : mVertexBuffers)
254       {
255         elementsCount = std::min(elementsCount, vertexBuffer->GetRenderableElementCount());
256       }
257       numVertices = elementsCount;
258     }
259
260     // Issue draw call only if there's non-zero numVertices
261     if(numVertices)
262     {
263       commandBuffer.Draw(numVertices, instanceCount, firstVertex, 0);
264     }
265   }
266   return true;
267 }
268
269 Graphics::PrimitiveTopology Geometry::GetTopology() const
270 {
271   Graphics::PrimitiveTopology topology = Graphics::PrimitiveTopology::TRIANGLE_LIST;
272
273   switch(mGeometryType)
274   {
275     case Dali::Geometry::TRIANGLES:
276     {
277       topology = Graphics::PrimitiveTopology::TRIANGLE_LIST;
278       break;
279     }
280     case Dali::Geometry::LINES:
281     {
282       topology = Graphics::PrimitiveTopology::LINE_LIST;
283       break;
284     }
285     case Dali::Geometry::POINTS:
286     {
287       topology = Graphics::PrimitiveTopology::POINT_LIST;
288       break;
289     }
290     case Dali::Geometry::TRIANGLE_STRIP:
291     {
292       topology = Graphics::PrimitiveTopology::TRIANGLE_STRIP;
293       break;
294     }
295     case Dali::Geometry::TRIANGLE_FAN:
296     {
297       topology = Graphics::PrimitiveTopology::TRIANGLE_FAN;
298       break;
299     }
300     case Dali::Geometry::LINE_LOOP:
301     {
302       topology = Graphics::PrimitiveTopology::LINE_LOOP;
303       break;
304     }
305     case Dali::Geometry::LINE_STRIP:
306     {
307       topology = Graphics::PrimitiveTopology::LINE_STRIP;
308       break;
309     }
310   }
311   return topology;
312 }
313
314 } // namespace Render
315 } // namespace Internal
316 } // namespace Dali