Merge pull request #189 from KhronosGroup/flatten-multidimensional-arrays
Add support for flattening multidimensional arrays into single dimension
This commit is contained in:
commit
f77d91e077
4
main.cpp
4
main.cpp
@ -446,6 +446,7 @@ struct CLIArguments
|
||||
bool hlsl = false;
|
||||
bool hlsl_compat = false;
|
||||
bool vulkan_semantics = false;
|
||||
bool flatten_multidimensional_arrays = false;
|
||||
bool remove_unused = false;
|
||||
bool cfg_analysis = true;
|
||||
};
|
||||
@ -461,6 +462,7 @@ static void print_help()
|
||||
"[--separate-shader-objects]"
|
||||
"[--pls-in format input-name] [--pls-out format output-name] [--remap source_name target_name "
|
||||
"components] [--extension ext] [--entry name] [--remove-unused-variables] "
|
||||
"[--flatten-multidimensional-arrays] "
|
||||
"[--remap-variable-type <variable_name> <new_variable_type>]\n");
|
||||
}
|
||||
|
||||
@ -583,6 +585,7 @@ int main(int argc, char *argv[])
|
||||
cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
|
||||
cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
|
||||
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
|
||||
cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
|
||||
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
||||
cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
|
||||
cbs.add("--separate-shader-objects", [&args](CLIParser &) { args.sso = true; });
|
||||
@ -690,6 +693,7 @@ int main(int argc, char *argv[])
|
||||
opts.es = args.es;
|
||||
opts.force_temporary = args.force_temporary;
|
||||
opts.separate_shader_objects = args.sso;
|
||||
opts.flatten_multidimensional_arrays = args.flatten_multidimensional_arrays;
|
||||
opts.vulkan_semantics = args.vulkan_semantics;
|
||||
opts.vertex.fixup_clipspace = args.fixup;
|
||||
opts.cfg_analysis = args.cfg_analysis;
|
||||
|
@ -0,0 +1,24 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform sampler2D uTextures[2 * 3 * 1];
|
||||
|
||||
layout(location = 1) in vec2 vUV;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(location = 0) flat in int vIndex;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 values3[2 * 3 * 1];
|
||||
for (int z = 0; z < 2; z++)
|
||||
{
|
||||
for (int y = 0; y < 3; y++)
|
||||
{
|
||||
for (int x = 0; x < 1; x++)
|
||||
{
|
||||
values3[z * 3 * 1 + y * 1 + x] = texture(uTextures[z * 3 * 1 + y * 1 + x], vUV);
|
||||
}
|
||||
}
|
||||
}
|
||||
FragColor = ((values3[1 * 3 * 1 + 2 * 1 + 0]) + (values3[0 * 3 * 1 + 2 * 1 + 0])) + (values3[(vIndex + 1) * 3 * 1 + 2 * 1 + vIndex]);
|
||||
}
|
||||
|
18
shaders/flatten/multi-dimensional.desktop.flatten_dim.frag
Normal file
18
shaders/flatten/multi-dimensional.desktop.flatten_dim.frag
Normal file
@ -0,0 +1,18 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(binding = 0) uniform sampler2D uTextures[2][3][1];
|
||||
layout(location = 0) flat in int vIndex;
|
||||
layout(location = 1) in vec2 vUV;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 values3[2][3][1];
|
||||
|
||||
for (int z = 0; z < 2; z++)
|
||||
for (int y = 0; y < 3; y++)
|
||||
for (int x = 0; x < 1; x++)
|
||||
values3[z][y][x] = texture(uTextures[z][y][x], vUV);
|
||||
|
||||
FragColor = values3[1][2][0] + values3[0][2][0] + values3[vIndex + 1][2][vIndex];
|
||||
}
|
@ -1816,10 +1816,8 @@ void CompilerGLSL::strip_enclosed_expression(string &expr)
|
||||
expr.erase(begin(expr));
|
||||
}
|
||||
|
||||
// Just like to_expression except that we enclose the expression inside parentheses if needed.
|
||||
string CompilerGLSL::to_enclosed_expression(uint32_t id)
|
||||
string CompilerGLSL::enclose_expression(const string &expr)
|
||||
{
|
||||
auto expr = to_expression(id);
|
||||
bool need_parens = false;
|
||||
uint32_t paren_count = 0;
|
||||
for (auto c : expr)
|
||||
@ -1848,6 +1846,12 @@ string CompilerGLSL::to_enclosed_expression(uint32_t id)
|
||||
return expr;
|
||||
}
|
||||
|
||||
// Just like to_expression except that we enclose the expression inside parentheses if needed.
|
||||
string CompilerGLSL::to_enclosed_expression(uint32_t id)
|
||||
{
|
||||
return enclose_expression(to_expression(id));
|
||||
}
|
||||
|
||||
string CompilerGLSL::to_expression(uint32_t id)
|
||||
{
|
||||
auto itr = invalid_expressions.find(id);
|
||||
@ -3525,6 +3529,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
||||
|
||||
bool access_chain_is_arrayed = false;
|
||||
bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
|
||||
bool pending_array_enclose = false;
|
||||
bool dimension_flatten = false;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
@ -3532,15 +3538,51 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
||||
|
||||
// Arrays
|
||||
if (!type->array.empty())
|
||||
{
|
||||
// If we are flattening multidimensional arrays, only create opening bracket on first
|
||||
// array index.
|
||||
if (options.flatten_multidimensional_arrays && !pending_array_enclose)
|
||||
{
|
||||
dimension_flatten = type->array.size() > 1;
|
||||
pending_array_enclose = dimension_flatten;
|
||||
if (pending_array_enclose)
|
||||
expr += "[";
|
||||
}
|
||||
|
||||
assert(type->parent_type);
|
||||
// If we are flattening multidimensional arrays, do manual stride computation.
|
||||
if (options.flatten_multidimensional_arrays && dimension_flatten)
|
||||
{
|
||||
auto &parent_type = get<SPIRType>(type->parent_type);
|
||||
|
||||
if (index_is_literal)
|
||||
expr += convert_to_string(index);
|
||||
else
|
||||
expr += to_enclosed_expression(index);
|
||||
|
||||
for (auto j = uint32_t(parent_type.array.size()); j; j--)
|
||||
{
|
||||
expr += " * ";
|
||||
expr += enclose_expression(to_array_size(parent_type, j - 1));
|
||||
}
|
||||
|
||||
if (parent_type.array.empty())
|
||||
pending_array_enclose = false;
|
||||
else
|
||||
expr += " + ";
|
||||
}
|
||||
else
|
||||
{
|
||||
expr += "[";
|
||||
if (index_is_literal)
|
||||
expr += convert_to_string(index);
|
||||
else
|
||||
expr += to_expression(index);
|
||||
}
|
||||
|
||||
if (!pending_array_enclose)
|
||||
expr += "]";
|
||||
|
||||
assert(type->parent_type);
|
||||
type = &get<SPIRType>(type->parent_type);
|
||||
|
||||
access_chain_is_arrayed = true;
|
||||
@ -3636,6 +3678,13 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
||||
SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
|
||||
}
|
||||
|
||||
if (pending_array_enclose)
|
||||
{
|
||||
SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
|
||||
"but the access chain was terminated in the middle of a multidimensional array. "
|
||||
"This is not supported.");
|
||||
}
|
||||
|
||||
if (need_transpose)
|
||||
*need_transpose = row_major_matrix_needs_conversion;
|
||||
return expr;
|
||||
@ -6022,6 +6071,31 @@ string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
|
||||
if (type.array.empty())
|
||||
return "";
|
||||
|
||||
if (options.flatten_multidimensional_arrays)
|
||||
{
|
||||
string res;
|
||||
res += "[";
|
||||
for (auto i = uint32_t(type.array.size()); i; i--)
|
||||
{
|
||||
res += enclose_expression(to_array_size(type, i - 1));
|
||||
if (i > 1)
|
||||
res += " * ";
|
||||
}
|
||||
res += "]";
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type.array.size() > 1)
|
||||
{
|
||||
if (!options.es && options.version < 430)
|
||||
require_extension("GL_ARB_arrays_of_arrays");
|
||||
else if (options.es && options.version < 310)
|
||||
SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
|
||||
"Try using --flatten-multidimensional-arrays or set "
|
||||
"options.flatten_multidimensional_arrays to true.");
|
||||
}
|
||||
|
||||
string res;
|
||||
for (auto i = uint32_t(type.array.size()); i; i--)
|
||||
{
|
||||
@ -6031,6 +6105,7 @@ string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
||||
{
|
||||
@ -6111,6 +6186,16 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
||||
|
||||
string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
|
||||
{
|
||||
if (type.array.size() > 1)
|
||||
{
|
||||
if (options.flatten_multidimensional_arrays)
|
||||
SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, e.g. float[][]().");
|
||||
else if (!options.es && options.version < 430)
|
||||
require_extension("GL_ARB_arrays_of_arrays");
|
||||
else if (options.es && options.version < 310)
|
||||
SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
|
||||
}
|
||||
|
||||
auto e = type_to_glsl(type);
|
||||
for (uint32_t i = 0; i < type.array.size(); i++)
|
||||
e += "[]";
|
||||
|
@ -73,6 +73,12 @@ public:
|
||||
// (EXT_shader_io_blocks) which makes things a bit more fuzzy.
|
||||
bool separate_shader_objects = false;
|
||||
|
||||
// Flattens multidimensional arrays, e.g. float foo[a][b][c] into single-dimensional arrays,
|
||||
// e.g. float foo[a * b * c].
|
||||
// This function does not change the actual SPIRType of any object.
|
||||
// Only the generated code, including declarations of interface variables are changed to be single array dimension.
|
||||
bool flatten_multidimensional_arrays = false;
|
||||
|
||||
enum Precision
|
||||
{
|
||||
DontCare,
|
||||
@ -359,6 +365,7 @@ protected:
|
||||
void append_global_func_args(const SPIRFunction &func, uint32_t index, std::vector<std::string> &arglist);
|
||||
std::string to_expression(uint32_t id);
|
||||
std::string to_enclosed_expression(uint32_t id);
|
||||
std::string enclose_expression(const std::string &expr);
|
||||
void strip_enclosed_expression(std::string &expr);
|
||||
std::string to_member_name(const SPIRType &type, uint32_t index);
|
||||
std::string type_to_glsl_constructor(const SPIRType &type);
|
||||
|
@ -121,7 +121,7 @@ def validate_shader(shader, vulkan):
|
||||
else:
|
||||
subprocess.check_call(['glslangValidator', shader])
|
||||
|
||||
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso):
|
||||
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim):
|
||||
spirv_f, spirv_path = tempfile.mkstemp()
|
||||
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
|
||||
os.close(spirv_f)
|
||||
@ -148,6 +148,8 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
|
||||
extra_args += ['--flatten-ubo']
|
||||
if sso:
|
||||
extra_args += ['--separate-shader-objects']
|
||||
if flatten_dim:
|
||||
extra_args += ['--flatten-multidimensional-arrays']
|
||||
|
||||
spirv_cross_path = './spirv-cross'
|
||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path] + extra_args)
|
||||
@ -244,6 +246,9 @@ def shader_is_flatten_ubo(shader):
|
||||
def shader_is_sso(shader):
|
||||
return '.sso.' in shader
|
||||
|
||||
def shader_is_flatten_dimensions(shader):
|
||||
return '.flatten_dim.' in shader
|
||||
|
||||
def test_shader(stats, shader, update, keep):
|
||||
joined_path = os.path.join(shader[0], shader[1])
|
||||
vulkan = shader_is_vulkan(shader[1])
|
||||
@ -254,9 +259,10 @@ def test_shader(stats, shader, update, keep):
|
||||
is_legacy = shader_is_legacy(shader[1])
|
||||
flatten_ubo = shader_is_flatten_ubo(shader[1])
|
||||
sso = shader_is_sso(shader[1])
|
||||
flatten_dim = shader_is_flatten_dimensions(shader[1])
|
||||
|
||||
print('Testing shader:', joined_path)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim)
|
||||
|
||||
# Only test GLSL stats if we have a shader following GL semantics.
|
||||
if stats and (not vulkan) and (not is_spirv) and (not desktop):
|
||||
|
Loading…
Reference in New Issue
Block a user