Updated spirv-cross.

This commit is contained in:
Бранимир Караџић
2021-07-26 17:38:51 -07:00
parent b42d4cc558
commit 8a0ae08123
33 changed files with 484 additions and 309 deletions

View File

@@ -1,27 +1,10 @@
/*
** Copyright (c) 2014-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and/or associated documentation files (the "Materials"),
** to deal in the Materials without restriction, including without limitation
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
** and/or sell copies of the Materials, and to permit persons to whom the
** Materials are furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Materials.
**
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
** IN THE MATERIALS.
* Copyright 2014-2016,2021 The Khronos Group, Inc.
* SPDX-License-Identifier: MIT
*
* MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
* STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
* HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
*/
#ifndef GLSLstd450_H

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cpp.hpp"
@@ -662,6 +662,7 @@ struct CLIArguments
bool glsl_emit_push_constant_as_ubo = false;
bool glsl_emit_ubo_as_plain_uniforms = false;
bool glsl_force_flattened_io_blocks = false;
uint32_t glsl_ovr_multiview_view_count = 0;
SmallVector<pair<uint32_t, uint32_t>> glsl_ext_framebuffer_fetch;
bool glsl_ext_framebuffer_fetch_noncoherent = false;
bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
@@ -779,6 +780,7 @@ static void print_help_glsl()
"\t[--remap-variable-type <variable_name> <new_variable_type>]:\n\t\tRemaps a variable type based on name.\n"
"\t\tPrimary use case is supporting external samplers in ESSL for video rendering on Android where you could remap a texture to a YUV one.\n"
"\t[--glsl-force-flattened-io-blocks]:\n\t\tAlways flatten I/O blocks and structs.\n"
"\t[--glsl-ovr-multiview-view-count count]:\n\t\tIn GL_OVR_multiview2, specify layout(num_views).\n"
);
// clang-format on
}
@@ -1280,6 +1282,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo;
opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms;
opts.force_flattened_io_blocks = args.glsl_force_flattened_io_blocks;
opts.ovr_multiview_view_count = args.glsl_ovr_multiview_view_count;
opts.emit_line_directives = args.emit_line_directives;
opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction;
opts.force_zero_initialized_variables = args.force_zero_initialized_variables;
@@ -1471,6 +1474,7 @@ static int main_inner(int argc, char *argv[])
cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; });
cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; });
cbs.add("--glsl-force-flattened-io-blocks", [&args](CLIParser &) { args.glsl_force_flattened_io_blocks = true; });
cbs.add("--glsl-ovr-multiview-view-count", [&args](CLIParser &parser) { args.glsl_ovr_multiview_view_count = parser.next_uint(); });
cbs.add("--glsl-remap-ext-framebuffer-fetch", [&args](CLIParser &parser) {
uint32_t input_index = parser.next_uint();
uint32_t color_attachment = parser.next_uint();

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2016-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cfg.hpp"

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2016-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_CFG_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_COMMON_HPP
@@ -417,6 +417,11 @@ struct IVariant
virtual ~IVariant() = default;
virtual IVariant *clone(ObjectPoolBase *pool) = 0;
ID self = 0;
protected:
IVariant() = default;
IVariant(const IVariant&) = default;
IVariant &operator=(const IVariant&) = default;
};
#define SPIRV_CROSS_DECLARE_CLONE(T) \

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cpp.hpp"

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_CPP_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cross.hpp"
@@ -167,6 +167,12 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
case OpTraceRayKHR:
case OpExecuteCallableNV:
case OpExecuteCallableKHR:
case OpRayQueryInitializeKHR:
case OpRayQueryTerminateKHR:
case OpRayQueryGenerateIntersectionKHR:
case OpRayQueryConfirmIntersectionKHR:
case OpRayQueryProceedKHR:
// There are various getters in ray query, but they are considered pure.
return false;
// OpExtInst is potentially impure depending on extension, but GLSL builtins are at least pure.

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2019-2021 Hans-Kristian Arntzen
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cross_c.h"
@@ -472,6 +472,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS:
options->glsl.force_flattened_io_blocks = value != 0;
break;
case SPVC_COMPILER_OPTION_GLSL_OVR_MULTIVIEW_VIEW_COUNT:
options->glsl.ovr_multiview_view_count = value;
break;
#endif
#if SPIRV_CROSS_C_API_HLSL

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2019-2021 Hans-Kristian Arntzen
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_C_API_H
@@ -40,7 +40,7 @@ extern "C" {
/* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
#define SPVC_C_API_VERSION_MINOR 47
#define SPVC_C_API_VERSION_MINOR 48
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
@@ -675,6 +675,8 @@ typedef enum spvc_compiler_option
SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING = 75 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE = 76 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_GLSL_OVR_MULTIVIEW_VIEW_COUNT = 77 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
} spvc_compiler_option;

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2019-2021 Hans-Kristian Arntzen
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_CONTAINERS_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_ERROR_HANDLING

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cross_parsed_ir.hpp"

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_PARSED_IR_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_cross_util.hpp"

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_UTIL_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_glsl.hpp"
@@ -465,7 +465,8 @@ void CompilerGLSL::find_static_extensions()
// Need to figure out if we should target KHR or NV extension based on capabilities.
for (auto &cap : ir.declared_capabilities)
{
if (cap == CapabilityRayTracingKHR || cap == CapabilityRayQueryKHR)
if (cap == CapabilityRayTracingKHR || cap == CapabilityRayQueryKHR ||
cap == CapabilityRayTraversalPrimitiveCullingKHR)
{
ray_tracing_is_khr = true;
break;
@@ -566,10 +567,46 @@ void CompilerGLSL::find_static_extensions()
case CapabilityVariablePointersStorageBuffer:
SPIRV_CROSS_THROW("VariablePointers capability is not supported in GLSL.");
case CapabilityMultiView:
if (options.vulkan_semantics)
require_extension_internal("GL_EXT_multiview");
else
{
require_extension_internal("GL_OVR_multiview2");
if (options.ovr_multiview_view_count == 0)
SPIRV_CROSS_THROW("ovr_multiview_view_count must be non-zero when using GL_OVR_multiview2.");
if (get_execution_model() != ExecutionModelVertex)
SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
}
break;
case CapabilityRayQueryKHR:
if (options.es || options.version < 460 || !options.vulkan_semantics)
SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
require_extension_internal("GL_EXT_ray_query");
ray_tracing_is_khr = true;
break;
case CapabilityRayTraversalPrimitiveCullingKHR:
if (options.es || options.version < 460 || !options.vulkan_semantics)
SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
require_extension_internal("GL_EXT_ray_flags_primitive_culling");
ray_tracing_is_khr = true;
break;
default:
break;
}
}
if (options.ovr_multiview_view_count)
{
if (options.vulkan_semantics)
SPIRV_CROSS_THROW("OVR_multiview2 cannot be used with Vulkan semantics.");
if (get_execution_model() != ExecutionModelVertex)
SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
require_extension_internal("GL_OVR_multiview2");
}
}
void CompilerGLSL::ray_tracing_khr_fixup_locations()
@@ -890,6 +927,10 @@ void CompilerGLSL::emit_header()
switch (execution.model)
{
case ExecutionModelVertex:
if (options.ovr_multiview_view_count)
inputs.push_back(join("num_views = ", options.ovr_multiview_view_count));
break;
case ExecutionModelGeometry:
if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
inputs.push_back(join("invocations = ", execution.invocations));
@@ -1035,6 +1076,10 @@ void CompilerGLSL::emit_header()
break;
}
for (auto &cap : ir.declared_capabilities)
if (cap == CapabilityRayTraversalPrimitiveCullingKHR)
statement("layout(primitive_culling);");
if (!inputs.empty())
statement("layout(", merge(inputs), ") in;");
if (!outputs.empty())
@@ -1110,8 +1155,22 @@ string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
res += "sample ";
if (flags.get(DecorationInvariant))
res += "invariant ";
if (flags.get(DecorationExplicitInterpAMD))
{
require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
res += "__explicitInterpAMD ";
}
if (flags.get(DecorationPerVertexNV))
{
if (options.es && options.version < 320)
SPIRV_CROSS_THROW("pervertexNV requires ESSL 320.");
else if (!options.es && options.version < 450)
SPIRV_CROSS_THROW("pervertexNV requires GLSL 450.");
require_extension_internal("GL_NV_fragment_shader_barycentric");
res += "pervertexNV ";
}
return res;
}
@@ -1121,8 +1180,7 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
if (is_legacy())
return "";
bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
if (!is_block)
return "";
@@ -6191,44 +6249,57 @@ bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t
if (cleft->specialization || cright->specialization)
return false;
// We can only use trivial construction if we have a scalar
// (should be possible to do it for vectors as well, but that is overkill for now).
if (lerptype.basetype != SPIRType::Boolean || lerptype.vecsize > 1)
auto &value_type = get<SPIRType>(cleft->constant_type);
if (lerptype.basetype != SPIRType::Boolean)
return false;
if (value_type.basetype == SPIRType::Struct || is_array(value_type))
return false;
if (!backend.use_constructor_splatting && value_type.vecsize != lerptype.vecsize)
return false;
// If our bool selects between 0 and 1, we can cast from bool instead, making our trivial constructor.
bool ret = false;
switch (type.basetype)
bool ret = true;
for (uint32_t col = 0; col < value_type.columns; col++)
{
case SPIRType::Short:
case SPIRType::UShort:
ret = cleft->scalar_u16() == 0 && cright->scalar_u16() == 1;
break;
for (uint32_t row = 0; row < value_type.vecsize; row++)
{
switch (type.basetype)
{
case SPIRType::Short:
case SPIRType::UShort:
ret = cleft->scalar_u16(col, row) == 0 && cright->scalar_u16(col, row) == 1;
break;
case SPIRType::Int:
case SPIRType::UInt:
ret = cleft->scalar() == 0 && cright->scalar() == 1;
break;
case SPIRType::Int:
case SPIRType::UInt:
ret = cleft->scalar(col, row) == 0 && cright->scalar(col, row) == 1;
break;
case SPIRType::Half:
ret = cleft->scalar_f16() == 0.0f && cright->scalar_f16() == 1.0f;
break;
case SPIRType::Half:
ret = cleft->scalar_f16(col, row) == 0.0f && cright->scalar_f16(col, row) == 1.0f;
break;
case SPIRType::Float:
ret = cleft->scalar_f32() == 0.0f && cright->scalar_f32() == 1.0f;
break;
case SPIRType::Float:
ret = cleft->scalar_f32(col, row) == 0.0f && cright->scalar_f32(col, row) == 1.0f;
break;
case SPIRType::Double:
ret = cleft->scalar_f64() == 0.0 && cright->scalar_f64() == 1.0;
break;
case SPIRType::Double:
ret = cleft->scalar_f64(col, row) == 0.0 && cright->scalar_f64(col, row) == 1.0;
break;
case SPIRType::Int64:
case SPIRType::UInt64:
ret = cleft->scalar_u64() == 0 && cright->scalar_u64() == 1;
break;
case SPIRType::Int64:
case SPIRType::UInt64:
ret = cleft->scalar_u64(col, row) == 0 && cright->scalar_u64(col, row) == 1;
break;
default:
break;
default:
return false;
}
}
if (!ret)
break;
}
if (ret)
@@ -8231,13 +8302,9 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
}
return "gl_BaseVertex";
}
else
{
// On regular GL, this is soft-enabled and we emit ifdefs in code.
require_extension_internal("GL_ARB_shader_draw_parameters");
return "SPIRV_Cross_BaseVertex";
}
break;
// On regular GL, this is soft-enabled and we emit ifdefs in code.
require_extension_internal("GL_ARB_shader_draw_parameters");
return "SPIRV_Cross_BaseVertex";
case BuiltInBaseInstance:
if (options.es)
@@ -8252,13 +8319,9 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
}
return "gl_BaseInstance";
}
else
{
// On regular GL, this is soft-enabled and we emit ifdefs in code.
require_extension_internal("GL_ARB_shader_draw_parameters");
return "SPIRV_Cross_BaseInstance";
}
break;
// On regular GL, this is soft-enabled and we emit ifdefs in code.
require_extension_internal("GL_ARB_shader_draw_parameters");
return "SPIRV_Cross_BaseInstance";
case BuiltInDrawIndex:
if (options.es)
@@ -8273,13 +8336,9 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
}
return "gl_DrawID";
}
else
{
// On regular GL, this is soft-enabled and we emit ifdefs in code.
require_extension_internal("GL_ARB_shader_draw_parameters");
return "gl_DrawIDARB";
}
break;
// On regular GL, this is soft-enabled and we emit ifdefs in code.
require_extension_internal("GL_ARB_shader_draw_parameters");
return "gl_DrawIDARB";
case BuiltInSampleId:
if (options.es && options.version < 320)
@@ -8308,15 +8367,9 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
case BuiltInViewIndex:
if (options.vulkan_semantics)
{
require_extension_internal("GL_EXT_multiview");
return "gl_ViewIndex";
}
else
{
require_extension_internal("GL_OVR_multiview2");
return "gl_ViewID_OVR";
}
case BuiltInNumSubgroups:
request_subgroup_feature(ShaderSubgroupSupportHelper::NumSubgroups);
@@ -12491,7 +12544,64 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
flush_control_dependent_expressions(current_emitting_block->self);
break;
// Don't bother forwarding temporaries. Avoids having to test expression invalidation with ray query objects.
case OpRayQueryInitializeKHR:
flush_variable_declaration(ops[0]);
statement("rayQueryInitializeEXT(",
to_expression(ops[0]), ", ", to_expression(ops[1]), ", ",
to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
to_expression(ops[6]), ", ", to_expression(ops[7]), ");");
break;
case OpRayQueryProceedKHR:
flush_variable_declaration(ops[0]);
emit_op(ops[0], ops[1], join("rayQueryProceedEXT(", to_expression(ops[2]), ")"), false);
break;
case OpRayQueryTerminateKHR:
flush_variable_declaration(ops[0]);
statement("rayQueryTerminateEXT(", to_expression(ops[0]), ");");
break;
case OpRayQueryGenerateIntersectionKHR:
flush_variable_declaration(ops[0]);
statement("rayQueryGenerateIntersectionEXT(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
break;
case OpRayQueryConfirmIntersectionKHR:
flush_variable_declaration(ops[0]);
statement("rayQueryConfirmIntersectionEXT(", to_expression(ops[0]), ");");
break;
#define GLSL_RAY_QUERY_GET_OP(op) \
case OpRayQueryGet##op##KHR: \
flush_variable_declaration(ops[2]); \
emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ")"), false); \
break
#define GLSL_RAY_QUERY_GET_OP2(op) \
case OpRayQueryGet##op##KHR: \
flush_variable_declaration(ops[2]); \
emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ", ", "bool(", to_expression(ops[3]), "))"), false); \
break
GLSL_RAY_QUERY_GET_OP(RayTMin);
GLSL_RAY_QUERY_GET_OP(RayFlags);
GLSL_RAY_QUERY_GET_OP(WorldRayOrigin);
GLSL_RAY_QUERY_GET_OP(WorldRayDirection);
GLSL_RAY_QUERY_GET_OP(IntersectionCandidateAABBOpaque);
GLSL_RAY_QUERY_GET_OP2(IntersectionType);
GLSL_RAY_QUERY_GET_OP2(IntersectionT);
GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceCustomIndex);
GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceId);
GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceShaderBindingTableRecordOffset);
GLSL_RAY_QUERY_GET_OP2(IntersectionGeometryIndex);
GLSL_RAY_QUERY_GET_OP2(IntersectionPrimitiveIndex);
GLSL_RAY_QUERY_GET_OP2(IntersectionBarycentrics);
GLSL_RAY_QUERY_GET_OP2(IntersectionFrontFace);
GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayDirection);
GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayOrigin);
GLSL_RAY_QUERY_GET_OP2(IntersectionObjectToWorld);
GLSL_RAY_QUERY_GET_OP2(IntersectionWorldToObject);
#undef GLSL_RAY_QUERY_GET_OP
#undef GLSL_RAY_QUERY_GET_OP2
case OpConvertUToAccelerationStructureKHR:
require_extension_internal("GL_EXT_ray_tracing");
GLSL_UFOP(accelerationStructureEXT);
break;
@@ -12811,17 +12921,20 @@ string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset
if (flags.get(DecorationRestrictPointerEXT))
return "restrict ";
// Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
type.basetype != SPIRType::Sampler)
return "";
string qual;
if (flags.get(DecorationNoContraction) && backend.support_precise_qualifier)
if (type_is_floating_point(type) && flags.get(DecorationNoContraction) && backend.support_precise_qualifier)
qual = "precise ";
// Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
bool type_supports_precision =
type.basetype == SPIRType::Float || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
type.basetype == SPIRType::Sampler;
if (!type_supports_precision)
return qual;
if (options.es)
{
auto &execution = get_entry_point();
@@ -13312,6 +13425,9 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
case SPIRType::AccelerationStructure:
return ray_tracing_is_khr ? "accelerationStructureEXT" : "accelerationStructureNV";
case SPIRType::RayQuery:
return "rayQueryEXT";
case SPIRType::Void:
return "void";

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2015-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_GLSL_HPP
@@ -133,6 +133,9 @@ public:
// what happens on legacy GLSL targets for blocks and structs.
bool force_flattened_io_blocks = false;
// If non-zero, controls layout(num_views = N) in; in GL_OVR_multiview2.
uint32_t ovr_multiview_view_count = 0;
enum Precision
{
DontCare,

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2016-2021 Robert Konrad
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +20,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_hlsl.hpp"
@@ -641,7 +641,6 @@ void CompilerHLSL::emit_builtin_outputs_in_struct()
default:
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
break;
}
if (type && semantic)
@@ -770,7 +769,6 @@ void CompilerHLSL::emit_builtin_inputs_in_struct()
default:
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
break;
}
if (type && semantic)
@@ -854,34 +852,25 @@ std::string CompilerHLSL::to_initializer_expression(const SPIRVariable &var)
return CompilerGLSL::to_initializer_expression(var);
}
void CompilerHLSL::emit_io_block(const SPIRVariable &var)
void CompilerHLSL::emit_interface_block_member_in_struct(const SPIRVariable &var, uint32_t member_index,
uint32_t location,
std::unordered_set<uint32_t> &active_locations)
{
auto &execution = get_entry_point();
auto type = get<SPIRType>(var.basetype);
auto semantic = to_semantic(location, execution.model, var.storage);
auto mbr_name = join(to_name(type.self), "_", to_member_name(type, member_index));
auto &mbr_type = get<SPIRType>(type.member_types[member_index]);
auto &type = get<SPIRType>(var.basetype);
add_resource_name(type.self);
statement(to_interpolation_qualifiers(get_member_decoration_bitset(type.self, member_index)),
type_to_glsl(mbr_type),
" ", mbr_name, type_to_array_glsl(mbr_type),
" : ", semantic, ";");
statement("struct ", to_name(type.self));
begin_scope();
type.member_name_cache.clear();
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
{
uint32_t location = get_accumulated_member_location(var, i, false);
string semantic = join(" : ", to_semantic(location, execution.model, var.storage));
add_member_name(type, i);
auto &membertype = get<SPIRType>(type.member_types[i]);
statement(to_interpolation_qualifiers(get_member_decoration_bitset(type.self, i)),
variable_decl(membertype, to_member_name(type, i)), semantic, ";");
}
end_scope_decl();
statement("");
statement("static ", variable_decl(var), ";");
statement("");
// Structs and arrays should consume more locations.
uint32_t consumed_locations = type_to_consumed_locations(mbr_type);
for (uint32_t i = 0; i < consumed_locations; i++)
active_locations.insert(location + i);
}
void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unordered_set<uint32_t> &active_locations)
@@ -916,7 +905,6 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
bool need_matrix_unroll = var.storage == StorageClassInput && execution.model == ExecutionModelVertex;
auto &m = ir.meta[var.self].decoration;
auto name = to_name(var.self);
if (use_location_number)
{
@@ -924,8 +912,8 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
// If an explicit location exists, use it with TEXCOORD[N] semantic.
// Otherwise, pick a vacant location.
if (m.decoration_flags.get(DecorationLocation))
location_number = m.location;
if (has_decoration(var.self, DecorationLocation))
location_number = get_decoration(var.self, DecorationLocation);
else
location_number = get_vacant_location();
@@ -1174,10 +1162,10 @@ void CompilerHLSL::emit_composite_constants()
auto &type = this->get<SPIRType>(c.constant_type);
// Cannot declare block type constants here.
// We do not have the struct type yet.
bool is_block = has_decoration(type.self, DecorationBlock);
if (!is_block && (type.basetype == SPIRType::Struct || !type.array.empty()))
if (type.basetype == SPIRType::Struct && is_builtin_type(type))
return;
if (type.basetype == SPIRType::Struct || !type.array.empty())
{
auto name = to_name(c.self);
statement("static const ", variable_decl(type, name), " = ", constant_expression(c), ";");
@@ -1195,6 +1183,18 @@ void CompilerHLSL::emit_specialization_constants_and_structs()
SpecializationConstant wg_x, wg_y, wg_z;
ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
std::unordered_set<TypeID> io_block_types;
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
if ((var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
!var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
interface_variable_exists_in_entry_point(var.self) &&
has_decoration(type.self, DecorationBlock))
{
io_block_types.insert(type.self);
}
});
auto loop_lock = ir.create_loop_hard_lock();
for (auto &id_ : ir.ids_for_constant_or_type)
{
@@ -1237,9 +1237,11 @@ void CompilerHLSL::emit_specialization_constants_and_structs()
else if (id.get_type() == TypeType)
{
auto &type = id.get<SPIRType>();
if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
(!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
!ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
bool is_non_io_block = has_decoration(type.self, DecorationBlock) &&
io_block_types.count(type.self) == 0;
bool is_buffer_block = has_decoration(type.self, DecorationBufferBlock);
if (type.basetype == SPIRType::Struct && type.array.empty() &&
!type.pointer && !is_non_io_block && !is_buffer_block)
{
if (emitted)
statement("");
@@ -1365,16 +1367,12 @@ void CompilerHLSL::emit_resources()
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
// Do not emit I/O blocks here.
// I/O blocks can be arrayed, so we must deal with them separately to support geometry shaders
// and tessellation down the line.
if (!block && var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
(var.storage == StorageClassInput || var.storage == StorageClassOutput) && !is_builtin_variable(var) &&
interface_variable_exists_in_entry_point(var.self))
{
// Only emit non-builtins which are not blocks here. Builtin variables are handled separately.
// Builtin variables are handled separately.
emit_interface_block_globally(var);
emitted = true;
}
@@ -1388,69 +1386,72 @@ void CompilerHLSL::emit_resources()
require_output = false;
unordered_set<uint32_t> active_inputs;
unordered_set<uint32_t> active_outputs;
SmallVector<SPIRVariable *> input_variables;
SmallVector<SPIRVariable *> output_variables;
struct IOVariable
{
const SPIRVariable *var;
uint32_t location;
uint32_t block_member_index;
bool block;
};
SmallVector<IOVariable> input_variables;
SmallVector<IOVariable> output_variables;
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
bool block = has_decoration(type.self, DecorationBlock);
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
return;
// Do not emit I/O blocks here.
// I/O blocks can be arrayed, so we must deal with them separately to support geometry shaders
// and tessellation down the line.
if (!block && !var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
if (!var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
interface_variable_exists_in_entry_point(var.self))
{
if (var.storage == StorageClassInput)
input_variables.push_back(&var);
else
output_variables.push_back(&var);
}
// Reserve input and output locations for block variables as necessary.
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
{
auto &active = var.storage == StorageClassInput ? active_inputs : active_outputs;
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
if (block)
{
if (has_member_decoration(type.self, i, DecorationLocation))
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
{
uint32_t location = get_member_decoration(type.self, i, DecorationLocation);
active.insert(location);
uint32_t location = get_declared_member_location(var, i, false);
if (var.storage == StorageClassInput)
input_variables.push_back({ &var, location, i, true });
else
output_variables.push_back({ &var, location, i, true });
}
}
// Emit the block struct and a global variable here.
emit_io_block(var);
else
{
uint32_t location = get_decoration(var.self, DecorationLocation);
if (var.storage == StorageClassInput)
input_variables.push_back({ &var, location, 0, false });
else
output_variables.push_back({ &var, location, 0, false });
}
}
});
const auto variable_compare = [&](const SPIRVariable *a, const SPIRVariable *b) -> bool {
const auto variable_compare = [&](const IOVariable &a, const IOVariable &b) -> bool {
// Sort input and output variables based on, from more robust to less robust:
// - Location
// - Variable has a location
// - Name comparison
// - Variable has a name
// - Fallback: ID
bool has_location_a = has_decoration(a->self, DecorationLocation);
bool has_location_b = has_decoration(b->self, DecorationLocation);
bool has_location_a = a.block || has_decoration(a.var->self, DecorationLocation);
bool has_location_b = b.block || has_decoration(b.var->self, DecorationLocation);
if (has_location_a && has_location_b)
{
return get_decoration(a->self, DecorationLocation) < get_decoration(b->self, DecorationLocation);
}
return a.location < b.location;
else if (has_location_a && !has_location_b)
return true;
else if (!has_location_a && has_location_b)
return false;
const auto &name1 = to_name(a->self);
const auto &name2 = to_name(b->self);
const auto &name1 = to_name(a.var->self);
const auto &name2 = to_name(b.var->self);
if (name1.empty() && name2.empty())
return a->self < b->self;
return a.var->self < b.var->self;
else if (name1.empty())
return true;
else if (name2.empty())
@@ -1477,8 +1478,13 @@ void CompilerHLSL::emit_resources()
begin_scope();
sort(input_variables.begin(), input_variables.end(), variable_compare);
for (auto var : input_variables)
emit_interface_block_in_struct(*var, active_inputs);
for (auto &var : input_variables)
{
if (var.block)
emit_interface_block_member_in_struct(*var.var, var.block_member_index, var.location, active_inputs);
else
emit_interface_block_in_struct(*var.var, active_inputs);
}
emit_builtin_inputs_in_struct();
end_scope_decl();
statement("");
@@ -1490,10 +1496,14 @@ void CompilerHLSL::emit_resources()
statement("struct SPIRV_Cross_Output");
begin_scope();
// FIXME: Use locations properly if they exist.
sort(output_variables.begin(), output_variables.end(), variable_compare);
for (auto var : output_variables)
emit_interface_block_in_struct(*var, active_outputs);
for (auto &var : output_variables)
{
if (var.block)
emit_interface_block_member_in_struct(*var.var, var.block_member_index, var.location, active_outputs);
else
emit_interface_block_in_struct(*var.var, active_outputs);
}
emit_builtin_outputs_in_struct();
end_scope_decl();
statement("");
@@ -1930,6 +1940,28 @@ void CompilerHLSL::emit_resources()
end_scope();
statement("");
}
for (TypeID type_id : composite_selection_workaround_types)
{
// Need out variable since HLSL does not support returning arrays.
auto &type = get<SPIRType>(type_id);
auto type_str = type_to_glsl(type);
auto type_arr_str = type_to_array_glsl(type);
statement("void spvSelectComposite(out ", type_str, " out_value", type_arr_str, ", bool cond, ",
type_str, " true_val", type_arr_str, ", ",
type_str, " false_val", type_arr_str, ")");
begin_scope();
statement("if (cond)");
begin_scope();
statement("out_value = true_val;");
end_scope();
statement("else");
begin_scope();
statement("out_value = false_val;");
end_scope();
end_scope();
statement("");
}
}
void CompilerHLSL::emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav,
@@ -2037,13 +2069,6 @@ void CompilerHLSL::emit_struct_member(const SPIRType &type, uint32_t member_type
if (index < memb.size())
memberflags = memb[index].decoration_flags;
string qualifiers;
bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
if (is_block)
qualifiers = to_interpolation_qualifiers(memberflags);
string packing_offset;
bool is_push_constant = type.storage == StorageClassPushConstant;
@@ -2058,7 +2083,7 @@ void CompilerHLSL::emit_struct_member(const SPIRType &type, uint32_t member_type
packing_offset = join(" : packoffset(c", offset / 16, packing_swizzle[(offset & 15) >> 2], ")");
}
statement(layout_for_member(type, index), qualifiers, qualifier,
statement(layout_for_member(type, index), qualifier,
variable_decl(membertype, to_member_name(type, index)), packing_offset, ";");
}
@@ -2393,27 +2418,6 @@ void CompilerHLSL::emit_hlsl_entry_point()
if (require_input)
arguments.push_back("SPIRV_Cross_Input stage_input");
// Add I/O blocks as separate arguments with appropriate storage qualifier.
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
return;
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
{
if (var.storage == StorageClassInput)
{
arguments.push_back(join("in ", variable_decl(type, join("stage_input", to_name(var.self)))));
}
else if (var.storage == StorageClassOutput)
{
arguments.push_back(join("out ", variable_decl(type, join("stage_output", to_name(var.self)))));
}
}
});
auto &execution = get_entry_point();
switch (execution.model)
@@ -2574,36 +2578,43 @@ void CompilerHLSL::emit_hlsl_entry_point()
// Copy from stage input struct to globals.
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
bool block = has_decoration(type.self, DecorationBlock);
if (var.storage != StorageClassInput)
return;
bool need_matrix_unroll = var.storage == StorageClassInput && execution.model == ExecutionModelVertex;
if (!block && !var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
if (!var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
interface_variable_exists_in_entry_point(var.self))
{
auto name = to_name(var.self);
auto &mtype = this->get<SPIRType>(var.basetype);
if (need_matrix_unroll && mtype.columns > 1)
if (block)
{
// Unroll matrices.
for (uint32_t col = 0; col < mtype.columns; col++)
statement(name, "[", col, "] = stage_input.", name, "_", col, ";");
auto type_name = to_name(type.self);
auto var_name = to_name(var.self);
for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(type.member_types.size()); mbr_idx++)
{
auto mbr_name = to_member_name(type, mbr_idx);
auto flat_name = join(type_name, "_", mbr_name);
statement(var_name, ".", mbr_name, " = stage_input.", flat_name, ";");
}
}
else
{
statement(name, " = stage_input.", name, ";");
auto name = to_name(var.self);
auto &mtype = this->get<SPIRType>(var.basetype);
if (need_matrix_unroll && mtype.columns > 1)
{
// Unroll matrices.
for (uint32_t col = 0; col < mtype.columns; col++)
statement(name, "[", col, "] = stage_input.", name, "_", col, ";");
}
else
{
statement(name, " = stage_input.", name, ";");
}
}
}
// I/O blocks don't use the common stage input/output struct, but separate outputs.
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
{
auto name = to_name(var.self);
statement(name, " = stage_input", name, ";");
}
});
// Run the shader.
@@ -2616,22 +2627,6 @@ void CompilerHLSL::emit_hlsl_entry_point()
else
SPIRV_CROSS_THROW("Unsupported shader stage.");
// Copy block outputs.
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
if (var.storage != StorageClassOutput)
return;
// I/O blocks don't use the common stage input/output struct, but separate outputs.
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
{
auto name = to_name(var.self);
statement("stage_output", name, " = ", name, ";");
}
});
// Copy stage outputs.
if (require_output)
{
@@ -2668,27 +2663,43 @@ void CompilerHLSL::emit_hlsl_entry_point()
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
bool block = has_decoration(type.self, DecorationBlock);
if (var.storage != StorageClassOutput)
return;
if (!block && var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
!is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
if (!var.remapped_variable && type.pointer &&
!is_builtin_variable(var) &&
interface_variable_exists_in_entry_point(var.self))
{
auto name = to_name(var.self);
if (legacy && execution.model == ExecutionModelFragment)
if (block)
{
string output_filler;
for (uint32_t size = type.vecsize; size < 4; ++size)
output_filler += ", 0.0";
statement("stage_output.", name, " = float4(", name, output_filler, ");");
// I/O blocks need to flatten output.
auto type_name = to_name(type.self);
auto var_name = to_name(var.self);
for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(type.member_types.size()); mbr_idx++)
{
auto mbr_name = to_member_name(type, mbr_idx);
auto flat_name = join(type_name, "_", mbr_name);
statement("stage_output.", flat_name, " = ", var_name, ".", mbr_name, ";");
}
}
else
{
statement("stage_output.", name, " = ", name, ";");
auto name = to_name(var.self);
if (legacy && execution.model == ExecutionModelFragment)
{
string output_filler;
for (uint32_t size = type.vecsize; size < 4; ++size)
output_filler += ", 0.0";
statement("stage_output.", name, " = float4(", name, output_filler, ");");
}
else
{
statement("stage_output.", name, " = ", name, ";");
}
}
}
});
@@ -4575,19 +4586,15 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i)
case OpGroupNonUniformInverseBallot:
SPIRV_CROSS_THROW("Cannot trivially implement InverseBallot in HLSL.");
break;
case OpGroupNonUniformBallotBitExtract:
SPIRV_CROSS_THROW("Cannot trivially implement BallotBitExtract in HLSL.");
break;
case OpGroupNonUniformBallotFindLSB:
SPIRV_CROSS_THROW("Cannot trivially implement BallotFindLSB in HLSL.");
break;
case OpGroupNonUniformBallotFindMSB:
SPIRV_CROSS_THROW("Cannot trivially implement BallotFindMSB in HLSL.");
break;
case OpGroupNonUniformBallotBitCount:
{
@@ -4787,6 +4794,34 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
break;
}
case OpSelect:
{
auto &value_type = expression_type(ops[3]);
if (value_type.basetype == SPIRType::Struct || is_array(value_type))
{
// HLSL does not support ternary expressions on composites.
// Cannot use branches, since we might be in a continue block
// where explicit control flow is prohibited.
// Emit a helper function where we can use control flow.
TypeID value_type_id = expression_type_id(ops[3]);
auto itr = std::find(composite_selection_workaround_types.begin(),
composite_selection_workaround_types.end(),
value_type_id);
if (itr == composite_selection_workaround_types.end())
{
composite_selection_workaround_types.push_back(value_type_id);
force_recompile();
}
emit_uninitialized_temporary_expression(ops[0], ops[1]);
statement("spvSelectComposite(",
to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
to_expression(ops[3]), ", ", to_expression(ops[4]), ");");
}
else
CompilerGLSL::emit_instruction(instruction);
break;
}
case OpStore:
{
emit_store(instruction);

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2016-2021 Robert Konrad
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_HLSL_HPP
@@ -219,7 +219,10 @@ private:
void emit_resources();
void declare_undefined_values() override;
void emit_interface_block_globally(const SPIRVariable &type);
void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
void emit_interface_block_in_struct(const SPIRVariable &var, std::unordered_set<uint32_t> &active_locations);
void emit_interface_block_member_in_struct(const SPIRVariable &var, uint32_t member_index,
uint32_t location,
std::unordered_set<uint32_t> &active_locations);
void emit_builtin_inputs_in_struct();
void emit_builtin_outputs_in_struct();
void emit_texture_op(const Instruction &i, bool sparse) override;
@@ -347,7 +350,6 @@ private:
uint32_t type_to_consumed_locations(const SPIRType &type) const;
void emit_io_block(const SPIRVariable &var);
std::string to_semantic(uint32_t location, spv::ExecutionModel em, spv::StorageClass sc);
uint32_t num_workgroups_builtin = 0;
@@ -369,6 +371,8 @@ private:
// Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but SV_Coverage is a scalar in HLSL.
bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override;
std::vector<TypeID> composite_selection_workaround_types;
};
} // namespace SPIRV_CROSS_NAMESPACE

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2016-2021 The Brenwill Workshop Ltd.
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_msl.hpp"
@@ -109,7 +109,6 @@ void CompilerMSL::add_msl_resource_binding(const MSLResourceBinding &binding)
default:
SPIRV_CROSS_THROW("Unexpected argument buffer resource base type. When padding argument buffer elements, "
"all descriptor set resources must be supplied with a base type by the app.");
break;
}
#undef ADD_ARG_IDX_TO_BINDING_NUM_LOOKUP
}
@@ -231,13 +230,12 @@ void CompilerMSL::build_implicit_builtins()
(active_input_builtins.get(BuiltInVertexId) || active_input_builtins.get(BuiltInVertexIndex) ||
active_input_builtins.get(BuiltInBaseVertex) || active_input_builtins.get(BuiltInInstanceId) ||
active_input_builtins.get(BuiltInInstanceIndex) || active_input_builtins.get(BuiltInBaseInstance));
bool need_sample_mask = msl_options.additional_fixed_sample_mask != 0xffffffff;
bool need_local_invocation_index = msl_options.emulate_subgroups && active_input_builtins.get(BuiltInSubgroupId);
bool need_workgroup_size = msl_options.emulate_subgroups && active_input_builtins.get(BuiltInNumSubgroups);
if (need_subpass_input || need_sample_pos || need_subgroup_mask || need_vertex_params || need_tesc_params ||
need_multiview || need_dispatch_base || need_vertex_base_params || need_grid_params || needs_sample_id ||
needs_subgroup_invocation_id || needs_subgroup_size || need_sample_mask || need_local_invocation_index ||
needs_subgroup_invocation_id || needs_subgroup_size || has_additional_fixed_sample_mask() || need_local_invocation_index ||
need_workgroup_size)
{
bool has_frag_coord = false;
@@ -268,7 +266,7 @@ void CompilerMSL::build_implicit_builtins()
if (var.storage == StorageClassOutput)
{
if (need_sample_mask && builtin == BuiltInSampleMask)
if (has_additional_fixed_sample_mask() && builtin == BuiltInSampleMask)
{
builtin_sample_mask_id = var.self;
mark_implicit_builtin(StorageClassOutput, BuiltInSampleMask, var.self);
@@ -758,7 +756,7 @@ void CompilerMSL::build_implicit_builtins()
builtin_dispatch_base_id = var_id;
}
if (need_sample_mask && !does_shader_write_sample_mask)
if (has_additional_fixed_sample_mask() && !does_shader_write_sample_mask)
{
uint32_t offset = ir.increase_bound_by(2);
uint32_t var_id = offset + 1;
@@ -5385,9 +5383,7 @@ void CompilerMSL::emit_custom_functions()
statement("// SPIR-V callers expect a uint4. We must convert.");
statement("// FIXME: This won't include higher bits if Apple ever supports");
statement("// 128 lanes in an SIMD-group.");
statement(
"return uint4((uint)((simd_vote::vote_t)vote & 0xFFFFFFFF), (uint)(((simd_vote::vote_t)vote >> "
"32) & 0xFFFFFFFF), 0, 0);");
statement("return uint4(as_type<uint2>((simd_vote::vote_t)vote), 0, 0);");
}
end_scope();
statement("");
@@ -7450,7 +7446,7 @@ void CompilerMSL::fix_up_interpolant_access_chain(const uint32_t *ops, uint32_t
// for that getting the base index.
for (uint32_t i = 3; i < length; ++i)
{
if (is_vector(*type) && is_scalar(result_type))
if (is_vector(*type) && !is_array(*type) && is_scalar(result_type))
{
// We don't want to combine the next index. Actually, we need to save it
// so we know to apply a swizzle to the result of the interpolation.
@@ -9912,7 +9908,6 @@ string CompilerMSL::to_component_argument(uint32_t id)
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";
}
}
@@ -10120,7 +10115,6 @@ static string create_swizzle(MSLComponentSwizzle swizzle)
return "spvSwizzle::alpha";
default:
SPIRV_CROSS_THROW("Invalid component swizzle.");
return "";
}
}
@@ -12314,29 +12308,17 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
break;
}
}
else if (var.storage == StorageClassOutput && is_builtin_variable(var) && active_output_builtins.get(bi_type))
else if (var.storage == StorageClassOutput && get_execution_model() == ExecutionModelFragment &&
is_builtin_variable(var) && active_output_builtins.get(bi_type) &&
bi_type == BuiltInSampleMask && has_additional_fixed_sample_mask())
{
if (bi_type == BuiltInSampleMask && get_execution_model() == ExecutionModelFragment &&
msl_options.additional_fixed_sample_mask != 0xffffffff)
{
// If the additional fixed sample mask was set, we need to adjust the sample_mask
// output to reflect that. If the shader outputs the sample_mask itself too, we need
// to AND the two masks to get the final one.
if (does_shader_write_sample_mask)
{
entry_func.fixup_hooks_out.push_back([=]() {
statement(to_expression(builtin_sample_mask_id),
" &= ", msl_options.additional_fixed_sample_mask, ";");
});
}
else
{
entry_func.fixup_hooks_out.push_back([=]() {
statement(to_expression(builtin_sample_mask_id), " = ",
msl_options.additional_fixed_sample_mask, ";");
});
}
}
// If the additional fixed sample mask was set, we need to adjust the sample_mask
// output to reflect that. If the shader outputs the sample_mask itself too, we need
// to AND the two masks to get the final one.
string op_str = does_shader_write_sample_mask ? " &= " : " = ";
entry_func.fixup_hooks_out.push_back([=]() {
statement(to_expression(builtin_sample_mask_id), op_str, additional_fixed_sample_mask_str(), ";");
});
}
});
}
@@ -13745,7 +13727,6 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
break;
default:
SPIRV_CROSS_THROW("Invalid BitCount operation.");
break;
}
break;
}
@@ -14054,7 +14035,6 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
case BuiltInClipDistance:
case BuiltInCullDistance:
case BuiltInLayer:
case BuiltInSampleMask:
if (get_execution_model() == ExecutionModelTessellationControl)
break;
if (storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point) &&
@@ -14062,6 +14042,24 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
return stage_out_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin, storage);
break;
case BuiltInSampleMask:
if (storage == StorageClassInput && current_function && (current_function->self == ir.default_entry_point) &&
(has_additional_fixed_sample_mask() || needs_sample_id))
{
string samp_mask_in;
samp_mask_in += "(" + CompilerGLSL::builtin_to_glsl(builtin, storage);
if (has_additional_fixed_sample_mask())
samp_mask_in += " & " + additional_fixed_sample_mask_str();
if (needs_sample_id)
samp_mask_in += " & (1 << gl_SampleID)";
samp_mask_in += ")";
return samp_mask_in;
}
if (storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point) &&
!is_stage_output_builtin_masked(builtin))
return stage_out_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin, storage);
break;
case BuiltInBaryCoordNV:
case BuiltInBaryCoordNoPerspNV:
if (storage == StorageClassInput && current_function && (current_function->self == ir.default_entry_point))
@@ -15940,3 +15938,10 @@ const char *CompilerMSL::get_combined_sampler_suffix() const
void CompilerMSL::emit_block_hints(const SPIRBlock &)
{
}
string CompilerMSL::additional_fixed_sample_mask_str() const
{
char print_buffer[32];
sprintf(print_buffer, "0x%x", msl_options.additional_fixed_sample_mask);
return print_buffer;
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2016-2021 The Brenwill Workshop Ltd.
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_MSL_HPP
@@ -1093,6 +1093,9 @@ protected:
bool variable_storage_requires_stage_io(spv::StorageClass storage) const;
bool has_additional_fixed_sample_mask() const { return msl_options.additional_fixed_sample_mask != 0xffffffff; }
std::string additional_fixed_sample_mask_str() const;
// OpcodeHandler that handles several MSL preprocessing operations.
struct OpCodePreprocessor : OpcodeHandler
{

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_parser.hpp"

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Arm Limited
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_PARSER_HPP

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Bradley Austin Davis
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#include "spirv_reflect.hpp"

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Bradley Austin Davis
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +19,6 @@
* At your option, you may choose to accept this material under either:
* 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
* 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
* SPDX-License-Identifier: Apache-2.0 OR MIT.
*/
#ifndef SPIRV_CROSS_REFLECT_HPP