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 = false;
|
||||||
bool hlsl_compat = false;
|
bool hlsl_compat = false;
|
||||||
bool vulkan_semantics = false;
|
bool vulkan_semantics = false;
|
||||||
|
bool flatten_multidimensional_arrays = false;
|
||||||
bool remove_unused = false;
|
bool remove_unused = false;
|
||||||
bool cfg_analysis = true;
|
bool cfg_analysis = true;
|
||||||
};
|
};
|
||||||
@ -461,6 +462,7 @@ static void print_help()
|
|||||||
"[--separate-shader-objects]"
|
"[--separate-shader-objects]"
|
||||||
"[--pls-in format input-name] [--pls-out format output-name] [--remap source_name target_name "
|
"[--pls-in format input-name] [--pls-out format output-name] [--remap source_name target_name "
|
||||||
"components] [--extension ext] [--entry name] [--remove-unused-variables] "
|
"components] [--extension ext] [--entry name] [--remove-unused-variables] "
|
||||||
|
"[--flatten-multidimensional-arrays] "
|
||||||
"[--remap-variable-type <variable_name> <new_variable_type>]\n");
|
"[--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", [&args](CLIParser &) { args.hlsl = true; });
|
||||||
cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
|
cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
|
||||||
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = 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("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
||||||
cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
|
cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
|
||||||
cbs.add("--separate-shader-objects", [&args](CLIParser &) { args.sso = true; });
|
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.es = args.es;
|
||||||
opts.force_temporary = args.force_temporary;
|
opts.force_temporary = args.force_temporary;
|
||||||
opts.separate_shader_objects = args.sso;
|
opts.separate_shader_objects = args.sso;
|
||||||
|
opts.flatten_multidimensional_arrays = args.flatten_multidimensional_arrays;
|
||||||
opts.vulkan_semantics = args.vulkan_semantics;
|
opts.vulkan_semantics = args.vulkan_semantics;
|
||||||
opts.vertex.fixup_clipspace = args.fixup;
|
opts.vertex.fixup_clipspace = args.fixup;
|
||||||
opts.cfg_analysis = args.cfg_analysis;
|
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];
|
||||||
|
}
|
111
spirv_glsl.cpp
111
spirv_glsl.cpp
@ -1816,10 +1816,8 @@ void CompilerGLSL::strip_enclosed_expression(string &expr)
|
|||||||
expr.erase(begin(expr));
|
expr.erase(begin(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just like to_expression except that we enclose the expression inside parentheses if needed.
|
string CompilerGLSL::enclose_expression(const string &expr)
|
||||||
string CompilerGLSL::to_enclosed_expression(uint32_t id)
|
|
||||||
{
|
{
|
||||||
auto expr = to_expression(id);
|
|
||||||
bool need_parens = false;
|
bool need_parens = false;
|
||||||
uint32_t paren_count = 0;
|
uint32_t paren_count = 0;
|
||||||
for (auto c : expr)
|
for (auto c : expr)
|
||||||
@ -1848,6 +1846,12 @@ string CompilerGLSL::to_enclosed_expression(uint32_t id)
|
|||||||
return expr;
|
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)
|
string CompilerGLSL::to_expression(uint32_t id)
|
||||||
{
|
{
|
||||||
auto itr = invalid_expressions.find(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 access_chain_is_arrayed = false;
|
||||||
bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
|
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++)
|
for (uint32_t i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@ -3533,14 +3539,50 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
// Arrays
|
// Arrays
|
||||||
if (!type->array.empty())
|
if (!type->array.empty())
|
||||||
{
|
{
|
||||||
expr += "[";
|
// If we are flattening multidimensional arrays, only create opening bracket on first
|
||||||
if (index_is_literal)
|
// array index.
|
||||||
expr += convert_to_string(index);
|
if (options.flatten_multidimensional_arrays && !pending_array_enclose)
|
||||||
else
|
{
|
||||||
expr += to_expression(index);
|
dimension_flatten = type->array.size() > 1;
|
||||||
expr += "]";
|
pending_array_enclose = dimension_flatten;
|
||||||
|
if (pending_array_enclose)
|
||||||
|
expr += "[";
|
||||||
|
}
|
||||||
|
|
||||||
assert(type->parent_type);
|
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 += "]";
|
||||||
|
|
||||||
type = &get<SPIRType>(type->parent_type);
|
type = &get<SPIRType>(type->parent_type);
|
||||||
|
|
||||||
access_chain_is_arrayed = true;
|
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!");
|
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)
|
if (need_transpose)
|
||||||
*need_transpose = row_major_matrix_needs_conversion;
|
*need_transpose = row_major_matrix_needs_conversion;
|
||||||
return expr;
|
return expr;
|
||||||
@ -6022,14 +6071,40 @@ string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
|
|||||||
if (type.array.empty())
|
if (type.array.empty())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
string res;
|
if (options.flatten_multidimensional_arrays)
|
||||||
for (auto i = uint32_t(type.array.size()); i; i--)
|
|
||||||
{
|
{
|
||||||
|
string res;
|
||||||
res += "[";
|
res += "[";
|
||||||
res += to_array_size(type, i - 1);
|
for (auto i = uint32_t(type.array.size()); i; i--)
|
||||||
|
{
|
||||||
|
res += enclose_expression(to_array_size(type, i - 1));
|
||||||
|
if (i > 1)
|
||||||
|
res += " * ";
|
||||||
|
}
|
||||||
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--)
|
||||||
|
{
|
||||||
|
res += "[";
|
||||||
|
res += to_array_size(type, i - 1);
|
||||||
|
res += "]";
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
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)
|
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);
|
auto e = type_to_glsl(type);
|
||||||
for (uint32_t i = 0; i < type.array.size(); i++)
|
for (uint32_t i = 0; i < type.array.size(); i++)
|
||||||
e += "[]";
|
e += "[]";
|
||||||
|
@ -73,6 +73,12 @@ public:
|
|||||||
// (EXT_shader_io_blocks) which makes things a bit more fuzzy.
|
// (EXT_shader_io_blocks) which makes things a bit more fuzzy.
|
||||||
bool separate_shader_objects = false;
|
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
|
enum Precision
|
||||||
{
|
{
|
||||||
DontCare,
|
DontCare,
|
||||||
@ -359,6 +365,7 @@ protected:
|
|||||||
void append_global_func_args(const SPIRFunction &func, uint32_t index, std::vector<std::string> &arglist);
|
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_expression(uint32_t id);
|
||||||
std::string to_enclosed_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);
|
void strip_enclosed_expression(std::string &expr);
|
||||||
std::string to_member_name(const SPIRType &type, uint32_t index);
|
std::string to_member_name(const SPIRType &type, uint32_t index);
|
||||||
std::string type_to_glsl_constructor(const SPIRType &type);
|
std::string type_to_glsl_constructor(const SPIRType &type);
|
||||||
|
@ -121,7 +121,7 @@ def validate_shader(shader, vulkan):
|
|||||||
else:
|
else:
|
||||||
subprocess.check_call(['glslangValidator', shader])
|
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()
|
spirv_f, spirv_path = tempfile.mkstemp()
|
||||||
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
|
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
|
||||||
os.close(spirv_f)
|
os.close(spirv_f)
|
||||||
@ -148,6 +148,8 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
|
|||||||
extra_args += ['--flatten-ubo']
|
extra_args += ['--flatten-ubo']
|
||||||
if sso:
|
if sso:
|
||||||
extra_args += ['--separate-shader-objects']
|
extra_args += ['--separate-shader-objects']
|
||||||
|
if flatten_dim:
|
||||||
|
extra_args += ['--flatten-multidimensional-arrays']
|
||||||
|
|
||||||
spirv_cross_path = './spirv-cross'
|
spirv_cross_path = './spirv-cross'
|
||||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path] + extra_args)
|
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):
|
def shader_is_sso(shader):
|
||||||
return '.sso.' in shader
|
return '.sso.' in shader
|
||||||
|
|
||||||
|
def shader_is_flatten_dimensions(shader):
|
||||||
|
return '.flatten_dim.' in shader
|
||||||
|
|
||||||
def test_shader(stats, shader, update, keep):
|
def test_shader(stats, shader, update, keep):
|
||||||
joined_path = os.path.join(shader[0], shader[1])
|
joined_path = os.path.join(shader[0], shader[1])
|
||||||
vulkan = shader_is_vulkan(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])
|
is_legacy = shader_is_legacy(shader[1])
|
||||||
flatten_ubo = shader_is_flatten_ubo(shader[1])
|
flatten_ubo = shader_is_flatten_ubo(shader[1])
|
||||||
sso = shader_is_sso(shader[1])
|
sso = shader_is_sso(shader[1])
|
||||||
|
flatten_dim = shader_is_flatten_dimensions(shader[1])
|
||||||
|
|
||||||
print('Testing shader:', joined_path)
|
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.
|
# Only test GLSL stats if we have a shader following GL semantics.
|
||||||
if stats and (not vulkan) and (not is_spirv) and (not desktop):
|
if stats and (not vulkan) and (not is_spirv) and (not desktop):
|
||||||
|
Loading…
Reference in New Issue
Block a user