]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/spirv.cpp
Add support for storage images in shaders
[libs/gl.git] / source / glsl / spirv.cpp
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)