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