From 2b1dc627491c987b0459226dcb8ac6aadd7ee4d3 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 11 Apr 2022 14:37:01 +0300 Subject: [PATCH] Add support for storage images in shaders --- builtin_data/_builtin.glsl | 38 +++++++++++++++ scripts/builtin_funcs.py | 40 ++++++++++------ source/glsl/debug.cpp | 4 ++ source/glsl/optimize.cpp | 2 + source/glsl/output.cpp | 3 ++ source/glsl/reflect.cpp | 2 + source/glsl/resolve.cpp | 64 ++++++++++++++++++++++--- source/glsl/resolve.h | 4 +- source/glsl/spirv.cpp | 92 +++++++++++++++++++++++++++++++++--- source/glsl/spirv.h | 4 +- source/glsl/spirvconstants.h | 27 +++++++++++ source/glsl/syntax.h | 4 +- source/glsl/validate.cpp | 14 ++++++ 13 files changed, 269 insertions(+), 29 deletions(-) diff --git a/builtin_data/_builtin.glsl b/builtin_data/_builtin.glsl index b671f944..157e05a7 100644 --- a/builtin_data/_builtin.glsl +++ b/builtin_data/_builtin.glsl @@ -41,6 +41,15 @@ typedef image(dimensions=cube, shadow, sampled) float samplerCubeShadow; typedef image(dimensions=cube[], shadow, sampled) float samplerCubeArrayShadow; typedef image(dimensions=2, sampled, multisample) float sampler2DMS; typedef image(dimensions=2[], sampled, multisample) float sampler2DMSArray; +typedef image(dimensions=1) float image1D; +typedef image(dimensions=2) float image2D; +typedef image(dimensions=3) float image3D; +typedef image(dimensions=cube) float imageCube; +typedef image(dimensions=1[]) float image1DArray; +typedef image(dimensions=2[]) float image2DArray; +typedef image(dimensions=cube[]) float imageCubeArray; +typedef image(dimensions=2, multisample) float image2DMS; +typedef image(dimensions=2[], multisample) float image2DMSArray; const float PI = 3.1415926535; @@ -532,6 +541,35 @@ vec4 texelFetch(sampler1DArray sampler, ivec2 P, int lod); vec4 texelFetch(sampler2DArray sampler, ivec3 P, int lod); vec4 texelFetch(sampler2DMS sampler, ivec2 P, int sample); vec4 texelFetch(sampler2DMSArray sampler, ivec3 P, int sample); +int imageSize(image1D image); +ivec2 imageSize(image2D image); +ivec3 imageSize(image3D image); +ivec2 imageSize(image1DArray image); +ivec3 imageSize(image2DArray image); +ivec2 imageSize(imageCube image); +ivec3 imageSize(imageCubeArray image); +ivec2 imageSize(image2DMS image); +ivec3 imageSize(image2DMSArray image); +int imageSamples(image2DMS image); +int imageSamples(image2DMSArray image); +vec4 imageLoad(image1D image, int P); +vec4 imageLoad(image2D image, ivec2 P); +vec4 imageLoad(image3D image, ivec3 P); +vec4 imageLoad(image1DArray image, ivec2 P); +vec4 imageLoad(image2DArray image, ivec3 P); +vec4 imageLoad(imageCube image, ivec3 P); +vec4 imageLoad(imageCubeArray image, ivec4 P); +vec4 imageLoad(image2DMS image, ivec2 P, int sample); +vec4 imageLoad(image2DMSArray image, ivec3 P, int sample); +void imageStore(image1D image, int P, vec4 data); +void imageStore(image2D image, ivec2 P, vec4 data); +void imageStore(image3D image, ivec3 P, vec4 data); +void imageStore(image1DArray image, ivec2 P, vec4 data); +void imageStore(image2DArray image, ivec3 P, vec4 data); +void imageStore(imageCube image, ivec3 P, vec4 data); +void imageStore(imageCubeArray image, ivec4 P, vec4 data); +void imageStore(image2DMS image, ivec2 P, int sample, vec4 data); +void imageStore(image2DMSArray image, ivec3 P, int sample, vec4 data); // END BUILTIN FUNCTIONS #pragma MSP stage(vertex) diff --git a/scripts/builtin_funcs.py b/scripts/builtin_funcs.py index 5ff3a57f..16c5721b 100755 --- a/scripts/builtin_funcs.py +++ b/scripts/builtin_funcs.py @@ -61,11 +61,15 @@ arithmeticvectypes = float32vectypes+sint32vectypes+uint32vectypes boolvectypes = ("bvec2", "bvec3", "bvec4") squarematrixtypes = ("mat2", "mat3", "mat4") matrixtypes = squarematrixtypes+("mat2x3", "mat3x2", "mat2x4", "mat4x2", "mat3x4", "mat4x3") -flatsamplertypes = ("sampler1D", "sampler2D", "sampler3D", "sampler1DArray", "sampler2DArray") -colorsamplertypes = flatsamplertypes+("samplerCube", "samplerCubeArray") -shadowsamplertypes = ("sampler1DShadow", "sampler2DShadow", "samplerCubeShadow", "sampler1DArrayShadow", "sampler2DArrayShadow", "samplerCubeArrayShadow") -mssamplertypes = ("sampler2DMS", "sampler2DMSArray") -samplertypes = colorsamplertypes+shadowsamplertypes +flatdimensions = ("1D", "2D", "3D", "1DArray", "2DArray") +colordimensions = flatdimensions+("Cube", "CubeArray") +shadowdimensions = ("1DShadow", "2DShadow", "CubeShadow", "1DArrayShadow", "2DArrayShadow", "CubeArrayShadow") +msdimensions = ("2DMS", "2DMSArray") +dimensions = colordimensions+shadowdimensions +samplertypes = lambda d: tuple("sampler"+i for i in d) +imagetypes = lambda d: tuple("image"+i for i in d) +for i in colordimensions+msdimensions: + traits["image"+i] = traits["sampler"+i] shared_funcs = [ # Trigonometric ("T radians(T degrees)", float32types), @@ -158,16 +162,24 @@ shared_funcs = [ ("int[T::Dim] findMSB(T value)", int32types), # Texture - ("int[T::IDim] textureSize(T sampler, int lod)", samplertypes+mssamplertypes), - ("vec2 textureQueryLod(T sampler, float[T::LDim] P)", samplertypes), - ("int textureQueryLevels(T sampler)", samplertypes), - ("int textureSamples(T sampler)", mssamplertypes), - ("vec4 texture(T sampler, float[T::CDim] P)", colorsamplertypes), - ("float texture(T sampler, float[T::CDim] P)", tuple(s for s in shadowsamplertypes if "CubeArray" not in s)), + ("int[T::IDim] textureSize(T sampler, int lod)", samplertypes(dimensions+msdimensions)), + ("vec2 textureQueryLod(T sampler, float[T::LDim] P)", samplertypes(dimensions)), + ("int textureQueryLevels(T sampler)", samplertypes(dimensions)), + ("int textureSamples(T sampler)", samplertypes(msdimensions)), + ("vec4 texture(T sampler, float[T::CDim] P)", samplertypes(colordimensions)), + ("float texture(T sampler, float[T::CDim] P)", tuple(s for s in samplertypes(shadowdimensions) if "CubeArray" not in s)), "float texture(samplerCubeArrayShadow sampler, vec4 P, float compare)", - ("vec4 textureLod(T sampler, float[T::CDim] P, float lod)", colorsamplertypes), - ("vec4 texelFetch(T sampler, int[T::CDim] P, int lod)", flatsamplertypes), - ("vec4 texelFetch(T sampler, int[T::CDim] P, int sample)", mssamplertypes) + ("vec4 textureLod(T sampler, float[T::CDim] P, float lod)", samplertypes(colordimensions)), + ("vec4 texelFetch(T sampler, int[T::CDim] P, int lod)", samplertypes(flatdimensions)), + ("vec4 texelFetch(T sampler, int[T::CDim] P, int sample)", samplertypes(msdimensions)), + + # Image + ("int[T::IDim] imageSize(T image)", imagetypes(colordimensions+msdimensions)), + ("int imageSamples(T image)", imagetypes(msdimensions)), + ("vec4 imageLoad(T image, int[T::CDim] P)", imagetypes(colordimensions)), + ("vec4 imageLoad(T image, int[T::CDim] P, int sample)", imagetypes(msdimensions)), + ("void imageStore(T image, int[T::CDim] P, vec4 data)", imagetypes(colordimensions)), + ("void imageStore(T image, int[T::CDim] P, int sample, vec4 data)", imagetypes(msdimensions)) ] fragment_funcs = [ diff --git a/source/glsl/debug.cpp b/source/glsl/debug.cpp index c741ed57..a090c362 100644 --- a/source/glsl/debug.cpp +++ b/source/glsl/debug.cpp @@ -355,6 +355,10 @@ void DumpTree::visit(ImageTypeDeclaration &type) branches.emplace_back(format("Dimensions: %s%s", dims[type.dimensions-1], (type.array ? " array" : ""))); if(type.base_type) branches.emplace_back(format("Element type: %s %s", get_label(*type.base_type), format_type(type.base_type->name))); + if(!type.format.empty()) + branches.emplace_back(format("Texel format: %s", type.format)); + if(type.sampled) + branches.emplace_back("Sampled"); if(type.shadow) branches.emplace_back("Shadow"); if(type.multisample) diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 6e4b5677..a35e2cd2 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -1229,6 +1229,8 @@ void UnusedTypeRemover::visit(ImageTypeDeclaration &type) { if(type.base_type) unused_nodes.erase(type.base_type); + if(type.base_image) + unused_nodes.erase(type.base_image); unused_nodes.insert(&type); } diff --git a/source/glsl/output.cpp b/source/glsl/output.cpp index 07da64e3..d28de156 100644 --- a/source/glsl/output.cpp +++ b/source/glsl/output.cpp @@ -295,6 +295,9 @@ void Formatter::visit(VariableDeclaration &var) else { string type_name = var.type_declaration->name; + if(const ImageTypeDeclaration *image = dynamic_cast(var.type_declaration)) + if(image->base_image) + type_name = image->base_image->name; if(var.array) type_name = type_name.substr(0, type_name.find('[')); append(format("%s %s", type_name, var.name)); diff --git a/source/glsl/reflect.cpp b/source/glsl/reflect.cpp index 64dbbf6e..e64b9a3c 100644 --- a/source/glsl/reflect.cpp +++ b/source/glsl/reflect.cpp @@ -180,6 +180,8 @@ void TypeComparer::visit(ImageTypeDeclaration &image) r_result = false; else if(image1->sampled!=image.sampled || image1->shadow!=image.shadow || image1->multisample!=image.multisample) r_result = false; + else if(image1->format!=image.format) + r_result = false; else if(image1->base_type && image.base_type) compare(*image1->base_type, *image.base_type); else diff --git a/source/glsl/resolve.cpp b/source/glsl/resolve.cpp index 7c58bc6b..aeccd1bf 100644 --- a/source/glsl/resolve.cpp +++ b/source/glsl/resolve.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "reflect.h" #include "resolve.h" @@ -46,7 +47,27 @@ TypeDeclaration *TypeResolver::get_or_create_array_type(TypeDeclaration &type) return array; } -void TypeResolver::resolve_type(TypeDeclaration *&type, const string &name, bool array) +TypeDeclaration *TypeResolver::get_or_create_image_type(ImageTypeDeclaration &type, const std::string &texel_format) +{ + if(texel_format.empty()) + return &type; + + auto key = make_pair(&type, texel_format); + auto i = image_types.find(key); + if(i!=image_types.end()) + return i->second; + + ImageTypeDeclaration *image = new ImageTypeDeclaration(type); + image->source = INTERNAL_SOURCE; + image->name = format("%s_%s", type.name, texel_format); + image->format = texel_format; + image->base_image = &type; + stage->content.body.insert(type_insert_point, image); + image_types[key] = image; + return image; +} + +void TypeResolver::resolve_type(TypeDeclaration *&type, const string &name, bool array, const Layout *layout) { TypeDeclaration *resolved = 0; auto i = stage->types.find(name); @@ -56,8 +77,23 @@ void TypeResolver::resolve_type(TypeDeclaration *&type, const string &name, bool resolved = (j!=alias_map.end() ? j->second : i->second); } - if(resolved && array) - resolved = get_or_create_array_type(*resolved); + if(resolved) + { + if(ImageTypeDeclaration *image = dynamic_cast(resolved)) + if(layout) + { + static const Regex r_format("^(r|rg|rgba)(8|16|8_snorm|16_snorm|16f|32f)$"); + for(const Layout::Qualifier &q: layout->qualifiers) + if(r_format.match(q.name)) + { + resolved = get_or_create_image_type(*image, q.name); + break; + } + } + + if(array) + resolved = get_or_create_array_type(*resolved); + } r_any_resolved |= (resolved!=type); type=resolved; @@ -99,6 +135,10 @@ void TypeResolver::visit(BasicTypeDeclaration &type) void TypeResolver::visit(ImageTypeDeclaration &type) { resolve_type(type.base_type, type.base, false); + + if(!type.format.empty() && type.base_image) + image_types[make_pair(type.base_image, type.format)] = &type; + stage->types.insert(make_pair(type.name, &type)); } @@ -116,7 +156,7 @@ void TypeResolver::visit(StructDeclaration &strct) void TypeResolver::visit(VariableDeclaration &var) { - resolve_type(var.type_declaration, var.type, var.array); + resolve_type(var.type_declaration, var.type, var.array, var.layout.get()); var.block_declaration = 0; if(StructDeclaration *strct = dynamic_cast(get_ultimate_base_type(var.type_declaration))) @@ -1104,6 +1144,13 @@ void ExpressionResolver::visit(FunctionCall &call) else if(compat!=SAME_TYPE) return; } + else + { + ImageTypeDeclaration *arg_image = dynamic_cast(arg_type); + ImageTypeDeclaration *param_image = dynamic_cast(param_type); + if(!arg_image || !param_image || arg_image->base_image!=param_image) + return; + } } resolve(call, call.declaration->return_type_declaration, false); } @@ -1198,8 +1245,13 @@ void FunctionResolver::visit(FunctionCall &call) bool has_signature = true; for(auto i=call.arguments.begin(); (has_signature && i!=call.arguments.end()); ++i) { - if((*i)->type) - append(arg_types, ",", (*i)->type->name); + if(const TypeDeclaration *type = (*i)->type) + { + if(const ImageTypeDeclaration *image = dynamic_cast(type)) + if(image->base_image) + type = image->base_image; + append(arg_types, ",", type->name); + } else has_signature = false; } diff --git a/source/glsl/resolve.h b/source/glsl/resolve.h index a11b849e..d592e4ef 100644 --- a/source/glsl/resolve.h +++ b/source/glsl/resolve.h @@ -31,6 +31,7 @@ private: Stage *stage = 0; std::map alias_map; std::map, TypeDeclaration *> array_types; + std::map, ImageTypeDeclaration *> image_types; NodeList::iterator type_insert_point; NodeList::iterator block_member_type_ins_pt; VariableDeclaration *iface_block = 0; @@ -41,7 +42,8 @@ public: private: TypeDeclaration *get_or_create_array_type(TypeDeclaration &); - void resolve_type(TypeDeclaration *&, const std::string &, bool); + TypeDeclaration *get_or_create_image_type(ImageTypeDeclaration &, const std::string &); + void resolve_type(TypeDeclaration *&, const std::string &, bool, const Layout * = 0); virtual void visit(Block &); virtual void visit(BasicTypeDeclaration &); virtual void visit(ImageTypeDeclaration &); diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 61e59378..9cb1b7f2 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -114,7 +114,11 @@ const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] = { "textureSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, - { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texel_fetch }, + { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageLoad", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageStore", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_store }, { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 }, { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 }, { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 }, @@ -199,6 +203,50 @@ SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const strin throw invalid_argument("SpirVGenerator::get_builtin_semantic"); } +SpirVFormat SpirVGenerator::get_format(const std::string &name) +{ + if(name.empty()) + return FORMAT_UNKNOWN; + else if(name=="rgba32f") + return FORMAT_RGBA32F; + else if(name=="rgba16f") + return FORMAT_RGBA16F; + else if(name=="r32f") + return FORMAT_R32F; + else if(name=="rgba8") + return FORMAT_RGBA8; + else if(name=="rgba8_snorm") + return FORMAT_RGBA8_SNORM; + else if(name=="rg32f") + return FORMAT_RG32F; + else if(name=="rg16f") + return FORMAT_RG16F; + else if(name=="r16f") + return FORMAT_R16F; + else if(name=="rgba16") + return FORMAT_RGBA16; + else if(name=="rg16") + return FORMAT_RG16; + else if(name=="rg8") + return FORMAT_RG8; + else if(name=="r16") + return FORMAT_RG16; + else if(name=="r8") + return FORMAT_RG8; + else if(name=="rgba16_snorm") + return FORMAT_RGBA16_SNORM; + else if(name=="rg16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="rg8_snorm") + return FORMAT_RG8_SNORM; + else if(name=="r16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="r8_snorm") + return FORMAT_RG8_SNORM; + else + throw invalid_argument("SpirVGenerator::get_format"); +} + void SpirVGenerator::use_capability(Capability cap) { if(used_capabilities.count(cap)) @@ -1292,11 +1340,13 @@ void SpirVGenerator::visit_builtin_texture_query(FunctionCall &call, const vecto Opcode opcode; if(call.name=="textureSize") opcode = OP_IMAGE_QUERY_SIZE_LOD; + else if(call.name=="imageSize") + opcode = OP_IMAGE_QUERY_SIZE; else if(call.name=="textureQueryLod") opcode = OP_IMAGE_QUERY_LOD; else if(call.name=="textureQueryLevels") opcode = OP_IMAGE_QUERY_LEVELS; - else if(call.name=="textureSamples") + else if(call.name=="textureSamples" || call.name=="imageSamples") opcode = OP_IMAGE_QUERY_SAMPLES; else throw internal_error("invalid texture query call"); @@ -1369,14 +1419,20 @@ void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector end_expression(opcode); } -void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector &argument_ids) +void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector &argument_ids) { const ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); - Opcode opcode = OP_IMAGE_FETCH; + Opcode opcode; + if(call.name=="texelFetch") + opcode = OP_IMAGE_FETCH; + else if(call.name=="imageLoad") + opcode = OP_IMAGE_READ; + else + throw internal_error("invalid texture fetch call"); bool need_sample = image.multisample; - bool need_lod = !need_sample; + bool need_lod = (opcode==OP_IMAGE_FETCH && !need_sample); if(argument_ids.size()!=2U+need_sample+need_lod) throw internal_error("invalid texture fetch call"); @@ -1392,6 +1448,27 @@ void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector< end_expression(opcode); } +void SpirVGenerator::visit_builtin_texture_store(FunctionCall &call, const vector &argument_ids) +{ + if(argument_ids.size()!=3) + throw internal_error("invalid texture store call"); + + const ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); + + begin_expression(OP_IMAGE_WRITE, get_id(*call.type), 3+image.multisample*2); + for(unsigned i=0; i<2; ++i) + writer.write(argument_ids[i]); + writer.write(argument_ids.back()); + if(image.multisample) + { + writer.write(0x40); // Sample + writer.write(argument_ids[2]); + } + end_expression(OP_IMAGE_WRITE); + + r_expression_result_id = 0; +} + void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector &argument_ids) { if(argument_ids.size()<1) @@ -1507,7 +1584,7 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) writer.write(image.array); writer.write(image.multisample); writer.write(image.sampled ? 1 : 2); - writer.write(0); // Format (unknown) + writer.write(get_format(image.format)); writer.end_op(OP_TYPE_IMAGE); if(image.sampled) @@ -1521,6 +1598,9 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D); else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array) use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY); + + if(image.multisample && !image.sampled) + use_capability(CAP_STORAGE_IMAGE_MULTISAMPLE); } void SpirVGenerator::visit(StructDeclaration &strct) diff --git a/source/glsl/spirv.h b/source/glsl/spirv.h index 23def508..e98fd91e 100644 --- a/source/glsl/spirv.h +++ b/source/glsl/spirv.h @@ -113,6 +113,7 @@ public: private: static StorageClass get_interface_storage(const std::string &, bool); static SpirVBuiltin get_builtin_semantic(const std::string &); + static SpirVFormat get_format(const std::string &); void use_capability(Capability); Id import_extension(const std::string &); Id get_id(Node &) const; @@ -153,7 +154,8 @@ private: void visit_builtin_matrix_comp_mult(FunctionCall &, const std::vector &); void visit_builtin_texture_query(FunctionCall &, const std::vector &); void visit_builtin_texture(FunctionCall &, const std::vector &); - void visit_builtin_texel_fetch(FunctionCall &, const std::vector &); + void visit_builtin_texture_fetch(FunctionCall &, const std::vector &); + void visit_builtin_texture_store(FunctionCall &, const std::vector &); void visit_builtin_interpolate(FunctionCall &, const std::vector &); virtual void visit(ExpressionStatement &); virtual void visit(InterfaceLayout &); diff --git a/source/glsl/spirvconstants.h b/source/glsl/spirvconstants.h index 64daa9ff..ac934eae 100644 --- a/source/glsl/spirvconstants.h +++ b/source/glsl/spirvconstants.h @@ -64,8 +64,11 @@ enum SpirVOpcode OP_IMAGE_SAMPLE_DREF_IMPLICIT_LOD = 89, OP_IMAGE_SAMPLE_DREF_EXPLICIT_LOD = 89, OP_IMAGE_FETCH = 95, + OP_IMAGE_READ = 98, + OP_IMAGE_WRITE = 99, OP_IMAGE = 100, OP_IMAGE_QUERY_SIZE_LOD = 103, + OP_IMAGE_QUERY_SIZE = 104, OP_IMAGE_QUERY_LOD = 105, OP_IMAGE_QUERY_LEVELS = 106, OP_IMAGE_QUERY_SAMPLES = 107, @@ -159,6 +162,7 @@ enum SpirVCapability { CAP_SHADER = 1, CAP_GEOMETRY = 2, + CAP_STORAGE_IMAGE_MULTISAMPLE = 27, CAP_IMAGE_CUBE_ARRAY = 34, CAP_SAMPLED_1D = 43, CAP_IMAGE_1D = 44, @@ -228,6 +232,29 @@ enum SpirVBuiltin BUILTIN_FRAG_DEPTH = 22 }; +enum SpirVFormat +{ + FORMAT_UNKNOWN = 0, + FORMAT_RGBA32F = 1, + FORMAT_RGBA16F = 2, + FORMAT_R32F = 3, + FORMAT_RGBA8 = 4, + FORMAT_RGBA8_SNORM = 5, + FORMAT_RG32F = 6, + FORMAT_RG16F = 7, + FORMAT_R16F = 9, + FORMAT_RGBA16 = 10, + FORMAT_RG16 = 12, + FORMAT_RG8 = 13, + FORMAT_R16 = 14, + FORMAT_R8 = 15, + FORMAT_RGBA16_SNORM = 16, + FORMAT_RG16_SNORM = 17, + FORMAT_RG8_SNORM = 18, + FORMAT_R16_SNORM = 19, + FORMAT_R8_SNORM = 20 +}; + enum SpirVGlslStd450Opcode { GLSL450_ROUND = 1, diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index b6a118d6..63e41921 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -364,12 +364,14 @@ struct ImageTypeDeclaration: TypeDeclaration Dimensions dimensions = TWO; bool array = false; - bool sampled = true; + bool sampled = false; bool shadow = false; bool multisample = false; std::string base; + std::string format; TypeDeclaration *base_type = 0; + ImageTypeDeclaration *base_image = 0; virtual ImageTypeDeclaration *clone() const { return new ImageTypeDeclaration(*this); } virtual void visit(NodeVisitor &); diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 883b950f..6151483c 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -156,6 +156,20 @@ void DeclarationValidator::visit(Layout &layout) allowed = (iface_block && !variable && iface_block->interface=="uniform"); value = false; } + else if(q.name=="rgba32f" || q.name=="rgba16f" || q.name=="rg32f" || q.name=="rg16f" || q.name=="r32f" || q.name=="r16f" || + q.name=="rgba16" || q.name=="rgba8" || q.name=="rg16" || q.name=="rg8" || q.name=="r16" || q.name=="r8" || + q.name=="rgba16_snorm" || q.name=="rgba8_snorm" || q.name=="rg16_snorm" || q.name=="rg8_snorm" || q.name=="r16_snorm" || q.name=="r8_snorm") + { + allowed = variable; + value = false; + if(allowed) + { + const TypeDeclaration *base_type = get_ultimate_base_type(variable->type_declaration); + const ImageTypeDeclaration *image = dynamic_cast(base_type); + allowed = (image && !image->sampled); + err_descr = (image ? "sampled image" : "non-image variable"); + } + } if(!allowed) { -- 2.43.0