int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { GLint buffersCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); // fast exit if (buffersCount == 0) { return 0; } GLint maxNumUniformBufferSlots = 0; glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots); std::vector<GLint> uniformBufferSlotMap(maxNumUniformBufferSlots, -1); for (int i = 0; i < buffersCount; i++) { const GLint NAME_LENGTH = 256; GLchar name[NAME_LENGTH]; GLint length = 0; GLint size = 0; GLint binding = -1; glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name); glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); GLuint blockIndex = glGetUniformBlockIndex(glprogram, name); // CHeck if there is a requested binding for this block auto requestedBinding = slotBindings.find(std::string(name)); if (requestedBinding != slotBindings.end()) { // If yes force it if (binding != (*requestedBinding)._location) { binding = (*requestedBinding)._location; glUniformBlockBinding(glprogram, blockIndex, binding); } } else if (binding == 0) { // If no binding was assigned then just do it finding a free slot auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot); if (slotIt != uniformBufferSlotMap.end()) { binding = slotIt - uniformBufferSlotMap.begin(); glUniformBlockBinding(glprogram, blockIndex, binding); } else { // This should neve happen, an active ubo cannot find an available slot among the max available?! binding = -1; } } // If binding is valid record it if (binding >= 0) { uniformBufferSlotMap[binding] = blockIndex; } Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER)); } return buffersCount; }
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) { GLint inputsCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); for (int i = 0; i < inputsCount; i++) { const GLint NAME_LENGTH = 256; GLchar name[NAME_LENGTH]; GLint length = 0; GLint size = 0; GLenum type = 0; glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); GLint binding = glGetAttribLocation(glprogram, name); auto elementResource = getFormatFromGLUniform(type); inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); } return inputsCount; }
int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) { GLint buffersCount = 0; glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount); // fast exit if (buffersCount == 0) { return 0; } GLint maxNumResourceBufferSlots = 0; glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxNumResourceBufferSlots); std::vector<GLint> resourceBufferSlotMap(maxNumResourceBufferSlots, -1); struct ResourceBlockInfo { using Vector = std::vector<ResourceBlockInfo>; const GLuint index{ 0 }; const std::string name; GLint binding{ -1 }; GLint size{ 0 }; static std::string getName(GLuint glprogram, GLuint i) { static const GLint NAME_LENGTH = 256; GLint length = 0; GLchar nameBuffer[NAME_LENGTH]; glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, i, NAME_LENGTH, &length, nameBuffer); return std::string(nameBuffer); } ResourceBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { GLenum props[2] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE}; glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, nullptr, &binding); } }; ResourceBlockInfo::Vector resourceBlocks; resourceBlocks.reserve(buffersCount); for (int i = 0; i < buffersCount; i++) { resourceBlocks.push_back(ResourceBlockInfo(glprogram, i)); } for (auto& info : resourceBlocks) { auto requestedBinding = slotBindings.find(info.name); if (requestedBinding != slotBindings.end()) { info.binding = (*requestedBinding)._location; glUniformBlockBinding(glprogram, info.index, info.binding); resourceBufferSlotMap[info.binding] = info.index; } } for (auto& info : resourceBlocks) { if (slotBindings.count(info.name)) { continue; } // If the binding is -1, or the binding maps to an already used binding if (info.binding == -1 || !isUnusedSlot(resourceBufferSlotMap[info.binding])) { // If no binding was assigned then just do it finding a free slot auto slotIt = std::find_if(resourceBufferSlotMap.begin(), resourceBufferSlotMap.end(), GLBackend::isUnusedSlot); if (slotIt != resourceBufferSlotMap.end()) { info.binding = slotIt - resourceBufferSlotMap.begin(); glUniformBlockBinding(glprogram, info.index, info.binding); } else { // This should never happen, an active ssbo cannot find an available slot among the max available?! info.binding = -1; } } resourceBufferSlotMap[info.binding] = info.index; } for (auto& info : resourceBlocks) { static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER); resourceBuffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); } return buffersCount; /* GLint ssboCount = 0; glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssboCount); if (ssboCount > 0) { GLint maxNameLength = 0; glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxNameLength); std::vector<GLchar> nameBytes(maxNameLength); for (GLint b = 0; b < ssboCount; b++) { GLint length; glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, b, maxNameLength, &length, nameBytes.data()); std::string bufferName(nameBytes.data()); GLenum props = GL_BUFFER_BINDING; GLint binding = -1; glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, b, 1, &props, 1, nullptr, &binding); auto requestedBinding = slotBindings.find(std::string(bufferName)); if (requestedBinding != slotBindings.end()) { if (binding != (*requestedBinding)._location) { binding = (*requestedBinding)._location; glShaderStorageBlockBinding(glprogram, b, binding); } } static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER); resourceBuffers.insert(Shader::Slot(bufferName, binding, element, -1)); } } return ssboCount;*/ }
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { GLint uniformsCount = 0; #if (GPU_FEATURE_PROFILE == GPU_LEGACY) GLint currentProgram = 0; glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); glUseProgram(glprogram); #endif glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); for (int i = 0; i < uniformsCount; i++) { const GLint NAME_LENGTH = 256; GLchar name[NAME_LENGTH]; GLint length = 0; GLint size = 0; GLenum type = 0; glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); GLint location = glGetUniformLocation(glprogram, name); const GLint INVALID_UNIFORM_LOCATION = -1; // Try to make sense of the gltype auto elementResource = getFormatFromGLUniform(type); // The uniform as a standard var type if (location != INVALID_UNIFORM_LOCATION) { // Let's make sure the name doesn't contains an array element std::string sname(name); auto foundBracket = sname.find_first_of('['); if (foundBracket != std::string::npos) { // std::string arrayname = sname.substr(0, foundBracket); if (sname[foundBracket + 1] == '0') { sname = sname.substr(0, foundBracket); } else { // skip this uniform since it's not the first element of an array continue; } } if (elementResource._resource == Resource::BUFFER) { uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); } else { // For texture/Sampler, the location is the actual binding value GLint binding = -1; glGetUniformiv(glprogram, location, &binding); auto requestedBinding = slotBindings.find(std::string(sname)); if (requestedBinding != slotBindings.end()) { if (binding != (*requestedBinding)._location) { binding = (*requestedBinding)._location; #if (GPU_FEATURE_PROFILE == GPU_LEGACY) glUniform1i(location, binding); #else glProgramUniform1i(glprogram, location, binding); #endif } } textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); } } } #if (GPU_FEATURE_PROFILE == GPU_LEGACY) glUseProgram(currentProgram); #endif return uniformsCount; }