Converted GPU buffers for geometry to new API
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-geometry.cpp
1 /*
2  * Copyright (c) 2021 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/gl-resources/context.h>
23 #include <dali/internal/render/gl-resources/gpu-buffer.h>
24 #include <dali/internal/render/renderers/render-vertex-buffer.h>
25 #include <dali/internal/render/shaders/program.h>
26
27 namespace Dali
28 {
29 namespace Internal
30 {
31 namespace Render
32 {
33 Geometry::Geometry()
34 : mIndices(),
35   mIndexBuffer(nullptr),
36   mGeometryType(Dali::Geometry::TRIANGLES),
37   mIndicesChanged(false),
38   mHasBeenUpdated(false),
39   mAttributesChanged(true)
40 {
41 }
42
43 Geometry::~Geometry() = default;
44
45 void Geometry::GlContextCreated(Context& context)
46 {
47 }
48
49 void Geometry::GlContextDestroyed()
50 {
51 }
52
53 void Geometry::AddVertexBuffer(Render::VertexBuffer* vertexBuffer)
54 {
55   mVertexBuffers.PushBack(vertexBuffer);
56   mAttributesChanged = true;
57 }
58
59 void Geometry::SetIndexBuffer(Dali::Vector<uint16_t>& indices)
60 {
61   mIndices.Swap(indices);
62   mIndicesChanged = true;
63 }
64
65 void Geometry::RemoveVertexBuffer(const Render::VertexBuffer* vertexBuffer)
66 {
67   const auto&& end = mVertexBuffers.End();
68   for(auto&& iter = mVertexBuffers.Begin(); iter != end; ++iter)
69   {
70     if(*iter == vertexBuffer)
71     {
72       //This will delete the gpu buffer associated to the RenderVertexBuffer if there is one
73       mVertexBuffers.Remove(iter);
74       mAttributesChanged = true;
75       break;
76     }
77   }
78 }
79
80 void Geometry::GetAttributeLocationFromProgram(Vector<GLint>& attributeLocation, Program& program, BufferIndex bufferIndex) const
81 {
82   attributeLocation.Clear();
83
84   for(auto&& vertexBuffer : mVertexBuffers)
85   {
86     const uint32_t attributeCount = vertexBuffer->GetAttributeCount();
87     for(uint32_t j = 0; j < attributeCount; ++j)
88     {
89       auto     attributeName = vertexBuffer->GetAttributeName(j);
90       uint32_t index         = program.RegisterCustomAttribute(attributeName);
91       GLint    location      = program.GetCustomAttributeLocation(index);
92
93       if(-1 == location)
94       {
95         DALI_LOG_WARNING("Attribute not found in the shader: %s\n", attributeName.GetCString());
96       }
97
98       attributeLocation.PushBack(location);
99     }
100   }
101 }
102
103 void Geometry::OnRenderFinished()
104 {
105   mHasBeenUpdated    = false;
106   mAttributesChanged = false;
107 }
108
109 void Geometry::Upload(Graphics::Controller& graphicsController)
110 {
111   if(!mHasBeenUpdated)
112   {
113     // Update buffers
114     if(mIndicesChanged)
115     {
116       if(mIndices.Empty())
117       {
118         mIndexBuffer = nullptr;
119       }
120       else
121       {
122         if(mIndexBuffer == nullptr)
123         {
124           mIndexBuffer = new GpuBuffer(graphicsController, 0 | Graphics::BufferUsage::INDEX_BUFFER);
125         }
126
127         uint32_t bufferSize = static_cast<uint32_t>(sizeof(uint16_t) * mIndices.Size());
128         mIndexBuffer->UpdateDataBuffer(graphicsController, bufferSize, &mIndices[0]);
129       }
130
131       mIndicesChanged = false;
132     }
133
134     for(auto&& buffer : mVertexBuffers)
135     {
136       if(!buffer->Update(graphicsController))
137       {
138         //Vertex buffer is not ready ( Size, data or format has not been specified yet )
139         return;
140       }
141     }
142
143     mHasBeenUpdated = true;
144   }
145 }
146
147 void Geometry::Draw(
148   Context&                 context,
149   Graphics::Controller&    graphicsController,
150   Graphics::CommandBuffer& commandBuffer,
151   BufferIndex              bufferIndex,
152   Vector<GLint>&           attributeLocation,
153   uint32_t                 elementBufferOffset,
154   uint32_t                 elementBufferCount)
155 {
156   //Bind buffers to attribute locations
157   uint32_t       base              = 0u;
158   const uint32_t vertexBufferCount = static_cast<uint32_t>(mVertexBuffers.Count());
159
160   std::vector<const Graphics::Buffer*> buffers;
161   std::vector<uint32_t>                offsets;
162
163   for(uint32_t i = 0; i < vertexBufferCount; ++i)
164   {
165     Graphics::Buffer* buffer = mVertexBuffers[i]->GetGpuBuffer().GetGraphicsObject();
166
167     if(buffer)
168     {
169       buffers.push_back(buffer);
170       offsets.push_back(0u);
171     }
172   }
173   commandBuffer.BindVertexBuffers(0, buffers, offsets);
174
175   uint32_t numIndices(0u);
176   intptr_t firstIndexOffset(0u);
177   if(mIndexBuffer)
178   {
179     numIndices = static_cast<uint32_t>(mIndices.Size());
180
181     if(elementBufferOffset != 0u)
182     {
183       elementBufferOffset = (elementBufferOffset >= numIndices) ? numIndices - 1 : elementBufferOffset;
184       firstIndexOffset    = elementBufferOffset * sizeof(GLushort);
185       numIndices -= elementBufferOffset;
186     }
187
188     if(elementBufferCount != 0u)
189     {
190       numIndices = std::min(elementBufferCount, numIndices);
191     }
192   }
193
194   GLenum geometryGLType(GL_NONE);
195   switch(mGeometryType)
196   {
197     case Dali::Geometry::TRIANGLES:
198     {
199       geometryGLType = GL_TRIANGLES;
200       break;
201     }
202     case Dali::Geometry::LINES:
203     {
204       geometryGLType = GL_LINES;
205       break;
206     }
207     case Dali::Geometry::POINTS:
208     {
209       geometryGLType = GL_POINTS;
210       break;
211     }
212     case Dali::Geometry::TRIANGLE_STRIP:
213     {
214       geometryGLType = GL_TRIANGLE_STRIP;
215       break;
216     }
217     case Dali::Geometry::TRIANGLE_FAN:
218     {
219       geometryGLType = GL_TRIANGLE_FAN;
220       break;
221     }
222     case Dali::Geometry::LINE_LOOP:
223     {
224       geometryGLType = GL_LINE_LOOP;
225       break;
226     }
227     case Dali::Geometry::LINE_STRIP:
228     {
229       geometryGLType = GL_LINE_STRIP;
230       break;
231     }
232   }
233
234   //Draw call
235   if(mIndexBuffer && geometryGLType != GL_POINTS)
236   {
237     //Indexed draw call
238     Graphics::Buffer* ibo = mIndexBuffer->GetGraphicsObject();
239     if(ibo)
240     {
241       commandBuffer.BindIndexBuffer(*ibo, 0, Graphics::Format::R16_UINT);
242     }
243
244     // Command buffer contains Texture bindings, vertex bindings and index buffer binding.
245     Graphics::SubmitInfo submitInfo{{}, 0 | Graphics::SubmitFlagBits::FLUSH};
246     submitInfo.cmdBuffer.push_back(&commandBuffer);
247     graphicsController.SubmitCommandBuffers(submitInfo);
248
249     //@todo This should all be done from inside Pipeline implementation.
250     //If there is only 1 vertex buffer, it should have been bound by SubmitCommandBuffers,
251     //and the single GL call from this will work on that bound buffer.
252     for(uint32_t i = 0; i < vertexBufferCount; ++i)
253     {
254       base += mVertexBuffers[i]->EnableVertexAttributes(context, attributeLocation, base);
255     }
256
257     // numIndices truncated, no value loss happening in practice
258     context.DrawElements(geometryGLType, static_cast<GLsizei>(numIndices), GL_UNSIGNED_SHORT, reinterpret_cast<void*>(firstIndexOffset));
259   }
260   else
261   {
262     //Unindex draw call
263     GLsizei numVertices(0u);
264     if(vertexBufferCount > 0)
265     {
266       // truncated, no value loss happening in practice
267       numVertices = static_cast<GLsizei>(mVertexBuffers[0]->GetElementCount());
268     }
269
270     // Command buffer contains Texture bindings & vertex bindings
271     Graphics::SubmitInfo submitInfo{{}, 0 | Graphics::SubmitFlagBits::FLUSH};
272     submitInfo.cmdBuffer.push_back(&commandBuffer);
273     graphicsController.SubmitCommandBuffers(submitInfo);
274
275     //@todo This should all be done from inside Pipeline implementation.
276     //If there is only 1 vertex buffer, it should have been bound by SubmitCommandBuffers,
277     //and the single GL call from this will work on that bound buffer.
278     for(uint32_t i = 0; i < vertexBufferCount; ++i)
279     {
280       base += mVertexBuffers[i]->EnableVertexAttributes(context, attributeLocation, base);
281     }
282
283     context.DrawArrays(geometryGLType, 0, numVertices);
284   }
285
286   //Disable attributes
287   for(auto&& attribute : attributeLocation)
288   {
289     if(attribute != -1)
290     {
291       context.DisableVertexAttributeArray(static_cast<GLuint>(attribute));
292     }
293   }
294 }
295
296 } // namespace Render
297 } // namespace Internal
298 } // namespace Dali