Merge "Support multiple window rendering" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-geometry.cpp
1 /*
2  * Copyright (c) 2018 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-property-buffer.h>
25 #include <dali/internal/render/shaders/program.h>
26
27 namespace Dali
28 {
29 namespace Internal
30 {
31 namespace Render
32 {
33
34 Geometry::Geometry()
35 : mIndices(),
36   mIndexBuffer(NULL),
37   mGeometryType( Dali::Geometry::TRIANGLES ),
38   mIndicesChanged(false),
39   mHasBeenUpdated(false),
40   mAttributesChanged(true)
41 {
42 }
43
44 Geometry::~Geometry()
45 {
46 }
47
48 void Geometry::GlContextCreated( Context& context )
49 {
50 }
51
52 void Geometry::GlContextDestroyed()
53 {
54 }
55
56 void Geometry::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
57 {
58   mVertexBuffers.PushBack( propertyBuffer );
59   mAttributesChanged = true;
60 }
61
62 void Geometry::SetIndexBuffer( Dali::Vector<uint16_t>& indices )
63 {
64   mIndices.Swap( indices );
65   mIndicesChanged = true;
66 }
67
68 void Geometry::RemovePropertyBuffer( const Render::PropertyBuffer* propertyBuffer )
69 {
70   const auto&& end = mVertexBuffers.End();
71   for( auto&& iter = mVertexBuffers.Begin(); iter != end; ++iter )
72   {
73     if( *iter == propertyBuffer )
74     {
75       //This will delete the gpu buffer associated to the RenderPropertyBuffer if there is one
76       mVertexBuffers.Remove( iter );
77       mAttributesChanged = true;
78       break;
79     }
80   }
81 }
82
83 void Geometry::GetAttributeLocationFromProgram( Vector<GLint>& attributeLocation, Program& program, BufferIndex bufferIndex ) const
84 {
85   attributeLocation.Clear();
86
87   for( auto&& vertexBuffer : mVertexBuffers )
88   {
89     const uint32_t attributeCount = vertexBuffer->GetAttributeCount();
90     for( uint32_t j = 0; j < attributeCount; ++j )
91     {
92       const std::string& attributeName = vertexBuffer->GetAttributeName( j );
93       uint32_t index = program.RegisterCustomAttribute( attributeName );
94       GLint location = program.GetCustomAttributeLocation( index );
95
96       if( -1 == location )
97       {
98         DALI_LOG_WARNING( "Attribute not found in the shader: %s\n", attributeName.c_str() );
99       }
100
101       attributeLocation.PushBack( location );
102     }
103   }
104 }
105
106 void Geometry::OnRenderFinished()
107 {
108   mHasBeenUpdated = false;
109   mAttributesChanged = false;
110 }
111
112 void Geometry::Upload( Context& context )
113 {
114   if( !mHasBeenUpdated )
115   {
116     // Update buffers
117     if( mIndicesChanged )
118     {
119       if( mIndices.Empty() )
120       {
121         mIndexBuffer = NULL;
122       }
123       else
124       {
125         if ( mIndexBuffer == NULL )
126         {
127           mIndexBuffer = new GpuBuffer( context );
128         }
129
130         uint32_t bufferSize = static_cast<uint32_t>( sizeof( uint16_t ) * mIndices.Size() );
131         mIndexBuffer->UpdateDataBuffer( context, bufferSize, &mIndices[0], GpuBuffer::STATIC_DRAW, GpuBuffer::ELEMENT_ARRAY_BUFFER );
132       }
133
134       mIndicesChanged = false;
135     }
136
137     for( auto&& buffer : mVertexBuffers )
138     {
139       if( !buffer->Update( context ) )
140       {
141         //Vertex buffer is not ready ( Size, data or format has not been specified yet )
142         return;
143       }
144     }
145
146     mHasBeenUpdated = true;
147   }
148 }
149
150 void Geometry::Draw(
151     Context& context,
152     BufferIndex bufferIndex,
153     Vector<GLint>& attributeLocation,
154     uint32_t elementBufferOffset,
155     uint32_t elementBufferCount )
156 {
157   //Bind buffers to attribute locations
158   uint32_t base = 0u;
159   const uint32_t vertexBufferCount = static_cast<uint32_t>( mVertexBuffers.Count() );
160   for( uint32_t i = 0; i < vertexBufferCount; ++i )
161   {
162     mVertexBuffers[i]->BindBuffer( context, GpuBuffer::ARRAY_BUFFER );
163     base += mVertexBuffers[i]->EnableVertexAttributes( context, attributeLocation, base );
164   }
165
166   uint32_t numIndices(0u);
167   intptr_t firstIndexOffset(0u);
168   if( mIndexBuffer )
169   {
170     numIndices = static_cast<uint32_t>( mIndices.Size() );
171
172     if( elementBufferOffset != 0u )
173     {
174       elementBufferOffset = (elementBufferOffset >= numIndices ) ? numIndices - 1 : elementBufferOffset;
175       firstIndexOffset = elementBufferOffset * sizeof(GLushort);
176       numIndices -= elementBufferOffset;
177     }
178
179     if( elementBufferCount != 0u )
180     {
181       numIndices = std::min( elementBufferCount, numIndices );
182     }
183   }
184
185   GLenum geometryGLType(GL_NONE);
186   switch(mGeometryType)
187   {
188     case Dali::Geometry::TRIANGLES:
189     {
190       geometryGLType = GL_TRIANGLES;
191       break;
192     }
193     case Dali::Geometry::LINES:
194     {
195       geometryGLType = GL_LINES;
196       break;
197     }
198     case Dali::Geometry::POINTS:
199     {
200       geometryGLType = GL_POINTS;
201       break;
202     }
203     case Dali::Geometry::TRIANGLE_STRIP:
204     {
205       geometryGLType = GL_TRIANGLE_STRIP;
206       break;
207     }
208     case Dali::Geometry::TRIANGLE_FAN:
209     {
210       geometryGLType = GL_TRIANGLE_FAN;
211       break;
212     }
213     case Dali::Geometry::LINE_LOOP:
214     {
215       geometryGLType = GL_LINE_LOOP;
216       break;
217     }
218     case Dali::Geometry::LINE_STRIP:
219     {
220       geometryGLType = GL_LINE_STRIP;
221       break;
222     }
223   }
224
225   //Draw call
226   if( mIndexBuffer && geometryGLType != GL_POINTS )
227   {
228     //Indexed draw call
229     mIndexBuffer->Bind( context, GpuBuffer::ELEMENT_ARRAY_BUFFER );
230     // numIndices truncated, no value loss happening in practice
231     context.DrawElements( geometryGLType, static_cast<GLsizei>( numIndices ), GL_UNSIGNED_SHORT, reinterpret_cast<void*>( firstIndexOffset ) );
232   }
233   else
234   {
235     //Unindex draw call
236     GLsizei numVertices(0u);
237     if( vertexBufferCount > 0 )
238     {
239       // truncated, no value loss happening in practice
240       numVertices = static_cast<GLsizei>( mVertexBuffers[0]->GetElementCount() );
241     }
242
243     context.DrawArrays( geometryGLType, 0, numVertices );
244   }
245
246   //Disable attributes
247   for( auto&& attribute : attributeLocation )
248   {
249     if( attribute != -1 )
250     {
251       context.DisableVertexAttributeArray( static_cast<GLuint>( attribute ) );
252     }
253   }
254 }
255
256 } // namespace SceneGraph
257 } // namespace Internal
258 } // namespace Dali