2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/render/shaders/program.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/gl-defines.h>
28 #include <dali/internal/common/shader-data.h>
29 #include <dali/internal/render/common/performance-monitor.h>
30 #include <dali/internal/render/gl-resources/gl-call-debug.h>
31 #include <dali/internal/render/shaders/program-cache.h>
32 #include <dali/public-api/common/constants.h>
33 #include <dali/public-api/common/dali-common.h>
34 #include <dali/public-api/common/dali-vector.h>
38 void LogWithLineNumbers(const char* source)
40 uint32_t lineNumber = 0u;
41 const char* prev = source;
42 const char* ptr = prev;
50 // seek the next end of line or end of text
51 while(*ptr != '\n' && *ptr != '\0')
56 std::string line(prev, ptr - prev);
57 Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, "%4d %s\n", lineNumber, line.c_str());
77 const char* const gStdAttribs[Program::ATTRIB_TYPE_LAST] =
79 "aPosition", // ATTRIB_POSITION
80 "aTexCoord", // ATTRIB_TEXCOORD
83 const char* const gStdUniforms[Program::UNIFORM_TYPE_LAST] =
85 "uMvpMatrix", // UNIFORM_MVP_MATRIX
86 "uModelView", // UNIFORM_MODELVIEW_MATRIX
87 "uProjection", // UNIFORM_PROJECTION_MATRIX
88 "uModelMatrix", // UNIFORM_MODEL_MATRIX,
89 "uViewMatrix", // UNIFORM_VIEW_MATRIX,
90 "uNormalMatrix", // UNIFORM_NORMAL_MATRIX
91 "uColor", // UNIFORM_COLOR
92 "sTexture", // UNIFORM_SAMPLER
93 "sTextureRect", // UNIFORM_SAMPLER_RECT
94 "sEffect", // UNIFORM_EFFECT_SAMPLER
95 "uSize" // UNIFORM_SIZE
102 Program* Program::New(ProgramCache& cache, Internal::ShaderDataPtr shaderData, bool modifiesGeometry)
104 size_t shaderHash = shaderData->GetHashValue();
105 Program* program = cache.GetProgram(shaderHash);
107 if(nullptr == program)
109 // program not found so create it
110 program = new Program(cache, shaderData, modifiesGeometry);
112 cache.AddProgram(shaderHash, program);
122 if(this != mCache.GetCurrentProgram())
124 LOG_GL("UseProgram(%d)\n", mProgramId);
125 CHECK_GL(mGlAbstraction, mGlAbstraction.UseProgram(mProgramId));
127 mCache.SetCurrentProgram(this);
132 bool Program::IsUsed()
134 return (this == mCache.GetCurrentProgram());
137 GLint Program::GetAttribLocation(AttribType type)
139 DALI_ASSERT_DEBUG(type != ATTRIB_UNKNOWN);
141 return GetCustomAttributeLocation(type);
144 uint32_t Program::RegisterCustomAttribute(ConstString name)
147 // find the value from cache
148 for(; index < static_cast<uint32_t>(mAttributeLocations.size()); ++index)
150 if(mAttributeLocations[index].first == name)
152 // name found so return index
156 // if we get here, index is one past end so push back the new name
157 mAttributeLocations.push_back(std::make_pair(name, ATTRIB_UNKNOWN));
161 GLint Program::GetCustomAttributeLocation(uint32_t attributeIndex)
163 // debug check that index is within name cache
164 DALI_ASSERT_DEBUG(mAttributeLocations.size() > attributeIndex);
166 // check if we have already queried the location of the attribute
167 GLint location = mAttributeLocations[attributeIndex].second;
169 if(location == ATTRIB_UNKNOWN)
171 location = CHECK_GL(mGlAbstraction, mGlAbstraction.GetAttribLocation(mProgramId, mAttributeLocations[attributeIndex].first.GetCString()));
173 mAttributeLocations[attributeIndex].second = location;
174 LOG_GL("GetAttributeLocation(program=%d,%s) = %d\n", mProgramId, mAttributeLocations[attributeIndex].first.GetCString(), mAttributeLocations[attributeIndex].second);
180 uint32_t Program::RegisterUniform(ConstString name)
183 // find the value from cache
184 for(; index < static_cast<uint32_t>(mUniformLocations.size()); ++index)
186 if(mUniformLocations[index].first == name)
188 // name found so return index
192 // if we get here, index is one past end so push back the new name
193 mUniformLocations.push_back(std::make_pair(name, UNIFORM_NOT_QUERIED));
197 GLint Program::GetUniformLocation(uint32_t uniformIndex)
199 // debug check that index is within name cache
200 DALI_ASSERT_DEBUG(mUniformLocations.size() > uniformIndex);
202 // check if we have already queried the location of the uniform
203 GLint location = mUniformLocations[uniformIndex].second;
205 if(location == UNIFORM_NOT_QUERIED)
207 location = CHECK_GL(mGlAbstraction, mGlAbstraction.GetUniformLocation(mProgramId, mUniformLocations[uniformIndex].first.GetCString()));
209 mUniformLocations[uniformIndex].second = location;
210 LOG_GL("GetUniformLocation(program=%d,%s) = %d\n", mProgramId, mUniformLocations[uniformIndex].first.GetCString(), mUniformLocations[uniformIndex].second);
219 * This struct is used to record the position of a uniform declaration
220 * within the fragment shader source code.
222 struct LocationPosition
224 GLint uniformLocation; ///< The location of the uniform (used as an identifier)
225 int32_t position; ///< the position of the uniform declaration
226 LocationPosition(GLint uniformLocation, int32_t position)
227 : uniformLocation(uniformLocation),
233 bool sortByPosition(LocationPosition a, LocationPosition b)
235 return a.position < b.position;
238 const char* const DELIMITERS = " \t\n";
242 const char* const mString;
243 const uint32_t mLength;
245 template<uint32_t kLength>
246 constexpr StringSize(const char (&string)[kLength])
248 mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
252 operator const char*() const
258 bool operator==(const StringSize& lhs, const char* rhs)
260 return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
263 constexpr StringSize UNIFORM{"uniform"};
264 constexpr StringSize SAMPLER_PREFIX{"sampler"};
265 constexpr StringSize SAMPLER_TYPES[] = {
270 constexpr auto END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
274 void Program::GetActiveSamplerUniforms()
276 GLint numberOfActiveUniforms = -1;
277 GLint uniformMaxNameLength = -1;
279 mGlAbstraction.GetProgramiv(mProgramId, GL_ACTIVE_UNIFORMS, &numberOfActiveUniforms);
280 mGlAbstraction.GetProgramiv(mProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength);
282 std::vector<std::string> samplerNames;
283 std::vector<char> name(uniformMaxNameLength + 1); // Allow for null terminator
284 std::vector<LocationPosition> samplerUniformLocations;
289 GLenum type = GL_ZERO;
291 for(int i = 0; i < numberOfActiveUniforms; ++i)
293 mGlAbstraction.GetActiveUniform(mProgramId, static_cast<GLuint>(i), uniformMaxNameLength, &nameLength, &number, &type, name.data());
295 if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES)
297 GLuint location = mGlAbstraction.GetUniformLocation(mProgramId, name.data());
298 samplerNames.push_back(name.data());
299 samplerUniformLocations.push_back(LocationPosition(location, -1));
304 //Determine declaration order of each sampler
305 char* fragShader = strdup(mProgramData->GetFragmentShader());
306 char* uniform = strstr(fragShader, UNIFORM);
307 int samplerPosition = 0;
310 char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
312 char* nextPtr = nullptr;
313 char* token = strtok_r(outerToken, DELIMITERS, &nextPtr);
316 if(SAMPLER_PREFIX == token)
318 token += SAMPLER_PREFIX.mLength;
319 if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
322 token = strtok_r(nullptr, DELIMITERS, &nextPtr);
323 for(uint32_t i = 0; i < static_cast<uint32_t>(samplerUniformLocations.size()); ++i)
325 if(samplerUniformLocations[i].position == -1 &&
326 strncmp(token, samplerNames[i].c_str(), samplerNames[i].size()) == 0)
328 samplerUniformLocations[i].position = samplerPosition++;
336 DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
342 token = strtok_r(nullptr, DELIMITERS, &nextPtr);
345 uniform = strstr(uniform, UNIFORM);
350 // Re-order according to declaration order in the fragment source.
351 uint32_t samplerUniformCount = static_cast<uint32_t>(samplerUniformLocations.size());
352 if(samplerUniformCount > 1)
354 std::sort(samplerUniformLocations.begin(), samplerUniformLocations.end(), sortByPosition);
357 mSamplerUniformLocations.resize(samplerUniformCount);
358 for(uint32_t i = 0; i < samplerUniformCount; ++i)
360 mSamplerUniformLocations[i] = samplerUniformLocations[i].uniformLocation;
364 bool Program::GetSamplerUniformLocation(uint32_t index, GLint& location)
367 if(index < mSamplerUniformLocations.size())
369 location = mSamplerUniformLocations[index];
375 uint32_t Program::GetActiveSamplerCount() const
377 return static_cast<uint32_t>(mSamplerUniformLocations.size());
380 void Program::SetUniform1i(GLint location, GLint value0)
382 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
384 if(UNIFORM_UNKNOWN == location)
386 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
387 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
388 // specified uniform variable will not be changed.following opengl silently do nothing
392 // check if uniform location fits the cache
393 if(location >= MAX_UNIFORM_CACHE_SIZE)
395 // not cached, make the gl call
396 LOG_GL("Uniform1i(%d,%d)\n", location, value0);
397 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform1i(location, value0));
401 // check if the value is different from what's already been set
402 if(value0 != mUniformCacheInt[location])
405 LOG_GL("Uniform1i(%d,%d)\n", location, value0);
406 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform1i(location, value0));
408 mUniformCacheInt[location] = value0;
413 void Program::SetUniform4i(GLint location, GLint value0, GLint value1, GLint value2, GLint value3)
415 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
417 if(UNIFORM_UNKNOWN == location)
419 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
420 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
421 // specified uniform variable will not be changed.following opengl silently do nothing
425 // Not caching these as based on current analysis this is not called that often by our shaders
426 LOG_GL("Uniform4i(%d,%d,%d,%d,%d)\n", location, value0, value1, value2, value3);
427 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform4i(location, value0, value1, value2, value3));
430 void Program::SetUniform1f(GLint location, GLfloat value0)
432 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
434 if(UNIFORM_UNKNOWN == location)
436 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
437 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
438 // specified uniform variable will not be changed.following opengl silently do nothing
442 // check if uniform location fits the cache
443 if(location >= MAX_UNIFORM_CACHE_SIZE)
445 // not cached, make the gl call
446 LOG_GL("Uniform1f(%d,%f)\n", location, value0);
447 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform1f(location, value0));
451 // check if the same value has already been set, reset if it is different
452 if((fabsf(value0 - mUniformCacheFloat[location]) >= Math::MACHINE_EPSILON_1))
455 LOG_GL("Uniform1f(%d,%f)\n", location, value0);
456 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform1f(location, value0));
459 mUniformCacheFloat[location] = value0;
464 void Program::SetUniform2f(GLint location, GLfloat value0, GLfloat value1)
466 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
468 if(UNIFORM_UNKNOWN == location)
470 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
471 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
472 // specified uniform variable will not be changed.following opengl silently do nothing
476 // check if uniform location fits the cache
477 if(location >= MAX_UNIFORM_CACHE_SIZE)
479 // not cached, make the gl call
480 LOG_GL("Uniform2f(%d,%f,%f)\n", location, value0, value1);
481 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform2f(location, value0, value1));
485 // check if the same value has already been set, reset if it is different
486 if((fabsf(value0 - mUniformCacheFloat2[location][0]) >= Math::MACHINE_EPSILON_1) ||
487 (fabsf(value1 - mUniformCacheFloat2[location][1]) >= Math::MACHINE_EPSILON_1))
490 LOG_GL("Uniform2f(%d,%f,%f)\n", location, value0, value1);
491 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform2f(location, value0, value1));
494 mUniformCacheFloat2[location][0] = value0;
495 mUniformCacheFloat2[location][1] = value1;
500 void Program::SetSizeUniform3f(GLint location, GLfloat value0, GLfloat value1, GLfloat value2)
502 if((fabsf(value0 - mSizeUniformCache.x) >= Math::MACHINE_EPSILON_1) ||
503 (fabsf(value1 - mSizeUniformCache.y) >= Math::MACHINE_EPSILON_1) ||
504 (fabsf(value2 - mSizeUniformCache.z) >= Math::MACHINE_EPSILON_1))
506 mSizeUniformCache.x = value0;
507 mSizeUniformCache.y = value1;
508 mSizeUniformCache.z = value2;
509 SetUniform3f(location, value0, value1, value2);
513 void Program::SetUniform3f(GLint location, GLfloat value0, GLfloat value1, GLfloat value2)
515 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
517 if(UNIFORM_UNKNOWN == location)
519 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
520 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
521 // specified uniform variable will not be changed.following opengl silently do nothing
525 // Not caching these as based on current analysis this is not called that often by our shaders
526 LOG_GL("Uniform3f(%d,%f,%f,%f)\n", location, value0, value1, value2);
527 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform3f(location, value0, value1, value2));
530 void Program::SetUniform4f(GLint location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3)
532 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
534 if(UNIFORM_UNKNOWN == location)
536 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
537 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
538 // specified uniform variable will not be changed.following opengl silently do nothing
542 // check if uniform location fits the cache
543 if(location >= MAX_UNIFORM_CACHE_SIZE)
545 // not cached, make the gl call
546 LOG_GL("Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3);
547 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform4f(location, value0, value1, value2, value3));
551 // check if the same value has already been set, reset if any component is different
552 // checking index 3 first because we're often animating alpha (rgba)
553 if((fabsf(value3 - mUniformCacheFloat4[location][3]) >= Math::MACHINE_EPSILON_1) ||
554 (fabsf(value0 - mUniformCacheFloat4[location][0]) >= Math::MACHINE_EPSILON_1) ||
555 (fabsf(value1 - mUniformCacheFloat4[location][1]) >= Math::MACHINE_EPSILON_1) ||
556 (fabsf(value2 - mUniformCacheFloat4[location][2]) >= Math::MACHINE_EPSILON_1))
559 LOG_GL("Uniform4f(%d,%f,%f,%f,%f)\n", location, value0, value1, value2, value3);
560 CHECK_GL(mGlAbstraction, mGlAbstraction.Uniform4f(location, value0, value1, value2, value3));
562 mUniformCacheFloat4[location][0] = value0;
563 mUniformCacheFloat4[location][1] = value1;
564 mUniformCacheFloat4[location][2] = value2;
565 mUniformCacheFloat4[location][3] = value3;
570 void Program::SetUniformMatrix4fv(GLint location, GLsizei count, const GLfloat* value)
572 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
574 if(UNIFORM_UNKNOWN == location)
576 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
577 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
578 // specified uniform variable will not be changed.following opengl silently do nothing
582 // Not caching these calls. Based on current analysis this is called very often
583 // but with different values (we're using this for MVP matrices)
584 // NOTE! we never want driver or GPU to transpose
585 LOG_GL("UniformMatrix4fv(%d,%d,GL_FALSE,%x)\n", location, count, value);
586 CHECK_GL(mGlAbstraction, mGlAbstraction.UniformMatrix4fv(location, count, GL_FALSE, value));
589 void Program::SetUniformMatrix3fv(GLint location, GLsizei count, const GLfloat* value)
591 DALI_ASSERT_DEBUG(IsUsed()); // should not call this if this program is not used
593 if(UNIFORM_UNKNOWN == location)
595 // From http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml : Notes
596 // If location is equal to UNIFORM_UNKNOWN, the data passed in will be silently ignored and the
597 // specified uniform variable will not be changed.following opengl silently do nothing
601 // Not caching these calls. Based on current analysis this is called very often
602 // but with different values (we're using this for MVP matrices)
603 // NOTE! we never want driver or GPU to transpose
604 LOG_GL("UniformMatrix3fv(%d,%d,GL_FALSE,%x)\n", location, count, value);
605 CHECK_GL(mGlAbstraction, mGlAbstraction.UniformMatrix3fv(location, count, GL_FALSE, value));
608 void Program::GlContextCreated()
612 void Program::GlContextDestroyed()
616 mFragmentShaderId = 0;
619 ResetAttribsUniformCache();
622 bool Program::ModifiesGeometry()
624 return mModifiesGeometry;
627 Program::Program(ProgramCache& cache, Internal::ShaderDataPtr shaderData, bool modifiesGeometry)
629 mGlAbstraction(mCache.GetGlAbstraction()),
630 mProjectionMatrix(nullptr),
631 mViewMatrix(nullptr),
634 mFragmentShaderId(0),
636 mProgramData(shaderData),
637 mModifiesGeometry(modifiesGeometry)
639 // reserve space for standard attributes
640 mAttributeLocations.reserve(ATTRIB_TYPE_LAST);
641 for(uint32_t i = 0; i < ATTRIB_TYPE_LAST; ++i)
643 RegisterCustomAttribute(ConstString(gStdAttribs[i]));
646 // reserve space for standard uniforms
647 mUniformLocations.reserve(UNIFORM_TYPE_LAST);
648 // reset built in uniform names in cache
649 for(uint32_t i = 0; i < UNIFORM_TYPE_LAST; ++i)
651 RegisterUniform(ConstString(gStdUniforms[i]));
655 ResetAttribsUniformCache();
665 DALI_ASSERT_ALWAYS(nullptr != mProgramData.Get() && "Program data is not initialized");
666 DALI_ASSERT_DEBUG(mProgramId == 0 && "mProgramId != 0, so about to leak a GL resource by overwriting it.");
668 LOG_GL("CreateProgram()\n");
669 mProgramId = CHECK_GL(mGlAbstraction, mGlAbstraction.CreateProgram());
671 GLint linked = GL_FALSE;
673 const bool binariesSupported = mCache.IsBinarySupported();
675 // if shader binaries are supported and ShaderData contains compiled bytecode?
676 if(binariesSupported && mProgramData->HasBinary())
678 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Using Compiled Shader, Size = %d\n", mProgramData->GetBufferSize());
680 CHECK_GL(mGlAbstraction, mGlAbstraction.ProgramBinary(mProgramId, mCache.ProgramBinaryFormat(), mProgramData->GetBufferData(), static_cast<GLsizei>(mProgramData->GetBufferSize()))); // truncated
682 CHECK_GL(mGlAbstraction, mGlAbstraction.ValidateProgram(mProgramId));
685 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_VALIDATE_STATUS, &success));
687 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ValidateProgram Status = %d\n", success);
689 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_LINK_STATUS, &linked));
691 if(GL_FALSE == linked)
693 DALI_LOG_ERROR("Failed to load program binary \n");
696 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &nLength));
699 Dali::Vector<char> szLog;
700 szLog.Reserve(nLength); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
701 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramInfoLog(mProgramId, nLength, &nLength, szLog.Begin()));
702 DALI_LOG_ERROR("Program Link Error: %s\n", szLog.Begin());
708 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Reused binary.\n");
712 // Fall back to compiling and linking the vertex and fragment sources
713 if(GL_FALSE == linked)
715 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - Runtime compilation\n");
716 if(CompileShader(GL_VERTEX_SHADER, mVertexShaderId, mProgramData->GetVertexShader()))
718 if(CompileShader(GL_FRAGMENT_SHADER, mFragmentShaderId, mProgramData->GetFragmentShader()))
722 if(binariesSupported && mLinked)
724 GLint binaryLength = 0;
726 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Compiled and linked.\n\nVS:\n%s\nFS:\n%s\n", mProgramData->GetVertexShader(), mProgramData->GetFragmentShader());
728 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength));
729 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
732 // Allocate space for the bytecode in ShaderData
733 mProgramData->AllocateBuffer(binaryLength);
734 // Copy the bytecode to ShaderData
735 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, nullptr, &binaryFormat, mProgramData->GetBufferData()));
736 mCache.StoreBinary(mProgramData);
737 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Saved binary.\n");
744 GetActiveSamplerUniforms();
750 void Program::Unload()
754 if(this == mCache.GetCurrentProgram())
756 CHECK_GL(mGlAbstraction, mGlAbstraction.UseProgram(0));
758 mCache.SetCurrentProgram(nullptr);
763 LOG_GL("DeleteProgram(%d)\n", mProgramId);
764 CHECK_GL(mGlAbstraction, mGlAbstraction.DeleteProgram(mProgramId));
771 bool Program::CompileShader(GLenum shaderType, GLuint& shaderId, const char* src)
775 LOG_GL("CreateShader(%d)\n", shaderType);
776 shaderId = CHECK_GL(mGlAbstraction, mGlAbstraction.CreateShader(shaderType));
777 LOG_GL("AttachShader(%d,%d)\n", mProgramId, shaderId);
778 CHECK_GL(mGlAbstraction, mGlAbstraction.AttachShader(mProgramId, shaderId));
781 LOG_GL("ShaderSource(%d)\n", shaderId);
782 CHECK_GL(mGlAbstraction, mGlAbstraction.ShaderSource(shaderId, 1, &src, nullptr));
784 LOG_GL("CompileShader(%d)\n", shaderId);
785 CHECK_GL(mGlAbstraction, mGlAbstraction.CompileShader(shaderId));
788 LOG_GL("GetShaderiv(%d)\n", shaderId);
789 CHECK_GL(mGlAbstraction, mGlAbstraction.GetShaderiv(shaderId, GL_COMPILE_STATUS, &compiled));
791 if(compiled == GL_FALSE)
793 DALI_LOG_ERROR("Failed to compile shader\n");
794 LogWithLineNumbers(src);
797 mGlAbstraction.GetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &nLength);
800 Dali::Vector<char> szLog;
801 szLog.Reserve(nLength); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
802 mGlAbstraction.GetShaderInfoLog(shaderId, nLength, &nLength, szLog.Begin());
803 DALI_LOG_ERROR("Shader Compiler Error: %s\n", szLog.Begin());
806 DALI_ASSERT_ALWAYS(0 && "Shader compilation failure");
809 return compiled != 0;
814 LOG_GL("LinkProgram(%d)\n", mProgramId);
815 CHECK_GL(mGlAbstraction, mGlAbstraction.LinkProgram(mProgramId));
818 LOG_GL("GetProgramiv(%d)\n", mProgramId);
819 CHECK_GL(mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_LINK_STATUS, &linked));
821 if(linked == GL_FALSE)
823 DALI_LOG_ERROR("Shader failed to link \n");
826 mGlAbstraction.GetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &nLength);
829 Dali::Vector<char> szLog;
830 szLog.Reserve(nLength); // Don't call Resize as we don't want to initialise the data, just reserve a buffer
831 mGlAbstraction.GetProgramInfoLog(mProgramId, nLength, &nLength, szLog.Begin());
832 DALI_LOG_ERROR("Shader Link Error: %s\n", szLog.Begin());
835 DALI_ASSERT_ALWAYS(0 && "Shader linking failure");
838 mLinked = linked != GL_FALSE;
841 void Program::FreeShaders()
845 LOG_GL("DeleteShader(%d)\n", mVertexShaderId);
846 CHECK_GL(mGlAbstraction, mGlAbstraction.DetachShader(mProgramId, mVertexShaderId));
847 CHECK_GL(mGlAbstraction, mGlAbstraction.DeleteShader(mVertexShaderId));
851 if(mFragmentShaderId)
853 LOG_GL("DeleteShader(%d)\n", mFragmentShaderId);
854 CHECK_GL(mGlAbstraction, mGlAbstraction.DetachShader(mProgramId, mFragmentShaderId));
855 CHECK_GL(mGlAbstraction, mGlAbstraction.DeleteShader(mFragmentShaderId));
856 mFragmentShaderId = 0;
860 void Program::ResetAttribsUniformCache()
862 // reset attribute locations
863 for(uint32_t i = 0; i < mAttributeLocations.size(); ++i)
865 mAttributeLocations[i].second = ATTRIB_UNKNOWN;
868 // reset all gl uniform locations
869 for(uint32_t i = 0; i < mUniformLocations.size(); ++i)
871 // reset gl program locations and names
872 mUniformLocations[i].second = UNIFORM_NOT_QUERIED;
875 mSamplerUniformLocations.clear();
877 // reset uniform caches
878 mSizeUniformCache.x = mSizeUniformCache.y = mSizeUniformCache.z = 0.f;
880 for(uint32_t i = 0; i < MAX_UNIFORM_CACHE_SIZE; ++i)
882 // GL initializes uniforms to 0
883 mUniformCacheInt[i] = 0;
884 mUniformCacheFloat[i] = 0.0f;
885 mUniformCacheFloat2[i][0] = 0.0f;
886 mUniformCacheFloat2[i][1] = 0.0f;
887 mUniformCacheFloat4[i][0] = 0.0f;
888 mUniformCacheFloat4[i][1] = 0.0f;
889 mUniformCacheFloat4[i][2] = 0.0f;
890 mUniformCacheFloat4[i][3] = 0.0f;
894 } // namespace Internal