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;
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)
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),
("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 = [
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)
{
if(type.base_type)
unused_nodes.erase(type.base_type);
+ if(type.base_image)
+ unused_nodes.erase(type.base_image);
unused_nodes.insert(&type);
}
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));
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
#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"
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);
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;
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));
}
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)))
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);
}
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;
}
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;
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 &);
{ "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 },
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))
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");
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");
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)
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)
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)
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;
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 &);
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,
{
CAP_SHADER = 1,
CAP_GEOMETRY = 2,
+ CAP_STORAGE_IMAGE_MULTISAMPLE = 27,
CAP_IMAGE_CUBE_ARRAY = 34,
CAP_SAMPLED_1D = 43,
CAP_IMAGE_1D = 44,
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,
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 &);
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)
{