diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index c34029ce..2cf64e79 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -2404,6 +2404,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) uint32_t comp = 0; bool gather = false; bool proj = false; + bool fetch = false; const uint32_t *opt = nullptr; switch (op) @@ -2418,23 +2419,29 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) case OpImageSampleProjDrefImplicitLod: case OpImageSampleProjDrefExplicitLod: dref = ops[4]; - proj = true; opt = &ops[5]; length -= 5; + proj = true; break; case OpImageDrefGather: dref = ops[4]; opt = &ops[5]; - gather = true; length -= 5; + gather = true; break; case OpImageGather: comp = ops[4]; opt = &ops[5]; - gather = true; length -= 5; + gather = true; + break; + + case OpImageFetch: + opt = &ops[4]; + length -= 4; + fetch = true; break; case OpImageSampleProjImplicitLod: @@ -2491,8 +2498,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) if (length) { - flags = opt[0]; - opt++; + flags = *opt++; length--; } @@ -2514,35 +2520,56 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) test(sample, ImageOperandsSampleMask); string expr; - string texop; + bool forward = false; + expr += to_function_name(img, imgtype, fetch, gather, proj, coffsets, (coffset || offset), (grad_x || grad_y), lod, + dref); + expr += "("; + expr += to_function_args(img, imgtype, fetch, gather, proj, coord, coord_components, dref, grad_x, grad_y, lod, + coffset, offset, bias, comp, sample, &forward); + expr += ")"; - if (op == OpImageFetch) - texop += "texelFetch"; + emit_op(result_type, id, expr, forward); +} + +// Returns the function name for a texture sampling function for the specified image and sampling characteristics. +// For some subclasses, the function is a method on the specified image. +string CompilerGLSL::to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, + bool has_lod, bool has_dref) +{ + string fname; + + if (is_fetch) + fname += "texelFetch"; else { - texop += "texture"; + fname += "texture"; - if (gather) - texop += "Gather"; - if (coffsets) - texop += "Offsets"; - if (proj) - texop += "Proj"; - if (grad_x || grad_y) - texop += "Grad"; - if (lod) - texop += "Lod"; + if (is_gather) + fname += "Gather"; + if (has_array_offsets) + fname += "Offsets"; + if (is_proj) + fname += "Proj"; + if (has_grad) + fname += "Grad"; + if (has_lod) + fname += "Lod"; } - if (coffset || offset) - texop += "Offset"; + if (has_offset) + fname += "Offset"; - if (is_legacy()) - texop = legacy_tex_op(texop, imgtype); + return is_legacy() ? legacy_tex_op(fname, imgtype) : fname; +} - expr += texop; - expr += "("; - expr += to_expression(img); +// Returns the function args for a texture sampling function for the specified image and sampling characteristics. +string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref, + uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, + uint32_t bias, uint32_t comp, uint32_t sample, bool *p_forward) +{ + string farg_str = to_expression(img); bool swizz_func = backend.swizzle_is_function; auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * { @@ -2578,84 +2605,84 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) // SPIR-V splits dref and coordinate. if (coord_components == 4) // GLSL also splits the arguments in two. { - expr += ", "; - expr += to_expression(coord); - expr += ", "; - expr += to_expression(dref); + farg_str += ", "; + farg_str += to_expression(coord); + farg_str += ", "; + farg_str += to_expression(dref); } else { // Create a composite which merges coord/dref into a single vector. auto type = expression_type(coord); type.vecsize = coord_components + 1; - expr += ", "; - expr += type_to_glsl_constructor(type); - expr += "("; - expr += coord_expr; - expr += ", "; - expr += to_expression(dref); - expr += ")"; + farg_str += ", "; + farg_str += type_to_glsl_constructor(type); + farg_str += "("; + farg_str += coord_expr; + farg_str += ", "; + farg_str += to_expression(dref); + farg_str += ")"; } } else { - expr += ", "; - expr += coord_expr; + farg_str += ", "; + farg_str += coord_expr; } if (grad_x || grad_y) { forward = forward && should_forward(grad_x); forward = forward && should_forward(grad_y); - expr += ", "; - expr += to_expression(grad_x); - expr += ", "; - expr += to_expression(grad_y); + farg_str += ", "; + farg_str += to_expression(grad_x); + farg_str += ", "; + farg_str += to_expression(grad_y); } if (lod) { forward = forward && should_forward(lod); - expr += ", "; - expr += to_expression(lod); + farg_str += ", "; + farg_str += to_expression(lod); } if (coffset) { forward = forward && should_forward(coffset); - expr += ", "; - expr += to_expression(coffset); + farg_str += ", "; + farg_str += to_expression(coffset); } else if (offset) { forward = forward && should_forward(offset); - expr += ", "; - expr += to_expression(offset); + farg_str += ", "; + farg_str += to_expression(offset); } if (bias) { forward = forward && should_forward(bias); - expr += ", "; - expr += to_expression(bias); + farg_str += ", "; + farg_str += to_expression(bias); } if (comp) { forward = forward && should_forward(comp); - expr += ", "; - expr += to_expression(comp); + farg_str += ", "; + farg_str += to_expression(comp); } if (sample) { - expr += ", "; - expr += to_expression(sample); + farg_str += ", "; + farg_str += to_expression(sample); } - expr += ")"; + *p_forward = forward; - emit_op(result_type, id, expr, forward); + return farg_str; } void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t) diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index a8824f6b..4aa94940 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -160,6 +160,14 @@ protected: virtual void emit_fixup(); virtual std::string variable_decl(const SPIRType &type, const std::string &name); virtual std::string to_func_call_arg(uint32_t id); + virtual std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, + bool has_lod, bool has_dref); + virtual std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref, + uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset, + uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample, + bool *p_forward); std::unique_ptr buffer; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 6c36b3d3..7e48cfbf 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -857,139 +857,50 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, bool is_decl) statement(decl, (is_decl ? ";" : "")); } -// Emit a texture operation -void CompilerMSL::emit_texture_op(const Instruction &i) +// Returns the texture sampling function string for the specified image and sampling characteristics. +string CompilerMSL::to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, + bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod, + bool has_dref) { - auto ops = stream(i); - auto op = static_cast(i.op); - uint32_t length = i.length; - - if (i.offset + length > spirv.size()) - SPIRV_CROSS_THROW("Compiler::compile() opcode out of range."); - - uint32_t result_type = ops[0]; - uint32_t id = ops[1]; - uint32_t img = ops[2]; - uint32_t coord = ops[3]; - uint32_t comp = 0; - bool gather = false; - bool fetch = false; - const uint32_t *opt = nullptr; - - switch (op) - { - case OpImageSampleDrefImplicitLod: - case OpImageSampleDrefExplicitLod: - opt = &ops[5]; - length -= 5; - break; - - case OpImageSampleProjDrefImplicitLod: - case OpImageSampleProjDrefExplicitLod: - opt = &ops[5]; - length -= 5; - break; - - case OpImageDrefGather: - opt = &ops[5]; - gather = true; - length -= 5; - break; - - case OpImageGather: - comp = ops[4]; - opt = &ops[5]; - gather = true; - length -= 5; - break; - - case OpImageFetch: - fetch = true; - opt = &ops[4]; - length -= 4; - break; - - case OpImageSampleImplicitLod: - case OpImageSampleExplicitLod: - case OpImageSampleProjImplicitLod: - case OpImageSampleProjExplicitLod: - default: - opt = &ops[4]; - length -= 4; - break; - } - - uint32_t bias = 0; - uint32_t lod = 0; - uint32_t grad_x = 0; - uint32_t grad_y = 0; - uint32_t coffset = 0; - uint32_t offset = 0; - uint32_t coffsets = 0; - uint32_t sample = 0; - uint32_t flags = 0; - - if (length) - { - flags = *opt; - opt++; - length--; - } - - auto test = [&](uint32_t &v, uint32_t flag) { - if (length && (flags & flag)) - { - v = *opt++; - length--; - } - }; - - test(bias, ImageOperandsBiasMask); - test(lod, ImageOperandsLodMask); - test(grad_x, ImageOperandsGradMask); - test(grad_y, ImageOperandsGradMask); - test(coffset, ImageOperandsConstOffsetMask); - test(offset, ImageOperandsOffsetMask); - test(coffsets, ImageOperandsConstOffsetsMask); - test(sample, ImageOperandsSampleMask); - - auto &img_type = expression_type(img).image; - // Texture reference - string expr = to_expression(img); + string fname = to_expression(img) + "."; // Texture function and sampler - if (fetch) - { - expr += ".read("; - } + if (is_fetch) + fname += "read"; + else if (is_gather) + fname += "gather"; else - { - expr += std::string(".") + (gather ? "gather" : "sample") + "(" + to_sampler_expression(img) + ", "; - } + fname += "sample"; - // Add texture coordinates + if (has_dref) + fname += "_compare"; + + return fname; +} + +// Returns the function args for a texture sampling function for the specified image and sampling characteristics. +string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, + uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x, + uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, + uint32_t comp, uint32_t sample, bool *p_forward) +{ + string farg_str = to_sampler_expression(img); + + // Texture coordinates bool forward = should_forward(coord); auto coord_expr = to_enclosed_expression(coord); string tex_coords = coord_expr; - string array_coord; + const char *alt_coord = ""; - switch (img_type.dim) + switch (imgtype.image.dim) { - case spv::DimBuffer: - break; case Dim1D: - if (img_type.arrayed) - { - tex_coords = coord_expr + ".x"; - array_coord = coord_expr + ".y"; - remove_duplicate_swizzle(tex_coords); - remove_duplicate_swizzle(array_coord); - } - else - { - tex_coords = coord_expr + ".x"; - } + tex_coords = coord_expr + ".x"; + remove_duplicate_swizzle(tex_coords); + + alt_coord = ".y"; + break; case Dim2D: @@ -1007,11 +918,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i) remove_duplicate_swizzle(tex_coords); } - if (img_type.arrayed) - { - array_coord = coord_expr + ".z"; - remove_duplicate_swizzle(array_coord); - } + alt_coord = ".z"; break; @@ -1033,40 +940,48 @@ void CompilerMSL::emit_texture_op(const Instruction &i) remove_duplicate_swizzle(tex_coords); } - if (img_type.arrayed) - { - array_coord = coord_expr + ".w"; - remove_duplicate_swizzle(array_coord); - } + alt_coord = ".w"; break; default: break; } - expr += tex_coords; - // Add texture array index - if (!array_coord.empty()) - expr += ", " + array_coord; + // Use alt coord for projection or texture array + if (imgtype.image.arrayed) + tex_coords += ", " + coord_expr + alt_coord; + else if (is_proj) + tex_coords += " / " + coord_expr + alt_coord; + + farg_str += ", "; + farg_str += tex_coords; + + // Depth compare reference value + if (dref) + { + forward = forward && should_forward(dref); + farg_str += ", "; + farg_str += to_expression(dref); + } // LOD Options if (bias) { forward = forward && should_forward(bias); - expr += ", bias(" + to_expression(bias) + ")"; + farg_str += ", bias(" + to_expression(bias) + ")"; } if (lod) { forward = forward && should_forward(lod); - if (fetch) + if (is_fetch) { - expr += ", " + to_expression(lod); + farg_str += ", " + to_expression(lod); } else { - expr += ", level(" + to_expression(lod) + ")"; + farg_str += ", level(" + to_expression(lod) + ")"; } } @@ -1075,7 +990,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i) forward = forward && should_forward(grad_x); forward = forward && should_forward(grad_y); string grad_opt; - switch (img_type.dim) + switch (imgtype.image.dim) { case Dim2D: grad_opt = "2d"; @@ -1090,7 +1005,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i) grad_opt = "unsupported_gradient_dimension"; break; } - expr += ", gradient" + grad_opt + "(" + to_expression(grad_x) + ", " + to_expression(grad_y) + ")"; + farg_str += ", gradient" + grad_opt + "(" + to_expression(grad_x) + ", " + to_expression(grad_y) + ")"; } // Add offsets @@ -1108,7 +1023,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i) if (!offset_expr.empty()) { - switch (img_type.dim) + switch (imgtype.image.dim) { case Dim2D: if (msl_config.flip_frag_y) @@ -1125,7 +1040,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i) remove_duplicate_swizzle(offset_expr); } - expr += ", " + offset_expr; + farg_str += ", " + offset_expr; break; case Dim3D: @@ -1145,7 +1060,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i) remove_duplicate_swizzle(offset_expr); } - expr += ", " + offset_expr; + farg_str += ", " + offset_expr; break; default: @@ -1156,12 +1071,41 @@ void CompilerMSL::emit_texture_op(const Instruction &i) if (comp) { forward = forward && should_forward(comp); - expr += ", " + to_expression(comp); + farg_str += ", " + to_component_argument(comp); } - expr += ")"; + *p_forward = forward; - emit_op(result_type, id, expr, forward); + return farg_str; +} + +// Returns a string to use in an image sampling function argument. +// The ID must be a scalar constant. +string CompilerMSL::to_component_argument(uint32_t id) +{ + if (ids[id].get_type() != TypeConstant) + { + SPIRV_CROSS_THROW("ID " + to_string(id) + " is not an OpConstant."); + return "component::x"; + } + + uint32_t component_index = get(id).scalar(); + switch (component_index) + { + case 0: + return "component::x"; + case 1: + return "component::y"; + case 2: + return "component::z"; + case 3: + return "component::w"; + + default: + SPIRV_CROSS_THROW("The value (" + to_string(component_index) + ") of OpConstant ID " + to_string(id) + + " is not a valid Component index, which must be one of 0, 1, 2, or 3."); + return "component::x"; + } } // Establish sampled image as expression object and assign the sampler to it. diff --git a/spirv_msl.hpp b/spirv_msl.hpp index e4be333a..494a2540 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -104,7 +104,6 @@ protected: void emit_header() override; void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override; void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override; - void emit_texture_op(const Instruction &i) override; void emit_fixup() override; std::string type_to_glsl(const SPIRType &type) override; std::string image_type_glsl(const SPIRType &type) override; @@ -114,6 +113,13 @@ protected: size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override; std::string to_func_call_arg(uint32_t id) override; std::string to_name(uint32_t id, bool allow_alias = true) override; + std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, + bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod, + bool has_dref) override; + std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, + uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x, + uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, + uint32_t comp, uint32_t sample, bool *p_forward) override; void register_custom_functions(); void emit_custom_functions(); @@ -150,6 +156,7 @@ protected: SPIRType &get_pad_type(uint32_t pad_len); size_t get_declared_type_size(uint32_t type_id) const; size_t get_declared_type_size(uint32_t type_id, uint64_t dec_mask) const; + std::string to_component_argument(uint32_t id); MSLConfiguration msl_config; std::set custom_function_ops;