|
@@ -370,6 +370,12 @@ void CompilerGLSL::remap_pls_variables()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location)
|
|
|
|
|
+{
|
|
|
|
|
+ subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
|
|
|
|
|
+ inout_color_attachments.insert(color_location);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void CompilerGLSL::find_static_extensions()
|
|
void CompilerGLSL::find_static_extensions()
|
|
|
{
|
|
{
|
|
|
ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
|
|
ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
|
|
@@ -455,7 +461,20 @@ void CompilerGLSL::find_static_extensions()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!pls_inputs.empty() || !pls_outputs.empty())
|
|
if (!pls_inputs.empty() || !pls_outputs.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ if (execution.model != ExecutionModelFragment)
|
|
|
|
|
+ SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
|
|
|
require_extension_internal("GL_EXT_shader_pixel_local_storage");
|
|
require_extension_internal("GL_EXT_shader_pixel_local_storage");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!inout_color_attachments.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ if (execution.model != ExecutionModelFragment)
|
|
|
|
|
+ SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
|
|
|
|
|
+ if (options.vulkan_semantics)
|
|
|
|
|
+ SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
|
|
|
|
|
+ require_extension_internal("GL_EXT_shader_framebuffer_fetch");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if (options.separate_shader_objects && !options.es && options.version < 410)
|
|
if (options.separate_shader_objects && !options.es && options.version < 410)
|
|
|
require_extension_internal("GL_ARB_separate_shader_objects");
|
|
require_extension_internal("GL_ARB_separate_shader_objects");
|
|
@@ -519,6 +538,8 @@ string CompilerGLSL::compile()
|
|
|
update_active_builtins();
|
|
update_active_builtins();
|
|
|
analyze_image_and_sampler_usage();
|
|
analyze_image_and_sampler_usage();
|
|
|
analyze_interlocked_resource_usage();
|
|
analyze_interlocked_resource_usage();
|
|
|
|
|
+ if (!inout_color_attachments.empty())
|
|
|
|
|
+ emit_inout_fragment_outputs_copy_to_subpass_inputs();
|
|
|
|
|
|
|
|
// Shaders might cast unrelated data to pointers of non-block types.
|
|
// Shaders might cast unrelated data to pointers of non-block types.
|
|
|
// Find all such instances and make sure we can cast the pointers to a synthesized block type.
|
|
// Find all such instances and make sure we can cast the pointers to a synthesized block type.
|
|
@@ -1519,6 +1540,9 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
|
|
|
if (is_legacy())
|
|
if (is_legacy())
|
|
|
return "";
|
|
return "";
|
|
|
|
|
|
|
|
|
|
+ if (subpass_input_is_framebuffer_fetch(var.self))
|
|
|
|
|
+ return "";
|
|
|
|
|
+
|
|
|
SmallVector<string> attr;
|
|
SmallVector<string> attr;
|
|
|
|
|
|
|
|
auto &type = get<SPIRType>(var.basetype);
|
|
auto &type = get<SPIRType>(var.basetype);
|
|
@@ -2031,12 +2055,22 @@ const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
|
|
|
{
|
|
{
|
|
|
auto &execution = get_entry_point();
|
|
auto &execution = get_entry_point();
|
|
|
|
|
|
|
|
|
|
+ if (subpass_input_is_framebuffer_fetch(var.self))
|
|
|
|
|
+ return "";
|
|
|
|
|
+
|
|
|
if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
|
|
if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
|
|
|
{
|
|
{
|
|
|
if (is_legacy() && execution.model == ExecutionModelVertex)
|
|
if (is_legacy() && execution.model == ExecutionModelVertex)
|
|
|
return var.storage == StorageClassInput ? "attribute " : "varying ";
|
|
return var.storage == StorageClassInput ? "attribute " : "varying ";
|
|
|
else if (is_legacy() && execution.model == ExecutionModelFragment)
|
|
else if (is_legacy() && execution.model == ExecutionModelFragment)
|
|
|
return "varying "; // Fragment outputs are renamed so they never hit this case.
|
|
return "varying "; // Fragment outputs are renamed so they never hit this case.
|
|
|
|
|
+ else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
|
|
|
|
|
+ return "inout ";
|
|
|
|
|
+ else
|
|
|
|
|
+ return "out ";
|
|
|
|
|
+ }
|
|
|
else
|
|
else
|
|
|
return var.storage == StorageClassInput ? "in " : "out ";
|
|
return var.storage == StorageClassInput ? "in " : "out ";
|
|
|
}
|
|
}
|
|
@@ -2229,7 +2263,7 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
|
|
|
void CompilerGLSL::emit_uniform(const SPIRVariable &var)
|
|
void CompilerGLSL::emit_uniform(const SPIRVariable &var)
|
|
|
{
|
|
{
|
|
|
auto &type = get<SPIRType>(var.basetype);
|
|
auto &type = get<SPIRType>(var.basetype);
|
|
|
- if (type.basetype == SPIRType::Image && type.image.sampled == 2)
|
|
|
|
|
|
|
+ if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
|
|
|
{
|
|
{
|
|
|
if (!options.es && options.version < 420)
|
|
if (!options.es && options.version < 420)
|
|
|
require_extension_internal("GL_ARB_shader_image_load_store");
|
|
require_extension_internal("GL_ARB_shader_image_load_store");
|
|
@@ -3025,9 +3059,18 @@ void CompilerGLSL::emit_resources()
|
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
|
|
auto &type = this->get<SPIRType>(var.basetype);
|
|
auto &type = this->get<SPIRType>(var.basetype);
|
|
|
|
|
|
|
|
|
|
+ bool is_hidden = is_hidden_variable(var);
|
|
|
|
|
+
|
|
|
|
|
+ // Unused output I/O variables might still be required to implement framebuffer fetch.
|
|
|
|
|
+ if (var.storage == StorageClassOutput && !is_legacy() &&
|
|
|
|
|
+ inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ is_hidden = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (var.storage != StorageClassFunction && type.pointer &&
|
|
if (var.storage != StorageClassFunction && type.pointer &&
|
|
|
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
|
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
|
|
- interface_variable_exists_in_entry_point(var.self) && !is_hidden_variable(var))
|
|
|
|
|
|
|
+ interface_variable_exists_in_entry_point(var.self) && !is_hidden)
|
|
|
{
|
|
{
|
|
|
emit_interface_block(var);
|
|
emit_interface_block(var);
|
|
|
emitted = true;
|
|
emitted = true;
|
|
@@ -3700,7 +3743,8 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c)
|
|
|
{
|
|
{
|
|
|
res = type_to_glsl_constructor(type) + "{ ";
|
|
res = type_to_glsl_constructor(type) + "{ ";
|
|
|
}
|
|
}
|
|
|
- else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type && !type.array.empty())
|
|
|
|
|
|
|
+ else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
|
|
|
|
|
+ !type.array.empty())
|
|
|
{
|
|
{
|
|
|
res = type_to_glsl_constructor(type) + "({ ";
|
|
res = type_to_glsl_constructor(type) + "({ ";
|
|
|
needs_trailing_tracket = true;
|
|
needs_trailing_tracket = true;
|
|
@@ -8474,6 +8518,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|
|
if (expr.expression_dependencies.empty())
|
|
if (expr.expression_dependencies.empty())
|
|
|
forwarded_temporaries.erase(ops[1]);
|
|
forwarded_temporaries.erase(ops[1]);
|
|
|
|
|
|
|
|
|
|
+ if (has_decoration(ops[1], DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
|
|
|
|
|
+ propagate_nonuniform_qualifier(ops[1]);
|
|
|
|
|
+
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -8481,9 +8528,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|
|
{
|
|
{
|
|
|
auto *var = maybe_get<SPIRVariable>(ops[0]);
|
|
auto *var = maybe_get<SPIRVariable>(ops[0]);
|
|
|
|
|
|
|
|
- if (has_decoration(ops[0], DecorationNonUniformEXT))
|
|
|
|
|
- propagate_nonuniform_qualifier(ops[0]);
|
|
|
|
|
-
|
|
|
|
|
if (var && var->statically_assigned)
|
|
if (var && var->statically_assigned)
|
|
|
var->static_expression = ops[1];
|
|
var->static_expression = ops[1];
|
|
|
else if (var && var->loop_variable && !var->loop_variable_enable)
|
|
else if (var && var->loop_variable && !var->loop_variable_enable)
|
|
@@ -9992,7 +10036,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|
|
}
|
|
}
|
|
|
else if (type.image.dim == DimSubpassData)
|
|
else if (type.image.dim == DimSubpassData)
|
|
|
{
|
|
{
|
|
|
- if (options.vulkan_semantics)
|
|
|
|
|
|
|
+ if (var && subpass_input_is_framebuffer_fetch(var->self))
|
|
|
|
|
+ {
|
|
|
|
|
+ imgexpr = to_expression(var->self);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (options.vulkan_semantics)
|
|
|
{
|
|
{
|
|
|
// With Vulkan semantics, use the proper Vulkan GLSL construct.
|
|
// With Vulkan semantics, use the proper Vulkan GLSL construct.
|
|
|
if (type.image.ms)
|
|
if (type.image.ms)
|
|
@@ -10088,7 +10136,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|
|
target_coord_type.basetype = SPIRType::Int;
|
|
target_coord_type.basetype = SPIRType::Int;
|
|
|
coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
|
|
coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
|
|
|
|
|
|
|
|
- auto &e = set<SPIRExpression>(id, join(to_expression(ops[2]), ", ", coord_expr), result_type, true);
|
|
|
|
|
|
|
+ auto expr = join(to_expression(ops[2]), ", ", coord_expr);
|
|
|
|
|
+ if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
|
|
|
|
|
+ convert_non_uniform_expression(expression_type(ops[2]), expr);
|
|
|
|
|
+
|
|
|
|
|
+ auto &e = set<SPIRExpression>(id, expr, result_type, true);
|
|
|
|
|
|
|
|
// When using the pointer, we need to know which variable it is actually loaded from.
|
|
// When using the pointer, we need to know which variable it is actually loaded from.
|
|
|
auto *var = maybe_get_backing_variable(ops[2]);
|
|
auto *var = maybe_get_backing_variable(ops[2]);
|
|
@@ -11232,6 +11284,13 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
|
|
|
|
|
|
|
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
|
|
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
|
|
|
return res + "subpassInput" + (type.image.ms ? "MS" : "");
|
|
return res + "subpassInput" + (type.image.ms ? "MS" : "");
|
|
|
|
|
+ else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
|
|
|
|
|
+ subpass_input_is_framebuffer_fetch(id))
|
|
|
|
|
+ {
|
|
|
|
|
+ SPIRType sampled_type = get<SPIRType>(type.image.type);
|
|
|
|
|
+ sampled_type.vecsize = 4;
|
|
|
|
|
+ return type_to_glsl(sampled_type);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// If we're emulating subpassInput with samplers, force sampler2D
|
|
// If we're emulating subpassInput with samplers, force sampler2D
|
|
|
// so we don't have to specify format.
|
|
// so we don't have to specify format.
|
|
@@ -13508,3 +13567,69 @@ void CompilerGLSL::emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id,
|
|
|
emit_store_statement(lhs_id, rhs_id);
|
|
emit_store_statement(lhs_id, rhs_id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
|
|
|
|
|
+{
|
|
|
|
|
+ if (!has_decoration(id, DecorationInputAttachmentIndex))
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
|
|
|
|
|
+ for (auto &remap : subpass_to_framebuffer_fetch_attachment)
|
|
|
|
|
+ if (remap.first == input_attachment_index)
|
|
|
|
|
+ return true;
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
|
|
|
|
|
+{
|
|
|
|
|
+ const SPIRVariable *ret = nullptr;
|
|
|
|
|
+ ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
|
|
|
|
|
+ if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
|
|
|
|
|
+ get_decoration(var.self, DecorationInputAttachmentIndex) == index)
|
|
|
|
|
+ {
|
|
|
|
|
+ ret = &var;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
|
|
|
|
|
+{
|
|
|
|
|
+ const SPIRVariable *ret = nullptr;
|
|
|
|
|
+ ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
|
|
|
|
|
+ if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
|
|
|
|
|
+ ret = &var;
|
|
|
|
|
+ });
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
|
|
|
|
|
+{
|
|
|
|
|
+ for (auto &remap : subpass_to_framebuffer_fetch_attachment)
|
|
|
|
|
+ {
|
|
|
|
|
+ auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
|
|
|
|
|
+ auto *output_var = find_color_output_by_location(remap.second);
|
|
|
|
|
+ if (!subpass_var)
|
|
|
|
|
+ continue;
|
|
|
|
|
+ if (!output_var)
|
|
|
|
|
+ SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able to read from it.");
|
|
|
|
|
+ if (is_array(get<SPIRType>(output_var->basetype)))
|
|
|
|
|
+ SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
|
|
|
|
|
+
|
|
|
|
|
+ auto &func = get<SPIRFunction>(get_entry_point().self);
|
|
|
|
|
+ func.fixup_hooks_in.push_back([=]() {
|
|
|
|
|
+ if (is_legacy())
|
|
|
|
|
+ {
|
|
|
|
|
+ statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
|
|
|
|
|
+ get_decoration(output_var->self, DecorationLocation), "];");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
|
|
|
|
|
+ statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
|
|
|
|
|
+ to_expression(output_var->self), ";");
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+}
|