features.arb_gpu_shader5 = (ver>=Version(4, 0));
features.arb_separate_shader_objects = (ver>=Version(4, 1));
features.arb_uniform_buffer_object = (ver>=Version(3, 2));
+ features.arb_shader_storage_buffer_object = (ver>=Version(4, 2));
features.ext_gpu_shader4 = (ver>=Version(2, 1));
features.ext_texture_array = (ver>=Version(3, 0));
features.uniform_binding_range = (ver>=Version(4, 3) ? 84 : ver>=Version(4, 0) ? 60 :
features.texture_binding_range = (ver>=Version(4, 3) ? 96 : ver>=Version(4, 0) ? 80 :
ver>=Version(3, 2) ? 48 : ver>=Version(1, 4) ? 32 : 16);
features.storage_texture_binding_range = 8;
+ features.storage_buffer_binding_range = 8;
break;
case OPENGL_ES:
if(ver.major==2)
features.arb_gpu_shader5 = (ver>=Version(3, 2));
features.arb_separate_shader_objects = (ver>=Version(3, 1));
features.arb_uniform_buffer_object = (ver>=Version(3, 0));
+ features.arb_shader_storage_buffer_object = (ver>=Version(3, 1));
features.ext_gpu_shader4 = (ver>=Version(3, 0));
features.ext_texture_array = (ver>=Version(3, 0));
features.uniform_binding_range = (ver>=Version(3, 2) ? 72 : ver>=Version(3, 1) ? 36 : 24);
features.texture_binding_range = (ver>=Version(3, 2) ? 96 : ver>=Version(3, 1) ? 48 :
ver>=Version(3, 0) ? 32 : 8);
features.storage_texture_binding_range = 4;
+ features.storage_buffer_binding_range = 4;
break;
case VULKAN:
features.glsl_version = Version(4, 60);
features.uniform_binding_range = 72;
features.texture_binding_range = 96;
features.storage_texture_binding_range = 24;
+ features.storage_buffer_binding_range = 24;
break;
default:
throw invalid_argument("Features::from_api_version");
bool arb_gpu_shader5 = false;
bool arb_separate_shader_objects = false;
bool arb_uniform_buffer_object = false;
+ bool arb_shader_storage_buffer_object = false;
bool ext_gpu_shader4 = false;
bool ext_texture_array = false;
unsigned constant_id_range = 0x80000000U;
unsigned uniform_binding_range = 24;
unsigned texture_binding_range = 16;
unsigned storage_texture_binding_range = 8;
+ unsigned storage_buffer_binding_range = 8;
static Features from_api_version(GraphicsApi, const Version &);
static Features latest(GraphicsApi);
allocate_locations("uniform");
for(VariableDeclaration *b: unbound_blocks)
- bind_uniform(b->layout, b->block_declaration->block_name, features.uniform_binding_range);
+ {
+ unsigned range = (b->interface=="buffer" ? features.storage_buffer_binding_range : features.uniform_binding_range);
+ bind_uniform(b->layout, b->block_declaration->block_name, range);
+ }
for(VariableDeclaration *t: unbound_textures)
{
const TypeDeclaration *base_type = get_ultimate_base_type(t->type_declaration);
unplaced_variables.push_back(&var);
}
- if(var.interface=="uniform")
+ if(var.interface=="uniform" || var.interface=="buffer")
{
if(var.block_declaration)
{
{
if(iface=="uniform")
return check_version(Version(3, 0));
+ else if(iface=="buffer")
+ return check_version(Version(3, 10));
else
return check_version(Version(3, 20));
}
+ else if(iface=="buffer")
+ {
+ if(check_version(Version(4, 30)))
+ return true;
+ else
+ return check_extension(&Features::arb_shader_storage_buffer_object);
+ }
else if(check_version(Version(1, 50)))
return true;
else if(iface=="uniform")
append("#extension GL_ARB_separate_shader_objects: require\n");
if(s.required_features.arb_uniform_buffer_object)
append("#extension GL_ARB_uniform_buffer_object: require\n");
+ if(s.required_features.arb_shader_storage_buffer_object)
+ append("#extension GL_ARB_shader_storage_buffer_object: require\n");
if(s.required_features.ext_gpu_shader4)
append("#extension GL_EXT_gpu_shader4: require\n");
if(s.required_features.ext_texture_array)
bool Parser::is_interface_qualifier(const string &token)
{
- return (token=="uniform" || token=="in" || token=="out");
+ return (token=="uniform" || token=="in" || token=="out" || token=="buffer");
}
bool Parser::is_sampling_qualifier(const string &token)
{
string next = tokenizer.peek_token(1);
if(is_type(next) || is_qualifier(next))
+ {
+ if(token=="buffer")
+ throw parse_error(tokenizer.get_location(), token, "buffer block declaration");
return parse_variable_declaration();
+ }
else
{
RefPtr<StructDeclaration> iface_strct = parse_interface_block();
return STORAGE_OUTPUT;
else if(iface=="uniform")
return (block ? STORAGE_UNIFORM : STORAGE_UNIFORM_CONSTANT);
+ else if(iface=="buffer")
+ return STORAGE_BUFFER;
else if(iface.empty())
return STORAGE_PRIVATE;
else
if(basic->kind==BasicTypeDeclaration::ARRAY)
{
if(!var.array_size)
- throw logic_error("array without size");
+ return get_array_type_id(*basic->base_type, 0, basic->extended_alignment);
SetFlag set_const(constant_expression);
r_expression_result_id = 0;
STORAGE_OUTPUT = 3,
STORAGE_PRIVATE = 6,
STORAGE_FUNCTION = 7,
- STORAGE_PUSH_CONSTANT = 9
+ STORAGE_PUSH_CONSTANT = 9,
+ STORAGE_BUFFER = 12
};
enum SpirVDecoration
}
else if(iface_block)
{
- allowed = (iface_block->interface=="uniform");
+ allowed = (iface_block->interface=="uniform" || iface_block->interface=="buffer");
err_descr = "non-uniform interface block";
}
}
error(var, "Type 'bool' not allowed on interface variable");
}
- if(var.array && !var.array_size)
- error(var, "Array must have a size");
+ if(var.array)
+ {
+ if(iface_block && iface_block->interface=="buffer")
+ {
+ if(&var!=iface_block->block_declaration->members.body.back().get())
+ error(var, "Unsized array is only allowed at the end of a storage block");
+ }
+ else if(!var.array_size)
+ error(var, "Array must have a size");
+ }
if(var.init_expression)
{
--- /dev/null
+buffer Data
+{
+ vec4 array[];
+ float value;
+};
+
+#pragma MSP stage(vertex)
+layout(location=0) in int i;
+void main()
+{
+ gl_Position = array[i];
+}
+
+/* Expected error:
+<test>:3: Unsized array is only allowed at the end of a storage block
+*/
--- /dev/null
+buffer Data
+{
+ vec4 array[];
+};
+
+#pragma MSP stage(vertex)
+layout(location=0) in int i;
+void main()
+{
+ gl_Position = array[i];
+}
+
+/* Expected output: vertex
+buffer Data
+{
+ vec4 array[];
+};
+layout(location=0) in int i;
+void main()
+{
+ gl_Position = array[i];
+ gl_Position.z = gl_Position.z*2.0-gl_Position.w;
+}
+*/