void OGL4ShaderProgram::CollectUniformBlocks() { GLint count = 0; glGetProgramiv(m_program, GL_ACTIVE_UNIFORM_BLOCKS, &count); for(int i = 0; i < count; ++i) { char szName[1024]; glGetActiveUniformBlockName(m_program, i, 1024, 0, szName); GLint bytes = 0; glGetActiveUniformBlockiv(m_program, i, GL_UNIFORM_BLOCK_DATA_SIZE, &bytes); OGL4BufferPtr pBuffer = std::make_shared<OGL4Buffer>(); if(pBuffer->Create(BT_CONSTANT_BUFFER, bytes, nullptr, true) == false) { pBuffer->Release(); pBuffer.reset(); continue; } UniformBlock block; block.index = i; block.name = szName; block.pBuffer = pBuffer; m_uniformBlocks.push_back(block); } }
static void CopyShaderState_UniformBlocks(GLuint newProgID, GLuint oldProgID) { if (!GLEW_ARB_uniform_buffer_object) return; GLsizei numUniformBlocks, maxNameLength; glGetProgramiv(oldProgID, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); glGetProgramiv(oldProgID, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxNameLength); if (maxNameLength <= 0) return; std::string name(maxNameLength, 0); for (int i = 0; i < numUniformBlocks; ++i) { GLsizei nameLength = 0; glGetActiveUniformBlockName(oldProgID, i, maxNameLength, &nameLength, &name[0]); name[maxNameLength - 1] = 0; if (nameLength == 0) continue; GLuint oldLoc = glGetUniformBlockIndex(oldProgID, &name[0]); GLuint newLoc = glGetUniformBlockIndex(newProgID, &name[0]); if (oldLoc == GL_INVALID_INDEX || newLoc == GL_INVALID_INDEX) continue; GLint value; glGetActiveUniformBlockiv(oldProgID, oldLoc, GL_UNIFORM_BLOCK_BINDING, &value); glUniformBlockBinding(newProgID, newLoc, value); } }
void RendererBasePimpl::InitDomainUniformBufferDecl(ShaderProgram * resource, unsigned int domain, GLuint program) { if (glGetActiveUniformBlockiv) { char uniformblock_name[1000]; GLint name_length; GLint block_binding; GLint block_data_size; GLint block_active_uniforms; GLint uniformblock_count; GLint referenced_by_vertex_shader; GLint referenced_by_geometry_shader; GLint referenced_by_fragment_shader; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &uniformblock_count); for (int i = 0; i < uniformblock_count; ++i) { glGetActiveUniformBlockName(program, i, 1000, &name_length, uniformblock_name); GLint params; glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_BINDING, &block_binding); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_DATA_SIZE, &block_data_size); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_NAME_LENGTH, ¶ms); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &block_active_uniforms); std::vector<GLuint> uniform_indices(block_active_uniforms, 0); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, reinterpret_cast<GLint*>(&uniform_indices[0])); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &referenced_by_vertex_shader); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &referenced_by_fragment_shader); std::vector<GLuint> uniform_offsets(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_OFFSET, reinterpret_cast<GLint*>(&uniform_offsets[0])); std::vector<GLuint> uniform_arraystrides(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_ARRAY_STRIDE, reinterpret_cast<GLint*>(&uniform_arraystrides[0])); std::vector<GLuint> uniform_matrixstrides(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_MATRIX_STRIDE, reinterpret_cast<GLint*>(&uniform_matrixstrides[0])); std::vector<GLuint> uniform_rowmajor(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_IS_ROW_MAJOR, reinterpret_cast<GLint*>(&uniform_rowmajor[0])); std::cout << "UniformBlock: " << uniformblock_name << "[" << i << "]" << std::endl; std::cout << " Size: " << block_data_size << std::endl; std::cout << " UniformCount: " << block_active_uniforms << std::endl; for (unsigned int p = 0; p < uniform_indices.size(); ++p) { std::cout << " Param: " << uniform_indices[p] << std::endl; std::cout << " Offset: " << uniform_offsets[p] << std::endl; std::cout << " ArrayStrides: " << uniform_arraystrides[p] << std::endl; std::cout << " MatrixStrides: " << uniform_matrixstrides[p] << std::endl; std::cout << " RowMajor: " << uniform_rowmajor[p] << std::endl; } //std::cout << " Location: " << glGetUniformLocation(pimpl->combined, uniformblock_name) << std::endl; } } }
bool effect::create() { _program = createProgram(&_shaders[0], _shaders.size()); if (!_program) return false; std::vector<std::string> uniformNames; GLint numUniforms, maxLength; glGetProgramiv(_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength); glGetProgramiv(_program, GL_ACTIVE_UNIFORMS, &numUniforms); char* buf = new char[maxLength]; for (int i = 0; i < numUniforms; ++i) { GLsizei size; glGetActiveUniformName(_program, i, maxLength, &size, buf); std::string name(buf); if (uniformNames.size() > 0 && uniformNames[i - 1] == name) break; else uniformNames.push_back(name); } delete[] buf; for (int i = 0; i < uniformNames.size(); ++i) { GLint uniformLocation = glGetUniformLocation(_program, uniformNames[i].c_str()); if (uniformLocation != -1) _uniforms[uniformNames[i]] = uniformLocation; } std::vector<std::string> uniformBlockNames; glGetProgramiv(_program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxLength); glGetProgramiv(_program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniforms); buf = new char[maxLength]; for (int i = 0; i < numUniforms; ++i) { GLsizei size; glGetActiveUniformBlockName(_program, i, maxLength, &size, buf); std::string name(buf); if (uniformBlockNames.size() > 0 && uniformBlockNames[i - 1] == name) break; else uniformBlockNames.push_back(name); } delete[] buf; for (int i = 0; i < uniformBlockNames.size(); ++i) { GLuint blockIndex = glGetUniformBlockIndex(_program, uniformBlockNames[i].c_str()); glUniformBlockBinding(_program, blockIndex, i); _blockUniforms[uniformBlockNames[i]] = i; } return true; }
std::string UniformBlock::getName() const { if (m_identity.isName()) return m_identity.name(); GLint length = getActive(GL_UNIFORM_BLOCK_NAME_LENGTH); std::vector<char> name(length); glGetActiveUniformBlockName(m_program->id(), blockIndex(), length, nullptr, name.data()); return std::string(name.data(), length); }
UniformBlockList Program::getActiveUniformBlocks() const { UniformBlockList ul; // Get the number of active attributes GLint num_uniform_blocks; getProgram(Program::ActiveUniformBlocks, &num_uniform_blocks); // GL: 3.1 // The the maximum size of the attribe name GLsizei max_name_length; getProgram(Program::ActiveUniformBlockMaxNameLength, &max_name_length); DEBUG_M("Num unifrom blocks %d", num_uniform_blocks); for(int ubo_index = 0; ubo_index < num_uniform_blocks; ubo_index++) { UniformBlockInfo ubi; getActiveUniformBlock( ubo_index, Program::UniformBlockActiveUniforms, &ubi.num_active_uniforms); GLsizei name_length; getActiveUniformBlock( ubo_index, Program::UniformBlockNameLength, &name_length); GLsizei written_name_length; std::vector<GLchar> block_name(name_length); glGetActiveUniformBlockName( getProgramId(), ubo_index, block_name.size(), &written_name_length, &block_name[0] ); ubi.name = std::string(&block_name[0], written_name_length); getActiveUniformBlock( ubo_index, Program::UniformBlockBinding, &ubi.binding); std::vector<GLint> active_uniforms(ubi.num_active_uniforms); getActiveUniformBlock( ubo_index, Program::UniformBlockActiveUniformIndices, &active_uniforms[0]); ul.push_back(ubi); } return ul; }
/* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */ static jstring android_glGetActiveUniformBlockName_II (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex) { GLint len = 0; glGetActiveUniformBlockiv((GLuint)program, (GLuint)uniformBlockIndex, GL_UNIFORM_BLOCK_NAME_LENGTH, &len); GLchar* name = (GLchar*)malloc(len); glGetActiveUniformBlockName((GLuint)program, (GLuint)uniformBlockIndex, len, NULL, name); jstring result = _env->NewStringUTF(name); free(name); return result; }
std::vector<std::string> GLshader::block_names_get() { GLint numBlocks; GLint nameLen; std::vector <std::string> name_list; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numBlocks); name_list.reserve(numBlocks); for (int blockIx = 0; blockIx < numBlocks; blockIx++) { glGetActiveUniformBlockiv(program, blockIx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen); std::vector <GLchar> name; name.resize(nameLen); glGetActiveUniformBlockName(program, blockIx, nameLen, NULL, &name[0]); name_list.push_back(std::string()); name_list.back().assign(name.begin(), name.end() - 1); //Remove the null terminator. } return name_list; }
/* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */ static void android_glGetActiveUniformBlockName_IILjava_nio_Buffer_2Ljava_nio_Buffer_2 (JNIEnv* _env, jobject _this, jint program, jint uniformBlockIndex, jobject length_buf, jobject uniformBlockName_buf) { jint _exception = 0; const char* _exceptionType; const char* _exceptionMessage; jarray _lengthArray = (jarray)0; jint _lengthBufferOffset = (jint)0; GLsizei* _length = (GLsizei*)0; jint _lengthRemaining; jarray _nameArray = (jarray)0; jint _nameBufferOffset = (jint)0; GLchar* _name = (GLchar*)0; jint _nameRemaining; _length = (GLsizei*)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); if (_length == NULL) { GLsizei* _lengthBase = (GLsizei*)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean*)0); _length = (GLsizei*)(_lengthBase + _lengthBufferOffset); } _name = (GLchar*)getPointer(_env, uniformBlockName_buf, &_nameArray, &_nameRemaining, &_nameBufferOffset); if (_name == NULL) { GLchar* _nameBase = (GLchar*)_env->GetPrimitiveArrayCritical(_nameArray, (jboolean*)0); _name = (GLchar*)(_nameBase + _nameBufferOffset); } glGetActiveUniformBlockName( (GLuint)program, (GLuint)uniformBlockIndex, (GLsizei)_nameRemaining, _length, _name ); if (_nameArray) { releasePointer(_env, _nameArray, _name, JNI_TRUE); } if (_lengthArray) { releasePointer(_env, _lengthArray, _length, JNI_TRUE); } }
void GLshader::print_block_names() { GLint numBlocks; GLint nameLen; GLint block_binding; GLint block_size; GLint ref_vertex; GLint ref_fragment; std::vector <std::string> name_list; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numBlocks); name_list.reserve(numBlocks); std::cout << "Found " << numBlocks << " block(s) in shader" << std::endl; for (int blockIx = 0; blockIx < numBlocks; blockIx++) { glGetActiveUniformBlockiv(program, blockIx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen); std::vector <GLchar> name; name.resize(nameLen); glGetActiveUniformBlockName(program, blockIx, nameLen, NULL, &name[0]); name_list.push_back(std::string()); name_list.back().assign(name.begin(), name.end() - 1); //Remove the null terminator. glGetActiveUniformBlockiv(program, blockIx, GL_UNIFORM_BLOCK_BINDING, &block_binding); glGetActiveUniformBlockiv(program, blockIx, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size); glGetActiveUniformBlockiv(program, blockIx, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &ref_vertex); glGetActiveUniformBlockiv(program, blockIx, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &ref_fragment); std::cout << "Name: " << name.data() << " block binding: " << block_binding << " block size: " << block_size << std::endl; std::cout << "ref vertex: " << ref_vertex << ", ref fragment: " << ref_fragment << std::endl; } for (unsigned int il = 0; il < name_list.size(); il++) { std::cout << "Block name: " << name_list[il] << ", index: " << get_block_index(name_list[il]) << std::endl; } }
bool ShaderProgram::Link() { Release(); if (!vertexShader_ || !pixelShader_ || !vertexShader_->GetGPUObjectName() || !pixelShader_->GetGPUObjectName()) return false; object_.name_ = glCreateProgram(); if (!object_.name_) { linkerOutput_ = "Could not create shader program"; return false; } glAttachShader(object_.name_, vertexShader_->GetGPUObjectName()); glAttachShader(object_.name_, pixelShader_->GetGPUObjectName()); glLinkProgram(object_.name_); int linked, length; glGetProgramiv(object_.name_, GL_LINK_STATUS, &linked); if (!linked) { glGetProgramiv(object_.name_, GL_INFO_LOG_LENGTH, &length); linkerOutput_.Resize((unsigned)length); int outLength; glGetProgramInfoLog(object_.name_, length, &outLength, &linkerOutput_[0]); glDeleteProgram(object_.name_); object_.name_ = 0; } else linkerOutput_.Clear(); if (!object_.name_) return false; const int MAX_NAME_LENGTH = 256; char nameBuffer[MAX_NAME_LENGTH]; int attributeCount, uniformCount, elementCount, nameLength; GLenum type; glUseProgram(object_.name_); // Check for vertex attributes glGetProgramiv(object_.name_, GL_ACTIVE_ATTRIBUTES, &attributeCount); for (int i = 0; i < attributeCount; ++i) { glGetActiveAttrib(object_.name_, i, (GLsizei)MAX_NAME_LENGTH, &nameLength, &elementCount, &type, nameBuffer); String name = String(nameBuffer, nameLength); VertexElementSemantic semantic = MAX_VERTEX_ELEMENT_SEMANTICS; unsigned char semanticIndex = 0; // Go in reverse order so that "binormal" is detected before "normal" for (unsigned j = MAX_VERTEX_ELEMENT_SEMANTICS - 1; j < MAX_VERTEX_ELEMENT_SEMANTICS; --j) { if (name.Contains(ShaderVariation::elementSemanticNames[j], false)) { semantic = (VertexElementSemantic)j; unsigned index = NumberPostfix(name); if (index != M_MAX_UNSIGNED) semanticIndex = (unsigned char)index; break; } } if (semantic == MAX_VERTEX_ELEMENT_SEMANTICS) { URHO3D_LOGWARNING("Found vertex attribute " + name + " with no known semantic in shader program " + vertexShader_->GetFullName() + " " + pixelShader_->GetFullName()); continue; } int location = glGetAttribLocation(object_.name_, name.CString()); vertexAttributes_[MakePair((unsigned char)semantic, semanticIndex)] = location; usedVertexAttributes_ |= (1u << location); } // Check for constant buffers #ifndef GL_ES_VERSION_2_0 HashMap<unsigned, unsigned> blockToBinding; if (Graphics::GetGL3Support()) { int numUniformBlocks = 0; glGetProgramiv(object_.name_, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); for (int i = 0; i < numUniformBlocks; ++i) { glGetActiveUniformBlockName(object_.name_, (GLuint)i, MAX_NAME_LENGTH, &nameLength, nameBuffer); String name(nameBuffer, (unsigned)nameLength); unsigned blockIndex = glGetUniformBlockIndex(object_.name_, name.CString()); unsigned group = M_MAX_UNSIGNED; // Try to recognize the use of the buffer from its name for (unsigned j = 0; j < MAX_SHADER_PARAMETER_GROUPS; ++j) { if (name.Contains(shaderParameterGroups[j], false)) { group = j; break; } } // If name is not recognized, search for a digit in the name and use that as the group index if (group == M_MAX_UNSIGNED) group = NumberPostfix(name); if (group >= MAX_SHADER_PARAMETER_GROUPS) { URHO3D_LOGWARNING("Skipping unrecognized uniform block " + name + " in shader program " + vertexShader_->GetFullName() + " " + pixelShader_->GetFullName()); continue; } // Find total constant buffer data size int dataSize; glGetActiveUniformBlockiv(object_.name_, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &dataSize); if (!dataSize) continue; unsigned bindingIndex = group; // Vertex shader constant buffer bindings occupy slots starting from zero to maximum supported, pixel shader bindings // from that point onward ShaderType shaderType = VS; if (name.Contains("PS", false)) { bindingIndex += MAX_SHADER_PARAMETER_GROUPS; shaderType = PS; } glUniformBlockBinding(object_.name_, blockIndex, bindingIndex); blockToBinding[blockIndex] = bindingIndex; constantBuffers_[bindingIndex] = graphics_->GetOrCreateConstantBuffer(shaderType, bindingIndex, (unsigned)dataSize); } } #endif // Check for shader parameters and texture units glGetProgramiv(object_.name_, GL_ACTIVE_UNIFORMS, &uniformCount); for (int i = 0; i < uniformCount; ++i) { glGetActiveUniform(object_.name_, (GLuint)i, MAX_NAME_LENGTH, nullptr, &elementCount, &type, nameBuffer); int location = glGetUniformLocation(object_.name_, nameBuffer); // Check for array index included in the name and strip it String name(nameBuffer); unsigned index = name.Find('['); if (index != String::NPOS) { // If not the first index, skip if (name.Find("[0]", index) == String::NPOS) continue; name = name.Substring(0, index); } if (name[0] == 'c') { // Store constant uniform String paramName = name.Substring(1); ShaderParameter parameter{paramName, type, location}; bool store = location >= 0; #ifndef GL_ES_VERSION_2_0 // If running OpenGL 3, the uniform may be inside a constant buffer if (parameter.location_ < 0 && Graphics::GetGL3Support()) { int blockIndex, blockOffset; glGetActiveUniformsiv(object_.name_, 1, (const GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &blockIndex); glGetActiveUniformsiv(object_.name_, 1, (const GLuint*)&i, GL_UNIFORM_OFFSET, &blockOffset); if (blockIndex >= 0) { parameter.offset_ = blockOffset; parameter.bufferPtr_ = constantBuffers_[blockToBinding[blockIndex]]; store = true; } } #endif if (store) shaderParameters_[StringHash(paramName)] = parameter; } else if (location >= 0 && name[0] == 's') { // Set the samplers here so that they do not have to be set later unsigned unit = graphics_->GetTextureUnit(name.Substring(1)); if (unit >= MAX_TEXTURE_UNITS) unit = NumberPostfix(name); if (unit < MAX_TEXTURE_UNITS) { useTextureUnits_[unit] = true; glUniform1iv(location, 1, reinterpret_cast<int*>(&unit)); } } } // Rehash the parameter & vertex attributes maps to ensure minimal load factor vertexAttributes_.Rehash(NextPowerOfTwo(vertexAttributes_.Size())); shaderParameters_.Rehash(NextPowerOfTwo(shaderParameters_.Size())); return true; }
/* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */ static void android_glGetActiveUniformBlockName_III_3II_3BI (JNIEnv* _env, jobject _this, jint program, jint uniformBlockIndex, int bufSize, jintArray length_ref, jint lengthOffset, jbyteArray name_ref, jint nameOffset) { jint _exception = 0; const char* _exceptionType; const char* _exceptionMessage; GLsizei* _length_base = (GLsizei*)0; jint _lengthRemaining; GLsizei* _length = (GLsizei*)0; GLchar* _name_base = (GLchar*)0; jint _nameRemaining; GLchar* _name = (GLchar*)0; if (!length_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "length == null"; goto exit; } if (lengthOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "lengthOffset < 0"; goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; _length_base = (GLsizei*)_env->GetIntArrayElements( length_ref, (jboolean*)0); _length = _length_base + lengthOffset; if (!name_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformBlockName == null"; goto exit; } if (nameOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformBlockNameOffset < 0"; goto exit; } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; _name_base = (GLchar*)_env->GetByteArrayElements( name_ref, (jboolean*)0); _name = _name_base + nameOffset; glGetActiveUniformBlockName( (GLuint)program, (GLuint)uniformBlockIndex, (GLsizei)bufSize, (GLsizei*)_length, (GLchar*)_name ); exit: if (_name_base) { _env->ReleaseByteArrayElements(name_ref, (jbyte*)_name_base, _exception ? JNI_ABORT: 0); } if (_length_base) { _env->ReleaseIntArrayElements(length_ref, (jint*)_length_base, _exception ? JNI_ABORT: 0); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } }
//--------------------------------------------------------------------- void GLSLESProgramManagerCommon::extractUniforms(GLuint programObject, const GpuConstantDefinitionMap* vertexConstantDefs, const GpuConstantDefinitionMap* fragmentConstantDefs, GLUniformReferenceList& list, GLUniformBufferList& sharedList) { // Scan through the active uniforms and add them to the reference list GLint uniformCount = 0; GLint maxLength = 0; char* uniformName = NULL; #define uniformLength 200 OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength)); // If the max length of active uniforms is 0, then there are 0 active. // There won't be any to extract so we can return. if(maxLength == 0) return; uniformName = new char[maxLength + 1]; GLUniformReference newGLUniformReference; // Get the number of active uniforms OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORMS, &uniformCount)); // Loop over each of the active uniforms, and add them to the reference container // only do this for user defined uniforms, ignore built in gl state uniforms for (GLuint index = 0; index < (GLuint)uniformCount; index++) { GLint arraySize = 0; GLenum glType = GL_NONE; OGRE_CHECK_GL_ERROR(glGetActiveUniform(programObject, index, maxLength, NULL, &arraySize, &glType, uniformName)); // Don't add built in uniforms newGLUniformReference.mLocation = glGetUniformLocation(programObject, uniformName); if (newGLUniformReference.mLocation >= 0) { // User defined uniform found, add it to the reference list String paramName = String( uniformName ); // If the uniform name has a "[" in it then its an array element uniform. String::size_type arrayStart = paramName.find("["); if (arrayStart != String::npos) { // If not the first array element then skip it and continue to the next uniform if (paramName.compare(arrayStart, paramName.size() - 1, "[0]") != 0) continue; paramName = paramName.substr(0, arrayStart); } // Find out which params object this comes from bool foundSource = completeParamSource(paramName, vertexConstantDefs, fragmentConstantDefs, newGLUniformReference); // Only add this parameter if we found the source if (foundSource) { assert(size_t (arraySize) == newGLUniformReference.mConstantDef->arraySize && "GL doesn't agree with our array size!"); list.push_back(newGLUniformReference); } // Don't bother adding individual array params, they will be // picked up in the 'parent' parameter can copied all at once // anyway, individual indexes are only needed for lookup from // user params } // end if } // end for if( uniformName != NULL ) { delete[] uniformName; } #if OGRE_NO_GLES3_SUPPORT == 0 // Now deal with uniform blocks GLint blockCount = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount)); for (int index = 0; index < blockCount; index++) { OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockName(programObject, index, uniformLength, NULL, uniformName)); GpuSharedParametersPtr blockSharedParams = GpuProgramManager::getSingleton().getSharedParameters(uniformName); GLint blockSize, blockBinding; OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize)); OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_BINDING, &blockBinding)); HardwareUniformBufferSharedPtr newUniformBuffer = HardwareBufferManager::getSingleton().createUniformBuffer(blockSize, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false, uniformName); GLES2HardwareUniformBuffer* hwGlBuffer = static_cast<GLES2HardwareUniformBuffer*>(newUniformBuffer.get()); hwGlBuffer->setGLBufferBinding(blockBinding); sharedList.push_back(newUniformBuffer); } #endif }
/** * Dump an uniform that belows to an uniform block. */ static void dumpUniformBlock(StateWriter &writer, GLint program, GLint size, GLenum type, const GLchar *name, GLuint index, GLuint block_index) { GLint offset = 0; GLint array_stride = 0; GLint matrix_stride = 0; GLint is_row_major = GL_FALSE; glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_OFFSET, &offset); glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_ARRAY_STRIDE, &array_stride); glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_MATRIX_STRIDE, &matrix_stride); glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_IS_ROW_MAJOR, &is_row_major); GLint slot = -1; glGetActiveUniformBlockiv(program, block_index, GL_UNIFORM_BLOCK_BINDING, &slot); if (slot == -1) { return; } AttribDesc desc(type, size, array_stride, matrix_stride, is_row_major); if (!desc) { return; } if (0) { GLint active_uniform_block_max_name_length = 0; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &active_uniform_block_max_name_length); GLchar* block_name = new GLchar[active_uniform_block_max_name_length]; GLint block_data_size = 0; glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_data_size); GLsizei length = 0; glGetActiveUniformBlockName(program, index, active_uniform_block_max_name_length, &length, block_name); std::cerr << "uniform `" << name << "`, size " << size << ", type " << enumToString(desc.type) << "\n" << " block " << block_index << ", name `" << block_name << "`, size " << block_data_size << "; binding " << slot << "; \n" << " offset " << offset << ", array stride " << array_stride << ", matrix stride " << matrix_stride << ", row_major " << is_row_major << "\n" ; delete [] block_name; } GLint ubo = 0; glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, slot, &ubo); GLint start = 0; glGetIntegeri_v(GL_UNIFORM_BUFFER_START, slot, &start); BufferMapping mapping; const GLbyte *raw_data = (const GLbyte *)mapping.map(GL_UNIFORM_BUFFER, ubo); if (raw_data) { std::string qualifiedName = resolveUniformName(name, size); dumpAttribArray(writer, qualifiedName, desc, raw_data + start + offset); } }
bool ShaderProgram::Link() { PROFILE(LinkShaderProgram); Release(); if (!graphics || !graphics->IsInitialized()) { LOGERROR("Can not link shader program without initialized Graphics subsystem"); return false; } if (!vs || !ps) { LOGERROR("Shader(s) are null, can not link shader program"); return false; } if (!vs->GLShader() || !ps->GLShader()) { LOGERROR("Shaders have not been compiled, can not link shader program"); return false; } const String& vsSourceCode = vs->Parent() ? vs->Parent()->SourceCode() : String::EMPTY; const String& psSourceCode = ps->Parent() ? ps->Parent()->SourceCode() : String::EMPTY; program = glCreateProgram(); if (!program) { LOGERROR("Could not create shader program"); return false; } glAttachShader(program, vs->GLShader()); glAttachShader(program, ps->GLShader()); glLinkProgram(program); int linked; glGetProgramiv(program, GL_LINK_STATUS, &linked); if (!linked) { int length, outLength; String errorString; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); errorString.Resize(length); glGetProgramInfoLog(program, length, &outLength, &errorString[0]); glDeleteProgram(program); program = 0; LOGERRORF("Could not link shaders %s: %s", FullName().CString(), errorString.CString()); return false; } LOGDEBUGF("Linked shaders %s", FullName().CString()); glUseProgram(program); char nameBuffer[MAX_NAME_LENGTH]; int numAttributes, numUniforms, numUniformBlocks, nameLength, numElements; GLenum type; attributes.Clear(); glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numAttributes); for (int i = 0; i < numAttributes; ++i) { glGetActiveAttrib(program, i, (GLsizei)MAX_NAME_LENGTH, &nameLength, &numElements, &type, nameBuffer); VertexAttribute newAttribute; newAttribute.name = String(nameBuffer, nameLength); newAttribute.semantic = SEM_POSITION; newAttribute.index = 0; for (size_t j = 0; elementSemanticNames[j]; ++j) { if (newAttribute.name.StartsWith(elementSemanticNames[j], false)) { int index = NumberPostfix(newAttribute.name); if (index >= 0) newAttribute.index = (unsigned char)index; break; } newAttribute.semantic = (ElementSemantic)(newAttribute.semantic + 1); } if (newAttribute.semantic == MAX_ELEMENT_SEMANTICS) { LOGWARNINGF("Found vertex attribute %s with no known semantic in shader program %s", newAttribute.name.CString(), FullName().CString()); continue; } newAttribute.location = glGetAttribLocation(program, newAttribute.name.CString()); attributes.Push(newAttribute); } glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms); int numTextures = 0; for (int i = 0; i < numUniforms; ++i) { glGetActiveUniform(program, i, MAX_NAME_LENGTH, &nameLength, &numElements, &type, nameBuffer); String name(nameBuffer, nameLength); if (type >= GL_SAMPLER_1D && type <= GL_SAMPLER_2D_SHADOW) { // Assign sampler uniforms to a texture unit according to the number appended to the sampler name int location = glGetUniformLocation(program, name.CString()); int unit = NumberPostfix(name); // If no unit number specified, assign in appearance order starting from unit 0 if (unit < 0) unit = numTextures; // Array samplers may have multiple elements, assign each sequentially if (numElements > 1) { Vector<int> units; for (int j = 0; j < numElements; ++j) units.Push(unit++); glUniform1iv(location, numElements, &units[0]); } else glUniform1iv(location, 1, &unit); numTextures += numElements; } } glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); for (int i = 0; i < numUniformBlocks; ++i) { glGetActiveUniformBlockName(program, i, (GLsizei)MAX_NAME_LENGTH, &nameLength, nameBuffer); // Determine whether uniform block belongs to vertex or pixel shader String name(nameBuffer, nameLength); bool foundVs = vsSourceCode.Contains(name); bool foundPs = psSourceCode.Contains(name); if (foundVs && foundPs) { LOGWARNINGF("Found uniform block %s in both vertex and pixel shader in shader program %s"); continue; } // Vertex shader constant buffer bindings occupy slots starting from zero to maximum supported, pixel shader bindings // from that point onward unsigned blockIndex = glGetUniformBlockIndex(program, name.CString()); int bindingIndex = NumberPostfix(name); // If no number postfix in the name, use the block index if (bindingIndex < 0) bindingIndex = blockIndex; if (foundPs) bindingIndex += (unsigned)graphics->NumVSConstantBuffers(); glUniformBlockBinding(program, blockIndex, bindingIndex); } return true; }
void VSShaderLib::addBlocks() { int count, dataSize, actualLen, activeUnif, maxUniLength; int uniType, uniSize, uniOffset, uniMatStride, uniArrayStride, auxSize; char *name, *name2; glGetProgramiv(pProgram, GL_ACTIVE_UNIFORM_BLOCKS, &count); for (int i = 0; i < count; ++i) { // Get buffers name UniformBlock block; glGetActiveUniformBlockiv(pProgram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &actualLen); name = (char *)malloc(sizeof(char) * actualLen); glGetActiveUniformBlockName(pProgram, i, actualLen, NULL, name); bool newBlock=true; if (spBlocks.count(name)) { newBlock = false; block = spBlocks[name]; } glGetActiveUniformBlockiv(pProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &dataSize); if (newBlock) { glGenBuffers(1, &block.buffer); glBindBuffer(GL_UNIFORM_BUFFER, block.buffer); glBufferData(GL_UNIFORM_BUFFER, dataSize, NULL, GL_DYNAMIC_DRAW); glUniformBlockBinding(pProgram, i, spBlockCount); glBindBufferRange(GL_UNIFORM_BUFFER, spBlockCount, block.buffer, 0, dataSize); } else { glBindBuffer(GL_UNIFORM_BUFFER, block.buffer); glUniformBlockBinding(pProgram, i, block.bindingIndex); } glGetActiveUniformBlockiv(pProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &activeUnif); unsigned int *indices; indices = (unsigned int *)malloc(sizeof(unsigned int) * activeUnif); glGetActiveUniformBlockiv(pProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, (int *)indices); glGetProgramiv(pProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLength); name2 = (char *)malloc(sizeof(char) * maxUniLength); for (int k = 0; k < activeUnif; ++k) { myBlockUniform bUni; GLenum type; glGetActiveUniform(pProgram, indices[k], maxUniLength, &actualLen, &uniSize, &type, name2); glGetActiveUniformsiv(pProgram, 1, &indices[k], GL_UNIFORM_TYPE, &uniType); glGetActiveUniformsiv(pProgram, 1, &indices[k], GL_UNIFORM_SIZE, &uniSize); glGetActiveUniformsiv(pProgram, 1, &indices[k], GL_UNIFORM_OFFSET, &uniOffset); glGetActiveUniformsiv(pProgram, 1, &indices[k], GL_UNIFORM_MATRIX_STRIDE, &uniMatStride); glGetActiveUniformsiv(pProgram, 1, &indices[k], GL_UNIFORM_ARRAY_STRIDE, &uniArrayStride); if (uniArrayStride > 0) auxSize = uniArrayStride * uniSize; else if (uniMatStride > 0) { switch (uniType) { case GL_FLOAT_MAT2: case GL_FLOAT_MAT2x3: case GL_FLOAT_MAT2x4: #ifndef __ANDROID_API__ case GL_DOUBLE_MAT2: case GL_DOUBLE_MAT2x3: case GL_DOUBLE_MAT2x4: auxSize = 2 * uniMatStride; break; #endif case GL_FLOAT_MAT3: case GL_FLOAT_MAT3x2: case GL_FLOAT_MAT3x4: #ifndef __ANDROID_API__ case GL_DOUBLE_MAT3: case GL_DOUBLE_MAT3x2: case GL_DOUBLE_MAT3x4: #endif auxSize = 3 * uniMatStride; break; case GL_FLOAT_MAT4: case GL_FLOAT_MAT4x2: case GL_FLOAT_MAT4x3: #ifndef __ANDROID_API__ case GL_DOUBLE_MAT4: case GL_DOUBLE_MAT4x2: case GL_DOUBLE_MAT4x3: #endif auxSize = 4 * uniMatStride; break; } } else auxSize = typeSize(uniType); bUni.offset = uniOffset; bUni.type = uniType; bUni.size = auxSize; bUni.arrayStride = uniArrayStride; block.uniformOffsets[name2] = bUni; } free(name2); if (newBlock) { block.size = dataSize; block.bindingIndex = spBlockCount; spBlockCount++; } spBlocks[name] = block; } }
//--------------------------------------------------------------------- void GLSLProgramManagerCommon::extractUniforms(GLuint programObject, const GpuConstantDefinitionMap* vertexConstantDefs, const GpuConstantDefinitionMap* geometryConstantDefs, const GpuConstantDefinitionMap* fragmentConstantDefs, const GpuConstantDefinitionMap* hullConstantDefs, const GpuConstantDefinitionMap* domainConstantDefs, const GpuConstantDefinitionMap* computeConstantDefs, GLUniformReferenceList& list, GLUniformBufferList& sharedList) { // Scan through the active uniforms and add them to the reference list GLint uniformCount = 0; #define uniformLength 200 // GLint uniformLength = 0; // glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformLength); char uniformName[uniformLength]; GLUniformReference newGLUniformReference; // Get the number of active uniforms OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORMS, &uniformCount)); // Loop over each of the active uniforms, and add them to the reference container // only do this for user defined uniforms, ignore built in gl state uniforms for (int index = 0; index < uniformCount; index++) { GLint arraySize; GLenum glType; OGRE_CHECK_GL_ERROR(glGetActiveUniform(programObject, index, uniformLength, NULL, &arraySize, &glType, uniformName)); // Don't add built in uniforms OGRE_CHECK_GL_ERROR(newGLUniformReference.mLocation = glGetUniformLocation(programObject, uniformName)); if (newGLUniformReference.mLocation >= 0) { // User defined uniform found, add it to the reference list String paramName = String( uniformName ); // Current ATI drivers (Catalyst 7.2 and earlier) and older NVidia drivers will include all array elements as uniforms but we only want the root array name and location // Also note that ATI Catalyst 6.8 to 7.2 there is a bug with glUniform that does not allow you to update a uniform array past the first uniform array element // ie you can't start updating an array starting at element 1, must always be element 0. // If the uniform name has a "[" in it then its an array element uniform. String::size_type arrayStart = paramName.find("["); if (arrayStart != String::npos) { // if not the first array element then skip it and continue to the next uniform if (paramName.compare(arrayStart, paramName.size() - 1, "[0]") != 0) continue; paramName = paramName.substr(0, arrayStart); } // Find out which params object this comes from bool foundSource = completeParamSource(paramName, vertexConstantDefs, geometryConstantDefs, fragmentConstantDefs, hullConstantDefs, domainConstantDefs, computeConstantDefs, newGLUniformReference); // Only add this parameter if we found the source if (foundSource) { assert(size_t (arraySize) == newGLUniformReference.mConstantDef->arraySize && "GL doesn't agree with our array size!"); list.push_back(newGLUniformReference); } // Don't bother adding individual array params, they will be // picked up in the 'parent' parameter can copied all at once // anyway, individual indexes are only needed for lookup from // user params } // end if } // end for // Now deal with uniform blocks GLint blockCount = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount)); for (int index = 0; index < blockCount; index++) { OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockName(programObject, index, uniformLength, NULL, uniformName)); GpuSharedParametersPtr blockSharedParams = GpuProgramManager::getSingleton().getSharedParameters(uniformName); GLint blockSize, blockBinding; OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize)); OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_BINDING, &blockBinding)); HardwareUniformBufferSharedPtr newUniformBuffer = HardwareBufferManager::getSingleton().createUniformBuffer(blockSize, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false, uniformName); GL3PlusHardwareUniformBuffer* hwGlBuffer = static_cast<GL3PlusHardwareUniformBuffer*>(newUniformBuffer.get()); hwGlBuffer->setGLBufferBinding(blockBinding); sharedList.push_back(newUniformBuffer); } }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL31_nglGetActiveUniformBlockName(JNIEnv *env, jclass clazz, jint program, jint uniformBlockIndex, jint bufSize, jlong length, jlong uniformBlockName, jlong function_pointer) { GLsizei *length_address = (GLsizei *)(intptr_t)length; GLchar *uniformBlockName_address = (GLchar *)(intptr_t)uniformBlockName; glGetActiveUniformBlockNamePROC glGetActiveUniformBlockName = (glGetActiveUniformBlockNamePROC)((intptr_t)function_pointer); glGetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length_address, uniformBlockName_address); }
PIGLIT_GL_TEST_CONFIG_END void piglit_init(int argc, char **argv) { int i; GLuint prog; const char *source = "#extension GL_ARB_uniform_buffer_object : enable\n" "uniform a { float u1; };\n" "uniform bbb { float u2; };\n" "uniform cc { float u3; };\n" "void main() {\n" " gl_FragColor = vec4(u1 + u2 + u3);\n" "}\n"; int blocks; bool pass = true; const char *names[3] = {"a", "bbb", "cc"}; bool found[3] = {false, false, false}; char no_write; char fill_char = 0xd0; piglit_require_extension("GL_ARB_uniform_buffer_object"); prog = piglit_build_simple_program(NULL, source); glGetProgramiv(prog, GL_ACTIVE_UNIFORM_BLOCKS, &blocks); assert(blocks == 3); for (i = 0; i < blocks; i++) { GLint written_strlen = 0; GLint namelen = 9999; char name[1000]; int name_index; /* This is the size including null terminator. */ glGetActiveUniformBlockiv(prog, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &namelen); memset(name, 0xd0, sizeof(name)); glGetActiveUniformBlockName(prog, i, sizeof(name), &written_strlen, name); if (written_strlen >= sizeof(name) - 1) { fprintf(stderr, "return strlen %d, longer than the buffer size\n", written_strlen); pass = false; continue; } else if (name[written_strlen] != 0) { fprintf(stderr, "return name[%d] was %d, expected 0\n", written_strlen, name[written_strlen]); pass = false; continue; } else if (strlen(name) != written_strlen) { fprintf(stderr, "return strlen was %d, but \"%s\" " "has strlen %d\n", written_strlen, name, (int)strlen(name)); pass = false; continue; } for (name_index = 0; name_index < ARRAY_SIZE(names); name_index++) { if (strcmp(names[name_index], name) == 0) { if (found[name_index]) { fprintf(stderr, "Uniform block \"%s\" " "returned twice.\n", name); pass = false; } found[name_index] = true; break; } } if (name_index == ARRAY_SIZE(names)) { fprintf(stderr, "block \"%s\" is not a known block name\n", name); pass = false; continue; } if (namelen != written_strlen + 1) { fprintf(stderr, "block \"%s\" had " "GL_UNIFORM_BLOCK_NAME_LENGTH %d, expected %d\n", name, namelen, written_strlen + 1); pass = false; continue; } /* Test for overflow by writing to a bufSize equal to * strlen and checking if a null terminator or * something landed past that. */ memset(name, fill_char, sizeof(name)); glGetActiveUniformBlockName(prog, i, written_strlen, NULL, name); if (name[written_strlen] != fill_char) { fprintf(stderr, "glGetActiveUniformName overflowed: " "name[%d] = 0x%02x instead of 0x%02x\n", written_strlen, name[written_strlen], fill_char); pass = false; } } no_write = fill_char; glGetActiveUniformBlockName(0xd0d0, 0, 1, NULL, &no_write); pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass; if (no_write != fill_char) pass = false; no_write = fill_char; glGetActiveUniformBlockName(prog, 0, -1, NULL, &no_write); pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass; if (no_write != fill_char) pass = false; no_write = fill_char; glGetActiveUniformBlockName(prog, blocks, 1, NULL, &no_write); pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass; if (no_write != fill_char) pass = false; glDeleteProgram(prog); piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL); }
void OGLShaderObject::_initActiveUniformBlock() noexcept { GLint numUniformBlock = 0; GLint maxUniformBlockLength = 0; GLint maxUniformLength = 0; glGetProgramiv(_program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlock); glGetProgramiv(_program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxUniformBlockLength); glGetProgramiv(_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLength); if (numUniformBlock) { auto nameUniformBlock = make_scope<GLchar[]>(maxUniformBlockLength + 1); nameUniformBlock[maxUniformBlockLength] = 0; for (GLint i = 0; i < numUniformBlock; ++i) { GLsizei lengthUniformBlock; glGetActiveUniformBlockName(_program, (GLuint)i, maxUniformBlockLength, &lengthUniformBlock, nameUniformBlock.get()); GLuint location = glGetUniformBlockIndex(_program, nameUniformBlock.get()); if (location == GL_INVALID_INDEX) continue; glUniformBlockBinding(_program, location, location); GLint size; GLint count; glGetActiveUniformBlockiv(_program, location, GL_UNIFORM_BLOCK_DATA_SIZE, &size); glGetActiveUniformBlockiv(_program, location, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &count); if (count) { std::vector<GLint> indices(count); glGetActiveUniformBlockiv(_program, location, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices.data()); std::vector<GLint> offset((std::size_t)count); std::vector<GLint> type((std::size_t)count); std::vector<GLint> datasize((std::size_t)count); std::vector<std::string> varlist((std::size_t)count); std::vector<GLchar> name(maxUniformLength); glGetActiveUniformsiv(_program, count, (GLuint*)&indices[0], GL_UNIFORM_OFFSET, &offset[0]); glGetActiveUniformsiv(_program, count, (GLuint*)&indices[0], GL_UNIFORM_TYPE, &type[0]); glGetActiveUniformsiv(_program, count, (GLuint*)&indices[0], GL_UNIFORM_SIZE, &datasize[0]); for (GLint j = 0; j < count; ++j) { GLsizei length = 0; #if !defined(EGLAPI) glGetActiveUniformName(_program, indices[j], maxUniformLength, &length, name.data()); #else glGetActiveUniform(_program, indices[j], maxUniformLength, &length, &datasize[j], (GLenum*)&type[j], name.data()); #endif varlist[j].append(name.data(), length); } auto uniformblock = std::make_shared<ShaderUniform>(); uniformblock->setName(nameUniformBlock.get()); uniformblock->setType(ShaderVariantType::SPT_BUFFER); uniformblock->setLocation(location); _activeUniforms.push_back(uniformblock); } } } }
//----------------------------------------------------------------------------- void CPUTMaterialEffectOGL::ReadShaderSamplersAndTextures( GLuint shaderProgram, CPUTShaderParameters *pShaderParameter ) { GLint numActiveUniforms; GLint activeUniformMaxLength; GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &numActiveUniforms)); GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength)); #ifndef CPUT_FOR_OGLES2 GLint numActiveUniformBlocks; GLint activeUniformBlockMaxLength = 50; GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks)); #else #warning "Need to do something with uniform blocks here" #endif // // #### This parameter is currently unsupported by Intel OGL drivers. // // GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &activeUniformBlockMaxLength)); GLchar* uniformVariableName = new GLchar[activeUniformMaxLength]; GLenum dataType; GLint size; for (int i = 0; i < numActiveUniforms; i++) { GL_CHECK(glGetActiveUniform(shaderProgram, i, activeUniformMaxLength, NULL, &size, &dataType, uniformVariableName)); switch(dataType) { #ifndef CPUT_FOR_OGLES case GL_SAMPLER_1D: #endif case GL_SAMPLER_2D: #ifndef CPUT_FOR_OGLES2 case GL_SAMPLER_3D: #endif case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE: pShaderParameter->mpTextureParameterNames.push_back(uniformVariableName); pShaderParameter->mpTextureParameterLocations.push_back(glGetUniformLocation(shaderProgram, uniformVariableName)); pShaderParameter->mTextureParameterCount++; break; default: // unsupported uniform type break; } } delete uniformVariableName; #ifndef CPUT_FOR_OGLES2 GLchar* uniformBlockName = new GLchar[activeUniformBlockMaxLength]; for (int i = 0; i < numActiveUniformBlocks; i++) { GL_CHECK(ES3_COMPAT(glGetActiveUniformBlockName(shaderProgram, i, activeUniformBlockMaxLength, NULL, uniformBlockName))); pShaderParameter->mConstantBufferParameterNames.push_back(uniformBlockName); pShaderParameter->mConstantBufferBindPoints.push_back(ES3_COMPAT(glGetUniformBlockIndex(shaderProgram, uniformBlockName))); pShaderParameter->mConstantBufferParameterCount++; } delete uniformBlockName; #else #warning "Need to do something with uniform blocks here" #endif /* glUseProgram(0); GLchar activeUniformNames[10][100]; GLchar activeUniformBlockNames[10][100]; GLchar activeAttributeNames[10][100]; GLint numActiveAttributes, activeAttributeMaxLength; GLint numActiveUniformBlocks, activeUniformBlockMaxLength; GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &numActiveUniforms)); GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength)); GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTES, &numActiveAttributes)); GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttributeMaxLength)); GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks)); GL_CHECK(glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &activeUniformBlockMaxLength)); GLsizei numBytesWritten; for (int i = 0; i < numActiveUniforms; i++) { GL_CHECK(glGetActiveUniform(shaderProgram, i, 100, &numBytesWritten, &size, &dataType, activeUniformNames[i])); } for (int i = 0; i < numActiveAttributes; i++) { GL_CHECK(glGetActiveAttrib(shaderProgram, i, 100, &numBytesWritten, &size, &dataType, activeAttributeNames[i])); } for (int i = 0; i < numActiveUniformBlocks; i++) { // GL_CHECK(glGetActiveUniformBlock(shaderProgram, i, )); } CheckDebugLog2(); GLuint g_gaussSampler; glGenSamplers(1, &g_gaussSampler); glSamplerParameteri(g_gaussSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(g_gaussSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glSamplerParameteri(g_gaussSampler, GL_TEXTURE_WRAP_S, GL_REPEAT); GLuint TextureName = gli::createTexture2D("/home/q-dawg/Develop/projects/Framework/CPUT_Linux/SampleStartCPUT/Media/Teapot/Texture/checker_20x.dds"); glBindTexture(GL_TEXTURE_2D, TextureName); GL_CHECK(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR )); GL_CHECK(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )); GL_CHECK(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT )); GL_CHECK(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT )); GL_CHECK(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT )); GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0)); GLint diffuseTextureLocation = glGetUniformLocation(shaderProgram, "diffuseTex"); CheckDebugLog2(); glUseProgram(mShaderProgram); glUniform1i(diffuseTextureLocation, 0); CheckDebugLog2(); GL_CHECK(glActiveTexture(GL_TEXTURE0 + 0)); GL_CHECK(glBindTexture(GL_TEXTURE_2D, TextureName)); glUseProgram(0); */ }
int main() { EmscriptenWebGLContextAttributes attrs; emscripten_webgl_init_context_attributes(&attrs); attrs.enableExtensionsByDefault = 1; attrs.majorVersion = 2; attrs.minorVersion = 0; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context( 0, &attrs ); if (!context) { printf("Skipped: WebGL 2 is not supported.\n"); #ifdef REPORT_RESULT REPORT_RESULT(); #endif return 0; } emscripten_webgl_make_context_current(context); const char *vertexShader = "#version 300 es\n" "uniform Block1a {\n" " uniform mat4 var1;\n" " uniform vec4 variable2;\n" "} block1bb;\n" "uniform Block2ccc {\n" " uniform mat4 var1;\n" " uniform vec4 variable2;\n" "} block2dddd;\n" "void main() {\n" " gl_Position = block1bb.var1*block1bb.variable2 + block2dddd.var1*block2dddd.variable2;\n" "}\n"; const char *fragmentShader = "#version 300 es\n" "precision lowp float;\n" " uniform Block3eeeee {\n" " uniform vec4 var1;\n" " uniform vec4 variable2;\n" "} block3ffffff;\n" // Append characters of different lengths to test name string lengths. "out vec4 outColor;\n" "void main() {\n" " outColor = block3ffffff.var1 + block3ffffff.variable2;\n" "}\n"; GLuint vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vertexShader, NULL); glCompileShader(vs); int ok = 0; glGetShaderiv(vs, GL_COMPILE_STATUS, &ok); if (!ok) { printf("Shader compilation error with vertex\n"); GLint infoLen = 0; glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen > 1) { char* infoLog = (char *)malloc(sizeof(char) * infoLen+1); glGetShaderInfoLog(vs, infoLen, NULL, infoLog); printf("Error compiling shader:\n%s\n", infoLog); } } GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, 1, &fragmentShader, NULL); glCompileShader(fs); glGetShaderiv(fs, GL_COMPILE_STATUS, &ok); if (!ok) { printf("Shader compilation error with fragment\n"); GLint infoLen = 0; glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen > 1) { char* infoLog = (char *)malloc(sizeof(char) * infoLen+1); glGetShaderInfoLog(vs, infoLen, NULL, infoLog); printf("Error compiling shader:\n%s\n", infoLog); } } GLuint program = glCreateProgram(); glAttachShader(program, vs); glAttachShader(program, fs); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &ok); assert(ok); int maxLength = 0; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxLength); printf("GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: %d\n", maxLength); assert(maxLength == 12); GLint numActiveUniformBlocks = -1; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks); assert(numActiveUniformBlocks == 3); // Dump all active uniform buffer blocks of the current program. for(int i = 0; i < numActiveUniformBlocks; ++i) { char str[256] = {}; GLsizei length = -1; glGetActiveUniformBlockName(program, i, 255, &length, str); assert(length > 0); printf("Active uniform block at index %d: %s\n", i, str); GLint param = -1; #define DUMPUNIFORMBLOCKSTATUS(stat) glGetActiveUniformBlockiv(program, i, stat, ¶m); printf("%s: %d\n", #stat, param); DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER); DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER); DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_BINDING); DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_DATA_SIZE); DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_NAME_LENGTH); DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS); GLint indices[16] = {}; glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices); for(size_t i = 0; i < param; ++i) printf("offset for index %d: %d\n", i, indices[i]); } #ifdef REPORT_RESULT REPORT_RESULT(); #endif return 0; }
void RendererBasePimpl::InitDomainUniformAndSamplers(ShaderProgram * resource, unsigned int domain, GLuint program) { char uniform_name[1000]; GLsizei name_length; GLint uniform_size; GLenum uniform_type; GLint uniform_count; GLuint uniform_location; glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_count); std::vector<std::pair<std::string, int> > uniform_names; std::vector<std::pair<std::string, int> > sampler_names; std::vector<UniformParam> uniform_vector; std::vector<GLuint> uniform_locations; std::vector<SamplerParam> sampler_vector; std::vector<GLuint> sampler_locations; unsigned int next_offset = 0; for (int i = 0; i < uniform_count; ++i) { glGetActiveUniform(program, i, 1000, &name_length, &uniform_size, &uniform_type, uniform_name); uniform_location = glGetUniformLocation(program, uniform_name); unsigned char rows = 1; unsigned char columns = 1; unsigned char type = 0; bool sampler = false; GetTypeInfo(uniform_type, type, rows, columns, sampler); if (sampler) { sampler_names.push_back(std::make_pair(uniform_name, sampler_names.size())); sampler_vector.push_back(SamplerParam()); sampler_vector.back().type = type; sampler_locations.push_back(uniform_location); } else { uniform_names.push_back(std::make_pair(uniform_name, uniform_names.size())); uniform_vector.push_back(UniformParam()); uniform_vector.back().array_length = uniform_size; uniform_vector.back().row_major = false; uniform_vector.back().type = type; uniform_vector.back().rows = rows; uniform_vector.back().columns = columns; uniform_vector.back().uniform_buffer_index = 0; uniform_vector.back().uniform_buffer_offset = next_offset; uniform_vector.back().uniform_buffer_array_stride = 0; uniform_vector.back().uniform_buffer_matrix_stride = rows > 1 ? rows : 0; uniform_locations.push_back(uniform_location); switch(type) { case DT_FLOAT: next_offset = next_offset + (sizeof(float) * rows * columns * uniform_size); break; default: std::cout << "Other types not supported yet." << std::endl; break; } } } std::sort(uniform_names.begin(), uniform_names.end()); std::sort(sampler_names.begin(), sampler_names.end()); resource->uniforms.Set(uniform_names.size()); resource->samplers.Set(sampler_names.size()); GLint uniformblock_count = 0; if (GLEW_ARB_uniform_buffer_object) { char uniformblock_name[1000]; GLint name_length; GLint block_binding; GLint block_data_size; GLint block_active_uniforms; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &uniformblock_count); resource->uniform_blocks.Set(uniform_names.size() > 0 ? uniformblock_count + 1 : uniformblock_count); //Add one because we make "no ubo" as 0 index. unsigned int total_uniforms_in_blocks = 0; for (int i = 0; i < uniformblock_count; ++i) { glGetActiveUniformBlockName(program, i, 1000, &name_length, uniformblock_name); GLint params; glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_BINDING, &block_binding); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_DATA_SIZE, &block_data_size); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_NAME_LENGTH, ¶ms); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &block_active_uniforms); std::vector<GLuint> uniform_indices(block_active_uniforms, 0); glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, reinterpret_cast<GLint*>(&uniform_indices[0])); std::vector<GLuint> uniform_offsets(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_OFFSET, reinterpret_cast<GLint*>(&uniform_offsets[0])); std::vector<GLuint> uniform_arraystrides(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_ARRAY_STRIDE, reinterpret_cast<GLint*>(&uniform_arraystrides[0])); std::vector<GLuint> uniform_matrixstrides(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_MATRIX_STRIDE, reinterpret_cast<GLint*>(&uniform_matrixstrides[0])); std::vector<GLuint> uniform_rowmajor(block_active_uniforms, 0); glGetActiveUniformsiv(program, block_active_uniforms, &uniform_indices[0], GL_UNIFORM_IS_ROW_MAJOR, reinterpret_cast<GLint*>(&uniform_rowmajor[0])); unsigned int block_index = uniform_names.size() > 0 ? (i + 1) : i;//Add one because we make "no ubo" as 0 index. resource->uniform_blocks[block_index].name = uniformblock_name; resource->uniform_blocks[block_index].byte_count = block_data_size; resource->uniform_blocks[block_index].uniform_indices.Set(block_active_uniforms); total_uniforms_in_blocks += block_active_uniforms; for (unsigned int p = 0; p < uniform_indices.size(); ++p) { uniform_vector[uniform_indices[p]].uniform_buffer_index = block_index; uniform_vector[uniform_indices[p]].uniform_buffer_offset = uniform_offsets[p]; uniform_vector[uniform_indices[p]].uniform_buffer_array_stride = uniform_arraystrides[p]; uniform_vector[uniform_indices[p]].uniform_buffer_matrix_stride = uniform_matrixstrides[p]; uniform_vector[uniform_indices[p]].row_major = uniform_rowmajor[p]; } //std::cout << " Location: " << glGetUniformLocation(pimpl->combined, uniformblock_name) << std::endl; } resource->uniform_blocks[0].uniform_indices.Set(uniform_names.size() - total_uniforms_in_blocks); } else { if (uniform_names.size() > 0) { resource->uniform_blocks.Set(1); resource->uniform_blocks[0].uniform_indices.Set(uniform_names.size()); } } if (uniform_names.size() > 0) { std::vector<unsigned int> block_param_count(resource->uniform_blocks.GetSize(), 0); unsigned int block_zero_size = 0; //Loop through all uniforms sorted by names. for (unsigned int i = 0; i < uniform_names.size(); ++i) { //Set uniform info in ShaderProgram.domains[domain].uniforms. int index = uniform_names[i].second; resource->uniforms[i] = uniform_vector[index]; resource->uniforms[i].name = uniform_names[i].first; //Put index in the parameter's block in ShaderProgram.domains[domain].uniform_blocks. int uniform_block_index = uniform_vector[index].uniform_buffer_index; resource->uniform_blocks[uniform_block_index].uniform_indices[block_param_count[uniform_block_index]] = i; block_param_count[uniform_block_index] += 1; //For block zero, calculate size. if (uniform_block_index == 0) { block_zero_size = std::max<unsigned int>( block_zero_size, uniform_vector[index].uniform_buffer_offset + uniform_vector[index].rows * uniform_vector[index].columns * sizeof(float) * uniform_vector[index].array_length); //Only for DT_FLOAT. Fix later. } } resource->uniform_blocks[0].byte_count = block_zero_size; } for (unsigned int i = 0; i < sampler_names.size(); ++i) { int index = sampler_names[i].second; resource->samplers[i] = sampler_vector[index]; resource->samplers[i].name = sampler_names[i].first; } ShaderProgramPimpl * program_pimpl = (ShaderProgramPimpl *) resource->PRIVATE; program_pimpl->uniform_locations.Set(uniform_names.size()); program_pimpl->sampler_locations.Set(sampler_names.size()); program_pimpl->sampler_units.Set(sampler_names.size()); program_pimpl->block_bind_points.Set(uniform_names.size() > 0 ? (uniformblock_count + 1) : uniformblock_count); program_pimpl->bound_uniform_buffers.Set(uniformblock_count + 1, 0); }
bool ShaderProgram::Link() { Release(); if (!vertexShader_ || !pixelShader_ || !vertexShader_->GetGPUObject() || !pixelShader_->GetGPUObject()) return false; object_ = glCreateProgram(); if (!object_) { linkerOutput_ = "Could not create shader program"; return false; } // Bind vertex attribute locations to ensure they are the same in all shaders // Note: this is not the same order as in VertexBuffer, instead a remapping is used to ensure everything except cube texture // coordinates fit to the first 8 for better GLES2 device compatibility glBindAttribLocation(object_, 0, "iPos"); glBindAttribLocation(object_, 1, "iNormal"); glBindAttribLocation(object_, 2, "iColor"); glBindAttribLocation(object_, 3, "iTexCoord"); glBindAttribLocation(object_, 4, "iTexCoord2"); glBindAttribLocation(object_, 5, "iTangent"); glBindAttribLocation(object_, 6, "iBlendWeights"); glBindAttribLocation(object_, 7, "iBlendIndices"); glBindAttribLocation(object_, 8, "iCubeTexCoord"); glBindAttribLocation(object_, 9, "iCubeTexCoord2"); #if !defined(GL_ES_VERSION_2_0) || defined(__EMSCRIPTEN__) glBindAttribLocation(object_, 10, "iInstanceMatrix1"); glBindAttribLocation(object_, 11, "iInstanceMatrix2"); glBindAttribLocation(object_, 12, "iInstanceMatrix3"); #endif glAttachShader(object_, vertexShader_->GetGPUObject()); glAttachShader(object_, pixelShader_->GetGPUObject()); glLinkProgram(object_); int linked, length; glGetProgramiv(object_, GL_LINK_STATUS, &linked); if (!linked) { glGetProgramiv(object_, GL_INFO_LOG_LENGTH, &length); linkerOutput_.Resize((unsigned)length); int outLength; glGetProgramInfoLog(object_, length, &outLength, &linkerOutput_[0]); glDeleteProgram(object_); object_ = 0; } else linkerOutput_.Clear(); if (!object_) return false; const int MAX_PARAMETER_NAME_LENGTH = 256; char uniformName[MAX_PARAMETER_NAME_LENGTH]; int uniformCount; glUseProgram(object_); glGetProgramiv(object_, GL_ACTIVE_UNIFORMS, &uniformCount); // Check for constant buffers #ifndef GL_ES_VERSION_2_0 HashMap<unsigned, unsigned> blockToBinding; if (Graphics::GetGL3Support()) { int numUniformBlocks = 0; glGetProgramiv(object_, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); for (int i = 0; i < numUniformBlocks; ++i) { int nameLength; glGetActiveUniformBlockName(object_, (GLuint)i, MAX_PARAMETER_NAME_LENGTH, &nameLength, uniformName); String name(uniformName, (unsigned)nameLength); unsigned blockIndex = glGetUniformBlockIndex(object_, name.CString()); unsigned group = M_MAX_UNSIGNED; // Try to recognize the use of the buffer from its name for (unsigned j = 0; j < MAX_SHADER_PARAMETER_GROUPS; ++j) { if (name.Contains(shaderParameterGroups[j], false)) { group = j; break; } } // If name is not recognized, search for a digit in the name and use that as the group index if (group == M_MAX_UNSIGNED) { for (unsigned j = 1; j < name.Length(); ++j) { if (name[j] >= '0' && name[j] <= '5') { group = name[j] - '0'; break; } } } if (group >= MAX_SHADER_PARAMETER_GROUPS) { URHO3D_LOGWARNING("Skipping unrecognized uniform block " + name + " in shader program " + vertexShader_->GetFullName() + " " + pixelShader_->GetFullName()); continue; } // Find total constant buffer data size int dataSize; glGetActiveUniformBlockiv(object_, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &dataSize); if (!dataSize) continue; unsigned bindingIndex = group; // Vertex shader constant buffer bindings occupy slots starting from zero to maximum supported, pixel shader bindings // from that point onward if (name.Contains("PS", false)) bindingIndex += MAX_SHADER_PARAMETER_GROUPS; glUniformBlockBinding(object_, blockIndex, bindingIndex); blockToBinding[blockIndex] = bindingIndex; constantBuffers_[bindingIndex] = graphics_->GetOrCreateConstantBuffer(bindingIndex, (unsigned)dataSize); } } #endif // Check for shader parameters and texture units for (int i = 0; i < uniformCount; ++i) { unsigned type; int count; glGetActiveUniform(object_, (GLuint)i, MAX_PARAMETER_NAME_LENGTH, 0, &count, &type, uniformName); int location = glGetUniformLocation(object_, uniformName); // Check for array index included in the name and strip it String name(uniformName); unsigned index = name.Find('['); if (index != String::NPOS) { // If not the first index, skip if (name.Find("[0]", index) == String::NPOS) continue; name = name.Substring(0, index); } if (name[0] == 'c') { // Store constant uniform String paramName = name.Substring(1); ShaderParameter newParam; newParam.type_ = type; newParam.location_ = location; #ifndef GL_ES_VERSION_2_0 // If running OpenGL 3, the uniform may be inside a constant buffer if (newParam.location_ < 0 && Graphics::GetGL3Support()) { int blockIndex, blockOffset; glGetActiveUniformsiv(object_, 1, (const GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &blockIndex); glGetActiveUniformsiv(object_, 1, (const GLuint*)&i, GL_UNIFORM_OFFSET, &blockOffset); if (blockIndex >= 0) { newParam.location_ = blockOffset; newParam.bufferPtr_ = constantBuffers_[blockToBinding[blockIndex]]; } } #endif if (newParam.location_ >= 0) shaderParameters_[StringHash(paramName)] = newParam; } else if (location >= 0 && name[0] == 's') { // Set the samplers here so that they do not have to be set later int unit = graphics_->GetTextureUnit(name.Substring(1)); if (unit >= MAX_TEXTURE_UNITS) { // If texture unit name is not recognized, search for a digit in the name and use that as the unit index for (unsigned j = 1; j < name.Length(); ++j) { if (name[j] >= '0' && name[j] <= '9') { unit = name[j] - '0'; break; } } } if (unit < MAX_TEXTURE_UNITS) { useTextureUnit_[unit] = true; glUniform1iv(location, 1, &unit); } } } // Rehash the parameter map to ensure minimal load factor shaderParameters_.Rehash(NextPowerOfTwo(shaderParameters_.Size())); return true; }
bool initProgram() { bool Validated = true; compiler Compiler; // Create program if(Validated) { compiler Compiler; GLuint VertShaderName = Compiler.create(GL_VERTEX_SHADER, getDataDirectory() + VERT_SHADER_SOURCE, "--version 150 --profile core"); GLuint FragShaderName = Compiler.create(GL_FRAGMENT_SHADER, getDataDirectory() + FRAG_SHADER_SOURCE, "--version 150 --profile core"); ProgramName = glCreateProgram(); glAttachShader(ProgramName, VertShaderName); glAttachShader(ProgramName, FragShaderName); glBindAttribLocation(ProgramName, semantic::attr::POSITION, "Position"); glBindFragDataLocation(ProgramName, semantic::frag::COLOR, "Color"); glLinkProgram(ProgramName); Validated = Validated && Compiler.check(); Validated = Validated && Compiler.checkProgram(ProgramName); } // Get variables locations if(Validated) { UniformMaterial = glGetUniformBlockIndex(ProgramName, "material"); UniformTransform = glGetUniformBlockIndex(ProgramName, "transform"); glUniformBlockBinding(ProgramName, UniformTransform, semantic::uniform::TRANSFORM0); glUniformBlockBinding(ProgramName, UniformMaterial, semantic::uniform::MATERIAL); } GLint ActiveUniformBlocks(0); glGetProgramiv(ProgramName, GL_ACTIVE_UNIFORM_BLOCKS, &ActiveUniformBlocks); for(GLint i = 0; i < ActiveUniformBlocks; ++i) { char Name[128]; memset(Name, '\0', sizeof(Name)); GLsizei Length(0); glGetActiveUniformBlockName(ProgramName, i, GLsizei(sizeof(Name)), &Length, Name); std::string StringName(Name); Validated = Validated && (StringName == std::string("material") || StringName == std::string("transform")); } GLint ActiveUniform(0); glGetProgramiv(ProgramName, GL_ACTIVE_UNIFORMS, &ActiveUniform); for(GLint i = 0; i < ActiveUniformBlocks; ++i) { char Name[128]; memset(Name, '\0', sizeof(Name)); GLsizei Length(0); glGetActiveUniformName(ProgramName, i, GLsizei(sizeof(Name)), &Length, Name); std::string StringName(Name); Validated = Validated && ( StringName == std::string("material.Diffuse") || StringName == std::string("transform.MVP")); } return Validated && this->checkError("initProgram"); }
PIGLIT_GL_TEST_CONFIG_END void piglit_init(int argc, char **argv) { bool pass = true; unsigned int i; GLuint vs, gs, fs, prog; const char *vs_source = "%s" "uniform vs { float v; };\n" "uniform vsgs { float vg; };\n" "uniform vsfs { float vf; };\n" "uniform vsgsfs { float vgf; };\n" "void main() {\n" " gl_Position = vec4(v + vg + vf + vgf);\n" "}\n"; const char *gs_source = "%s" "layout(triangles) in;\n" "layout(triangle_strip, max_vertices=3) out;\n" "uniform gs { float g; };\n" "uniform vsgs { float vg; };\n" "uniform gsfs { float gf; };\n" "uniform vsgsfs { float vgf; };\n" "void main() {\n" " for(int i = 0; i < 3; i++) {\n" " gl_Position = vec4(g + vg + gf + vgf);\n" " EmitVertex();\n" " }\n" "}\n"; const char *fs_source = "%s" "uniform fs { float f; };\n" "uniform vsfs { float vf; };\n" "uniform gsfs { float gf; };\n" "uniform vsgsfs { float vgf; };\n" "void main() {\n" " gl_FragColor = vec4(f + vf + gf + vgf);\n" "}\n"; char name[10]; bool use_gs = piglit_get_gl_version() >= 32; const char *header; char *temp_source; int num_uniforms_used = 0; if (use_gs) { header = "#version 150\n"; } else { header = "#extension GL_ARB_uniform_buffer_object : enable\n"; piglit_require_extension("GL_ARB_uniform_buffer_object"); } prog = glCreateProgram(); asprintf(&temp_source, vs_source, header); vs = piglit_compile_shader_text(GL_VERTEX_SHADER, temp_source); glAttachShader(prog, vs); free(temp_source); if (use_gs) { asprintf(&temp_source, gs_source, header); gs = piglit_compile_shader_text(GL_GEOMETRY_SHADER, temp_source); glAttachShader(prog, gs); free(temp_source); } asprintf(&temp_source, fs_source, header); fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, temp_source); glAttachShader(prog, fs); free(temp_source); glLinkProgram(prog); if (!piglit_link_check_status(prog)) { piglit_report_result(PIGLIT_FAIL); } if (use_gs) { num_uniforms_used = 7; printf(" v g f\n"); } else { num_uniforms_used = 6; printf(" v f\n"); } for (i = 0; i < num_uniforms_used; i++) { GLint ref_vs = 0, ref_gs = 0, ref_fs = 0; bool block_fail = false; glGetActiveUniformBlockName(prog, i, sizeof(name), NULL, name); glGetActiveUniformBlockiv(prog, i, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &ref_vs); if (use_gs) { glGetActiveUniformBlockiv(prog, i, GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER, &ref_gs); } glGetActiveUniformBlockiv(prog, i, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &ref_fs); if (use_gs) { printf("%10s: %d %d %d", name, ref_vs, ref_gs, ref_fs); } else { printf("%10s: %d %d", name, ref_vs, ref_fs); } if ((strstr(name, "vs") != 0) != ref_vs) block_fail = true; if (use_gs) { if ((strstr(name, "gs") != 0) != ref_gs) block_fail = true; } if ((strstr(name, "fs") != 0) != ref_fs) block_fail = true; if (block_fail) { printf(" FAIL"); pass = false; } printf("\n"); } piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL); }
/*! adds a shader object */ shader_object* shader::add_shader_src(const string& identifier, const string& option, ext::GLSL_VERSION glsl_version, const char* vs_text, const char* gs_text, const char* fs_text) { // success flag (if it's 1 (true), we successfully created a shader object) int success; GLchar info_log[A2E_SHADER_LOG_SIZE]; if(gs_text != nullptr && strcmp(gs_text, "") == 0) gs_text = nullptr; // create a new shader object if none exists for this identifier if(shaders.count(identifier) == 0) { shaders[identifier] = new shader_object(identifier); } // add a new program object to this shader shaders[identifier]->programs.push_back(new shader_object::internal_shader_object()); if(option != "") { shaders[identifier]->options[option] = shaders[identifier]->programs.back(); } shader_object::internal_shader_object& shd_obj = *shaders[identifier]->programs.back(); shaders[identifier]->glsl_version = std::max(shaders[identifier]->glsl_version, glsl_version); // create the vertex shader object shd_obj.vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(shd_obj.vertex_shader, 1, (GLchar const**)&vs_text, nullptr); glCompileShader(shd_obj.vertex_shader); glGetShaderiv(shd_obj.vertex_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shd_obj.vertex_shader, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in vertex shader \"%s/%s\" compilation!", identifier, option); log_pretty_print(info_log, vs_text); return 0; } #if !defined(FLOOR_IOS) // create the geometry shader object if(gs_text != nullptr && strcmp(gs_text, "") != 0) { shd_obj.geometry_shader = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(shd_obj.geometry_shader, 1, (GLchar const**)&gs_text, nullptr); glCompileShader(shd_obj.geometry_shader); glGetShaderiv(shd_obj.geometry_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shd_obj.geometry_shader, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in geometry shader \"%s/%s\" compilation!", identifier, option); log_pretty_print(info_log, gs_text); return 0; } } else shd_obj.geometry_shader = 0; #else if(gs_text != nullptr && strcmp(gs_text, "") != 0) { log_error("geometry shaders are not supported in OpenGL ES 2.0 or 3.0!"); } shd_obj.geometry_shader = 0; #endif // create the fragment shader object shd_obj.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(shd_obj.fragment_shader, 1, (GLchar const**)&fs_text, nullptr); glCompileShader(shd_obj.fragment_shader); glGetShaderiv(shd_obj.fragment_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shd_obj.fragment_shader, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in fragment shader \"%s/%s\" compilation!", identifier, option); log_pretty_print(info_log, fs_text); return 0; } // create the program object shd_obj.program = glCreateProgram(); // attach the vertex and fragment shader progam to it glAttachShader(shd_obj.program, shd_obj.vertex_shader); glAttachShader(shd_obj.program, shd_obj.fragment_shader); if(gs_text != nullptr) { glAttachShader(shd_obj.program, shd_obj.geometry_shader); } // WIP: program binary #if defined(A2E_DEBUG_PROGRAM_BINARY) #if defined(__APPLE__) { fstream progcode_vs("/tmp/a2e_shd_code_vs.glsl", fstream::out); progcode_vs << vs_text << endl; progcode_vs.close(); if(shd_obj.geometry_shader != 0) { fstream progcode_gs("/tmp/a2e_shd_code_gs.glsl", fstream::out); progcode_gs << gs_text << endl; progcode_gs.close(); } fstream progcode_fs("/tmp/a2e_shd_code_fs.glsl", fstream::out); progcode_fs << fs_text << endl; progcode_fs.close(); string output_vs = "", output_gs = "", output_fs = ""; core::system("cgc -profile gp4vp -strict -oglsl /tmp/a2e_shd_code_vs.glsl 2>&1", output_vs); if(shd_obj.geometry_shader != 0) { core::system("cgc -profile gp4gp -strict -oglsl -po POINT /tmp/a2e_shd_code_gs.glsl 2>&1", output_gs); } core::system("cgc -profile gp4fp -strict -oglsl /tmp/a2e_shd_code_fs.glsl 2>&1", output_fs); system("rm /tmp/a2e_shd_code_vs.glsl"); if(shd_obj.geometry_shader != 0) { system("rm /tmp/a2e_shd_code_gs.glsl"); } system("rm /tmp/a2e_shd_code_fs.glsl"); // shader_debug::add(identifier, option, output_vs, output_gs, output_fs); } #else if(exts->is_ext_supported("GL_ARB_get_program_binary")) glProgramParameteri(shd_obj.program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); #endif #endif // now link the program object glLinkProgram(shd_obj.program); glGetProgramiv(shd_obj.program, GL_LINK_STATUS, &success); if(!success) { glGetProgramInfoLog(shd_obj.program, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in program \"%s/%s\" linkage!\nInfo log: %s", identifier, option, info_log); return 0; } glUseProgram(shd_obj.program); // bind frag data locations (frag_color, frag_color_2, frag_color_3, ...) bool fd_relink = false; #if !defined(FLOOR_IOS) const unsigned int max_draw_buffers = exts->get_max_draw_buffers(); for(unsigned int i = 0; i < max_draw_buffers; i++) { string name = "frag_color"; if(i >= 1) name += "_"+to_string(i+1); const GLint location = glGetFragDataLocation(shd_obj.program, name.c_str()); // check if the frag color exists and must be bound to a different location if(location >= 0 && i != (GLuint)location) { // if so, bind it to the correct location glBindFragDataLocation(shd_obj.program, i, name.c_str()); fd_relink = true; } } #else // NOTE: MRTs are not support in OpenGL ES 2.0 // in OpenGL ES 3.0 the locations are already set in the shader #endif if(fd_relink) { // program must be linked again after the frag data locations were modified // (double-linkage sucks, but there's no other way in opengl 3.2 ...) glLinkProgram(shd_obj.program); } // WIP: program binary #if defined(A2E_DEBUG_PROGRAM_BINARY) #if !defined(__APPLE__) if(exts->is_ext_supported("GL_ARB_get_program_binary")) { GLint binary_length = 0; glGetProgramiv(shd_obj.program, GL_PROGRAM_BINARY_LENGTH, &binary_length); unsigned char* binary = new unsigned char[binary_length]; GLenum binary_format = 0; glGetProgramBinary(shd_obj.program, binary_length, nullptr, &binary_format, binary); string binary_fname = "shader_binary_"+identifier+"_"+to_string(shaders[identifier]->programs.size()-1)+".dat"; f->open_file(binary_fname.c_str(), file_io::OT_WRITE_BINARY); f->write_block((const char*)binary, binary_length, false); f->close_file(); delete [] binary; } #endif #endif // grab number and names of all attributes and uniforms and get their locations (needs to be done before validation, b/c we have to set sampler locations) GLint attr_count = 0, uni_count = 0, max_attr_len = 0, max_uni_len = 0; GLint var_location = 0; GLint var_size = 0; GLenum var_type = 0; glGetProgramiv(shd_obj.program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_len); glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uni_len); glGetProgramiv(shd_obj.program, GL_ACTIVE_ATTRIBUTES, &attr_count); glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORMS, &uni_count); max_attr_len+=2; max_uni_len+=2; #if !defined(FLOOR_IOS) || defined(PLATFORM_X64) GLint uni_block_count = 0, max_uni_block_len = 0; glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_uni_block_len); glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORM_BLOCKS, &uni_block_count); max_uni_block_len+=2; #endif // note: this may report weird attribute/uniform names (and locations), if uniforms/attributes are optimized away by the compiler bool print_debug_info = false; //if(identifier == "SIMPLE") { /*if(identifier == "FONT") { print_debug_info = true; cout << endl << "## " << identifier << "::" << option << endl; }*/ GLchar* attr_name = new GLchar[(size_t)max_attr_len]; if(print_debug_info) log_undecorated("## shader: %s", identifier); if(print_debug_info) log_undecorated("GL_ACTIVE_ATTRIBUTES: %u", attr_count); for(GLuint attr = 0; attr < (GLuint)attr_count; attr++) { memset(attr_name, 0, (size_t)max_attr_len); glGetActiveAttrib(shd_obj.program, attr, max_attr_len-1, nullptr, &var_size, &var_type, attr_name); var_location = glGetAttribLocation(shd_obj.program, attr_name); if(var_location < 0) { if(print_debug_info) log_error("Warning: could not get location for attribute \"%s\" in shader #%s/%s!", attr_name, identifier, option); continue; } if(print_debug_info) log_undecorated("attribute #%u: %s", var_location, attr_name); string attribute_name = attr_name; if(attribute_name.find("[") != string::npos) attribute_name = attribute_name.substr(0, attribute_name.find("[")); shd_obj.attributes.insert(make_pair(attribute_name, shader_object::internal_shader_object::shader_variable((size_t)var_location, (size_t)var_size, var_type))); } delete [] attr_name; GLchar* uni_name = new GLchar[(size_t)max_uni_len]; if(print_debug_info) log_undecorated("GL_ACTIVE_UNIFORMS: %u", uni_count); for(GLuint uniform = 0; uniform < (GLuint)uni_count; uniform++) { memset(uni_name, 0, (size_t)max_uni_len); glGetActiveUniform(shd_obj.program, uniform, max_uni_len-1, nullptr, &var_size, &var_type, uni_name); var_location = glGetUniformLocation(shd_obj.program, uni_name); if(var_location < 0) { if(print_debug_info) log_error("Warning: could not get location for uniform \"%s\" in shader #%s/%s!", uni_name, identifier, option); continue; } if(print_debug_info) log_undecorated("uniform #%u: %s", var_location, uni_name); string uniform_name = uni_name; if(uniform_name.find("[") != string::npos) uniform_name = uniform_name.substr(0, uniform_name.find("[")); shd_obj.uniforms.insert(make_pair(uniform_name, shader_object::internal_shader_object::shader_variable((size_t)var_location, (size_t)var_size, var_type))); // if the uniform is a sampler, add it to the sampler mapping (with increasing id/num) if(shader_class::is_gl_sampler_type(var_type)) { shd_obj.samplers.insert(make_pair(uniform_name, shd_obj.samplers.size())); // while we are at it, also set the sampler location to a dummy value (this has to be done to satisfy program validation) glUniform1i(var_location, (GLint)shd_obj.samplers.size()-1); } } delete [] uni_name; #if !defined(FLOOR_IOS) || defined(PLATFORM_X64) GLchar* uni_block_name = new GLchar[(size_t)max_uni_block_len]; if(print_debug_info) log_undecorated("GL_ACTIVE_UNIFORM_BLOCKS: %u", uni_block_count); for(GLuint block = 0; block < (GLuint)uni_block_count; block++) { memset(uni_block_name, 0, (size_t)max_uni_block_len); glGetActiveUniformBlockName(shd_obj.program, (GLuint)block, max_uni_block_len-1, nullptr, uni_block_name); GLuint block_index = glGetUniformBlockIndex(shd_obj.program, uni_block_name); if(block_index == GL_INVALID_INDEX) { if(print_debug_info) log_error("Warning: could not get index for uniform block \"%s\" in shader #%s/%s!", uni_block_name, identifier, option); continue; } GLint data_size = 0; glGetActiveUniformBlockiv(shd_obj.program, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &data_size); if(print_debug_info) log_undecorated("uniform block #%u (size: %u): %s", block_index, data_size, uni_block_name); const string uniform_block_name = uni_block_name; shd_obj.blocks.insert(make_pair(uniform_block_name, shader_object::internal_shader_object::shader_variable(block_index, (size_t)data_size, GL_UNIFORM_BUFFER))); // TODO: handle samplers? } delete [] uni_block_name; #endif // validate the program object glValidateProgram(shd_obj.program); glGetProgramiv(shd_obj.program, GL_VALIDATE_STATUS, &success); if(!success) { glGetProgramInfoLog(shd_obj.program, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in program \"%s/%s\" validation!\nInfo log: %s", identifier, option, info_log); return 0; } else { glGetProgramInfoLog(shd_obj.program, A2E_SHADER_LOG_SIZE, nullptr, info_log); // check if shader will run in software (if so, print out a debug message) if(strstr((const char*)info_log, (const char*)"software") != nullptr) { log_debug("program \"%s/%s\" validation: %s", identifier, option, info_log); } } // glUseProgram(0); return shaders[identifier]; }