Refactor emit_texture_op() function.

CompilerGLSL add to_function_name() and to_function_args() functions to organize
structure of emit_texture_op() function.
CompilerMSL add support for MSL gather(), gather_compare() and sample_compare() functions.
This commit is contained in:
Bill Hollings 2016-12-28 18:36:42 -05:00
parent c8e2269a78
commit a2b8a0e5c9
4 changed files with 191 additions and 205 deletions

View File

@ -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)

View File

@ -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<std::ostringstream> buffer;

View File

@ -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<Op>(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<SPIRConstant>(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.

View File

@ -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<uint32_t> custom_function_ops;