|
|
|
|
@@ -153,237 +153,6 @@ static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
|
|
|
|
|
/** \name Creation / Destruction
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static Type gpu_type_from_gl_type(int gl_type)
|
|
|
|
|
{
|
|
|
|
|
switch (gl_type) {
|
|
|
|
|
case GL_FLOAT:
|
|
|
|
|
return Type::FLOAT;
|
|
|
|
|
case GL_FLOAT_VEC2:
|
|
|
|
|
return Type::VEC2;
|
|
|
|
|
case GL_FLOAT_VEC3:
|
|
|
|
|
return Type::VEC3;
|
|
|
|
|
case GL_FLOAT_VEC4:
|
|
|
|
|
return Type::VEC4;
|
|
|
|
|
case GL_FLOAT_MAT3:
|
|
|
|
|
return Type::MAT3;
|
|
|
|
|
case GL_FLOAT_MAT4:
|
|
|
|
|
return Type::MAT4;
|
|
|
|
|
case GL_UNSIGNED_INT:
|
|
|
|
|
return Type::UINT;
|
|
|
|
|
case GL_UNSIGNED_INT_VEC2:
|
|
|
|
|
return Type::UVEC2;
|
|
|
|
|
case GL_UNSIGNED_INT_VEC3:
|
|
|
|
|
return Type::UVEC3;
|
|
|
|
|
case GL_UNSIGNED_INT_VEC4:
|
|
|
|
|
return Type::UVEC4;
|
|
|
|
|
case GL_INT:
|
|
|
|
|
return Type::INT;
|
|
|
|
|
case GL_INT_VEC2:
|
|
|
|
|
return Type::IVEC2;
|
|
|
|
|
case GL_INT_VEC3:
|
|
|
|
|
return Type::IVEC3;
|
|
|
|
|
case GL_INT_VEC4:
|
|
|
|
|
return Type::IVEC4;
|
|
|
|
|
case GL_BOOL:
|
|
|
|
|
return Type::BOOL;
|
|
|
|
|
case GL_FLOAT_MAT2:
|
|
|
|
|
case GL_FLOAT_MAT2x3:
|
|
|
|
|
case GL_FLOAT_MAT2x4:
|
|
|
|
|
case GL_FLOAT_MAT3x2:
|
|
|
|
|
case GL_FLOAT_MAT3x4:
|
|
|
|
|
case GL_FLOAT_MAT4x2:
|
|
|
|
|
case GL_FLOAT_MAT4x3:
|
|
|
|
|
default:
|
|
|
|
|
BLI_assert(0);
|
|
|
|
|
}
|
|
|
|
|
return Type::FLOAT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLShaderInterface::GLShaderInterface(GLuint program)
|
|
|
|
|
{
|
|
|
|
|
GLuint last_program;
|
|
|
|
|
glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program);
|
|
|
|
|
|
|
|
|
|
/* Necessary to make #glUniform works. */
|
|
|
|
|
glUseProgram(program);
|
|
|
|
|
|
|
|
|
|
GLint max_attr_name_len = 0, attr_len = 0;
|
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len);
|
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
|
|
|
|
|
|
|
|
|
|
GLint max_ubo_name_len = 0, ubo_len = 0;
|
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
|
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
|
|
|
|
|
|
|
|
|
|
GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0;
|
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
|
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
|
|
|
|
|
uniform_len = active_uniform_len;
|
|
|
|
|
|
|
|
|
|
GLint max_ssbo_name_len = 0, ssbo_len = 0;
|
|
|
|
|
glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssbo_len);
|
|
|
|
|
glGetProgramInterfaceiv(
|
|
|
|
|
program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len);
|
|
|
|
|
|
|
|
|
|
BLI_assert_msg(ubo_len <= 16, "enabled_ubo_mask_ is uint16_t");
|
|
|
|
|
|
|
|
|
|
/* Work around driver bug with Intel HD 4600 on Windows 7/8, where
|
|
|
|
|
* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */
|
|
|
|
|
if (attr_len > 0 && max_attr_name_len == 0) {
|
|
|
|
|
max_attr_name_len = 256;
|
|
|
|
|
}
|
|
|
|
|
if (ubo_len > 0 && max_ubo_name_len == 0) {
|
|
|
|
|
max_ubo_name_len = 256;
|
|
|
|
|
}
|
|
|
|
|
if (uniform_len > 0 && max_uniform_name_len == 0) {
|
|
|
|
|
max_uniform_name_len = 256;
|
|
|
|
|
}
|
|
|
|
|
if (ssbo_len > 0 && max_ssbo_name_len == 0) {
|
|
|
|
|
max_ssbo_name_len = 256;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
|
|
|
|
|
* allocating the uniform array. */
|
|
|
|
|
GLint max_ubo_uni_len = 0;
|
|
|
|
|
for (int i = 0; i < ubo_len; i++) {
|
|
|
|
|
GLint ubo_uni_len;
|
|
|
|
|
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
|
|
|
|
|
max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len);
|
|
|
|
|
uniform_len -= ubo_uni_len;
|
|
|
|
|
}
|
|
|
|
|
/* Bit set to true if uniform comes from a uniform block. */
|
|
|
|
|
BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__);
|
|
|
|
|
/* Set uniforms from block for exclusion. */
|
|
|
|
|
GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__);
|
|
|
|
|
for (int i = 0; i < ubo_len; i++) {
|
|
|
|
|
GLint ubo_uni_len;
|
|
|
|
|
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
|
|
|
|
|
glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids);
|
|
|
|
|
for (int u = 0; u < ubo_uni_len; u++) {
|
|
|
|
|
BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(ubo_uni_ids);
|
|
|
|
|
|
|
|
|
|
int input_tot_len = attr_len + ubo_len + uniform_len + ssbo_len;
|
|
|
|
|
inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
|
|
|
|
|
|
|
|
|
|
const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
|
|
|
|
|
uniform_len * max_uniform_name_len +
|
|
|
|
|
ssbo_len * max_ssbo_name_len;
|
|
|
|
|
name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer");
|
|
|
|
|
uint32_t name_buffer_offset = 0;
|
|
|
|
|
|
|
|
|
|
/* Attributes */
|
|
|
|
|
enabled_attr_mask_ = 0;
|
|
|
|
|
for (int i = 0; i < attr_len; i++) {
|
|
|
|
|
char *name = name_buffer_ + name_buffer_offset;
|
|
|
|
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
|
|
|
GLsizei name_len = 0;
|
|
|
|
|
GLenum type;
|
|
|
|
|
GLint size;
|
|
|
|
|
|
|
|
|
|
glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name);
|
|
|
|
|
GLint location = glGetAttribLocation(program, name);
|
|
|
|
|
/* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
|
|
|
|
|
if (location == -1) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderInput *input = &inputs_[attr_len_++];
|
|
|
|
|
input->location = input->binding = location;
|
|
|
|
|
|
|
|
|
|
name_buffer_offset += set_input_name(input, name, name_len);
|
|
|
|
|
enabled_attr_mask_ |= (1 << input->location);
|
|
|
|
|
|
|
|
|
|
/* Used in `GPU_shader_get_attribute_info`. */
|
|
|
|
|
attr_types_[input->location] = uint8_t(gpu_type_from_gl_type(type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Uniform Blocks */
|
|
|
|
|
for (int i = 0; i < ubo_len; i++) {
|
|
|
|
|
char *name = name_buffer_ + name_buffer_offset;
|
|
|
|
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
|
|
|
GLsizei name_len = 0;
|
|
|
|
|
|
|
|
|
|
glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
|
|
|
|
|
|
|
|
|
|
ShaderInput *input = &inputs_[attr_len_ + ubo_len_++];
|
|
|
|
|
input->binding = input->location = block_binding(program, i);
|
|
|
|
|
|
|
|
|
|
name_buffer_offset += this->set_input_name(input, name, name_len);
|
|
|
|
|
enabled_ubo_mask_ |= (1 << input->binding);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Uniforms & samplers & images */
|
|
|
|
|
for (int i = 0, sampler = 0, image = 0; i < active_uniform_len; i++) {
|
|
|
|
|
if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
char *name = name_buffer_ + name_buffer_offset;
|
|
|
|
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
|
|
|
GLsizei name_len = 0;
|
|
|
|
|
|
|
|
|
|
glGetActiveUniformName(program, i, remaining_buffer, &name_len, name);
|
|
|
|
|
|
|
|
|
|
ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_++];
|
|
|
|
|
input->location = glGetUniformLocation(program, name);
|
|
|
|
|
input->binding = sampler_binding(program, i, input->location, &sampler);
|
|
|
|
|
|
|
|
|
|
name_buffer_offset += this->set_input_name(input, name, name_len);
|
|
|
|
|
enabled_tex_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
|
|
|
|
|
|
|
|
|
|
if (input->binding == -1) {
|
|
|
|
|
input->binding = image_binding(program, i, input->location, &image);
|
|
|
|
|
|
|
|
|
|
enabled_ima_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* SSBOs */
|
|
|
|
|
for (int i = 0; i < ssbo_len; i++) {
|
|
|
|
|
char *name = name_buffer_ + name_buffer_offset;
|
|
|
|
|
GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
|
|
|
|
|
GLsizei name_len = 0;
|
|
|
|
|
glGetProgramResourceName(
|
|
|
|
|
program, GL_SHADER_STORAGE_BLOCK, i, remaining_buffer, &name_len, name);
|
|
|
|
|
|
|
|
|
|
const GLint binding = ssbo_binding(program, i);
|
|
|
|
|
|
|
|
|
|
ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_++];
|
|
|
|
|
input->binding = input->location = binding;
|
|
|
|
|
|
|
|
|
|
name_buffer_offset += this->set_input_name(input, name, name_len);
|
|
|
|
|
enabled_ssbo_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Builtin Uniforms */
|
|
|
|
|
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
|
|
|
|
|
GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
|
|
|
|
|
builtins_[u] = glGetUniformLocation(program, builtin_uniform_name(u));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Builtin Uniforms Blocks */
|
|
|
|
|
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
|
|
|
|
|
GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
|
|
|
|
|
const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
|
|
|
|
|
builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(uniforms_from_blocks);
|
|
|
|
|
|
|
|
|
|
/* Resize name buffer to save some memory. */
|
|
|
|
|
if (name_buffer_offset < name_buffer_len) {
|
|
|
|
|
name_buffer_ = (char *)MEM_reallocN(name_buffer_, name_buffer_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this->debug_print();
|
|
|
|
|
|
|
|
|
|
this->sort_inputs();
|
|
|
|
|
|
|
|
|
|
glUseProgram(last_program);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info)
|
|
|
|
|
{
|
|
|
|
|
using namespace blender::gpu::shader;
|
|
|
|
|
|