Merge changes I7fd36a6d,I2c2e4fe7 into devel/new_mesh
[platform/core/uifw/dali-core.git] / dali / internal / render / gl-resources / gpu-buffer.cpp
1 /*
2  * Copyright (c) 2014 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
18 // CLASS HEADER
19 #include <dali/internal/render/gl-resources/gpu-buffer.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23
24 namespace Dali
25 {
26
27 namespace Internal
28 {
29
30 namespace
31 {
32 /**
33  * Helper to get our type enum as GL enum
34  * @param type to convert
35  * @return the corresponding GL enum or -1
36  */
37 inline GLenum TypeAsGlEnum( GpuBuffer::Target type )
38 {
39   GLenum retval( -1 );
40   switch( type )
41   {
42     case GpuBuffer::ARRAY_BUFFER :
43     {
44       retval = GL_ARRAY_BUFFER;
45       break;
46     }
47     case GpuBuffer::ELEMENT_ARRAY_BUFFER :
48     {
49       retval = GL_ELEMENT_ARRAY_BUFFER;
50       break;
51     }
52     case GpuBuffer::TRANSFORM_FEEDBACK_BUFFER :
53     {
54       retval = GL_TRANSFORM_FEEDBACK_BUFFER;
55       break;
56     }
57   }
58   return retval;
59 }
60
61 /**
62  * Helper to get our drawmode enum as GL enum
63  * @param type to convert
64  * @return the corresponding GL enum or -1
65  */
66 inline GLenum ModeAsGlEnum( GpuBuffer::Usage type )
67 {
68   GLenum retval( -1 );
69   switch( type )
70   {
71     case GpuBuffer::STREAM_DRAW :
72     {
73       retval = GL_STREAM_DRAW;
74       break;
75     }
76     case GpuBuffer::STATIC_DRAW :
77     {
78       retval = GL_STATIC_DRAW;
79       break;
80     }
81     case GpuBuffer::DYNAMIC_DRAW :
82     {
83       retval = GL_DYNAMIC_DRAW;
84       break;
85     }
86   }
87   return retval;
88 }
89
90 }
91
92 GpuBuffer::GpuBuffer( Context& context, Target target, Usage usage )
93 : mContext( context ),
94   mCapacity( 0 ),
95   mSize( 0 ),
96   mBufferId( 0 ),
97   mTarget( target ),
98   mUsage( usage ),
99   mBufferCreated( false )
100 {
101 }
102
103 GpuBuffer::~GpuBuffer()
104 {
105   // If we have a buffer then delete it.
106   if (mBufferId)
107   {
108     // If a buffer object that is currently bound is deleted, the binding reverts to 0
109     // (the absence of any buffer object, which reverts to client memory usage)
110     mContext.DeleteBuffers(1,&mBufferId);
111   }
112 }
113
114 /*
115  * Creates or updates the buffer data depending on whether it
116  * already exists or not.
117  */
118 void GpuBuffer::UpdateDataBuffer(GLsizeiptr size,const GLvoid *data)
119 {
120   DALI_ASSERT_DEBUG( size > 0 );
121   mSize = size;
122   // make sure we have a buffer name/id before uploading
123   if (mBufferId == 0)
124   {
125     mContext.GenBuffers(1,&mBufferId);
126     DALI_ASSERT_DEBUG(mBufferId);
127   }
128
129   // make sure the buffer is bound, don't perform any checks because size may be zero
130   BindNoChecks(mBufferId);
131
132   // if the buffer has already been created, just update the data providing it fits
133   if (mBufferCreated )
134   {
135     // if the data will fit in the existing buffer, just update it
136     if (size <= mCapacity )
137     {
138       mContext.BufferSubData( TypeAsGlEnum(mTarget), 0, size, data );
139     }
140     else
141     {
142       // create a new buffer of the larger size,
143       // gl should automatically deallocate the old buffer
144       mContext.BufferData( TypeAsGlEnum(mTarget), size, data, ModeAsGlEnum( mUsage ) );
145       mCapacity = size;
146     }
147   }
148   else
149   {
150     // create the buffer
151     mContext.BufferData( TypeAsGlEnum(mTarget), size, data, ModeAsGlEnum( mUsage ) );
152     mBufferCreated = true;
153     mCapacity = size;
154   }
155
156   switch (mTarget)
157   {
158     case ARRAY_BUFFER:
159     {
160       mContext.BindArrayBuffer(0);
161       break;
162     }
163     case ELEMENT_ARRAY_BUFFER:
164     {
165       mContext.BindElementArrayBuffer(0);
166       break;
167     }
168     case TRANSFORM_FEEDBACK_BUFFER:
169     {
170       mContext.BindTransformFeedbackBuffer(0);
171       break;
172     }
173   }
174 }
175
176 void GpuBuffer::Bind() const
177 {
178   DALI_ASSERT_DEBUG(mCapacity);
179
180   BindNoChecks(mBufferId);
181 }
182
183 bool GpuBuffer::BufferIsValid() const
184 {
185   return mBufferCreated && (0 != mCapacity );
186 }
187
188 void GpuBuffer::GlContextDestroyed()
189 {
190   // If the context is destroyed, GL would have released the buffer.
191   mCapacity = 0;
192   mSize = 0;
193   mBufferId = 0;
194   mBufferCreated = false;
195 }
196
197 void GpuBuffer::BindNoChecks(GLuint bufferId) const
198 {
199   // context currently only supports two targets, element and array
200   // and it caches both of them (as in it won't bind them if the
201   // buffer id is already bound).
202
203   if (mTarget == ARRAY_BUFFER)
204   {
205     mContext.BindArrayBuffer(bufferId);
206   }
207   else
208   {
209     mContext.BindElementArrayBuffer(bufferId);
210   }
211 }
212
213
214 } // namespace Internal
215
216 } //namespace Dali