]> git.tdb.fi Git - libs/gl.git/commitdiff
Add support for storage images in shaders
authorMikko Rasa <tdb@tdb.fi>
Mon, 11 Apr 2022 11:37:01 +0000 (14:37 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 11 Apr 2022 12:03:53 +0000 (15:03 +0300)
13 files changed:
builtin_data/_builtin.glsl
scripts/builtin_funcs.py
source/glsl/debug.cpp
source/glsl/optimize.cpp
source/glsl/output.cpp
source/glsl/reflect.cpp
source/glsl/resolve.cpp
source/glsl/resolve.h
source/glsl/spirv.cpp
source/glsl/spirv.h
source/glsl/spirvconstants.h
source/glsl/syntax.h
source/glsl/validate.cpp

index b671f944df83da4960a5809fc4b28ab4f07839ff..157e05a792bc658cca519e1c6154062db734267d 100644 (file)
@@ -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)
index 5ff3a57fc68150e58bbc6378f6063b93a449c634..16c5721b0a3de9e77b23a67d664001bdedb9ef77 100755 (executable)
@@ -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 = [
index c741ed57665b2dfae993073c13b387fcec61b0aa..a090c3622079bd9bfeedf2fc517a276d7877d463 100644 (file)
@@ -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)
index 6e4b56771fa3222ce778a53d37b828b5d34554cf..a35e2cd244941cb125b5e3450734ba2e88254b37 100644 (file)
@@ -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);
 }
 
index 07da64e3ba565cdca64a8bb9f58b5d34f11c11eb..d28de156c5a881fede9fb116052370102338c80a 100644 (file)
@@ -295,6 +295,9 @@ void Formatter::visit(VariableDeclaration &var)
        else
        {
                string type_name = var.type_declaration->name;
+               if(const ImageTypeDeclaration *image = dynamic_cast<const ImageTypeDeclaration *>(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));
index 64dbbf6e0e140ddc47385b75f6a966a2658fea8b..e64b9a3c5f175fe6cf3d046f80da15990686456a 100644 (file)
@@ -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
index 7c58bc6b0fe309b3137e2e10b239601cf5797e8e..aeccd1bf05ad18debdc3717264b4e58bfdf25493 100644 (file)
@@ -1,5 +1,6 @@
 #include <msp/core/algorithm.h>
 #include <msp/core/raii.h>
+#include <msp/strings/regex.h>
 #include <msp/strings/utils.h>
 #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<ImageTypeDeclaration *>(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<StructDeclaration *>(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<ImageTypeDeclaration *>(arg_type);
+                               ImageTypeDeclaration *param_image = dynamic_cast<ImageTypeDeclaration *>(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<const ImageTypeDeclaration *>(type))
+                                       if(image->base_image)
+                                               type = image->base_image;
+                               append(arg_types, ",", type->name);
+                       }
                        else
                                has_signature = false;
                }
index a11b849e251acafd887061521ea9e51bf0369141..d592e4efd5a60ddaea72b0533db48474abfe8df8 100644 (file)
@@ -31,6 +31,7 @@ private:
        Stage *stage = 0;
        std::map<TypeDeclaration *, TypeDeclaration *> alias_map;
        std::map<std::pair<TypeDeclaration *, bool>, TypeDeclaration *> array_types;
+       std::map<std::pair<ImageTypeDeclaration *, std::string>, ImageTypeDeclaration *> image_types;
        NodeList<Statement>::iterator type_insert_point;
        NodeList<Statement>::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 &);
index 61e5937856b30d7abc38afc2d5143b03e1ca4b1e..9cb1b7f2e112a8d8d06d85dc92ab3f1d8561dcd5 100644 (file)
@@ -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<Id>
        end_expression(opcode);
 }
 
-void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector<Id> &argument_ids)
+void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector<Id> &argument_ids)
 {
        const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*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<Id> &argument_ids)
+{
+       if(argument_ids.size()!=3)
+               throw internal_error("invalid texture store call");
+
+       const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*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<Id> &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)
index 23def508d719d6ba23296f4d50da59d730e0d264..e98fd91e7142ec0fecabd8850c76557071c5ea06 100644 (file)
@@ -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<Id> &);
        void visit_builtin_texture_query(FunctionCall &, const std::vector<Id> &);
        void visit_builtin_texture(FunctionCall &, const std::vector<Id> &);
-       void visit_builtin_texel_fetch(FunctionCall &, const std::vector<Id> &);
+       void visit_builtin_texture_fetch(FunctionCall &, const std::vector<Id> &);
+       void visit_builtin_texture_store(FunctionCall &, const std::vector<Id> &);
        void visit_builtin_interpolate(FunctionCall &, const std::vector<Id> &);
        virtual void visit(ExpressionStatement &);
        virtual void visit(InterfaceLayout &);
index 64daa9ff01a58f60a92b2ca54669f1f9ac026b73..ac934eae1209c5f9fa2689a3a8b95e3961011d51 100644 (file)
@@ -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,
index b6a118d695218c0652624170d5107546857c6e8c..63e419212f6a68da5f37568d21681d23d8656929 100644 (file)
@@ -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 &);
index 883b950ff07f2e46d9aa0037ddfce2fa2719c425..6151483cbd640d2fcc09c08b5294f69a199e21c3 100644 (file)
@@ -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<const ImageTypeDeclaration *>(base_type);
+                               allowed = (image && !image->sampled);
+                               err_descr = (image ? "sampled image" : "non-image variable");
+                       }
+               }
 
                if(!allowed)
                {