mirror of
https://github.com/KhronosGroup/SPIRV-Cross.git
synced 2024-11-15 00:11:06 +00:00
Merge with KhronosGroup/SPIRV-Cross
This commit is contained in:
commit
84c3092aba
@ -16,6 +16,8 @@ cmake_minimum_required(VERSION 2.8)
|
||||
project(SPIRV-Cross)
|
||||
enable_testing()
|
||||
|
||||
option(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS "Instead of throwing exceptions assert" OFF)
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Makefile")
|
||||
if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
|
||||
message(FATAL_ERROR "Build out of tree to avoid overwriting Makefile")
|
||||
@ -50,24 +52,35 @@ target_link_libraries(spirv-cross-msl spirv-cross-glsl)
|
||||
target_link_libraries(spirv-cross-cpp spirv-cross-glsl)
|
||||
target_include_directories(spirv-cross-core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set(spirv-compiler-options "")
|
||||
set(spirv-compiler-defines "")
|
||||
|
||||
if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
|
||||
set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
|
||||
endif()
|
||||
|
||||
# To specify special debug or optimization options, use
|
||||
# -DCMAKE_CXX_COMPILE_FLAGS
|
||||
# However, we require the C++11 dialect.
|
||||
if (NOT "${MSVC}")
|
||||
set(spirv-compiler-options -std=c++11 -Wall -Wextra -Werror -Wshadow)
|
||||
set(spirv-compiler-defines __STDC_LIMIT_MACROS)
|
||||
target_compile_options(spirv-cross-core PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross-glsl PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross-msl PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross-cpp PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross PRIVATE ${spirv-compiler-options})
|
||||
target_compile_definitions(spirv-cross-core PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross-glsl PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross-msl PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross-cpp PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross PRIVATE ${spirv-compiler-defines})
|
||||
endif(NOT "${MSVC}")
|
||||
set(spirv-compiler-options ${spirv-compiler-options} -std=c++11 -Wall -Wextra -Werror -Wshadow)
|
||||
set(spirv-compiler-defines ${spirv-compiler-defines} __STDC_LIMIT_MACROS)
|
||||
|
||||
if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
|
||||
set(spirv-compiler-options ${spirv-compiler-options} -fno-exceptions)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_options(spirv-cross-core PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross-glsl PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross-msl PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross-cpp PRIVATE ${spirv-compiler-options})
|
||||
target_compile_options(spirv-cross PRIVATE ${spirv-compiler-options})
|
||||
target_compile_definitions(spirv-cross-core PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross-glsl PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross-msl PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross-cpp PRIVATE ${spirv-compiler-defines})
|
||||
target_compile_definitions(spirv-cross PRIVATE ${spirv-compiler-defines})
|
||||
|
||||
# Set up tests, using only the simplest modes of the test_shaders
|
||||
# script. You have to invoke the script manually to:
|
||||
@ -80,5 +93,6 @@ if(${PYTHONINTERP_FOUND} AND ${PYTHON_VERSION_MAJOR} GREATER 2)
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders)
|
||||
else()
|
||||
message(WARNING "Testing disabled. Could not find python3")
|
||||
message(WARNING "Testing disabled. Could not find python3. If you have python3 installed try running "
|
||||
"cmake with -DPYTHON_EXECUTABLE:FILEPATH=/path/to/python3 to help it find the executable")
|
||||
endif()
|
||||
|
6
Makefile
6
Makefile
@ -15,7 +15,11 @@ CXXFLAGS += -std=c++11 -Wall -Wextra -Wshadow -D__STDC_LIMIT_MACROS
|
||||
ifeq ($(DEBUG), 1)
|
||||
CXXFLAGS += -O0 -g
|
||||
else
|
||||
CXXFLAGS += -O2 -g
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
endif
|
||||
|
||||
ifeq ($(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS), 1)
|
||||
CXXFLAGS += -DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS -fno-exceptions
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
@ -23,6 +23,8 @@ However, most missing features are expected to be "trivial" improvements at this
|
||||
|
||||
SPIRV-Cross has been tested on Linux, OSX and Windows.
|
||||
|
||||
The make and CMake build flavors offer the option to treat exceptions as assertions. To disable exceptions for make just append SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=1 to the command line. For CMake append -DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=ON. By default exceptions are enabled.
|
||||
|
||||
### Linux and macOS
|
||||
|
||||
Just run `make` on the command line. A recent GCC (4.8+) or Clang (3.x+) compiler is required as SPIRV-Cross uses C++11 extensively.
|
||||
|
31
main.cpp
31
main.cpp
@ -30,6 +30,17 @@ using namespace spv;
|
||||
using namespace spirv_cross;
|
||||
using namespace std;
|
||||
|
||||
#ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
#define THROW(x) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, "%s.", x); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
#else
|
||||
#define THROW(x) runtime_error(x)
|
||||
#endif
|
||||
|
||||
struct CLIParser;
|
||||
struct CLICallbacks
|
||||
{
|
||||
@ -53,7 +64,9 @@ struct CLIParser
|
||||
|
||||
bool parse()
|
||||
{
|
||||
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
try
|
||||
#endif
|
||||
{
|
||||
while (argc && !ended_state)
|
||||
{
|
||||
@ -69,7 +82,7 @@ struct CLIParser
|
||||
auto itr = cbs.callbacks.find(next);
|
||||
if (itr == ::end(cbs.callbacks))
|
||||
{
|
||||
throw logic_error("Invalid argument.\n");
|
||||
THROW("Invalid argument");
|
||||
}
|
||||
|
||||
itr->second(*this);
|
||||
@ -78,6 +91,7 @@ struct CLIParser
|
||||
|
||||
return true;
|
||||
}
|
||||
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
catch (...)
|
||||
{
|
||||
if (cbs.error_handler)
|
||||
@ -86,6 +100,7 @@ struct CLIParser
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void end()
|
||||
@ -97,13 +112,13 @@ struct CLIParser
|
||||
{
|
||||
if (!argc)
|
||||
{
|
||||
throw logic_error("Tried to parse uint, but nothing left in arguments.\n");
|
||||
THROW("Tried to parse uint, but nothing left in arguments");
|
||||
}
|
||||
|
||||
uint32_t val = stoul(*argv);
|
||||
if (val > numeric_limits<uint32_t>::max())
|
||||
{
|
||||
throw out_of_range("next_uint() out of range.\n");
|
||||
THROW("next_uint() out of range");
|
||||
}
|
||||
|
||||
argc--;
|
||||
@ -116,7 +131,7 @@ struct CLIParser
|
||||
{
|
||||
if (!argc)
|
||||
{
|
||||
throw logic_error("Tried to parse double, but nothing left in arguments.\n");
|
||||
THROW("Tried to parse double, but nothing left in arguments");
|
||||
}
|
||||
|
||||
double val = stod(*argv);
|
||||
@ -131,7 +146,7 @@ struct CLIParser
|
||||
{
|
||||
if (!argc)
|
||||
{
|
||||
throw logic_error("Tried to parse string, but nothing left in arguments.\n");
|
||||
THROW("Tried to parse string, but nothing left in arguments");
|
||||
}
|
||||
|
||||
const char *ret = *argv;
|
||||
@ -202,7 +217,7 @@ static void print_resources(const Compiler &compiler, const char *tag, const vec
|
||||
|
||||
uint32_t block_size = 0;
|
||||
if (is_sized_block)
|
||||
block_size = compiler.get_declared_struct_size(compiler.get_type(res.base_type_id));
|
||||
block_size = uint32_t(compiler.get_declared_struct_size(compiler.get_type(res.base_type_id)));
|
||||
|
||||
string array;
|
||||
for (auto arr : type.array)
|
||||
@ -219,6 +234,10 @@ static void print_resources(const Compiler &compiler, const char *tag, const vec
|
||||
fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding));
|
||||
if (mask & (1ull << DecorationInputAttachmentIndex))
|
||||
fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex));
|
||||
if (mask & (1ull << DecorationNonReadable))
|
||||
fprintf(stderr, " writeonly");
|
||||
if (mask & (1ull << DecorationNonWritable))
|
||||
fprintf(stderr, " readonly");
|
||||
if (is_sized_block)
|
||||
fprintf(stderr, " (BlockSize : %u bytes)", block_size);
|
||||
fprintf(stderr, "\n");
|
||||
|
@ -17,13 +17,31 @@
|
||||
#ifndef SPIRV_CROSS_COMMON_HPP
|
||||
#define SPIRV_CROSS_COMMON_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace spirv_cross
|
||||
{
|
||||
|
||||
#ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
#ifndef _MSC_VER
|
||||
[[noreturn]]
|
||||
#endif
|
||||
inline void
|
||||
report_and_abort(const std::string &msg)
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
(void)msg;
|
||||
#else
|
||||
fprintf(stderr, "There was a compiler error: %s\n", msg.c_str());
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
#define SPIRV_CROSS_THROW(x) report_and_abort(x)
|
||||
#else
|
||||
class CompilerError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
@ -33,6 +51,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#define SPIRV_CROSS_THROW(x) throw CompilerError(x)
|
||||
#endif
|
||||
|
||||
namespace inner
|
||||
{
|
||||
template <typename T>
|
||||
@ -792,7 +813,7 @@ public:
|
||||
{
|
||||
holder = std::move(val);
|
||||
if (type != TypeNone && type != new_type)
|
||||
throw CompilerError("Overwriting a variant with new type.");
|
||||
SPIRV_CROSS_THROW("Overwriting a variant with new type.");
|
||||
type = new_type;
|
||||
}
|
||||
|
||||
@ -800,9 +821,9 @@ public:
|
||||
T &get()
|
||||
{
|
||||
if (!holder)
|
||||
throw CompilerError("nullptr");
|
||||
SPIRV_CROSS_THROW("nullptr");
|
||||
if (T::type != type)
|
||||
throw CompilerError("Bad cast");
|
||||
SPIRV_CROSS_THROW("Bad cast");
|
||||
return *static_cast<T *>(holder.get());
|
||||
}
|
||||
|
||||
@ -810,9 +831,9 @@ public:
|
||||
const T &get() const
|
||||
{
|
||||
if (!holder)
|
||||
throw CompilerError("nullptr");
|
||||
SPIRV_CROSS_THROW("nullptr");
|
||||
if (T::type != type)
|
||||
throw CompilerError("Bad cast");
|
||||
SPIRV_CROSS_THROW("Bad cast");
|
||||
return *static_cast<const T *>(holder.get());
|
||||
}
|
||||
|
||||
@ -872,7 +893,6 @@ struct Meta
|
||||
uint32_t input_attachment = 0;
|
||||
uint32_t spec_id = 0;
|
||||
bool builtin = false;
|
||||
bool per_instance = false;
|
||||
};
|
||||
|
||||
Decoration decoration;
|
||||
|
@ -116,8 +116,8 @@ void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
auto &flags = meta[var.self].decoration.decoration_flags;
|
||||
if ((flags & (1ull << DecorationBinding)) || (flags & (1ull << DecorationDescriptorSet)))
|
||||
throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
|
||||
"Remap to location with reflection API first or disable these decorations.");
|
||||
SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
|
||||
"Remap to location with reflection API first or disable these decorations.");
|
||||
|
||||
emit_block_struct(type);
|
||||
auto buffer_name = to_name(type.self);
|
||||
@ -298,7 +298,7 @@ string CompilerCPP::compile()
|
||||
do
|
||||
{
|
||||
if (pass_count >= 3)
|
||||
throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
|
||||
SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
|
||||
|
||||
resource_registrations.clear();
|
||||
reset();
|
||||
@ -469,7 +469,7 @@ void CompilerCPP::emit_header()
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("Unsupported execution model.");
|
||||
SPIRV_CROSS_THROW("Unsupported execution model.");
|
||||
}
|
||||
|
||||
switch (execution.model)
|
||||
@ -506,6 +506,6 @@ void CompilerCPP::emit_header()
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("Unsupported execution model.");
|
||||
SPIRV_CROSS_THROW("Unsupported execution model.");
|
||||
}
|
||||
}
|
||||
|
121
spirv_cross.cpp
121
spirv_cross.cpp
@ -33,7 +33,7 @@ Instruction::Instruction(const vector<uint32_t> &spirv, uint32_t &index)
|
||||
count = (spirv[index] >> 16) & 0xffff;
|
||||
|
||||
if (count == 0)
|
||||
throw CompilerError("SPIR-V instructions cannot consume 0 words. Invalid SPIR-V file.");
|
||||
SPIRV_CROSS_THROW("SPIR-V instructions cannot consume 0 words. Invalid SPIR-V file.");
|
||||
|
||||
offset = index + 1;
|
||||
length = count - 1;
|
||||
@ -41,7 +41,7 @@ Instruction::Instruction(const vector<uint32_t> &spirv, uint32_t &index)
|
||||
index += count;
|
||||
|
||||
if (index > spirv.size())
|
||||
throw CompilerError("SPIR-V instruction goes out of bounds.");
|
||||
SPIRV_CROSS_THROW("SPIR-V instruction goes out of bounds.");
|
||||
}
|
||||
|
||||
Compiler::Compiler(vector<uint32_t> ir)
|
||||
@ -328,7 +328,7 @@ const SPIRType &Compiler::expression_type(uint32_t id) const
|
||||
return get<SPIRType>(get<SPIRUndef>(id).basetype);
|
||||
|
||||
default:
|
||||
throw CompilerError("Cannot resolve expression type.");
|
||||
SPIRV_CROSS_THROW("Cannot resolve expression type.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -665,7 +665,7 @@ static string extract_string(const vector<uint32_t> &spirv, uint32_t offset)
|
||||
}
|
||||
}
|
||||
|
||||
throw CompilerError("String was not terminated before EOF");
|
||||
SPIRV_CROSS_THROW("String was not terminated before EOF");
|
||||
}
|
||||
|
||||
static bool is_valid_spirv_version(uint32_t version)
|
||||
@ -687,7 +687,7 @@ void Compiler::parse()
|
||||
{
|
||||
auto len = spirv.size();
|
||||
if (len < 5)
|
||||
throw CompilerError("SPIRV file too small.");
|
||||
SPIRV_CROSS_THROW("SPIRV file too small.");
|
||||
|
||||
auto s = spirv.data();
|
||||
|
||||
@ -696,7 +696,7 @@ void Compiler::parse()
|
||||
transform(begin(spirv), end(spirv), begin(spirv), [](uint32_t c) { return swap_endian(c); });
|
||||
|
||||
if (s[0] != MagicNumber || !is_valid_spirv_version(s[1]))
|
||||
throw CompilerError("Invalid SPIRV format.");
|
||||
SPIRV_CROSS_THROW("Invalid SPIRV format.");
|
||||
|
||||
uint32_t bound = s[3];
|
||||
ids.resize(bound);
|
||||
@ -710,9 +710,9 @@ void Compiler::parse()
|
||||
parse(i);
|
||||
|
||||
if (current_function)
|
||||
throw CompilerError("Function was not terminated.");
|
||||
SPIRV_CROSS_THROW("Function was not terminated.");
|
||||
if (current_block)
|
||||
throw CompilerError("Block was not terminated.");
|
||||
SPIRV_CROSS_THROW("Block was not terminated.");
|
||||
}
|
||||
|
||||
void Compiler::flatten_interface_block(uint32_t id)
|
||||
@ -722,24 +722,24 @@ void Compiler::flatten_interface_block(uint32_t id)
|
||||
auto flags = meta.at(type.self).decoration.decoration_flags;
|
||||
|
||||
if (!type.array.empty())
|
||||
throw CompilerError("Type is array of UBOs.");
|
||||
SPIRV_CROSS_THROW("Type is array of UBOs.");
|
||||
if (type.basetype != SPIRType::Struct)
|
||||
throw CompilerError("Type is not a struct.");
|
||||
SPIRV_CROSS_THROW("Type is not a struct.");
|
||||
if ((flags & (1ull << DecorationBlock)) == 0)
|
||||
throw CompilerError("Type is not a block.");
|
||||
SPIRV_CROSS_THROW("Type is not a block.");
|
||||
if (type.member_types.empty())
|
||||
throw CompilerError("Member list of struct is empty.");
|
||||
SPIRV_CROSS_THROW("Member list of struct is empty.");
|
||||
|
||||
uint32_t t = type.member_types[0];
|
||||
for (auto &m : type.member_types)
|
||||
if (t != m)
|
||||
throw CompilerError("Types in block differ.");
|
||||
SPIRV_CROSS_THROW("Types in block differ.");
|
||||
|
||||
auto &mtype = get<SPIRType>(t);
|
||||
if (!mtype.array.empty())
|
||||
throw CompilerError("Member type cannot be arrays.");
|
||||
SPIRV_CROSS_THROW("Member type cannot be arrays.");
|
||||
if (mtype.basetype == SPIRType::Struct)
|
||||
throw CompilerError("Member type cannot be struct.");
|
||||
SPIRV_CROSS_THROW("Member type cannot be struct.");
|
||||
|
||||
// Inherit variable name from interface block name.
|
||||
meta.at(var.self).decoration.alias = meta.at(type.self).decoration.alias;
|
||||
@ -794,7 +794,7 @@ void Compiler::set_name(uint32_t id, const std::string &name)
|
||||
return;
|
||||
|
||||
// Functions in glslangValidator are mangled with name(<mangled> stuff.
|
||||
// Normally, we would never see '(' in any legal indentifiers, so just strip them out.
|
||||
// Normally, we would never see '(' in any legal identifiers, so just strip them out.
|
||||
str = name.substr(0, name.find('('));
|
||||
|
||||
for (uint32_t i = 0; i < str.size(); i++)
|
||||
@ -890,7 +890,7 @@ uint32_t Compiler::get_member_decoration(uint32_t id, uint32_t index, Decoration
|
||||
case DecorationSpecId:
|
||||
return dec.spec_id;
|
||||
default:
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1025,7 +1025,7 @@ uint32_t Compiler::get_decoration(uint32_t id, Decoration decoration) const
|
||||
case DecorationSpecId:
|
||||
return dec.spec_id;
|
||||
default:
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1118,7 +1118,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
{
|
||||
uint32_t cap = ops[0];
|
||||
if (cap == CapabilityKernel)
|
||||
throw CompilerError("Kernel capability not supported.");
|
||||
SPIRV_CROSS_THROW("Kernel capability not supported.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1129,7 +1129,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
if (ext == "GLSL.std.450")
|
||||
set<SPIRExtension>(id, SPIRExtension::GLSL);
|
||||
else
|
||||
throw CompilerError("Only GLSL.std.450 extension interface supported.");
|
||||
SPIRV_CROSS_THROW("Only GLSL.std.450 extension interface supported.");
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1336,6 +1336,10 @@ void Compiler::parse(const Instruction &instruction)
|
||||
type.image.ms = ops[5] != 0;
|
||||
type.image.sampled = ops[6];
|
||||
type.image.format = static_cast<ImageFormat>(ops[7]);
|
||||
if (length > 8)
|
||||
type.image.video = ops[8];
|
||||
else
|
||||
type.image.video = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1368,7 +1372,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
|
||||
ptrbase = base;
|
||||
if (ptrbase.pointer)
|
||||
throw CompilerError("Cannot make pointer-to-pointer type.");
|
||||
SPIRV_CROSS_THROW("Cannot make pointer-to-pointer type.");
|
||||
ptrbase.pointer = true;
|
||||
ptrbase.storage = static_cast<StorageClass>(ops[1]);
|
||||
|
||||
@ -1431,7 +1435,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
if (storage == StorageClassFunction)
|
||||
{
|
||||
if (!current_function)
|
||||
throw CompilerError("No function currently in scope");
|
||||
SPIRV_CROSS_THROW("No function currently in scope");
|
||||
current_function->add_local_variable(id);
|
||||
}
|
||||
else if (storage == StorageClassPrivate || storage == StorageClassWorkgroup || storage == StorageClassOutput)
|
||||
@ -1444,17 +1448,6 @@ void Compiler::parse(const Instruction &instruction)
|
||||
if (variable_storage_is_aliased(var))
|
||||
aliased_variables.push_back(var.self);
|
||||
|
||||
// glslangValidator does not emit required qualifiers here.
|
||||
// Solve this by making the image access as restricted as possible
|
||||
// and loosen up if we need to.
|
||||
auto &vartype = expression_type(id);
|
||||
if (vartype.basetype == SPIRType::Image)
|
||||
{
|
||||
auto &flags = meta.at(id).decoration.decoration_flags;
|
||||
flags |= 1ull << DecorationNonWritable;
|
||||
flags |= 1ull << DecorationNonReadable;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1466,9 +1459,9 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpPhi:
|
||||
{
|
||||
if (!current_function)
|
||||
throw CompilerError("No function currently in scope");
|
||||
SPIRV_CROSS_THROW("No function currently in scope");
|
||||
if (!current_block)
|
||||
throw CompilerError("No block currently in scope");
|
||||
SPIRV_CROSS_THROW("No block currently in scope");
|
||||
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
@ -1560,7 +1553,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("OpConstantComposite only supports 1, 2, 3 and 4 columns.");
|
||||
SPIRV_CROSS_THROW("OpConstantComposite only supports 1, 2, 3 and 4 columns.");
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1618,7 +1611,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("OpConstantComposite only supports 1, 2, 3 and 4 components.");
|
||||
SPIRV_CROSS_THROW("OpConstantComposite only supports 1, 2, 3 and 4 components.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1635,7 +1628,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
uint32_t type = ops[3];
|
||||
|
||||
if (current_function)
|
||||
throw CompilerError("Must end a function before starting a new one!");
|
||||
SPIRV_CROSS_THROW("Must end a function before starting a new one!");
|
||||
|
||||
current_function = &set<SPIRFunction>(id, res, type);
|
||||
break;
|
||||
@ -1647,7 +1640,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
uint32_t id = ops[1];
|
||||
|
||||
if (!current_function)
|
||||
throw CompilerError("Must be in a function!");
|
||||
SPIRV_CROSS_THROW("Must be in a function!");
|
||||
|
||||
current_function->add_parameter(type, id);
|
||||
set<SPIRVariable>(id, type, StorageClassFunction);
|
||||
@ -1659,7 +1652,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
if (current_block)
|
||||
{
|
||||
// Very specific error message, but seems to come up quite often.
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Cannot end a function before ending the current block.\n"
|
||||
"Likely cause: If this SPIR-V was created from glslang HLSL, make sure the entry point is valid.");
|
||||
}
|
||||
@ -1672,7 +1665,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
{
|
||||
// OpLabel always starts a block.
|
||||
if (!current_function)
|
||||
throw CompilerError("Blocks cannot exist outside functions!");
|
||||
SPIRV_CROSS_THROW("Blocks cannot exist outside functions!");
|
||||
|
||||
uint32_t id = ops[0];
|
||||
|
||||
@ -1681,7 +1674,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
current_function->entry_block = id;
|
||||
|
||||
if (current_block)
|
||||
throw CompilerError("Cannot start a block before ending the current block.");
|
||||
SPIRV_CROSS_THROW("Cannot start a block before ending the current block.");
|
||||
|
||||
current_block = &set<SPIRBlock>(id);
|
||||
break;
|
||||
@ -1691,7 +1684,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpBranch:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
|
||||
uint32_t target = ops[0];
|
||||
current_block->terminator = SPIRBlock::Direct;
|
||||
@ -1703,7 +1696,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpBranchConditional:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
|
||||
current_block->condition = ops[0];
|
||||
current_block->true_block = ops[1];
|
||||
@ -1717,10 +1710,10 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpSwitch:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
|
||||
if (current_block->merge == SPIRBlock::MergeNone)
|
||||
throw CompilerError("Switch statement is not structured");
|
||||
SPIRV_CROSS_THROW("Switch statement is not structured");
|
||||
|
||||
current_block->terminator = SPIRBlock::MultiSelect;
|
||||
|
||||
@ -1740,7 +1733,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpKill:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
current_block->terminator = SPIRBlock::Kill;
|
||||
current_block = nullptr;
|
||||
break;
|
||||
@ -1749,7 +1742,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpReturn:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
current_block->terminator = SPIRBlock::Return;
|
||||
current_block = nullptr;
|
||||
break;
|
||||
@ -1758,7 +1751,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpReturnValue:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
current_block->terminator = SPIRBlock::Return;
|
||||
current_block->return_value = ops[0];
|
||||
current_block = nullptr;
|
||||
@ -1768,7 +1761,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpUnreachable:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to end a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to end a non-existing block.");
|
||||
current_block->terminator = SPIRBlock::Unreachable;
|
||||
current_block = nullptr;
|
||||
break;
|
||||
@ -1777,7 +1770,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpSelectionMerge:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to modify a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to modify a non-existing block.");
|
||||
|
||||
current_block->next_block = ops[0];
|
||||
current_block->merge = SPIRBlock::MergeSelection;
|
||||
@ -1788,7 +1781,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpLoopMerge:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Trying to modify a non-existing block.");
|
||||
SPIRV_CROSS_THROW("Trying to modify a non-existing block.");
|
||||
|
||||
current_block->merge_block = ops[0];
|
||||
current_block->continue_block = ops[1];
|
||||
@ -1808,7 +1801,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpSpecConstantOp:
|
||||
{
|
||||
if (length < 3)
|
||||
throw CompilerError("OpSpecConstantOp not enough arguments.");
|
||||
SPIRV_CROSS_THROW("OpSpecConstantOp not enough arguments.");
|
||||
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
@ -1822,7 +1815,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
default:
|
||||
{
|
||||
if (!current_block)
|
||||
throw CompilerError("Currently no block to insert opcode.");
|
||||
SPIRV_CROSS_THROW("Currently no block to insert opcode.");
|
||||
|
||||
current_block->ops.push_back(instruction);
|
||||
break;
|
||||
@ -2046,7 +2039,7 @@ uint32_t Compiler::type_struct_member_offset(const SPIRType &type, uint32_t inde
|
||||
if (dec.decoration_flags & (1ull << DecorationOffset))
|
||||
return dec.offset;
|
||||
else
|
||||
throw CompilerError("Struct member does not have Offset set.");
|
||||
SPIRV_CROSS_THROW("Struct member does not have Offset set.");
|
||||
}
|
||||
|
||||
uint32_t Compiler::type_struct_member_array_stride(const SPIRType &type, uint32_t index) const
|
||||
@ -2057,7 +2050,7 @@ uint32_t Compiler::type_struct_member_array_stride(const SPIRType &type, uint32_
|
||||
if (dec.decoration_flags & (1ull << DecorationArrayStride))
|
||||
return dec.array_stride;
|
||||
else
|
||||
throw CompilerError("Struct member does not have ArrayStride set.");
|
||||
SPIRV_CROSS_THROW("Struct member does not have ArrayStride set.");
|
||||
}
|
||||
|
||||
size_t Compiler::get_declared_struct_size(const SPIRType &type) const
|
||||
@ -2084,7 +2077,7 @@ size_t Compiler::get_declared_struct_member_size(const SPIRType &struct_type, ui
|
||||
case SPIRType::Image:
|
||||
case SPIRType::SampledImage:
|
||||
case SPIRType::Sampler:
|
||||
throw CompilerError("Querying size for object with opaque size.\n");
|
||||
SPIRV_CROSS_THROW("Querying size for object with opaque size.\n");
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -2363,7 +2356,7 @@ SPIREntryPoint &Compiler::get_entry_point(const std::string &name)
|
||||
[&](const std::pair<uint32_t, SPIREntryPoint> &entry) -> bool { return entry.second.name == name; });
|
||||
|
||||
if (itr == end(entry_points))
|
||||
throw CompilerError("Entry point does not exist.");
|
||||
SPIRV_CROSS_THROW("Entry point does not exist.");
|
||||
|
||||
return itr->second;
|
||||
}
|
||||
@ -2375,7 +2368,7 @@ const SPIREntryPoint &Compiler::get_entry_point(const std::string &name) const
|
||||
[&](const std::pair<uint32_t, SPIREntryPoint> &entry) -> bool { return entry.second.name == name; });
|
||||
|
||||
if (itr == end(entry_points))
|
||||
throw CompilerError("Entry point does not exist.");
|
||||
SPIRV_CROSS_THROW("Entry point does not exist.");
|
||||
|
||||
return itr->second;
|
||||
}
|
||||
@ -2619,11 +2612,11 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar
|
||||
bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
|
||||
bool separate_sampler = type.basetype == SPIRType::Sampler;
|
||||
if (separate_image)
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Attempting to use arrays of separate images. This is not possible to statically remap to plain GLSL.");
|
||||
if (separate_sampler)
|
||||
throw CompilerError("Attempting to use arrays of separate samplers. This is not possible to statically "
|
||||
"remap to plain GLSL.");
|
||||
SPIRV_CROSS_THROW("Attempting to use arrays of separate samplers. This is not possible to statically "
|
||||
"remap to plain GLSL.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2938,7 +2931,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
if (potential == 0)
|
||||
potential = block;
|
||||
else
|
||||
potential = -1u;
|
||||
potential = ~(0u);
|
||||
}
|
||||
builder.add_block(block);
|
||||
}
|
||||
@ -2965,7 +2958,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
auto block = loop_variable.second;
|
||||
|
||||
// The variable was accessed in multiple continue blocks, ignore.
|
||||
if (block == -1u || block == 0)
|
||||
if (block == ~(0u) || block == 0)
|
||||
continue;
|
||||
|
||||
// Dead code.
|
||||
|
@ -140,6 +140,8 @@ public:
|
||||
bool is_decoration_set(uint32_t id, spv::Decoration decoration) const;
|
||||
|
||||
// Gets the value for decorations which take arguments.
|
||||
// If the decoration is a boolean (i.e. spv::DecorationNonWritable),
|
||||
// 1 will be returned.
|
||||
// If decoration doesn't exist or decoration is not recognized,
|
||||
// 0 will be returned.
|
||||
uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const;
|
||||
@ -329,7 +331,7 @@ protected:
|
||||
return nullptr;
|
||||
|
||||
if (instr.offset + instr.length > spirv.size())
|
||||
throw CompilerError("Compiler::stream() out of range.");
|
||||
SPIRV_CROSS_THROW("Compiler::stream() out of range.");
|
||||
return &spirv[instr.offset];
|
||||
}
|
||||
std::vector<uint32_t> spirv;
|
||||
@ -485,7 +487,7 @@ protected:
|
||||
|
||||
void analyze_variable_scope(SPIRFunction &function);
|
||||
|
||||
private:
|
||||
protected:
|
||||
void parse();
|
||||
void parse(const Instruction &i);
|
||||
|
||||
|
309
spirv_glsl.cpp
309
spirv_glsl.cpp
@ -184,7 +184,7 @@ void CompilerGLSL::remap_pls_variables()
|
||||
}
|
||||
|
||||
if (var.storage != StorageClassInput && !input_is_target)
|
||||
throw CompilerError("Can only use in and target variables for PLS inputs.");
|
||||
SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
|
||||
var.remapped_variable = true;
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ void CompilerGLSL::remap_pls_variables()
|
||||
{
|
||||
auto &var = get<SPIRVariable>(output.id);
|
||||
if (var.storage != StorageClassOutput)
|
||||
throw CompilerError("Can only use out variables for PLS outputs.");
|
||||
SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
|
||||
var.remapped_variable = true;
|
||||
}
|
||||
}
|
||||
@ -207,7 +207,7 @@ void CompilerGLSL::find_static_extensions()
|
||||
if (type.basetype == SPIRType::Double)
|
||||
{
|
||||
if (options.es)
|
||||
throw CompilerError("FP64 not supported in ES profile.");
|
||||
SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
|
||||
if (!options.es && options.version < 400)
|
||||
require_extension("GL_ARB_gpu_shader_fp64");
|
||||
}
|
||||
@ -215,7 +215,7 @@ void CompilerGLSL::find_static_extensions()
|
||||
if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
|
||||
{
|
||||
if (options.es)
|
||||
throw CompilerError("64-bit integers not supported in ES profile.");
|
||||
SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
|
||||
if (!options.es)
|
||||
require_extension("GL_ARB_gpu_shader_int64");
|
||||
}
|
||||
@ -229,7 +229,7 @@ void CompilerGLSL::find_static_extensions()
|
||||
if (!options.es && options.version < 430)
|
||||
require_extension("GL_ARB_compute_shader");
|
||||
if (options.es && options.version < 310)
|
||||
throw CompilerError("At least ESSL 3.10 required for compute shaders.");
|
||||
SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
|
||||
break;
|
||||
|
||||
case ExecutionModelGeometry:
|
||||
@ -266,12 +266,13 @@ string CompilerGLSL::compile()
|
||||
{
|
||||
// Scan the SPIR-V to find trivial uses of extensions.
|
||||
find_static_extensions();
|
||||
fixup_image_load_store_access();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
{
|
||||
if (pass_count >= 3)
|
||||
throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
|
||||
SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
|
||||
|
||||
reset();
|
||||
|
||||
@ -561,7 +562,7 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
|
||||
{
|
||||
auto check_desktop = [this] {
|
||||
if (options.es)
|
||||
throw CompilerError("Attempting to use image format not supported in ES profile.");
|
||||
SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
|
||||
};
|
||||
|
||||
switch (format)
|
||||
@ -747,7 +748,7 @@ uint32_t CompilerGLSL::type_to_std430_alignment(const SPIRType &type, uint64_t f
|
||||
// Rule 8 implied.
|
||||
}
|
||||
|
||||
throw CompilerError("Did not find suitable std430 rule for type. Bogus decorations?");
|
||||
SPIRV_CROSS_THROW("Did not find suitable std430 rule for type. Bogus decorations?");
|
||||
}
|
||||
|
||||
uint32_t CompilerGLSL::type_to_std430_array_stride(const SPIRType &type, uint64_t flags)
|
||||
@ -978,7 +979,7 @@ void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
|
||||
|
||||
#if 0
|
||||
if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
|
||||
throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
|
||||
SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
|
||||
"Remap to location with reflection API first or disable these decorations.");
|
||||
#endif
|
||||
|
||||
@ -1096,7 +1097,7 @@ void CompilerGLSL::emit_uniform(const SPIRVariable &var)
|
||||
if (!options.es && options.version < 420)
|
||||
require_extension("GL_ARB_shader_image_load_store");
|
||||
else if (options.es && options.version < 310)
|
||||
throw CompilerError("At least ESSL 3.10 required for shader image load store.");
|
||||
SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
|
||||
}
|
||||
|
||||
add_resource_name(var.self);
|
||||
@ -1182,14 +1183,14 @@ void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
|
||||
// FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
|
||||
m.alias = "gl_FragData";
|
||||
if (location != 0)
|
||||
throw CompilerError("Arrayed output variable used, but location is not 0. "
|
||||
"This is unimplemented in SPIRV-Cross.");
|
||||
SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
|
||||
"This is unimplemented in SPIRV-Cross.");
|
||||
|
||||
if (is_legacy_es())
|
||||
require_extension("GL_EXT_draw_buffers");
|
||||
}
|
||||
else
|
||||
throw CompilerError("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
|
||||
SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
|
||||
|
||||
var.compat_builtin = true; // We don't want to declare this variable, but use the name as-is.
|
||||
}
|
||||
@ -1234,13 +1235,13 @@ void CompilerGLSL::emit_pls()
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
if (execution.model != ExecutionModelFragment)
|
||||
throw CompilerError("Pixel local storage only supported in fragment shaders.");
|
||||
SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
|
||||
|
||||
if (!options.es)
|
||||
throw CompilerError("Pixel local storage only supported in OpenGL ES.");
|
||||
SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
|
||||
|
||||
if (options.version < 300)
|
||||
throw CompilerError("Pixel local storage only supported in ESSL 3.0 and above.");
|
||||
SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
|
||||
|
||||
if (!pls_inputs.empty())
|
||||
{
|
||||
@ -1263,6 +1264,30 @@ void CompilerGLSL::emit_pls()
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::fixup_image_load_store_access()
|
||||
{
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() != TypeVariable)
|
||||
continue;
|
||||
|
||||
uint32_t var = id.get<SPIRVariable>().self;
|
||||
auto &vartype = expression_type(var);
|
||||
if (vartype.basetype == SPIRType::Image)
|
||||
{
|
||||
// Older glslangValidator does not emit required qualifiers here.
|
||||
// Solve this by making the image access as restricted as possible and loosen up if we need to.
|
||||
// If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
|
||||
|
||||
auto &flags = meta.at(var).decoration.decoration_flags;
|
||||
static const uint64_t NoWrite = 1ull << DecorationNonWritable;
|
||||
static const uint64_t NoRead = 1ull << DecorationNonReadable;
|
||||
if ((flags & (NoWrite | NoRead)) == 0)
|
||||
flags |= NoRead | NoWrite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_resources()
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
@ -1651,7 +1676,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
||||
case OpSelect:
|
||||
{
|
||||
if (cop.arguments.size() < 3)
|
||||
throw CompilerError("Not enough arguments to OpSpecConstantOp.");
|
||||
SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
|
||||
|
||||
// This one is pretty annoying. It's triggered from
|
||||
// uint(bool), int(bool) from spec constants.
|
||||
@ -1660,7 +1685,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
||||
// If we cannot, fail.
|
||||
if (!to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
|
||||
{
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Cannot implement specialization constant op OpSelect. "
|
||||
"Need trivial select implementation which can be resolved to a simple cast from boolean.");
|
||||
}
|
||||
@ -1669,7 +1694,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
||||
|
||||
default:
|
||||
// Some opcodes are unimplemented here, these are currently not possible to test from glslang.
|
||||
throw CompilerError("Unimplemented spec constant op.");
|
||||
SPIRV_CROSS_THROW("Unimplemented spec constant op.");
|
||||
}
|
||||
|
||||
SPIRType::BaseType input_type;
|
||||
@ -1692,7 +1717,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
||||
if (binary)
|
||||
{
|
||||
if (cop.arguments.size() < 2)
|
||||
throw CompilerError("Not enough arguments to OpSpecConstantOp.");
|
||||
SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
|
||||
|
||||
string cast_op0;
|
||||
string cast_op1;
|
||||
@ -1714,7 +1739,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
||||
else if (unary)
|
||||
{
|
||||
if (cop.arguments.size() < 1)
|
||||
throw CompilerError("Not enough arguments to OpSpecConstantOp.");
|
||||
SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
|
||||
|
||||
// Auto-bitcast to result type as needed.
|
||||
// Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
|
||||
@ -1723,7 +1748,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
||||
else
|
||||
{
|
||||
if (cop.arguments.size() < 1)
|
||||
throw CompilerError("Not enough arguments to OpSpecConstantOp.");
|
||||
SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
|
||||
return join(op, "(", to_expression(cop.arguments[0]), ")");
|
||||
}
|
||||
}
|
||||
@ -1939,7 +1964,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("Invalid constant expression basetype.");
|
||||
SPIRV_CROSS_THROW("Invalid constant expression basetype.");
|
||||
}
|
||||
|
||||
if (c.vector_size() > 1)
|
||||
@ -2206,7 +2231,9 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
|
||||
else if (op == "textureProjLod")
|
||||
return join("texture", type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
|
||||
else
|
||||
throw CompilerError(join("Unsupported legacy texture op: ", op));
|
||||
{
|
||||
SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
|
||||
}
|
||||
}
|
||||
|
||||
bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
|
||||
@ -2351,7 +2378,7 @@ string CompilerGLSL::to_combined_image_sampler(uint32_t image_id, uint32_t samp_
|
||||
return to_expression(itr->id);
|
||||
else
|
||||
{
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Cannot find mapping for combined sampler parameter, was build_combined_image_samplers() used "
|
||||
"before compile() was called?");
|
||||
}
|
||||
@ -2368,8 +2395,8 @@ string CompilerGLSL::to_combined_image_sampler(uint32_t image_id, uint32_t samp_
|
||||
return to_expression(itr->combined_id);
|
||||
else
|
||||
{
|
||||
throw CompilerError("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
|
||||
"before compile() was called?");
|
||||
SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
|
||||
"before compile() was called?");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2392,7 +2419,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
uint32_t length = i.length;
|
||||
|
||||
if (i.offset + length > spirv.size())
|
||||
throw CompilerError("Compiler::parse() opcode out of range.");
|
||||
SPIRV_CROSS_THROW("Compiler::parse() opcode out of range.");
|
||||
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
@ -2402,6 +2429,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
uint32_t comp = 0;
|
||||
bool gather = false;
|
||||
bool proj = false;
|
||||
bool fetch = false;
|
||||
const uint32_t *opt = nullptr;
|
||||
|
||||
switch (op)
|
||||
@ -2416,23 +2444,29 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
case OpImageSampleProjDrefImplicitLod:
|
||||
case OpImageSampleProjDrefExplicitLod:
|
||||
dref = ops[4];
|
||||
proj = true;
|
||||
opt = &ops[5];
|
||||
length -= 5;
|
||||
proj = true;
|
||||
break;
|
||||
|
||||
case OpImageDrefGather:
|
||||
dref = ops[4];
|
||||
opt = &ops[5];
|
||||
gather = true;
|
||||
length -= 5;
|
||||
gather = true;
|
||||
break;
|
||||
|
||||
case OpImageGather:
|
||||
comp = ops[4];
|
||||
opt = &ops[5];
|
||||
gather = true;
|
||||
length -= 5;
|
||||
gather = true;
|
||||
break;
|
||||
|
||||
case OpImageFetch:
|
||||
opt = &ops[4];
|
||||
length -= 4;
|
||||
fetch = true;
|
||||
break;
|
||||
|
||||
case OpImageSampleProjImplicitLod:
|
||||
@ -2489,8 +2523,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
|
||||
if (length)
|
||||
{
|
||||
flags = opt[0];
|
||||
opt++;
|
||||
flags = *opt++;
|
||||
length--;
|
||||
}
|
||||
|
||||
@ -2512,35 +2545,55 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
test(sample, ImageOperandsSampleMask);
|
||||
|
||||
string expr;
|
||||
string texop;
|
||||
bool forward = false;
|
||||
expr += to_function_name(img, imgtype, fetch, gather, proj, coffsets, (coffset || offset), (grad_x || grad_y), lod,
|
||||
dref);
|
||||
expr += "(";
|
||||
expr += to_function_args(img, imgtype, fetch, gather, proj, coord, coord_components, dref, grad_x, grad_y, lod,
|
||||
coffset, offset, bias, comp, sample, &forward);
|
||||
expr += ")";
|
||||
|
||||
if (op == OpImageFetch)
|
||||
texop += "texelFetch";
|
||||
emit_op(result_type, id, expr, forward);
|
||||
}
|
||||
|
||||
// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
|
||||
// For some subclasses, the function is a method on the specified image.
|
||||
string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
|
||||
bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod, bool)
|
||||
{
|
||||
string fname;
|
||||
|
||||
if (is_fetch)
|
||||
fname += "texelFetch";
|
||||
else
|
||||
{
|
||||
texop += "texture";
|
||||
fname += "texture";
|
||||
|
||||
if (gather)
|
||||
texop += "Gather";
|
||||
if (coffsets)
|
||||
texop += "Offsets";
|
||||
if (proj)
|
||||
texop += "Proj";
|
||||
if (grad_x || grad_y)
|
||||
texop += "Grad";
|
||||
if (lod)
|
||||
texop += "Lod";
|
||||
if (is_gather)
|
||||
fname += "Gather";
|
||||
if (has_array_offsets)
|
||||
fname += "Offsets";
|
||||
if (is_proj)
|
||||
fname += "Proj";
|
||||
if (has_grad)
|
||||
fname += "Grad";
|
||||
if (has_lod)
|
||||
fname += "Lod";
|
||||
}
|
||||
|
||||
if (coffset || offset)
|
||||
texop += "Offset";
|
||||
if (has_offset)
|
||||
fname += "Offset";
|
||||
|
||||
if (is_legacy())
|
||||
texop = legacy_tex_op(texop, imgtype);
|
||||
return is_legacy() ? legacy_tex_op(fname, imgtype) : fname;
|
||||
}
|
||||
|
||||
expr += texop;
|
||||
expr += "(";
|
||||
expr += to_expression(img);
|
||||
// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
|
||||
string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &, bool, bool, bool, uint32_t coord,
|
||||
uint32_t coord_components, uint32_t dref, uint32_t grad_x, uint32_t grad_y,
|
||||
uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp,
|
||||
uint32_t sample, bool *p_forward)
|
||||
{
|
||||
string farg_str = to_expression(img);
|
||||
|
||||
bool swizz_func = backend.swizzle_is_function;
|
||||
auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
|
||||
@ -2576,84 +2629,93 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
|
||||
// SPIR-V splits dref and coordinate.
|
||||
if (coord_components == 4) // GLSL also splits the arguments in two.
|
||||
{
|
||||
expr += ", ";
|
||||
expr += to_expression(coord);
|
||||
expr += ", ";
|
||||
expr += to_expression(dref);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(coord);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(dref);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a composite which merges coord/dref into a single vector.
|
||||
auto type = expression_type(coord);
|
||||
type.vecsize = coord_components + 1;
|
||||
expr += ", ";
|
||||
expr += type_to_glsl_constructor(type);
|
||||
expr += "(";
|
||||
expr += coord_expr;
|
||||
expr += ", ";
|
||||
expr += to_expression(dref);
|
||||
expr += ")";
|
||||
farg_str += ", ";
|
||||
farg_str += type_to_glsl_constructor(type);
|
||||
farg_str += "(";
|
||||
farg_str += coord_expr;
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(dref);
|
||||
farg_str += ")";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
expr += ", ";
|
||||
expr += coord_expr;
|
||||
farg_str += ", ";
|
||||
farg_str += coord_expr;
|
||||
}
|
||||
|
||||
if (grad_x || grad_y)
|
||||
{
|
||||
forward = forward && should_forward(grad_x);
|
||||
forward = forward && should_forward(grad_y);
|
||||
expr += ", ";
|
||||
expr += to_expression(grad_x);
|
||||
expr += ", ";
|
||||
expr += to_expression(grad_y);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(grad_x);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(grad_y);
|
||||
}
|
||||
|
||||
if (lod)
|
||||
{
|
||||
forward = forward && should_forward(lod);
|
||||
expr += ", ";
|
||||
expr += to_expression(lod);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(lod);
|
||||
}
|
||||
|
||||
if (coffset)
|
||||
{
|
||||
forward = forward && should_forward(coffset);
|
||||
expr += ", ";
|
||||
expr += to_expression(coffset);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(coffset);
|
||||
}
|
||||
else if (offset)
|
||||
{
|
||||
forward = forward && should_forward(offset);
|
||||
expr += ", ";
|
||||
expr += to_expression(offset);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(offset);
|
||||
}
|
||||
|
||||
if (bias)
|
||||
{
|
||||
forward = forward && should_forward(bias);
|
||||
expr += ", ";
|
||||
expr += to_expression(bias);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(bias);
|
||||
}
|
||||
|
||||
if (comp)
|
||||
{
|
||||
forward = forward && should_forward(comp);
|
||||
expr += ", ";
|
||||
expr += to_expression(comp);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(comp);
|
||||
}
|
||||
|
||||
if (sample)
|
||||
{
|
||||
expr += ", ";
|
||||
expr += to_expression(sample);
|
||||
farg_str += ", ";
|
||||
farg_str += to_expression(sample);
|
||||
}
|
||||
|
||||
expr += ")";
|
||||
*p_forward = forward;
|
||||
|
||||
emit_op(result_type, id, expr, forward);
|
||||
return farg_str;
|
||||
}
|
||||
|
||||
// Some languages may have additional standard library functions whose names conflict
|
||||
// with a function defined in the body of the shader. Subclasses can override to rename
|
||||
// the function name defined in the shader to avoid conflict with the language standard
|
||||
// functions (eg. MSL includes saturate()).
|
||||
string CompilerGLSL::clean_func_name(string func_name)
|
||||
{
|
||||
return func_name;
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t)
|
||||
@ -2671,7 +2733,7 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
|
||||
emit_unary_func_op(result_type, id, args[0], "roundEven");
|
||||
else
|
||||
throw CompilerError("roundEven supported only in ESSL 300 and GLSL 130 and up.");
|
||||
SPIRV_CROSS_THROW("roundEven supported only in ESSL 300 and GLSL 130 and up.");
|
||||
break;
|
||||
|
||||
case GLSLstd450Trunc:
|
||||
@ -2955,14 +3017,16 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
|
||||
return "gl_Position";
|
||||
case BuiltInPointSize:
|
||||
return "gl_PointSize";
|
||||
case BuiltInClipDistance:
|
||||
return "gl_ClipDistance";
|
||||
case BuiltInVertexId:
|
||||
if (options.vulkan_semantics)
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
|
||||
return "gl_VertexID";
|
||||
case BuiltInInstanceId:
|
||||
if (options.vulkan_semantics)
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
|
||||
return "gl_InstanceID";
|
||||
case BuiltInVertexIndex:
|
||||
@ -3008,7 +3072,7 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
|
||||
case BuiltInLocalInvocationIndex:
|
||||
return "gl_LocalInvocationIndex";
|
||||
default:
|
||||
return "gl_???";
|
||||
return join("gl_BuiltIn_", convert_to_string(builtin));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3025,7 +3089,7 @@ const char *CompilerGLSL::index_to_swizzle(uint32_t index)
|
||||
case 3:
|
||||
return "w";
|
||||
default:
|
||||
throw CompilerError("Swizzle index out of range");
|
||||
SPIRV_CROSS_THROW("Swizzle index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3074,7 +3138,7 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32
|
||||
index = get<SPIRConstant>(index).scalar();
|
||||
|
||||
if (index >= type->member_types.size())
|
||||
throw CompilerError("Member index is out of bounds!");
|
||||
SPIRV_CROSS_THROW("Member index is out of bounds!");
|
||||
|
||||
BuiltIn builtin;
|
||||
if (is_member_builtin(*type, index, &builtin))
|
||||
@ -3148,7 +3212,7 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32
|
||||
temp.vecsize = 1;
|
||||
}
|
||||
else
|
||||
throw CompilerError("Cannot subdivide a scalar value!");
|
||||
SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
|
||||
}
|
||||
|
||||
return expr;
|
||||
@ -3582,7 +3646,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
|
||||
string funexpr;
|
||||
vector<string> arglist;
|
||||
funexpr += to_name(func) + "(";
|
||||
funexpr += clean_func_name(to_name(func)) + "(";
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
// Do not pass in separate images or samplers if we're remapping
|
||||
@ -3656,7 +3720,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
length -= 2;
|
||||
|
||||
if (!length)
|
||||
throw CompilerError("Invalid input to OpCompositeConstruct.");
|
||||
SPIRV_CROSS_THROW("Invalid input to OpCompositeConstruct.");
|
||||
|
||||
bool forward = true;
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
@ -4233,7 +4297,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw CompilerError("Illegal argument to OpQuantizeToF16.");
|
||||
SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
|
||||
}
|
||||
|
||||
emit_op(result_type, id, op, should_forward(arg));
|
||||
@ -4460,7 +4524,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
BFOP(textureQueryLOD);
|
||||
}
|
||||
else if (options.es)
|
||||
throw CompilerError("textureQueryLod not supported in ES profile.");
|
||||
SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
|
||||
else
|
||||
BFOP(textureQueryLod);
|
||||
break;
|
||||
@ -4471,7 +4535,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
if (!options.es && options.version < 430)
|
||||
require_extension("GL_ARB_texture_query_levels");
|
||||
if (options.es)
|
||||
throw CompilerError("textureQueryLevels not supported in ES profile.");
|
||||
SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
|
||||
UFOP(textureQueryLevels);
|
||||
break;
|
||||
}
|
||||
@ -4480,7 +4544,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
auto *var = maybe_get_backing_variable(ops[2]);
|
||||
if (!var)
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Bug. OpImageQuerySamples must have a backing variable so we know if the image is sampled or not.");
|
||||
|
||||
auto &type = get<SPIRType>(var->basetype);
|
||||
@ -4531,7 +4595,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
|
||||
{
|
||||
if (type.image.ms)
|
||||
throw CompilerError("Trying to remap multisampled image to variable, this is not possible.");
|
||||
SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
|
||||
|
||||
auto itr =
|
||||
find_if(begin(pls_inputs), end(pls_inputs), [var](const PlsRemap &pls) { return pls.id == var->self; });
|
||||
@ -4541,7 +4605,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
// For non-PLS inputs, we rely on subpass type remapping information to get it right
|
||||
// since ImageRead always returns 4-component vectors and the backing type is opaque.
|
||||
if (!var->remapped_components)
|
||||
throw CompilerError("subpassInput was remapped, but remap_components is not set correctly.");
|
||||
SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
|
||||
imgexpr = remap_swizzle(result_type, var->remapped_components, ops[2]);
|
||||
}
|
||||
else
|
||||
@ -4562,7 +4626,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || length != 6)
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
|
||||
uint32_t samples = ops[5];
|
||||
@ -4577,7 +4641,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || length != 6)
|
||||
throw CompilerError(
|
||||
SPIRV_CROSS_THROW(
|
||||
"Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
|
||||
uint32_t samples = ops[5];
|
||||
@ -4599,8 +4663,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || length != 6)
|
||||
throw CompilerError(
|
||||
"Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
|
||||
uint32_t samples = ops[5];
|
||||
imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
|
||||
@ -4660,7 +4723,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
uint32_t operands = ops[3];
|
||||
if (operands != ImageOperandsSampleMask || length != 5)
|
||||
throw CompilerError("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
|
||||
SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
|
||||
uint32_t samples = ops[4];
|
||||
statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(samples),
|
||||
", ", to_expression(ops[2]), ");");
|
||||
@ -4686,7 +4749,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
emit_op(result_type, id, join("imageSize(", to_expression(ops[2]), ")"), true);
|
||||
}
|
||||
else
|
||||
throw CompilerError("Invalid type for OpImageQuerySize.");
|
||||
SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4801,7 +4864,7 @@ bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
|
||||
// swaps matrix elements while retaining the original dimensional form of the matrix.
|
||||
const auto type = expression_type(id);
|
||||
if (type.columns != type.vecsize)
|
||||
throw CompilerError("Row-major matrices must be square on this platform.");
|
||||
SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -4822,7 +4885,7 @@ bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, u
|
||||
// swaps matrix elements while retaining the original dimensional form of the matrix.
|
||||
const auto mbr_type = get<SPIRType>(type.member_types[index]);
|
||||
if (mbr_type.columns != mbr_type.vecsize)
|
||||
throw CompilerError("Row-major matrices must be square on this platform.");
|
||||
SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -4989,7 +5052,7 @@ uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t inde
|
||||
assert(type.array.size() == type.array_size_literal.size());
|
||||
|
||||
if (!type.array_size_literal[index])
|
||||
throw CompilerError("The array size is not a literal, but a specialization constant or spec constant op.");
|
||||
SPIRV_CROSS_THROW("The array size is not a literal, but a specialization constant or spec constant op.");
|
||||
|
||||
return type.array[index];
|
||||
}
|
||||
@ -5086,7 +5149,7 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
||||
res += "2D";
|
||||
break;
|
||||
default:
|
||||
throw CompilerError("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
|
||||
SPIRV_CROSS_THROW("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
|
||||
}
|
||||
|
||||
if (type.image.ms)
|
||||
@ -5304,11 +5367,11 @@ void CompilerGLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_f
|
||||
|
||||
if (func.self == entry_point)
|
||||
{
|
||||
decl += "main";
|
||||
decl += clean_func_name("main");
|
||||
processing_entry_point = true;
|
||||
}
|
||||
else
|
||||
decl += to_name(func.self);
|
||||
decl += clean_func_name(to_name(func.self));
|
||||
|
||||
decl += "(";
|
||||
vector<string> arglist;
|
||||
@ -5746,7 +5809,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("For/while loop detected, but need while/for loop semantics.");
|
||||
SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
|
||||
}
|
||||
|
||||
begin_scope();
|
||||
@ -5793,7 +5856,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("For/while loop detected, but need while/for loop semantics.");
|
||||
SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
|
||||
}
|
||||
|
||||
begin_scope();
|
||||
@ -5959,7 +6022,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
||||
statement("default:");
|
||||
begin_scope();
|
||||
if (is_break(block.default_block))
|
||||
throw CompilerError("Cannot break; out of a switch statement and out of a loop at the same time ...");
|
||||
SPIRV_CROSS_THROW("Cannot break; out of a switch statement and out of a loop at the same time ...");
|
||||
branch(block.self, block.default_block);
|
||||
end_scope();
|
||||
}
|
||||
@ -6000,7 +6063,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
||||
break;
|
||||
|
||||
default:
|
||||
throw CompilerError("Unimplemented block terminator.");
|
||||
SPIRV_CROSS_THROW("Unimplemented block terminator.");
|
||||
}
|
||||
|
||||
if (block.next_block && emit_next_block)
|
||||
@ -6046,7 +6109,7 @@ void CompilerGLSL::begin_scope()
|
||||
void CompilerGLSL::end_scope()
|
||||
{
|
||||
if (!indent)
|
||||
throw CompilerError("Popping empty indent stack.");
|
||||
SPIRV_CROSS_THROW("Popping empty indent stack.");
|
||||
indent--;
|
||||
statement("}");
|
||||
}
|
||||
@ -6054,7 +6117,7 @@ void CompilerGLSL::end_scope()
|
||||
void CompilerGLSL::end_scope_decl()
|
||||
{
|
||||
if (!indent)
|
||||
throw CompilerError("Popping empty indent stack.");
|
||||
SPIRV_CROSS_THROW("Popping empty indent stack.");
|
||||
indent--;
|
||||
statement("};");
|
||||
}
|
||||
@ -6062,7 +6125,7 @@ void CompilerGLSL::end_scope_decl()
|
||||
void CompilerGLSL::end_scope_decl(const string &decl)
|
||||
{
|
||||
if (!indent)
|
||||
throw CompilerError("Popping empty indent stack.");
|
||||
SPIRV_CROSS_THROW("Popping empty indent stack.");
|
||||
indent--;
|
||||
statement("} ", decl, ";");
|
||||
}
|
||||
@ -6082,10 +6145,10 @@ void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_
|
||||
auto &type = get<SPIRType>(var->basetype);
|
||||
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
|
||||
{
|
||||
throw CompilerError("Tried passing a remapped subpassInput variable to a function. "
|
||||
"This will not work correctly because type-remapping information is lost. "
|
||||
"To workaround, please consider not passing the subpass input as a function parameter, "
|
||||
"or use in/out variables instead which do not need type remapping information.");
|
||||
SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
|
||||
"This will not work correctly because type-remapping information is lost. "
|
||||
"To workaround, please consider not passing the subpass input as a function parameter, "
|
||||
"or use in/out variables instead which do not need type remapping information.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,6 +160,15 @@ protected:
|
||||
virtual void emit_fixup();
|
||||
virtual std::string variable_decl(const SPIRType &type, const std::string &name);
|
||||
virtual std::string to_func_call_arg(uint32_t id);
|
||||
virtual std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather,
|
||||
bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad,
|
||||
bool has_lod, bool has_dref);
|
||||
virtual std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather,
|
||||
bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref,
|
||||
uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset,
|
||||
uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample,
|
||||
bool *p_forward);
|
||||
virtual std::string clean_func_name(std::string func_name);
|
||||
|
||||
std::unique_ptr<std::ostringstream> buffer;
|
||||
|
||||
@ -390,8 +399,8 @@ protected:
|
||||
void find_static_extensions();
|
||||
|
||||
std::string emit_for_loop_initializers(const SPIRBlock &block);
|
||||
|
||||
bool optimize_read_modify_write(const std::string &lhs, const std::string &rhs);
|
||||
void fixup_image_load_store_access();
|
||||
};
|
||||
}
|
||||
|
||||
|
852
spirv_msl.cpp
852
spirv_msl.cpp
File diff suppressed because it is too large
Load Diff
117
spirv_msl.hpp
117
spirv_msl.hpp
@ -19,6 +19,8 @@
|
||||
|
||||
#include "spirv_glsl.hpp"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace spirv_cross
|
||||
@ -39,10 +41,6 @@ struct MSLConfiguration
|
||||
struct MSLVertexAttr
|
||||
{
|
||||
uint32_t location = 0;
|
||||
uint32_t msl_buffer = 0;
|
||||
uint32_t msl_offset = 0;
|
||||
uint32_t msl_stride = 0;
|
||||
bool per_instance = false;
|
||||
bool used_by_shader = false;
|
||||
};
|
||||
|
||||
@ -95,7 +93,7 @@ public:
|
||||
// Compiles the SPIR-V code into Metal Shading Language using default configuration parameters.
|
||||
std::string compile() override;
|
||||
|
||||
void set_func_name(std::string func_name);
|
||||
void set_entry_point_name(std::string func_name);
|
||||
|
||||
protected:
|
||||
void emit_instruction(const Instruction &instr) override;
|
||||
@ -104,7 +102,6 @@ protected:
|
||||
void emit_header() override;
|
||||
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
|
||||
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
|
||||
void emit_texture_op(const Instruction &i) override;
|
||||
void emit_fixup() override;
|
||||
std::string type_to_glsl(const SPIRType &type) override;
|
||||
std::string image_type_glsl(const SPIRType &type) override;
|
||||
@ -114,28 +111,34 @@ protected:
|
||||
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
||||
std::string to_func_call_arg(uint32_t id) override;
|
||||
std::string to_name(uint32_t id, bool allow_alias = true) override;
|
||||
std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
|
||||
bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
|
||||
bool has_dref) override;
|
||||
std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
|
||||
uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x,
|
||||
uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias,
|
||||
uint32_t comp, uint32_t sample, bool *p_forward) override;
|
||||
|
||||
void extract_builtins();
|
||||
void add_builtin(spv::BuiltIn builtin_type);
|
||||
void register_custom_functions();
|
||||
void emit_custom_functions();
|
||||
void localize_global_variables();
|
||||
void extract_global_variables_from_functions();
|
||||
void extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids,
|
||||
std::set<uint32_t> &global_var_ids,
|
||||
std::set<uint32_t> &processed_func_ids);
|
||||
|
||||
std::unordered_map<uint32_t, std::set<uint32_t>> function_global_vars;
|
||||
|
||||
void add_interface_structs();
|
||||
void bind_vertex_attributes(std::set<uint32_t> &bindings);
|
||||
uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0);
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> function_global_vars;
|
||||
void extract_global_variables_from_function(uint32_t func_id, std::unordered_set<uint32_t> &added_arg_ids,
|
||||
std::unordered_set<uint32_t> &global_var_ids,
|
||||
std::unordered_set<uint32_t> &processed_func_ids);
|
||||
uint32_t add_interface_block(spv::StorageClass storage);
|
||||
void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);
|
||||
|
||||
void emit_resources();
|
||||
void emit_interface_block(uint32_t ib_var_id);
|
||||
void emit_function_prototype(SPIRFunction &func, bool is_decl);
|
||||
void emit_function_declarations();
|
||||
void populate_func_name_overrides();
|
||||
|
||||
std::string func_type_decl(SPIRType &type);
|
||||
std::string _clean_msl_main_func_name;
|
||||
std::string clean_func_name(std::string func_name);
|
||||
std::string clean_func_name(std::string func_name) override;
|
||||
std::string entry_point_args(bool append_comma);
|
||||
std::string get_entry_point_name();
|
||||
std::string to_qualified_member_name(const SPIRType &type, uint32_t index);
|
||||
@ -145,54 +148,70 @@ protected:
|
||||
std::string builtin_type_decl(spv::BuiltIn builtin);
|
||||
std::string member_attribute_qualifier(const SPIRType &type, uint32_t index);
|
||||
std::string argument_decl(const SPIRFunction::Parameter &arg);
|
||||
std::string get_vtx_idx_var_name(bool per_instance);
|
||||
uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype);
|
||||
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
|
||||
uint32_t pad_to_offset(SPIRType &struct_type, bool is_indxd_vtx_input, uint32_t offset, uint32_t struct_size);
|
||||
SPIRType &get_pad_type(uint32_t pad_len);
|
||||
size_t get_declared_type_size(const SPIRType &type) const;
|
||||
size_t get_declared_type_size(const SPIRType &type, uint64_t dec_mask) const;
|
||||
size_t get_declared_type_size(uint32_t type_id) const;
|
||||
size_t get_declared_type_size(uint32_t type_id, uint64_t dec_mask) const;
|
||||
std::string to_component_argument(uint32_t id);
|
||||
|
||||
MSLConfiguration msl_config;
|
||||
std::unordered_map<std::string, std::string> func_name_overrides;
|
||||
std::set<uint32_t> custom_function_ops;
|
||||
std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location;
|
||||
std::vector<MSLResourceBinding *> resource_bindings;
|
||||
std::unordered_map<uint32_t, uint32_t> builtin_vars;
|
||||
MSLResourceBinding next_metal_resource_index;
|
||||
std::unordered_map<uint32_t, uint32_t> pad_type_ids_by_pad_len;
|
||||
std::vector<uint32_t> stage_in_var_ids;
|
||||
uint32_t stage_in_var_id = 0;
|
||||
uint32_t stage_out_var_id = 0;
|
||||
uint32_t stage_uniforms_var_id = 0;
|
||||
uint32_t stage_uniforms_var_id = 0;
|
||||
std::string qual_pos_var_name;
|
||||
std::string stage_in_var_name = "in";
|
||||
std::string stage_out_var_name = "out";
|
||||
std::string stage_uniform_var_name = "uniforms";
|
||||
std::string stage_uniform_var_name = "uniforms";
|
||||
std::string sampler_name_suffix = "Smplr";
|
||||
std::vector<std::string> reserved_names = {"kernel", "bias"};
|
||||
};
|
||||
std::vector<std::string> reserved_names = {"kernel", "bias"};
|
||||
|
||||
// Sorts the members of a SPIRType and associated Meta info based on a settable sorting
|
||||
// aspect, which defines which aspect of the struct members will be used to sort them.
|
||||
// Regardless of the sorting aspect, built-in members always appear at the end of the struct.
|
||||
struct MemberSorter
|
||||
{
|
||||
enum SortAspect
|
||||
// Extracts a set of opcodes that should be implemented as a bespoke custom function
|
||||
// whose full source code is output as part of the shader source code.
|
||||
struct CustomFunctionHandler : OpcodeHandler
|
||||
{
|
||||
Location,
|
||||
Offset,
|
||||
Alphabetical
|
||||
CustomFunctionHandler(const CompilerMSL &compiler_, std::set<uint32_t> &custom_function_ops_)
|
||||
: compiler(compiler_)
|
||||
, custom_function_ops(custom_function_ops_)
|
||||
{
|
||||
}
|
||||
|
||||
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
|
||||
|
||||
const CompilerMSL &compiler;
|
||||
std::set<uint32_t> &custom_function_ops;
|
||||
};
|
||||
|
||||
void sort();
|
||||
bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
|
||||
MemberSorter(SPIRType &t, Meta &m, SortAspect sa)
|
||||
: type(t)
|
||||
, meta(m)
|
||||
, sort_aspect(sa)
|
||||
// Sorts the members of a SPIRType and associated Meta info based on a settable sorting
|
||||
// aspect, which defines which aspect of the struct members will be used to sort them.
|
||||
// Regardless of the sorting aspect, built-in members always appear at the end of the struct.
|
||||
struct MemberSorter
|
||||
{
|
||||
}
|
||||
SPIRType &type;
|
||||
Meta &meta;
|
||||
SortAspect sort_aspect;
|
||||
enum SortAspect
|
||||
{
|
||||
Location,
|
||||
LocationReverse,
|
||||
Offset,
|
||||
OffsetThenLocationReverse,
|
||||
Alphabetical
|
||||
};
|
||||
|
||||
void sort();
|
||||
bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
|
||||
MemberSorter(SPIRType &t, Meta &m, SortAspect sa)
|
||||
: type(t)
|
||||
, meta(m)
|
||||
, sort_aspect(sa)
|
||||
{
|
||||
}
|
||||
SPIRType &type;
|
||||
Meta &meta;
|
||||
SortAspect sort_aspect;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user