ContextObserver removal, part I: Program no longer is context observer
[platform/core/uifw/dali-core.git] / dali / internal / render / gl-resources / context.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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/gl-resources/context.h>
19
20 // EXTERNAL INCLUDES
21 #include <algorithm>
22 #include <limits>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/constants.h>
26 #include <dali/internal/render/gl-resources/context-observer.h>
27 #include <dali/internal/render/shaders/program.h>
28 #include <dali/integration-api/platform-abstraction.h>
29 #include <dali/internal/render/common/render-manager.h>
30 #include <dali/integration-api/debug.h>
31
32 using namespace std;
33
34 namespace Dali
35 {
36
37 namespace Internal
38 {
39
40 namespace // unnamed namespace
41 {
42
43 /**
44  * GL error strings
45  */
46 struct errorStrings
47 {
48   const GLenum errorCode;
49   const char* errorString;
50 };
51 errorStrings errors[] =
52 {
53    { GL_NO_ERROR,           "GL_NO_ERROR" },
54    { GL_INVALID_ENUM,       "GL_INVALID_ENUM" },
55    { GL_INVALID_VALUE,      "GL_INVALID_VALUE" },
56    { GL_INVALID_OPERATION,  "GL_INVALID_OPERATION" },
57    { GL_OUT_OF_MEMORY,      "GL_OUT_OF_MEMORY" }
58 };
59
60 /*
61  * Called by std::for_each from ~Context
62  */
63 void deletePrograms(std::pair< std::size_t, Program* > hashProgram)
64 {
65   DALI_ASSERT_DEBUG( hashProgram.second );
66   delete hashProgram.second;
67 }
68
69 const unsigned int UNINITIALIZED_TEXTURE_UNIT = std::numeric_limits<unsigned int>::max();// GL_MAX_TEXTURE_UNITS can't be used because it's depreciated in gles2
70
71 } // unnamed namespace
72
73 #ifdef DEBUG_ENABLED
74 Debug::Filter* Context::gGlLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_CONTEXT");
75 #endif
76
77 Context::Context(Integration::GlAbstraction& glAbstraction)
78 : mGlAbstraction(glAbstraction),
79   mGlContextCreated(false),
80   mColorMask(true),
81   mStencilMask(0xFF),
82   mBlendEnabled(false),
83   mDepthTestEnabled(false),
84   mDepthMaskEnabled(false),
85   mDitherEnabled(true), // This the only GL capability which defaults to true
86   mPolygonOffsetFillEnabled(false),
87   mSampleAlphaToCoverageEnabled(false),
88   mSampleCoverageEnabled(false),
89   mScissorTestEnabled(false),
90   mStencilTestEnabled(false),
91   mClearColorSet(false),
92   mBoundArrayBufferId(0),
93   mBoundElementArrayBufferId(0),
94   mBoundTransformFeedbackBufferId(0),
95   mActiveTextureUnit( UNINITIALIZED_TEXTURE_UNIT ),
96   mUsingDefaultBlendColor(true),
97   mBlendFuncSeparateSrcRGB(GL_ONE),
98   mBlendFuncSeparateDstRGB(GL_ZERO),
99   mBlendFuncSeparateSrcAlpha(GL_ONE),
100   mBlendFuncSeparateDstAlpha(GL_ZERO),
101   mBlendEquationSeparateModeRGB( GL_FUNC_ADD ),
102   mBlendEquationSeparateModeAlpha( GL_FUNC_ADD ),
103   mMaxTextureSize(0),
104   mMaxTextureUnits(0),
105   mClearColor(Color::WHITE),    // initial color, never used until it's been set by the user
106   mCullFaceMode(CullNone),
107   mViewPort( 0, 0, 0, 0 ),
108   mCurrentProgram( NULL )
109 {
110 }
111
112 Context::~Context()
113 {
114   // release the cached programs
115   std::for_each(mProgramCache.begin(), mProgramCache.end(), deletePrograms);
116   mProgramCache.clear();
117
118   DALI_ASSERT_DEBUG(mObservers.empty());
119 }
120
121 void Context::GlContextCreated()
122 {
123   DALI_ASSERT_DEBUG(!mGlContextCreated);
124
125   mGlContextCreated = true;
126
127   // Set the initial GL state, and check it.
128   ResetGlState();
129
130   const std::set<ContextObserver*>::iterator end = mObservers.end();
131   for ( std::set<ContextObserver*>::iterator it = mObservers.begin();
132       it != end; ++it )
133   {
134     (*it)->GlContextCreated();
135   }
136
137   const ProgramContainer::iterator endp = mProgramCache.end();
138   for ( ProgramContainer::iterator itp = mProgramCache.begin(); itp != endp; ++itp )
139   {
140     (*itp).second->GlContextCreated();
141   }
142 }
143
144 void Context::GlContextToBeDestroyed()
145 {
146   DALI_ASSERT_DEBUG(mGlContextCreated);
147
148   const std::set<ContextObserver*>::iterator end = mObservers.end();
149   for ( std::set<ContextObserver*>::iterator it = mObservers.begin();
150       it != end; ++it )
151   {
152     (*it)->GlContextToBeDestroyed();
153   }
154
155   const ProgramContainer::iterator endp = mProgramCache.end();
156   for ( ProgramContainer::iterator itp = mProgramCache.begin(); itp != endp; ++itp )
157   {
158     (*itp).second->GlContextDestroyed();
159   }
160
161   mGlContextCreated = false;
162 }
163
164 void Context::AddObserver(ContextObserver& observer)
165 {
166   mObservers.insert(&observer);
167 }
168
169 void Context::RemoveObserver(ContextObserver& observer)
170 {
171   mObservers.erase(&observer);
172 }
173
174 const char* Context::ErrorToString( GLenum errorCode )
175 {
176   for( unsigned int i = 0; i < sizeof(errors) / sizeof(errors[0]); ++i)
177   {
178     if (errorCode == errors[i].errorCode)
179     {
180       return errors[i].errorString;
181     }
182   }
183   return "Unknown Open GLES error";
184 }
185
186 Program* Context::GetCachedProgram( std::size_t hash ) const
187 {
188   std::map< std::size_t, Program* >::const_iterator iter = mProgramCache.find(hash);
189
190   if (iter != mProgramCache.end())
191   {
192      return iter->second;
193   }
194   return NULL;
195 }
196
197 void Context::CacheProgram( std::size_t hash, Program* pointer )
198 {
199   mProgramCache[ hash ] = pointer;
200 }
201
202 const Rect< int >& Context::GetViewport()
203 {
204   return mViewPort;
205 }
206
207 void Context::FlushVertexAttributeLocations()
208 {
209   for( unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i )
210   {
211     // see if our cached state is different to the actual state
212     if (mVertexAttributeCurrentState[ i ] != mVertexAttributeCachedState[ i ] )
213     {
214       // it's different so make the change to the driver
215       // and update the cached state
216       mVertexAttributeCurrentState[ i ] = mVertexAttributeCachedState[ i ];
217
218       if (mVertexAttributeCurrentState[ i ] )
219       {
220         LOG_GL("EnableVertexAttribArray %d\n", i);
221         CHECK_GL( *this, mGlAbstraction.EnableVertexAttribArray( i ) );
222       }
223       else
224       {
225         LOG_GL("DisableVertexAttribArray %d\n", i);
226         CHECK_GL( *this, mGlAbstraction.DisableVertexAttribArray( i ) );
227       }
228     }
229   }
230
231 }
232
233 void Context::SetVertexAttributeLocation(unsigned int location, bool state)
234 {
235
236   if( location >= MAX_ATTRIBUTE_CACHE_SIZE )
237   {
238     // not cached, make the gl call through context
239     if ( state )
240     {
241        LOG_GL("EnableVertexAttribArray %d\n", location);
242        CHECK_GL( *this, mGlAbstraction.EnableVertexAttribArray( location ) );
243     }
244     else
245     {
246       LOG_GL("DisableVertexAttribArray %d\n", location);
247       CHECK_GL( *this, mGlAbstraction.DisableVertexAttribArray( location ) );
248     }
249   }
250   else
251   {
252     // set the cached state, it will be set at the next draw call
253     // if it's different from the current driver state
254     mVertexAttributeCachedState[ location ] = state;
255   }
256 }
257
258 void Context::ResetVertexAttributeState()
259 {
260   // reset attribute cache
261   for( unsigned int i=0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i )
262   {
263     mVertexAttributeCachedState[ i ] = false;
264     mVertexAttributeCurrentState[ i ] = false;
265
266     LOG_GL("DisableVertexAttribArray %d\n", i);
267     CHECK_GL( *this, mGlAbstraction.DisableVertexAttribArray( i ) );
268   }
269 }
270
271 void Context::ResetGlState()
272 {
273   DALI_ASSERT_DEBUG(mGlContextCreated);
274
275   mClearColorSet = false;
276   // Render manager will call clear in next render
277
278   // Reset internal state and Synchronize it with real OpenGL context.
279   // This may seem like overkill, but the GL context is not owned by dali-core,
280   // and no assumptions should be made about the initial state.
281   mColorMask = true;
282   mGlAbstraction.ColorMask( true, true, true, true );
283
284   mStencilMask = 0xFF;
285   mGlAbstraction.StencilMask( 0xFF );
286
287   mBlendEnabled = false;
288   mGlAbstraction.Disable(GL_BLEND);
289
290   mDepthTestEnabled = false;
291   mGlAbstraction.Disable(GL_DEPTH_TEST);
292
293   mDepthMaskEnabled = false;
294   mGlAbstraction.DepthMask(GL_FALSE);
295
296   mDitherEnabled = false; // This the only GL capability which defaults to true
297   mGlAbstraction.Disable(GL_DITHER);
298
299   mPolygonOffsetFillEnabled = false;
300   mGlAbstraction.Disable(GL_POLYGON_OFFSET_FILL);
301
302   mSampleAlphaToCoverageEnabled = false;
303   mGlAbstraction.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE);
304
305   mSampleCoverageEnabled = false;
306   mGlAbstraction.Disable(GL_SAMPLE_COVERAGE);
307
308   mScissorTestEnabled = false;
309   mGlAbstraction.Disable(GL_SCISSOR_TEST);
310
311   mStencilTestEnabled = false;
312   mGlAbstraction.Disable(GL_STENCIL_TEST);
313
314   mBoundArrayBufferId = 0;
315   LOG_GL("BindBuffer GL_ARRAY_BUFFER 0\n");
316   mGlAbstraction.BindBuffer(GL_ARRAY_BUFFER, mBoundArrayBufferId);
317
318   mBoundElementArrayBufferId = 0;
319   LOG_GL("BindBuffer GL_ELEMENT_ARRAY_BUFFER 0\n");
320   mGlAbstraction.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBoundElementArrayBufferId);
321
322 #ifndef EMSCRIPTEN // not in WebGL
323   mBoundTransformFeedbackBufferId = 0;
324   LOG_GL("BindBuffer GL_TRANSFORM_FEEDBACK_BUFFER 0\n");
325   mGlAbstraction.BindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mBoundTransformFeedbackBufferId);
326 #endif
327
328   mActiveTextureUnit = UNINITIALIZED_TEXTURE_UNIT;
329
330   mUsingDefaultBlendColor = true;
331   mGlAbstraction.BlendColor( 0.0f, 0.0f, 0.0f, 0.0f );
332
333   mBlendFuncSeparateSrcRGB = GL_ONE;
334   mBlendFuncSeparateDstRGB = GL_ZERO;
335   mBlendFuncSeparateSrcAlpha = GL_ONE;
336   mBlendFuncSeparateDstAlpha = GL_ZERO;
337   mGlAbstraction.BlendFuncSeparate( mBlendFuncSeparateSrcRGB, mBlendFuncSeparateDstRGB,
338                                     mBlendFuncSeparateSrcAlpha, mBlendFuncSeparateDstAlpha );
339
340   // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
341   mBlendEquationSeparateModeRGB = GL_FUNC_ADD;
342   mBlendEquationSeparateModeAlpha = GL_FUNC_ADD;
343   mGlAbstraction.BlendEquationSeparate( mBlendEquationSeparateModeRGB, mBlendEquationSeparateModeAlpha);
344
345   mCullFaceMode = CullNone;
346   mGlAbstraction.Disable(GL_CULL_FACE);
347   mGlAbstraction.FrontFace(GL_CCW);
348   mGlAbstraction.CullFace(GL_BACK);
349
350   // get max texture units
351   mGlAbstraction.GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxTextureUnits);
352   DALI_ASSERT_DEBUG(mMaxTextureUnits > 7);  // according to GLES 2.0 specification
353   mBound2dTextureId.reserve(mMaxTextureUnits);
354   // rebind texture units
355   for( int i=0; i < mMaxTextureUnits; ++i )
356   {
357     mBound2dTextureId[ i ] = 0;
358     // set active texture
359     mGlAbstraction.ActiveTexture( GL_TEXTURE0 + i );
360     // bind the previous texture
361     mGlAbstraction.BindTexture(GL_TEXTURE_2D, mBound2dTextureId[ i ] );
362   }
363
364   // get maximum texture size
365   mGlAbstraction.GetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
366
367   GLint numProgramBinaryFormats;
368   mGlAbstraction.GetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &numProgramBinaryFormats);
369   if( GL_NO_ERROR == mGlAbstraction.GetError() && 0 != numProgramBinaryFormats )
370   {
371     mProgramBinaryFormats.resize(numProgramBinaryFormats);
372     mGlAbstraction.GetIntegerv(GL_PROGRAM_BINARY_FORMATS_OES, &mProgramBinaryFormats[0]);
373   }
374
375   // reset viewport, this will be set to something useful when rendering
376   mViewPort.x = mViewPort.y = mViewPort.width = mViewPort.height = 0;
377
378   ResetVertexAttributeState();
379 }
380
381 #ifdef DALI_CONTEXT_LOGGING
382
383 void Context::PrintCurrentState()
384 {
385   DALI_LOG_INFO(SceneGraph::Context::gGlLogFilter, Debug::General,
386                 "----------------- Context State BEGIN -----------------\n"
387                 "Blend = %s\n"
388                 "Cull Face = %s\n"
389                 "Depth Test = %s\n"
390                 "Depth Mask = %s\n"
391                 "Dither = %s\n"
392                 "Polygon Offset Fill = %s\n"
393                 "Sample Alpha To Coverage = %s\n"
394                 "Sample Coverage = %s\n"
395                 "Scissor Test = %s\n"
396                 "Stencil Test = %s\n"
397                 "----------------- Context State END -----------------\n",
398                 mBlendEnabled ? "Enabled" : "Disabled",
399                 mDepthTestEnabled ? "Enabled" : "Disabled",
400                 mDepthMaskEnabled ? "Enabled" : "Disabled",
401                 mDitherEnabled ? "Enabled" : "Disabled",
402                 mPolygonOffsetFillEnabled ? "Enabled" : "Disabled",
403                 mSampleAlphaToCoverageEnabled ? "Enabled" : "Disabled",
404                 mSampleCoverageEnabled ? "Enabled" : "Disabled",
405                 mScissorTestEnabled ? "Enabled" : "Disabled",
406                 mStencilTestEnabled ? "Enabled" : "Disabled");
407 }
408
409 #endif // DALI_CONTEXT_LOGGING
410
411 } // namespace Internal
412
413 } // namespace Dali