mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 05:06:40 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifndef GLSLstd450_H
|
||||
#define GLSLstd450_H
|
||||
|
||||
static const int GLSLstd450Version = 100;
|
||||
static const int GLSLstd450Revision = 3;
|
||||
|
||||
enum GLSLstd450 {
|
||||
GLSLstd450Bad = 0, // Don't use
|
||||
|
||||
GLSLstd450Round = 1,
|
||||
GLSLstd450RoundEven = 2,
|
||||
GLSLstd450Trunc = 3,
|
||||
GLSLstd450FAbs = 4,
|
||||
GLSLstd450SAbs = 5,
|
||||
GLSLstd450FSign = 6,
|
||||
GLSLstd450SSign = 7,
|
||||
GLSLstd450Floor = 8,
|
||||
GLSLstd450Ceil = 9,
|
||||
GLSLstd450Fract = 10,
|
||||
|
||||
GLSLstd450Radians = 11,
|
||||
GLSLstd450Degrees = 12,
|
||||
GLSLstd450Sin = 13,
|
||||
GLSLstd450Cos = 14,
|
||||
GLSLstd450Tan = 15,
|
||||
GLSLstd450Asin = 16,
|
||||
GLSLstd450Acos = 17,
|
||||
GLSLstd450Atan = 18,
|
||||
GLSLstd450Sinh = 19,
|
||||
GLSLstd450Cosh = 20,
|
||||
GLSLstd450Tanh = 21,
|
||||
GLSLstd450Asinh = 22,
|
||||
GLSLstd450Acosh = 23,
|
||||
GLSLstd450Atanh = 24,
|
||||
GLSLstd450Atan2 = 25,
|
||||
|
||||
GLSLstd450Pow = 26,
|
||||
GLSLstd450Exp = 27,
|
||||
GLSLstd450Log = 28,
|
||||
GLSLstd450Exp2 = 29,
|
||||
GLSLstd450Log2 = 30,
|
||||
GLSLstd450Sqrt = 31,
|
||||
GLSLstd450InverseSqrt = 32,
|
||||
|
||||
GLSLstd450Determinant = 33,
|
||||
GLSLstd450MatrixInverse = 34,
|
||||
|
||||
GLSLstd450Modf = 35, // second operand needs an OpVariable to write to
|
||||
GLSLstd450ModfStruct = 36, // no OpVariable operand
|
||||
GLSLstd450FMin = 37,
|
||||
GLSLstd450UMin = 38,
|
||||
GLSLstd450SMin = 39,
|
||||
GLSLstd450FMax = 40,
|
||||
GLSLstd450UMax = 41,
|
||||
GLSLstd450SMax = 42,
|
||||
GLSLstd450FClamp = 43,
|
||||
GLSLstd450UClamp = 44,
|
||||
GLSLstd450SClamp = 45,
|
||||
GLSLstd450FMix = 46,
|
||||
GLSLstd450IMix = 47, // Reserved
|
||||
GLSLstd450Step = 48,
|
||||
GLSLstd450SmoothStep = 49,
|
||||
|
||||
GLSLstd450Fma = 50,
|
||||
GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
|
||||
GLSLstd450FrexpStruct = 52, // no OpVariable operand
|
||||
GLSLstd450Ldexp = 53,
|
||||
|
||||
GLSLstd450PackSnorm4x8 = 54,
|
||||
GLSLstd450PackUnorm4x8 = 55,
|
||||
GLSLstd450PackSnorm2x16 = 56,
|
||||
GLSLstd450PackUnorm2x16 = 57,
|
||||
GLSLstd450PackHalf2x16 = 58,
|
||||
GLSLstd450PackDouble2x32 = 59,
|
||||
GLSLstd450UnpackSnorm2x16 = 60,
|
||||
GLSLstd450UnpackUnorm2x16 = 61,
|
||||
GLSLstd450UnpackHalf2x16 = 62,
|
||||
GLSLstd450UnpackSnorm4x8 = 63,
|
||||
GLSLstd450UnpackUnorm4x8 = 64,
|
||||
GLSLstd450UnpackDouble2x32 = 65,
|
||||
|
||||
GLSLstd450Length = 66,
|
||||
GLSLstd450Distance = 67,
|
||||
GLSLstd450Cross = 68,
|
||||
GLSLstd450Normalize = 69,
|
||||
GLSLstd450FaceForward = 70,
|
||||
GLSLstd450Reflect = 71,
|
||||
GLSLstd450Refract = 72,
|
||||
|
||||
GLSLstd450FindILsb = 73,
|
||||
GLSLstd450FindSMsb = 74,
|
||||
GLSLstd450FindUMsb = 75,
|
||||
|
||||
GLSLstd450InterpolateAtCentroid = 76,
|
||||
GLSLstd450InterpolateAtSample = 77,
|
||||
GLSLstd450InterpolateAtOffset = 78,
|
||||
|
||||
GLSLstd450NMin = 79,
|
||||
GLSLstd450NMax = 80,
|
||||
GLSLstd450NClamp = 81,
|
||||
|
||||
GLSLstd450Count
|
||||
};
|
||||
|
||||
#endif // #ifndef GLSLstd450_H
|
||||
+2192
File diff suppressed because it is too large
Load Diff
+2203
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2016-2021 Arm Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_CFG_HPP
|
||||
|
||||
#include "spirv_common.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
class Compiler;
|
||||
class CFG
|
||||
{
|
||||
public:
|
||||
CFG(Compiler &compiler, const SPIRFunction &function);
|
||||
|
||||
Compiler &get_compiler()
|
||||
{
|
||||
return compiler;
|
||||
}
|
||||
|
||||
const Compiler &get_compiler() const
|
||||
{
|
||||
return compiler;
|
||||
}
|
||||
|
||||
const SPIRFunction &get_function() const
|
||||
{
|
||||
return func;
|
||||
}
|
||||
|
||||
uint32_t get_immediate_dominator(uint32_t block) const
|
||||
{
|
||||
auto itr = immediate_dominators.find(block);
|
||||
if (itr != std::end(immediate_dominators))
|
||||
return itr->second;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t get_visit_order(uint32_t block) const
|
||||
{
|
||||
auto itr = visit_order.find(block);
|
||||
assert(itr != std::end(visit_order));
|
||||
int v = itr->second.get();
|
||||
assert(v > 0);
|
||||
return uint32_t(v);
|
||||
}
|
||||
|
||||
uint32_t find_common_dominator(uint32_t a, uint32_t b) const;
|
||||
|
||||
const SmallVector<uint32_t> &get_preceding_edges(uint32_t block) const
|
||||
{
|
||||
auto itr = preceding_edges.find(block);
|
||||
if (itr != std::end(preceding_edges))
|
||||
return itr->second;
|
||||
else
|
||||
return empty_vector;
|
||||
}
|
||||
|
||||
const SmallVector<uint32_t> &get_succeeding_edges(uint32_t block) const
|
||||
{
|
||||
auto itr = succeeding_edges.find(block);
|
||||
if (itr != std::end(succeeding_edges))
|
||||
return itr->second;
|
||||
else
|
||||
return empty_vector;
|
||||
}
|
||||
|
||||
template <typename Op>
|
||||
void walk_from(std::unordered_set<uint32_t> &seen_blocks, uint32_t block, const Op &op) const
|
||||
{
|
||||
if (seen_blocks.count(block))
|
||||
return;
|
||||
seen_blocks.insert(block);
|
||||
|
||||
if (op(block))
|
||||
{
|
||||
for (auto b : get_succeeding_edges(block))
|
||||
walk_from(seen_blocks, b, op);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t find_loop_dominator(uint32_t block) const;
|
||||
|
||||
bool node_terminates_control_flow_in_sub_graph(BlockID from, BlockID to) const;
|
||||
|
||||
private:
|
||||
struct VisitOrder
|
||||
{
|
||||
int &get()
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
const int &get() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
int v = -1;
|
||||
};
|
||||
|
||||
Compiler &compiler;
|
||||
const SPIRFunction &func;
|
||||
std::unordered_map<uint32_t, SmallVector<uint32_t>> preceding_edges;
|
||||
std::unordered_map<uint32_t, SmallVector<uint32_t>> succeeding_edges;
|
||||
std::unordered_map<uint32_t, uint32_t> immediate_dominators;
|
||||
std::unordered_map<uint32_t, VisitOrder> visit_order;
|
||||
SmallVector<uint32_t> post_order;
|
||||
SmallVector<uint32_t> empty_vector;
|
||||
|
||||
void add_branch(uint32_t from, uint32_t to);
|
||||
void build_post_order_visit_order();
|
||||
void build_immediate_dominators();
|
||||
bool post_order_visit(uint32_t block);
|
||||
uint32_t visit_count = 0;
|
||||
|
||||
bool is_back_edge(uint32_t to) const;
|
||||
bool has_visited_forward_edge(uint32_t to) const;
|
||||
};
|
||||
|
||||
class DominatorBuilder
|
||||
{
|
||||
public:
|
||||
DominatorBuilder(const CFG &cfg);
|
||||
|
||||
void add_block(uint32_t block);
|
||||
uint32_t get_dominator() const
|
||||
{
|
||||
return dominator;
|
||||
}
|
||||
|
||||
void lift_continue_block_dominator();
|
||||
|
||||
private:
|
||||
const CFG &cfg;
|
||||
uint32_t dominator = 0;
|
||||
};
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Hans-Kristian Arntzen
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_CONTAINERS_HPP
|
||||
|
||||
#include "spirv_cross_error_handling.hpp"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef SPIRV_CROSS_NAMESPACE_OVERRIDE
|
||||
#define SPIRV_CROSS_NAMESPACE SPIRV_CROSS_NAMESPACE_OVERRIDE
|
||||
#else
|
||||
#define SPIRV_CROSS_NAMESPACE spirv_cross
|
||||
#endif
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
#ifndef SPIRV_CROSS_FORCE_STL_TYPES
|
||||
// std::aligned_storage does not support size == 0, so roll our own.
|
||||
template <typename T, size_t N>
|
||||
class AlignedBuffer
|
||||
{
|
||||
public:
|
||||
T *data()
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
// MSVC 2013 workarounds, sigh ...
|
||||
// Only use this workaround on MSVC 2013 due to some confusion around default initialized unions.
|
||||
// Spec seems to suggest the memory will be zero-initialized, which is *not* what we want.
|
||||
return reinterpret_cast<T *>(u.aligned_char);
|
||||
#else
|
||||
return reinterpret_cast<T *>(aligned_char);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
// MSVC 2013 workarounds, sigh ...
|
||||
union
|
||||
{
|
||||
char aligned_char[sizeof(T) * N];
|
||||
double dummy_aligner;
|
||||
} u;
|
||||
#else
|
||||
alignas(T) char aligned_char[sizeof(T) * N];
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class AlignedBuffer<T, 0>
|
||||
{
|
||||
public:
|
||||
T *data()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// An immutable version of SmallVector which erases type information about storage.
|
||||
template <typename T>
|
||||
class VectorView
|
||||
{
|
||||
public:
|
||||
T &operator[](size_t i) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr[i];
|
||||
}
|
||||
|
||||
const T &operator[](size_t i) const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr[i];
|
||||
}
|
||||
|
||||
bool empty() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return buffer_size == 0;
|
||||
}
|
||||
|
||||
size_t size() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
T *data() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const T *data() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T *begin() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T *end() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr + buffer_size;
|
||||
}
|
||||
|
||||
const T *begin() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const T *end() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr + buffer_size;
|
||||
}
|
||||
|
||||
T &front() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr[0];
|
||||
}
|
||||
|
||||
const T &front() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr[0];
|
||||
}
|
||||
|
||||
T &back() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr[buffer_size - 1];
|
||||
}
|
||||
|
||||
const T &back() const SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
return ptr[buffer_size - 1];
|
||||
}
|
||||
|
||||
// Makes it easier to consume SmallVector.
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
explicit operator std::vector<T>() const
|
||||
{
|
||||
// Another MSVC 2013 workaround. It does not understand lvalue/rvalue qualified operations.
|
||||
return std::vector<T>(ptr, ptr + buffer_size);
|
||||
}
|
||||
#else
|
||||
// Makes it easier to consume SmallVector.
|
||||
explicit operator std::vector<T>() const &
|
||||
{
|
||||
return std::vector<T>(ptr, ptr + buffer_size);
|
||||
}
|
||||
|
||||
// If we are converting as an r-value, we can pilfer our elements.
|
||||
explicit operator std::vector<T>() &&
|
||||
{
|
||||
return std::vector<T>(std::make_move_iterator(ptr), std::make_move_iterator(ptr + buffer_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Avoid sliced copies. Base class should only be read as a reference.
|
||||
VectorView(const VectorView &) = delete;
|
||||
void operator=(const VectorView &) = delete;
|
||||
|
||||
protected:
|
||||
VectorView() = default;
|
||||
T *ptr = nullptr;
|
||||
size_t buffer_size = 0;
|
||||
};
|
||||
|
||||
// Simple vector which supports up to N elements inline, without malloc/free.
|
||||
// We use a lot of throwaway vectors all over the place which triggers allocations.
|
||||
// This class only implements the subset of std::vector we need in SPIRV-Cross.
|
||||
// It is *NOT* a drop-in replacement in general projects.
|
||||
template <typename T, size_t N = 8>
|
||||
class SmallVector : public VectorView<T>
|
||||
{
|
||||
public:
|
||||
SmallVector() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
this->ptr = stack_storage.data();
|
||||
buffer_capacity = N;
|
||||
}
|
||||
|
||||
SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector()
|
||||
{
|
||||
auto count = size_t(arg_list_end - arg_list_begin);
|
||||
reserve(count);
|
||||
for (size_t i = 0; i < count; i++, arg_list_begin++)
|
||||
new (&this->ptr[i]) T(*arg_list_begin);
|
||||
this->buffer_size = count;
|
||||
}
|
||||
|
||||
SmallVector(std::initializer_list<T> init) SPIRV_CROSS_NOEXCEPT : SmallVector(init.begin(), init.end())
|
||||
{
|
||||
}
|
||||
|
||||
SmallVector(SmallVector &&other) SPIRV_CROSS_NOEXCEPT : SmallVector()
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
SmallVector &operator=(SmallVector &&other) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
clear();
|
||||
if (other.ptr != other.stack_storage.data())
|
||||
{
|
||||
// Pilfer allocated pointer.
|
||||
if (this->ptr != stack_storage.data())
|
||||
free(this->ptr);
|
||||
this->ptr = other.ptr;
|
||||
this->buffer_size = other.buffer_size;
|
||||
buffer_capacity = other.buffer_capacity;
|
||||
other.ptr = nullptr;
|
||||
other.buffer_size = 0;
|
||||
other.buffer_capacity = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to move the stack contents individually.
|
||||
reserve(other.buffer_size);
|
||||
for (size_t i = 0; i < other.buffer_size; i++)
|
||||
{
|
||||
new (&this->ptr[i]) T(std::move(other.ptr[i]));
|
||||
other.ptr[i].~T();
|
||||
}
|
||||
this->buffer_size = other.buffer_size;
|
||||
other.buffer_size = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT : SmallVector()
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
SmallVector &operator=(const SmallVector &other) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
clear();
|
||||
reserve(other.buffer_size);
|
||||
for (size_t i = 0; i < other.buffer_size; i++)
|
||||
new (&this->ptr[i]) T(other.ptr[i]);
|
||||
this->buffer_size = other.buffer_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT : SmallVector()
|
||||
{
|
||||
resize(count);
|
||||
}
|
||||
|
||||
~SmallVector()
|
||||
{
|
||||
clear();
|
||||
if (this->ptr != stack_storage.data())
|
||||
free(this->ptr);
|
||||
}
|
||||
|
||||
void clear() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
for (size_t i = 0; i < this->buffer_size; i++)
|
||||
this->ptr[i].~T();
|
||||
this->buffer_size = 0;
|
||||
}
|
||||
|
||||
void push_back(const T &t) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
reserve(this->buffer_size + 1);
|
||||
new (&this->ptr[this->buffer_size]) T(t);
|
||||
this->buffer_size++;
|
||||
}
|
||||
|
||||
void push_back(T &&t) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
reserve(this->buffer_size + 1);
|
||||
new (&this->ptr[this->buffer_size]) T(std::move(t));
|
||||
this->buffer_size++;
|
||||
}
|
||||
|
||||
void pop_back() SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
// Work around false positive warning on GCC 8.3.
|
||||
// Calling pop_back on empty vector is undefined.
|
||||
if (!this->empty())
|
||||
resize(this->buffer_size - 1);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void emplace_back(Ts &&... ts) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
reserve(this->buffer_size + 1);
|
||||
new (&this->ptr[this->buffer_size]) T(std::forward<Ts>(ts)...);
|
||||
this->buffer_size++;
|
||||
}
|
||||
|
||||
void reserve(size_t count) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
if ((count > std::numeric_limits<size_t>::max() / sizeof(T)) ||
|
||||
(count > std::numeric_limits<size_t>::max() / 2))
|
||||
{
|
||||
// Only way this should ever happen is with garbage input, terminate.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if (count > buffer_capacity)
|
||||
{
|
||||
size_t target_capacity = buffer_capacity;
|
||||
if (target_capacity == 0)
|
||||
target_capacity = 1;
|
||||
|
||||
// Weird parens works around macro issues on Windows if NOMINMAX is not used.
|
||||
target_capacity = (std::max)(target_capacity, N);
|
||||
|
||||
// Need to ensure there is a POT value of target capacity which is larger than count,
|
||||
// otherwise this will overflow.
|
||||
while (target_capacity < count)
|
||||
target_capacity <<= 1u;
|
||||
|
||||
T *new_buffer =
|
||||
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
|
||||
|
||||
// If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery.
|
||||
if (!new_buffer)
|
||||
std::terminate();
|
||||
|
||||
// In case for some reason two allocations both come from same stack.
|
||||
if (new_buffer != this->ptr)
|
||||
{
|
||||
// We don't deal with types which can throw in move constructor.
|
||||
for (size_t i = 0; i < this->buffer_size; i++)
|
||||
{
|
||||
new (&new_buffer[i]) T(std::move(this->ptr[i]));
|
||||
this->ptr[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->ptr != stack_storage.data())
|
||||
free(this->ptr);
|
||||
this->ptr = new_buffer;
|
||||
buffer_capacity = target_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(T *itr, const T *insert_begin, const T *insert_end) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
auto count = size_t(insert_end - insert_begin);
|
||||
if (itr == this->end())
|
||||
{
|
||||
reserve(this->buffer_size + count);
|
||||
for (size_t i = 0; i < count; i++, insert_begin++)
|
||||
new (&this->ptr[this->buffer_size + i]) T(*insert_begin);
|
||||
this->buffer_size += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->buffer_size + count > buffer_capacity)
|
||||
{
|
||||
auto target_capacity = this->buffer_size + count;
|
||||
if (target_capacity == 0)
|
||||
target_capacity = 1;
|
||||
if (target_capacity < N)
|
||||
target_capacity = N;
|
||||
|
||||
while (target_capacity < count)
|
||||
target_capacity <<= 1u;
|
||||
|
||||
// Need to allocate new buffer. Move everything to a new buffer.
|
||||
T *new_buffer =
|
||||
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
|
||||
|
||||
// If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery.
|
||||
if (!new_buffer)
|
||||
std::terminate();
|
||||
|
||||
// First, move elements from source buffer to new buffer.
|
||||
// We don't deal with types which can throw in move constructor.
|
||||
auto *target_itr = new_buffer;
|
||||
auto *original_source_itr = this->begin();
|
||||
|
||||
if (new_buffer != this->ptr)
|
||||
{
|
||||
while (original_source_itr != itr)
|
||||
{
|
||||
new (target_itr) T(std::move(*original_source_itr));
|
||||
original_source_itr->~T();
|
||||
++original_source_itr;
|
||||
++target_itr;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy-construct new elements.
|
||||
for (auto *source_itr = insert_begin; source_itr != insert_end; ++source_itr, ++target_itr)
|
||||
new (target_itr) T(*source_itr);
|
||||
|
||||
// Move over the other half.
|
||||
if (new_buffer != this->ptr || insert_begin != insert_end)
|
||||
{
|
||||
while (original_source_itr != this->end())
|
||||
{
|
||||
new (target_itr) T(std::move(*original_source_itr));
|
||||
original_source_itr->~T();
|
||||
++original_source_itr;
|
||||
++target_itr;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->ptr != stack_storage.data())
|
||||
free(this->ptr);
|
||||
this->ptr = new_buffer;
|
||||
buffer_capacity = target_capacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move in place, need to be a bit careful about which elements are constructed and which are not.
|
||||
// Move the end and construct the new elements.
|
||||
auto *target_itr = this->end() + count;
|
||||
auto *source_itr = this->end();
|
||||
while (target_itr != this->end() && source_itr != itr)
|
||||
{
|
||||
--target_itr;
|
||||
--source_itr;
|
||||
new (target_itr) T(std::move(*source_itr));
|
||||
}
|
||||
|
||||
// For already constructed elements we can move-assign.
|
||||
std::move_backward(itr, source_itr, target_itr);
|
||||
|
||||
// For the inserts which go to already constructed elements, we can do a plain copy.
|
||||
while (itr != this->end() && insert_begin != insert_end)
|
||||
*itr++ = *insert_begin++;
|
||||
|
||||
// For inserts into newly allocated memory, we must copy-construct instead.
|
||||
while (insert_begin != insert_end)
|
||||
{
|
||||
new (itr) T(*insert_begin);
|
||||
++itr;
|
||||
++insert_begin;
|
||||
}
|
||||
}
|
||||
|
||||
this->buffer_size += count;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(T *itr, const T &value) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
insert(itr, &value, &value + 1);
|
||||
}
|
||||
|
||||
T *erase(T *itr) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
std::move(itr + 1, this->end(), itr);
|
||||
this->ptr[--this->buffer_size].~T();
|
||||
return itr;
|
||||
}
|
||||
|
||||
void erase(T *start_erase, T *end_erase) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
if (end_erase == this->end())
|
||||
{
|
||||
resize(size_t(start_erase - this->begin()));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_size = this->buffer_size - (end_erase - start_erase);
|
||||
std::move(end_erase, this->end(), start_erase);
|
||||
resize(new_size);
|
||||
}
|
||||
}
|
||||
|
||||
void resize(size_t new_size) SPIRV_CROSS_NOEXCEPT
|
||||
{
|
||||
if (new_size < this->buffer_size)
|
||||
{
|
||||
for (size_t i = new_size; i < this->buffer_size; i++)
|
||||
this->ptr[i].~T();
|
||||
}
|
||||
else if (new_size > this->buffer_size)
|
||||
{
|
||||
reserve(new_size);
|
||||
for (size_t i = this->buffer_size; i < new_size; i++)
|
||||
new (&this->ptr[i]) T();
|
||||
}
|
||||
|
||||
this->buffer_size = new_size;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t buffer_capacity = 0;
|
||||
AlignedBuffer<T, N> stack_storage;
|
||||
};
|
||||
|
||||
// A vector without stack storage.
|
||||
// Could also be a typedef-ed to std::vector,
|
||||
// but might as well use the one we have.
|
||||
template <typename T>
|
||||
using Vector = SmallVector<T, 0>;
|
||||
|
||||
#else // SPIRV_CROSS_FORCE_STL_TYPES
|
||||
|
||||
template <typename T, size_t N = 8>
|
||||
using SmallVector = std::vector<T>;
|
||||
template <typename T>
|
||||
using Vector = std::vector<T>;
|
||||
template <typename T>
|
||||
using VectorView = std::vector<T>;
|
||||
|
||||
#endif // SPIRV_CROSS_FORCE_STL_TYPES
|
||||
|
||||
// An object pool which we use for allocating IVariant-derived objects.
|
||||
// We know we are going to allocate a bunch of objects of each type,
|
||||
// so amortize the mallocs.
|
||||
class ObjectPoolBase
|
||||
{
|
||||
public:
|
||||
virtual ~ObjectPoolBase() = default;
|
||||
virtual void free_opaque(void *ptr) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ObjectPool : public ObjectPoolBase
|
||||
{
|
||||
public:
|
||||
explicit ObjectPool(unsigned start_object_count_ = 16)
|
||||
: start_object_count(start_object_count_)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
T *allocate(P &&... p)
|
||||
{
|
||||
if (vacants.empty())
|
||||
{
|
||||
unsigned num_objects = start_object_count << memory.size();
|
||||
T *ptr = static_cast<T *>(malloc(num_objects * sizeof(T)));
|
||||
if (!ptr)
|
||||
return nullptr;
|
||||
|
||||
for (unsigned i = 0; i < num_objects; i++)
|
||||
vacants.push_back(&ptr[i]);
|
||||
|
||||
memory.emplace_back(ptr);
|
||||
}
|
||||
|
||||
T *ptr = vacants.back();
|
||||
vacants.pop_back();
|
||||
new (ptr) T(std::forward<P>(p)...);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void free(T *ptr)
|
||||
{
|
||||
ptr->~T();
|
||||
vacants.push_back(ptr);
|
||||
}
|
||||
|
||||
void free_opaque(void *ptr) override
|
||||
{
|
||||
free(static_cast<T *>(ptr));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
vacants.clear();
|
||||
memory.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector<T *> vacants;
|
||||
|
||||
struct MallocDeleter
|
||||
{
|
||||
void operator()(T *ptr)
|
||||
{
|
||||
::free(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
SmallVector<std::unique_ptr<T, MallocDeleter>> memory;
|
||||
unsigned start_object_count;
|
||||
};
|
||||
|
||||
template <size_t StackSize = 4096, size_t BlockSize = 4096>
|
||||
class StringStream
|
||||
{
|
||||
public:
|
||||
StringStream()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
~StringStream()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Disable copies and moves. Makes it easier to implement, and we don't need it.
|
||||
StringStream(const StringStream &) = delete;
|
||||
void operator=(const StringStream &) = delete;
|
||||
|
||||
template <typename T, typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0>
|
||||
StringStream &operator<<(const T &t)
|
||||
{
|
||||
auto s = std::to_string(t);
|
||||
append(s.data(), s.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Only overload this to make float/double conversions ambiguous.
|
||||
StringStream &operator<<(uint32_t v)
|
||||
{
|
||||
auto s = std::to_string(v);
|
||||
append(s.data(), s.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream &operator<<(char c)
|
||||
{
|
||||
append(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream &operator<<(const std::string &s)
|
||||
{
|
||||
append(s.data(), s.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream &operator<<(const char *s)
|
||||
{
|
||||
append(s, strlen(s));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
StringStream &operator<<(const char (&s)[N])
|
||||
{
|
||||
append(s, strlen(s));
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
std::string ret;
|
||||
size_t target_size = 0;
|
||||
for (auto &saved : saved_buffers)
|
||||
target_size += saved.offset;
|
||||
target_size += current_buffer.offset;
|
||||
ret.reserve(target_size);
|
||||
|
||||
for (auto &saved : saved_buffers)
|
||||
ret.insert(ret.end(), saved.buffer, saved.buffer + saved.offset);
|
||||
ret.insert(ret.end(), current_buffer.buffer, current_buffer.buffer + current_buffer.offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for (auto &saved : saved_buffers)
|
||||
if (saved.buffer != stack_buffer)
|
||||
free(saved.buffer);
|
||||
if (current_buffer.buffer != stack_buffer)
|
||||
free(current_buffer.buffer);
|
||||
|
||||
saved_buffers.clear();
|
||||
current_buffer.buffer = stack_buffer;
|
||||
current_buffer.offset = 0;
|
||||
current_buffer.size = sizeof(stack_buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Buffer
|
||||
{
|
||||
char *buffer = nullptr;
|
||||
size_t offset = 0;
|
||||
size_t size = 0;
|
||||
};
|
||||
Buffer current_buffer;
|
||||
char stack_buffer[StackSize];
|
||||
SmallVector<Buffer> saved_buffers;
|
||||
|
||||
void append(const char *s, size_t len)
|
||||
{
|
||||
size_t avail = current_buffer.size - current_buffer.offset;
|
||||
if (avail < len)
|
||||
{
|
||||
if (avail > 0)
|
||||
{
|
||||
memcpy(current_buffer.buffer + current_buffer.offset, s, avail);
|
||||
s += avail;
|
||||
len -= avail;
|
||||
current_buffer.offset += avail;
|
||||
}
|
||||
|
||||
saved_buffers.push_back(current_buffer);
|
||||
size_t target_size = len > BlockSize ? len : BlockSize;
|
||||
current_buffer.buffer = static_cast<char *>(malloc(target_size));
|
||||
if (!current_buffer.buffer)
|
||||
SPIRV_CROSS_THROW("Out of memory.");
|
||||
|
||||
memcpy(current_buffer.buffer, s, len);
|
||||
current_buffer.offset = len;
|
||||
current_buffer.size = target_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(current_buffer.buffer + current_buffer.offset, s, len);
|
||||
current_buffer.offset += len;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2015-2021 Arm Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_ERROR_HANDLING
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
|
||||
#ifdef SPIRV_CROSS_NAMESPACE_OVERRIDE
|
||||
#define SPIRV_CROSS_NAMESPACE SPIRV_CROSS_NAMESPACE_OVERRIDE
|
||||
#else
|
||||
#define SPIRV_CROSS_NAMESPACE spirv_cross
|
||||
#endif
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
#ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
[[noreturn]]
|
||||
#elif defined(_MSC_VER)
|
||||
__declspec(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
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
#define SPIRV_CROSS_THROW(x) report_and_abort(x)
|
||||
#else
|
||||
class CompilerError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit CompilerError(const std::string &str)
|
||||
: std::runtime_error(str)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#define SPIRV_CROSS_THROW(x) throw CompilerError(x)
|
||||
#endif
|
||||
|
||||
// MSVC 2013 does not have noexcept. We need this for Variant to get move constructor to work correctly
|
||||
// instead of copy constructor.
|
||||
// MSVC 2013 ignores that move constructors cannot throw in std::vector, so just don't define it.
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define SPIRV_CROSS_NOEXCEPT
|
||||
#else
|
||||
#define SPIRV_CROSS_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201402l
|
||||
#define SPIRV_CROSS_DEPRECATED(reason) [[deprecated(reason)]]
|
||||
#elif defined(__GNUC__)
|
||||
#define SPIRV_CROSS_DEPRECATED(reason) __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SPIRV_CROSS_DEPRECATED(reason) __declspec(deprecated(reason))
|
||||
#else
|
||||
#define SPIRV_CROSS_DEPRECATED(reason)
|
||||
#endif
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2018-2021 Arm Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_PARSED_IR_HPP
|
||||
|
||||
#include "spirv_common.hpp"
|
||||
#include <stdint.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
|
||||
// This data structure holds all information needed to perform cross-compilation and reflection.
|
||||
// It is the output of the Parser, but any implementation could create this structure.
|
||||
// It is intentionally very "open" and struct-like with some helper functions to deal with decorations.
|
||||
// Parser is the reference implementation of how this data structure should be filled in.
|
||||
|
||||
class ParsedIR
|
||||
{
|
||||
private:
|
||||
// This must be destroyed after the "ids" vector.
|
||||
std::unique_ptr<ObjectPoolGroup> pool_group;
|
||||
|
||||
public:
|
||||
ParsedIR();
|
||||
|
||||
// Due to custom allocations from object pools, we cannot use a default copy constructor.
|
||||
ParsedIR(const ParsedIR &other);
|
||||
ParsedIR &operator=(const ParsedIR &other);
|
||||
|
||||
// Moves are unproblematic, but we need to implement it anyways, since MSVC 2013 does not understand
|
||||
// how to default-implement these.
|
||||
ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT;
|
||||
ParsedIR &operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT;
|
||||
|
||||
// Resizes ids, meta and block_meta.
|
||||
void set_id_bounds(uint32_t bounds);
|
||||
|
||||
// The raw SPIR-V, instructions and opcodes refer to this by offset + count.
|
||||
std::vector<uint32_t> spirv;
|
||||
|
||||
// Holds various data structures which inherit from IVariant.
|
||||
SmallVector<Variant> ids;
|
||||
|
||||
// Various meta data for IDs, decorations, names, etc.
|
||||
std::unordered_map<ID, Meta> meta;
|
||||
|
||||
// Holds all IDs which have a certain type.
|
||||
// This is needed so we can iterate through a specific kind of resource quickly,
|
||||
// and in-order of module declaration.
|
||||
SmallVector<ID> ids_for_type[TypeCount];
|
||||
|
||||
// Special purpose lists which contain a union of types.
|
||||
// This is needed so we can declare specialization constants and structs in an interleaved fashion,
|
||||
// among other things.
|
||||
// Constants can be of struct type, and struct array sizes can use specialization constants.
|
||||
SmallVector<ID> ids_for_constant_or_type;
|
||||
SmallVector<ID> ids_for_constant_or_variable;
|
||||
|
||||
// Declared capabilities and extensions in the SPIR-V module.
|
||||
// Not really used except for reflection at the moment.
|
||||
SmallVector<spv::Capability> declared_capabilities;
|
||||
SmallVector<std::string> declared_extensions;
|
||||
|
||||
// Meta data about blocks. The cross-compiler needs to query if a block is either of these types.
|
||||
// It is a bitset as there can be more than one tag per block.
|
||||
enum BlockMetaFlagBits
|
||||
{
|
||||
BLOCK_META_LOOP_HEADER_BIT = 1 << 0,
|
||||
BLOCK_META_CONTINUE_BIT = 1 << 1,
|
||||
BLOCK_META_LOOP_MERGE_BIT = 1 << 2,
|
||||
BLOCK_META_SELECTION_MERGE_BIT = 1 << 3,
|
||||
BLOCK_META_MULTISELECT_MERGE_BIT = 1 << 4
|
||||
};
|
||||
using BlockMetaFlags = uint8_t;
|
||||
SmallVector<BlockMetaFlags> block_meta;
|
||||
std::unordered_map<BlockID, BlockID> continue_block_to_loop_header;
|
||||
|
||||
// Normally, we'd stick SPIREntryPoint in ids array, but it conflicts with SPIRFunction.
|
||||
// Entry points can therefore be seen as some sort of meta structure.
|
||||
std::unordered_map<FunctionID, SPIREntryPoint> entry_points;
|
||||
FunctionID default_entry_point = 0;
|
||||
|
||||
struct Source
|
||||
{
|
||||
uint32_t version = 0;
|
||||
bool es = false;
|
||||
bool known = false;
|
||||
bool hlsl = false;
|
||||
|
||||
Source() = default;
|
||||
};
|
||||
|
||||
Source source;
|
||||
|
||||
spv::AddressingModel addressing_model = spv::AddressingModelMax;
|
||||
spv::MemoryModel memory_model = spv::MemoryModelMax;
|
||||
|
||||
// Decoration handling methods.
|
||||
// Can be useful for simple "raw" reflection.
|
||||
// However, most members are here because the Parser needs most of these,
|
||||
// and might as well just have the whole suite of decoration/name handling in one place.
|
||||
void set_name(ID id, const std::string &name);
|
||||
const std::string &get_name(ID id) const;
|
||||
void set_decoration(ID id, spv::Decoration decoration, uint32_t argument = 0);
|
||||
void set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument);
|
||||
bool has_decoration(ID id, spv::Decoration decoration) const;
|
||||
uint32_t get_decoration(ID id, spv::Decoration decoration) const;
|
||||
const std::string &get_decoration_string(ID id, spv::Decoration decoration) const;
|
||||
const Bitset &get_decoration_bitset(ID id) const;
|
||||
void unset_decoration(ID id, spv::Decoration decoration);
|
||||
|
||||
// Decoration handling methods (for members of a struct).
|
||||
void set_member_name(TypeID id, uint32_t index, const std::string &name);
|
||||
const std::string &get_member_name(TypeID id, uint32_t index) const;
|
||||
void set_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0);
|
||||
void set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration,
|
||||
const std::string &argument);
|
||||
uint32_t get_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
|
||||
const std::string &get_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration) const;
|
||||
bool has_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
|
||||
const Bitset &get_member_decoration_bitset(TypeID id, uint32_t index) const;
|
||||
void unset_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration);
|
||||
|
||||
void mark_used_as_array_length(ID id);
|
||||
uint32_t increase_bound_by(uint32_t count);
|
||||
Bitset get_buffer_block_flags(const SPIRVariable &var) const;
|
||||
Bitset get_buffer_block_type_flags(const SPIRType &type) const;
|
||||
|
||||
void add_typed_id(Types type, ID id);
|
||||
void remove_typed_id(Types type, ID id);
|
||||
|
||||
class LoopLock
|
||||
{
|
||||
public:
|
||||
explicit LoopLock(uint32_t *counter);
|
||||
LoopLock(const LoopLock &) = delete;
|
||||
void operator=(const LoopLock &) = delete;
|
||||
LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT;
|
||||
LoopLock &operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT;
|
||||
~LoopLock();
|
||||
|
||||
private:
|
||||
uint32_t *lock;
|
||||
};
|
||||
|
||||
// This must be held while iterating over a type ID array.
|
||||
// It is undefined if someone calls set<>() while we're iterating over a data structure, so we must
|
||||
// make sure that this case is avoided.
|
||||
|
||||
// If we have a hard lock, it is an error to call set<>(), and an exception is thrown.
|
||||
// If we have a soft lock, we silently ignore any additions to the typed arrays.
|
||||
// This should only be used for physical ID remapping where we need to create an ID, but we will never
|
||||
// care about iterating over them.
|
||||
LoopLock create_loop_hard_lock() const;
|
||||
LoopLock create_loop_soft_lock() const;
|
||||
|
||||
template <typename T, typename Op>
|
||||
void for_each_typed_id(const Op &op)
|
||||
{
|
||||
auto loop_lock = create_loop_hard_lock();
|
||||
for (auto &id : ids_for_type[T::type])
|
||||
{
|
||||
if (ids[id].get_type() == static_cast<Types>(T::type))
|
||||
op(id, get<T>(id));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Op>
|
||||
void for_each_typed_id(const Op &op) const
|
||||
{
|
||||
auto loop_lock = create_loop_hard_lock();
|
||||
for (auto &id : ids_for_type[T::type])
|
||||
{
|
||||
if (ids[id].get_type() == static_cast<Types>(T::type))
|
||||
op(id, get<T>(id));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void reset_all_of_type()
|
||||
{
|
||||
reset_all_of_type(static_cast<Types>(T::type));
|
||||
}
|
||||
|
||||
void reset_all_of_type(Types type);
|
||||
|
||||
Meta *find_meta(ID id);
|
||||
const Meta *find_meta(ID id) const;
|
||||
|
||||
const std::string &get_empty_string() const
|
||||
{
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set);
|
||||
|
||||
void fixup_reserved_names();
|
||||
|
||||
static void sanitize_underscores(std::string &str);
|
||||
static void sanitize_identifier(std::string &str, bool member, bool allow_reserved_prefixes);
|
||||
static bool is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes);
|
||||
|
||||
uint32_t get_spirv_version() const;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T &get(uint32_t id)
|
||||
{
|
||||
return variant_get<T>(ids[id]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T &get(uint32_t id) const
|
||||
{
|
||||
return variant_get<T>(ids[id]);
|
||||
}
|
||||
|
||||
mutable uint32_t loop_iteration_depth_hard = 0;
|
||||
mutable uint32_t loop_iteration_depth_soft = 0;
|
||||
std::string empty_string;
|
||||
Bitset cleared_bitset;
|
||||
|
||||
std::unordered_set<uint32_t> meta_needing_name_fixup;
|
||||
};
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* Copyright 2015-2021 Arm Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_GLSL_HPP
|
||||
|
||||
#include "GLSL.std.450.h"
|
||||
#include "spirv_cross.hpp"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
enum PlsFormat
|
||||
{
|
||||
PlsNone = 0,
|
||||
|
||||
PlsR11FG11FB10F,
|
||||
PlsR32F,
|
||||
PlsRG16F,
|
||||
PlsRGB10A2,
|
||||
PlsRGBA8,
|
||||
PlsRG16,
|
||||
|
||||
PlsRGBA8I,
|
||||
PlsRG16I,
|
||||
|
||||
PlsRGB10A2UI,
|
||||
PlsRGBA8UI,
|
||||
PlsRG16UI,
|
||||
PlsR32UI
|
||||
};
|
||||
|
||||
struct PlsRemap
|
||||
{
|
||||
uint32_t id;
|
||||
PlsFormat format;
|
||||
};
|
||||
|
||||
enum AccessChainFlagBits
|
||||
{
|
||||
ACCESS_CHAIN_INDEX_IS_LITERAL_BIT = 1 << 0,
|
||||
ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1,
|
||||
ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2,
|
||||
ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3,
|
||||
ACCESS_CHAIN_LITERAL_MSB_FORCE_ID = 1 << 4,
|
||||
ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT = 1 << 5,
|
||||
ACCESS_CHAIN_FORCE_COMPOSITE_BIT = 1 << 6
|
||||
};
|
||||
typedef uint32_t AccessChainFlags;
|
||||
|
||||
class CompilerGLSL : public Compiler
|
||||
{
|
||||
public:
|
||||
struct Options
|
||||
{
|
||||
// The shading language version. Corresponds to #version $VALUE.
|
||||
uint32_t version = 450;
|
||||
|
||||
// Emit the OpenGL ES shading language instead of desktop OpenGL.
|
||||
bool es = false;
|
||||
|
||||
// Debug option to always emit temporary variables for all expressions.
|
||||
bool force_temporary = false;
|
||||
|
||||
// If true, Vulkan GLSL features are used instead of GL-compatible features.
|
||||
// Mostly useful for debugging SPIR-V files.
|
||||
bool vulkan_semantics = false;
|
||||
|
||||
// If true, gl_PerVertex is explicitly redeclared in vertex, geometry and tessellation shaders.
|
||||
// The members of gl_PerVertex is determined by which built-ins are declared by the shader.
|
||||
// This option is ignored in ES versions, as redeclaration in ES is not required, and it depends on a different extension
|
||||
// (EXT_shader_io_blocks) which makes things a bit more fuzzy.
|
||||
bool separate_shader_objects = false;
|
||||
|
||||
// Flattens multidimensional arrays, e.g. float foo[a][b][c] into single-dimensional arrays,
|
||||
// e.g. float foo[a * b * c].
|
||||
// This function does not change the actual SPIRType of any object.
|
||||
// Only the generated code, including declarations of interface variables are changed to be single array dimension.
|
||||
bool flatten_multidimensional_arrays = false;
|
||||
|
||||
// For older desktop GLSL targets than version 420, the
|
||||
// GL_ARB_shading_language_420pack extensions is used to be able to support
|
||||
// layout(binding) on UBOs and samplers.
|
||||
// If disabled on older targets, binding decorations will be stripped.
|
||||
bool enable_420pack_extension = true;
|
||||
|
||||
// In non-Vulkan GLSL, emit push constant blocks as UBOs rather than plain uniforms.
|
||||
bool emit_push_constant_as_uniform_buffer = false;
|
||||
|
||||
// Always emit uniform blocks as plain uniforms, regardless of the GLSL version, even when UBOs are supported.
|
||||
// Does not apply to shader storage or push constant blocks.
|
||||
bool emit_uniform_buffer_as_plain_uniforms = false;
|
||||
|
||||
// Emit OpLine directives if present in the module.
|
||||
// May not correspond exactly to original source, but should be a good approximation.
|
||||
bool emit_line_directives = false;
|
||||
|
||||
// In cases where readonly/writeonly decoration are not used at all,
|
||||
// we try to deduce which qualifier(s) we should actually used, since actually emitting
|
||||
// read-write decoration is very rare, and older glslang/HLSL compilers tend to just emit readwrite as a matter of fact.
|
||||
// The default (true) is to enable automatic deduction for these cases, but if you trust the decorations set
|
||||
// by the SPIR-V, it's recommended to set this to false.
|
||||
bool enable_storage_image_qualifier_deduction = true;
|
||||
|
||||
// On some targets (WebGPU), uninitialized variables are banned.
|
||||
// If this is enabled, all variables (temporaries, Private, Function)
|
||||
// which would otherwise be uninitialized will now be initialized to 0 instead.
|
||||
bool force_zero_initialized_variables = false;
|
||||
|
||||
// In GLSL, force use of I/O block flattening, similar to
|
||||
// what happens on legacy GLSL targets for blocks and structs.
|
||||
bool force_flattened_io_blocks = false;
|
||||
|
||||
enum Precision
|
||||
{
|
||||
DontCare,
|
||||
Lowp,
|
||||
Mediump,
|
||||
Highp
|
||||
};
|
||||
|
||||
struct VertexOptions
|
||||
{
|
||||
// "Vertex-like shader" here is any shader stage that can write BuiltInPosition.
|
||||
|
||||
// GLSL: In vertex-like shaders, rewrite [0, w] depth (Vulkan/D3D style) to [-w, w] depth (GL style).
|
||||
// MSL: In vertex-like shaders, rewrite [-w, w] depth (GL style) to [0, w] depth.
|
||||
// HLSL: In vertex-like shaders, rewrite [-w, w] depth (GL style) to [0, w] depth.
|
||||
bool fixup_clipspace = false;
|
||||
|
||||
// In vertex-like shaders, inverts gl_Position.y or equivalent.
|
||||
bool flip_vert_y = false;
|
||||
|
||||
// GLSL only, for HLSL version of this option, see CompilerHLSL.
|
||||
// If true, the backend will assume that InstanceIndex will need to apply
|
||||
// a base instance offset. Set to false if you know you will never use base instance
|
||||
// functionality as it might remove some internal uniforms.
|
||||
bool support_nonzero_base_instance = true;
|
||||
} vertex;
|
||||
|
||||
struct FragmentOptions
|
||||
{
|
||||
// Add precision mediump float in ES targets when emitting GLES source.
|
||||
// Add precision highp int in ES targets when emitting GLES source.
|
||||
Precision default_float_precision = Mediump;
|
||||
Precision default_int_precision = Highp;
|
||||
} fragment;
|
||||
};
|
||||
|
||||
void remap_pixel_local_storage(std::vector<PlsRemap> inputs, std::vector<PlsRemap> outputs)
|
||||
{
|
||||
pls_inputs = std::move(inputs);
|
||||
pls_outputs = std::move(outputs);
|
||||
remap_pls_variables();
|
||||
}
|
||||
|
||||
// Redirect a subpassInput reading from input_attachment_index to instead load its value from
|
||||
// the color attachment at location = color_location. Requires ESSL.
|
||||
void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location);
|
||||
|
||||
explicit CompilerGLSL(std::vector<uint32_t> spirv_)
|
||||
: Compiler(std::move(spirv_))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
CompilerGLSL(const uint32_t *ir_, size_t word_count)
|
||||
: Compiler(ir_, word_count)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
explicit CompilerGLSL(const ParsedIR &ir_)
|
||||
: Compiler(ir_)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
explicit CompilerGLSL(ParsedIR &&ir_)
|
||||
: Compiler(std::move(ir_))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
const Options &get_common_options() const
|
||||
{
|
||||
return options;
|
||||
}
|
||||
|
||||
void set_common_options(const Options &opts)
|
||||
{
|
||||
options = opts;
|
||||
}
|
||||
|
||||
std::string compile() override;
|
||||
|
||||
// Returns the current string held in the conversion buffer. Useful for
|
||||
// capturing what has been converted so far when compile() throws an error.
|
||||
std::string get_partial_source();
|
||||
|
||||
// Adds a line to be added right after #version in GLSL backend.
|
||||
// This is useful for enabling custom extensions which are outside the scope of SPIRV-Cross.
|
||||
// This can be combined with variable remapping.
|
||||
// A new-line will be added.
|
||||
//
|
||||
// While add_header_line() is a more generic way of adding arbitrary text to the header
|
||||
// of a GLSL file, require_extension() should be used when adding extensions since it will
|
||||
// avoid creating collisions with SPIRV-Cross generated extensions.
|
||||
//
|
||||
// Code added via add_header_line() is typically backend-specific.
|
||||
void add_header_line(const std::string &str);
|
||||
|
||||
// Adds an extension which is required to run this shader, e.g.
|
||||
// require_extension("GL_KHR_my_extension");
|
||||
void require_extension(const std::string &ext);
|
||||
|
||||
// Legacy GLSL compatibility method.
|
||||
// Takes a uniform or push constant variable and flattens it into a (i|u)vec4 array[N]; array instead.
|
||||
// For this to work, all types in the block must be the same basic type, e.g. mixing vec2 and vec4 is fine, but
|
||||
// mixing int and float is not.
|
||||
// The name of the uniform array will be the same as the interface block name.
|
||||
void flatten_buffer_block(VariableID id);
|
||||
|
||||
// After compilation, query if a variable ID was used as a depth resource.
|
||||
// This is meaningful for MSL since descriptor types depend on this knowledge.
|
||||
// Cases which return true:
|
||||
// - Images which are declared with depth = 1 image type.
|
||||
// - Samplers which are statically used at least once with Dref opcodes.
|
||||
// - Images which are statically used at least once with Dref opcodes.
|
||||
bool variable_is_depth_or_compare(VariableID id) const;
|
||||
|
||||
// If a shader output is active in this stage, but inactive in a subsequent stage,
|
||||
// this can be signalled here. This can be used to work around certain cross-stage matching problems
|
||||
// which plagues MSL and HLSL in certain scenarios.
|
||||
// An output which matches one of these will not be emitted in stage output interfaces, but rather treated as a private
|
||||
// variable.
|
||||
// This option is only meaningful for MSL and HLSL, since GLSL matches by location directly.
|
||||
// Masking builtins only takes effect if the builtin in question is part of the stage output interface.
|
||||
void mask_stage_output_by_location(uint32_t location, uint32_t component);
|
||||
void mask_stage_output_by_builtin(spv::BuiltIn builtin);
|
||||
|
||||
protected:
|
||||
struct ShaderSubgroupSupportHelper
|
||||
{
|
||||
// lower enum value = greater priority
|
||||
enum Candidate
|
||||
{
|
||||
KHR_shader_subgroup_ballot,
|
||||
KHR_shader_subgroup_basic,
|
||||
KHR_shader_subgroup_vote,
|
||||
NV_gpu_shader_5,
|
||||
NV_shader_thread_group,
|
||||
NV_shader_thread_shuffle,
|
||||
ARB_shader_ballot,
|
||||
ARB_shader_group_vote,
|
||||
AMD_gcn_shader,
|
||||
|
||||
CandidateCount
|
||||
};
|
||||
|
||||
static const char *get_extension_name(Candidate c);
|
||||
static SmallVector<std::string> get_extra_required_extension_names(Candidate c);
|
||||
static const char *get_extra_required_extension_predicate(Candidate c);
|
||||
|
||||
enum Feature
|
||||
{
|
||||
SubgroupMask = 0,
|
||||
SubgroupSize = 1,
|
||||
SubgroupInvocationID = 2,
|
||||
SubgroupID = 3,
|
||||
NumSubgroups = 4,
|
||||
SubgroupBroadcast_First = 5,
|
||||
SubgroupBallotFindLSB_MSB = 6,
|
||||
SubgroupAll_Any_AllEqualBool = 7,
|
||||
SubgroupAllEqualT = 8,
|
||||
SubgroupElect = 9,
|
||||
SubgroupBarrier = 10,
|
||||
SubgroupMemBarrier = 11,
|
||||
SubgroupBallot = 12,
|
||||
SubgroupInverseBallot_InclBitCount_ExclBitCout = 13,
|
||||
SubgroupBallotBitExtract = 14,
|
||||
SubgroupBallotBitCount = 15,
|
||||
|
||||
FeatureCount
|
||||
};
|
||||
|
||||
using FeatureMask = uint32_t;
|
||||
static_assert(sizeof(FeatureMask) * 8u >= FeatureCount, "Mask type needs more bits.");
|
||||
|
||||
using CandidateVector = SmallVector<Candidate, CandidateCount>;
|
||||
using FeatureVector = SmallVector<Feature>;
|
||||
|
||||
static FeatureVector get_feature_dependencies(Feature feature);
|
||||
static FeatureMask get_feature_dependency_mask(Feature feature);
|
||||
static bool can_feature_be_implemented_without_extensions(Feature feature);
|
||||
static Candidate get_KHR_extension_for_feature(Feature feature);
|
||||
|
||||
struct Result
|
||||
{
|
||||
Result();
|
||||
uint32_t weights[CandidateCount];
|
||||
};
|
||||
|
||||
void request_feature(Feature feature);
|
||||
bool is_feature_requested(Feature feature) const;
|
||||
Result resolve() const;
|
||||
|
||||
static CandidateVector get_candidates_for_feature(Feature ft, const Result &r);
|
||||
|
||||
private:
|
||||
static CandidateVector get_candidates_for_feature(Feature ft);
|
||||
static FeatureMask build_mask(const SmallVector<Feature> &features);
|
||||
FeatureMask feature_mask = 0;
|
||||
};
|
||||
|
||||
// TODO remove this function when all subgroup ops are supported (or make it always return true)
|
||||
static bool is_supported_subgroup_op_in_opengl(spv::Op op);
|
||||
|
||||
void reset();
|
||||
void emit_function(SPIRFunction &func, const Bitset &return_flags);
|
||||
|
||||
bool has_extension(const std::string &ext) const;
|
||||
void require_extension_internal(const std::string &ext);
|
||||
|
||||
// Virtualize methods which need to be overridden by subclass targets like C++ and such.
|
||||
virtual void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags);
|
||||
|
||||
SPIRBlock *current_emitting_block = nullptr;
|
||||
SPIRBlock *current_emitting_switch = nullptr;
|
||||
bool current_emitting_switch_fallthrough = false;
|
||||
|
||||
virtual void emit_instruction(const Instruction &instr);
|
||||
void emit_block_instructions(SPIRBlock &block);
|
||||
virtual void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
|
||||
uint32_t count);
|
||||
virtual void emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t result_id, uint32_t op,
|
||||
const uint32_t *args, uint32_t count);
|
||||
virtual void emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t result_id, uint32_t op,
|
||||
const uint32_t *args, uint32_t count);
|
||||
virtual void emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t result_id, uint32_t op,
|
||||
const uint32_t *args, uint32_t count);
|
||||
virtual void emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
|
||||
uint32_t count);
|
||||
virtual void emit_header();
|
||||
void emit_line_directive(uint32_t file_id, uint32_t line_literal);
|
||||
void build_workgroup_size(SmallVector<std::string> &arguments, const SpecializationConstant &x,
|
||||
const SpecializationConstant &y, const SpecializationConstant &z);
|
||||
|
||||
void request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature);
|
||||
|
||||
virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
|
||||
virtual void emit_texture_op(const Instruction &i, bool sparse);
|
||||
virtual std::string to_texture_op(const Instruction &i, bool sparse, bool *forward,
|
||||
SmallVector<uint32_t> &inherited_expressions);
|
||||
virtual void emit_subgroup_op(const Instruction &i);
|
||||
virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0);
|
||||
virtual std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage);
|
||||
virtual void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const std::string &qualifier = "", uint32_t base_offset = 0);
|
||||
virtual void emit_struct_padding_target(const SPIRType &type);
|
||||
virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0);
|
||||
std::string constant_expression(const SPIRConstant &c);
|
||||
std::string constant_op_expression(const SPIRConstantOp &cop);
|
||||
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
|
||||
virtual void emit_fixup();
|
||||
virtual std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0);
|
||||
virtual bool variable_decl_is_remapped_storage(const SPIRVariable &var, spv::StorageClass storage) const;
|
||||
virtual std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id);
|
||||
|
||||
struct TextureFunctionBaseArguments
|
||||
{
|
||||
// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor.
|
||||
TextureFunctionBaseArguments() = default;
|
||||
VariableID img = 0;
|
||||
const SPIRType *imgtype = nullptr;
|
||||
bool is_fetch = false, is_gather = false, is_proj = false;
|
||||
};
|
||||
|
||||
struct TextureFunctionNameArguments
|
||||
{
|
||||
// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor.
|
||||
TextureFunctionNameArguments() = default;
|
||||
TextureFunctionBaseArguments base;
|
||||
bool has_array_offsets = false, has_offset = false, has_grad = false;
|
||||
bool has_dref = false, is_sparse_feedback = false, has_min_lod = false;
|
||||
uint32_t lod = 0;
|
||||
};
|
||||
virtual std::string to_function_name(const TextureFunctionNameArguments &args);
|
||||
|
||||
struct TextureFunctionArguments
|
||||
{
|
||||
// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor.
|
||||
TextureFunctionArguments() = default;
|
||||
TextureFunctionBaseArguments base;
|
||||
uint32_t coord = 0, coord_components = 0, dref = 0;
|
||||
uint32_t grad_x = 0, grad_y = 0, lod = 0, coffset = 0, offset = 0;
|
||||
uint32_t bias = 0, component = 0, sample = 0, sparse_texel = 0, min_lod = 0;
|
||||
bool nonuniform_expression = false;
|
||||
};
|
||||
virtual std::string to_function_args(const TextureFunctionArguments &args, bool *p_forward);
|
||||
|
||||
void emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id,
|
||||
uint32_t &texel_id);
|
||||
uint32_t get_sparse_feedback_texel_id(uint32_t id) const;
|
||||
virtual void emit_buffer_block(const SPIRVariable &type);
|
||||
virtual void emit_push_constant_block(const SPIRVariable &var);
|
||||
virtual void emit_uniform(const SPIRVariable &var);
|
||||
virtual std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id,
|
||||
bool packed_type, bool row_major);
|
||||
|
||||
virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const;
|
||||
|
||||
void emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id,
|
||||
SmallVector<uint32_t> chain);
|
||||
|
||||
StringStream<> buffer;
|
||||
|
||||
template <typename T>
|
||||
inline void statement_inner(T &&t)
|
||||
{
|
||||
buffer << std::forward<T>(t);
|
||||
statement_count++;
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
inline void statement_inner(T &&t, Ts &&... ts)
|
||||
{
|
||||
buffer << std::forward<T>(t);
|
||||
statement_count++;
|
||||
statement_inner(std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
inline void statement(Ts &&... ts)
|
||||
{
|
||||
if (is_forcing_recompilation())
|
||||
{
|
||||
// Do not bother emitting code while force_recompile is active.
|
||||
// We will compile again.
|
||||
statement_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (redirect_statement)
|
||||
{
|
||||
redirect_statement->push_back(join(std::forward<Ts>(ts)...));
|
||||
statement_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < indent; i++)
|
||||
buffer << " ";
|
||||
statement_inner(std::forward<Ts>(ts)...);
|
||||
buffer << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
inline void statement_no_indent(Ts &&... ts)
|
||||
{
|
||||
auto old_indent = indent;
|
||||
indent = 0;
|
||||
statement(std::forward<Ts>(ts)...);
|
||||
indent = old_indent;
|
||||
}
|
||||
|
||||
// Used for implementing continue blocks where
|
||||
// we want to obtain a list of statements we can merge
|
||||
// on a single line separated by comma.
|
||||
SmallVector<std::string> *redirect_statement = nullptr;
|
||||
const SPIRBlock *current_continue_block = nullptr;
|
||||
|
||||
void begin_scope();
|
||||
void end_scope();
|
||||
void end_scope(const std::string &trailer);
|
||||
void end_scope_decl();
|
||||
void end_scope_decl(const std::string &decl);
|
||||
|
||||
Options options;
|
||||
|
||||
virtual std::string type_to_array_glsl(
|
||||
const SPIRType &type); // Allow Metal to use the array<T> template to make arrays a value type
|
||||
std::string to_array_size(const SPIRType &type, uint32_t index);
|
||||
uint32_t to_array_size_literal(const SPIRType &type, uint32_t index) const;
|
||||
uint32_t to_array_size_literal(const SPIRType &type) const;
|
||||
virtual std::string variable_decl(const SPIRVariable &variable); // Threadgroup arrays can't have a wrapper type
|
||||
std::string variable_decl_function_local(SPIRVariable &variable);
|
||||
|
||||
void add_local_variable_name(uint32_t id);
|
||||
void add_resource_name(uint32_t id);
|
||||
void add_member_name(SPIRType &type, uint32_t name);
|
||||
void add_function_overload(const SPIRFunction &func);
|
||||
|
||||
virtual bool is_non_native_row_major_matrix(uint32_t id);
|
||||
virtual bool member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index);
|
||||
bool member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const;
|
||||
bool member_is_packed_physical_type(const SPIRType &type, uint32_t index) const;
|
||||
virtual std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type,
|
||||
uint32_t physical_type_id, bool is_packed);
|
||||
|
||||
std::unordered_set<std::string> local_variable_names;
|
||||
std::unordered_set<std::string> resource_names;
|
||||
std::unordered_set<std::string> block_input_names;
|
||||
std::unordered_set<std::string> block_output_names;
|
||||
std::unordered_set<std::string> block_ubo_names;
|
||||
std::unordered_set<std::string> block_ssbo_names;
|
||||
std::unordered_set<std::string> block_names; // A union of all block_*_names.
|
||||
std::unordered_map<std::string, std::unordered_set<uint64_t>> function_overloads;
|
||||
std::unordered_map<uint32_t, std::string> preserved_aliases;
|
||||
void preserve_alias_on_reset(uint32_t id);
|
||||
void reset_name_caches();
|
||||
|
||||
bool processing_entry_point = false;
|
||||
|
||||
// Can be overriden by subclass backends for trivial things which
|
||||
// shouldn't need polymorphism.
|
||||
struct BackendVariations
|
||||
{
|
||||
std::string discard_literal = "discard";
|
||||
std::string demote_literal = "demote";
|
||||
std::string null_pointer_literal = "";
|
||||
bool float_literal_suffix = false;
|
||||
bool double_literal_suffix = true;
|
||||
bool uint32_t_literal_suffix = true;
|
||||
bool long_long_literal_suffix = false;
|
||||
const char *basic_int_type = "int";
|
||||
const char *basic_uint_type = "uint";
|
||||
const char *basic_int8_type = "int8_t";
|
||||
const char *basic_uint8_type = "uint8_t";
|
||||
const char *basic_int16_type = "int16_t";
|
||||
const char *basic_uint16_type = "uint16_t";
|
||||
const char *int16_t_literal_suffix = "s";
|
||||
const char *uint16_t_literal_suffix = "us";
|
||||
const char *nonuniform_qualifier = "nonuniformEXT";
|
||||
const char *boolean_mix_function = "mix";
|
||||
bool swizzle_is_function = false;
|
||||
bool shared_is_implied = false;
|
||||
bool unsized_array_supported = true;
|
||||
bool explicit_struct_type = false;
|
||||
bool use_initializer_list = false;
|
||||
bool use_typed_initializer_list = false;
|
||||
bool can_declare_struct_inline = true;
|
||||
bool can_declare_arrays_inline = true;
|
||||
bool native_row_major_matrix = true;
|
||||
bool use_constructor_splatting = true;
|
||||
bool allow_precision_qualifiers = false;
|
||||
bool can_swizzle_scalar = false;
|
||||
bool force_gl_in_out_block = false;
|
||||
bool can_return_array = true;
|
||||
bool allow_truncated_access_chain = false;
|
||||
bool supports_extensions = false;
|
||||
bool supports_empty_struct = false;
|
||||
bool array_is_value_type = true;
|
||||
bool buffer_offset_array_is_value_type = true;
|
||||
bool comparison_image_samples_scalar = false;
|
||||
bool native_pointers = false;
|
||||
bool support_small_type_sampling_result = false;
|
||||
bool support_case_fallthrough = true;
|
||||
bool use_array_constructor = false;
|
||||
bool needs_row_major_load_workaround = false;
|
||||
bool support_pointer_to_pointer = false;
|
||||
} backend;
|
||||
|
||||
void emit_struct(SPIRType &type);
|
||||
void emit_resources();
|
||||
void emit_extension_workarounds(spv::ExecutionModel model);
|
||||
void emit_buffer_block_native(const SPIRVariable &var);
|
||||
void emit_buffer_reference_block(SPIRType &type, bool forward_declaration);
|
||||
void emit_buffer_block_legacy(const SPIRVariable &var);
|
||||
void emit_buffer_block_flattened(const SPIRVariable &type);
|
||||
void fixup_implicit_builtin_block_names();
|
||||
void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
|
||||
bool should_force_emit_builtin_block(spv::StorageClass storage);
|
||||
void emit_push_constant_block_vulkan(const SPIRVariable &var);
|
||||
void emit_push_constant_block_glsl(const SPIRVariable &var);
|
||||
void emit_interface_block(const SPIRVariable &type);
|
||||
void emit_flattened_io_block(const SPIRVariable &var, const char *qual);
|
||||
void emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual,
|
||||
const SmallVector<uint32_t> &indices);
|
||||
void emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual,
|
||||
const SmallVector<uint32_t> &indices);
|
||||
void emit_block_chain(SPIRBlock &block);
|
||||
void emit_hoisted_temporaries(SmallVector<std::pair<TypeID, ID>> &temporaries);
|
||||
std::string constant_value_macro_name(uint32_t id);
|
||||
void emit_constant(const SPIRConstant &constant);
|
||||
void emit_specialization_constant_op(const SPIRConstantOp &constant);
|
||||
std::string emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block);
|
||||
bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method);
|
||||
|
||||
void branch(BlockID from, BlockID to);
|
||||
void branch_to_continue(BlockID from, BlockID to);
|
||||
void branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block);
|
||||
void flush_phi(BlockID from, BlockID to);
|
||||
void flush_variable_declaration(uint32_t id);
|
||||
void flush_undeclared_variables(SPIRBlock &block);
|
||||
void emit_variable_temporary_copies(const SPIRVariable &var);
|
||||
|
||||
bool should_dereference(uint32_t id);
|
||||
bool should_forward(uint32_t id) const;
|
||||
bool should_suppress_usage_tracking(uint32_t id) const;
|
||||
void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp);
|
||||
void emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op);
|
||||
bool to_trivial_mix_op(const SPIRType &type, std::string &op, uint32_t left, uint32_t right, uint32_t lerp);
|
||||
void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
||||
uint32_t op3, const char *op);
|
||||
void emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
||||
const char *op);
|
||||
void emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
|
||||
void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
|
||||
void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, const char *op);
|
||||
|
||||
void emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
|
||||
SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type);
|
||||
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
|
||||
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
|
||||
void emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
||||
const char *op, SPIRType::BaseType input_type);
|
||||
void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
||||
const char *op, SPIRType::BaseType input_type);
|
||||
void emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
||||
uint32_t op2, const char *op, SPIRType::BaseType expected_result_type,
|
||||
SPIRType::BaseType input_type0, SPIRType::BaseType input_type1,
|
||||
SPIRType::BaseType input_type2);
|
||||
void emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
||||
uint32_t op3, const char *op, SPIRType::BaseType offset_count_type);
|
||||
|
||||
void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
|
||||
void emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op);
|
||||
void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
|
||||
void emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
|
||||
bool negate, SPIRType::BaseType expected_type);
|
||||
void emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
|
||||
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
|
||||
|
||||
SPIRType binary_op_bitcast_helper(std::string &cast_op0, std::string &cast_op1, SPIRType::BaseType &input_type,
|
||||
uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type);
|
||||
|
||||
virtual bool emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0);
|
||||
|
||||
std::string to_ternary_expression(const SPIRType &result_type, uint32_t select, uint32_t true_value,
|
||||
uint32_t false_value);
|
||||
|
||||
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
|
||||
bool expression_is_forwarded(uint32_t id) const;
|
||||
bool expression_suppresses_usage_tracking(uint32_t id) const;
|
||||
bool expression_read_implies_multiple_reads(uint32_t id) const;
|
||||
SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
|
||||
bool suppress_usage_tracking = false);
|
||||
|
||||
void access_chain_internal_append_index(std::string &expr, uint32_t base, const SPIRType *type,
|
||||
AccessChainFlags flags, bool &access_chain_is_arrayed, uint32_t index);
|
||||
|
||||
std::string access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, AccessChainFlags flags,
|
||||
AccessChainMeta *meta);
|
||||
|
||||
spv::StorageClass get_expression_effective_storage_class(uint32_t ptr);
|
||||
virtual bool access_chain_needs_stage_io_builtin_translation(uint32_t base);
|
||||
|
||||
virtual void prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type,
|
||||
spv::StorageClass storage, bool &is_packed);
|
||||
|
||||
std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
|
||||
AccessChainMeta *meta = nullptr, bool ptr_chain = false);
|
||||
|
||||
std::string flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||
const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
|
||||
uint32_t array_stride, bool need_transpose);
|
||||
std::string flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||
const SPIRType &target_type, uint32_t offset);
|
||||
std::string flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||
const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
|
||||
bool need_transpose);
|
||||
std::string flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||
const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
|
||||
bool need_transpose);
|
||||
std::pair<std::string, uint32_t> flattened_access_chain_offset(const SPIRType &basetype, const uint32_t *indices,
|
||||
uint32_t count, uint32_t offset,
|
||||
uint32_t word_stride, bool *need_transpose = nullptr,
|
||||
uint32_t *matrix_stride = nullptr,
|
||||
uint32_t *array_stride = nullptr,
|
||||
bool ptr_chain = false);
|
||||
|
||||
const char *index_to_swizzle(uint32_t index);
|
||||
std::string remap_swizzle(const SPIRType &result_type, uint32_t input_components, const std::string &expr);
|
||||
std::string declare_temporary(uint32_t type, uint32_t id);
|
||||
void emit_uninitialized_temporary(uint32_t type, uint32_t id);
|
||||
SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id);
|
||||
void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
|
||||
std::string to_non_uniform_aware_expression(uint32_t id);
|
||||
std::string to_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset);
|
||||
std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type);
|
||||
std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_unpacked_row_major_matrix_expression(uint32_t id);
|
||||
std::string to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_dereferenced_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_pointer_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_enclosed_pointer_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_extract_component_expression(uint32_t id, uint32_t index);
|
||||
std::string to_extract_constant_composite_expression(uint32_t result_type, const SPIRConstant &c,
|
||||
const uint32_t *chain, uint32_t length);
|
||||
std::string enclose_expression(const std::string &expr);
|
||||
std::string dereference_expression(const SPIRType &expression_type, const std::string &expr);
|
||||
std::string address_of_expression(const std::string &expr);
|
||||
void strip_enclosed_expression(std::string &expr);
|
||||
std::string to_member_name(const SPIRType &type, uint32_t index);
|
||||
virtual std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain);
|
||||
std::string to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices);
|
||||
std::string type_to_glsl_constructor(const SPIRType &type);
|
||||
std::string argument_decl(const SPIRFunction::Parameter &arg);
|
||||
virtual std::string to_qualifiers_glsl(uint32_t id);
|
||||
void fixup_io_block_patch_qualifiers(const SPIRVariable &var);
|
||||
void emit_output_variable_initializer(const SPIRVariable &var);
|
||||
const char *to_precision_qualifiers_glsl(uint32_t id);
|
||||
virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var);
|
||||
const char *flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags);
|
||||
const char *format_to_glsl(spv::ImageFormat format);
|
||||
virtual std::string layout_for_member(const SPIRType &type, uint32_t index);
|
||||
virtual std::string to_interpolation_qualifiers(const Bitset &flags);
|
||||
std::string layout_for_variable(const SPIRVariable &variable);
|
||||
std::string to_combined_image_sampler(VariableID image_id, VariableID samp_id);
|
||||
virtual bool skip_argument(uint32_t id) const;
|
||||
virtual void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id,
|
||||
spv::StorageClass lhs_storage, spv::StorageClass rhs_storage);
|
||||
virtual void emit_block_hints(const SPIRBlock &block);
|
||||
virtual std::string to_initializer_expression(const SPIRVariable &var);
|
||||
virtual std::string to_zero_initialized_expression(uint32_t type_id);
|
||||
bool type_can_zero_initialize(const SPIRType &type) const;
|
||||
|
||||
bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
|
||||
uint32_t *failed_index = nullptr, uint32_t start_offset = 0,
|
||||
uint32_t end_offset = ~(0u));
|
||||
std::string buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout);
|
||||
|
||||
uint32_t type_to_packed_base_size(const SPIRType &type, BufferPackingStandard packing);
|
||||
uint32_t type_to_packed_alignment(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing);
|
||||
uint32_t type_to_packed_array_stride(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing);
|
||||
uint32_t type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing);
|
||||
uint32_t type_to_location_count(const SPIRType &type) const;
|
||||
|
||||
std::string bitcast_glsl(const SPIRType &result_type, uint32_t arg);
|
||||
virtual std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type);
|
||||
|
||||
std::string bitcast_expression(SPIRType::BaseType target_type, uint32_t arg);
|
||||
std::string bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type, const std::string &expr);
|
||||
|
||||
std::string build_composite_combiner(uint32_t result_type, const uint32_t *elems, uint32_t length);
|
||||
bool remove_duplicate_swizzle(std::string &op);
|
||||
bool remove_unity_swizzle(uint32_t base, std::string &op);
|
||||
|
||||
// Can modify flags to remote readonly/writeonly if image type
|
||||
// and force recompile.
|
||||
bool check_atomic_image(uint32_t id);
|
||||
|
||||
virtual void replace_illegal_names();
|
||||
void replace_illegal_names(const std::unordered_set<std::string> &keywords);
|
||||
virtual void emit_entry_point_declarations();
|
||||
|
||||
void replace_fragment_output(SPIRVariable &var);
|
||||
void replace_fragment_outputs();
|
||||
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t id);
|
||||
|
||||
uint32_t indent = 0;
|
||||
|
||||
std::unordered_set<uint32_t> emitted_functions;
|
||||
|
||||
// Ensure that we declare phi-variable copies even if the original declaration isn't deferred
|
||||
std::unordered_set<uint32_t> flushed_phi_variables;
|
||||
|
||||
std::unordered_set<uint32_t> flattened_buffer_blocks;
|
||||
std::unordered_map<uint32_t, bool> flattened_structs;
|
||||
|
||||
ShaderSubgroupSupportHelper shader_subgroup_supporter;
|
||||
|
||||
std::string load_flattened_struct(const std::string &basename, const SPIRType &type);
|
||||
std::string to_flattened_struct_member(const std::string &basename, const SPIRType &type, uint32_t index);
|
||||
void store_flattened_struct(uint32_t lhs_id, uint32_t value);
|
||||
void store_flattened_struct(const std::string &basename, uint32_t rhs, const SPIRType &type,
|
||||
const SmallVector<uint32_t> &indices);
|
||||
std::string to_flattened_access_chain_expression(uint32_t id);
|
||||
|
||||
// Usage tracking. If a temporary is used more than once, use the temporary instead to
|
||||
// avoid AST explosion when SPIRV is generated with pure SSA and doesn't write stuff to variables.
|
||||
std::unordered_map<uint32_t, uint32_t> expression_usage_counts;
|
||||
void track_expression_read(uint32_t id);
|
||||
|
||||
SmallVector<std::string> forced_extensions;
|
||||
SmallVector<std::string> header_lines;
|
||||
|
||||
// Used when expressions emit extra opcodes with their own unique IDs,
|
||||
// and we need to reuse the IDs across recompilation loops.
|
||||
// Currently used by NMin/Max/Clamp implementations.
|
||||
std::unordered_map<uint32_t, uint32_t> extra_sub_expressions;
|
||||
|
||||
SmallVector<TypeID> workaround_ubo_load_overload_types;
|
||||
void request_workaround_wrapper_overload(TypeID id);
|
||||
void rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr);
|
||||
|
||||
uint32_t statement_count = 0;
|
||||
|
||||
inline bool is_legacy() const
|
||||
{
|
||||
return (options.es && options.version < 300) || (!options.es && options.version < 130);
|
||||
}
|
||||
|
||||
inline bool is_legacy_es() const
|
||||
{
|
||||
return options.es && options.version < 300;
|
||||
}
|
||||
|
||||
inline bool is_legacy_desktop() const
|
||||
{
|
||||
return !options.es && options.version < 130;
|
||||
}
|
||||
|
||||
bool requires_transpose_2x2 = false;
|
||||
bool requires_transpose_3x3 = false;
|
||||
bool requires_transpose_4x4 = false;
|
||||
bool ray_tracing_is_khr = false;
|
||||
void ray_tracing_khr_fixup_locations();
|
||||
|
||||
bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure);
|
||||
void register_call_out_argument(uint32_t id);
|
||||
void register_impure_function_call();
|
||||
void register_control_dependent_expression(uint32_t expr);
|
||||
|
||||
// GL_EXT_shader_pixel_local_storage support.
|
||||
std::vector<PlsRemap> pls_inputs;
|
||||
std::vector<PlsRemap> pls_outputs;
|
||||
std::string pls_decl(const PlsRemap &variable);
|
||||
const char *to_pls_qualifiers_glsl(const SPIRVariable &variable);
|
||||
void emit_pls();
|
||||
void remap_pls_variables();
|
||||
|
||||
// GL_EXT_shader_framebuffer_fetch support.
|
||||
std::vector<std::pair<uint32_t, uint32_t>> subpass_to_framebuffer_fetch_attachment;
|
||||
std::unordered_set<uint32_t> inout_color_attachments;
|
||||
bool subpass_input_is_framebuffer_fetch(uint32_t id) const;
|
||||
void emit_inout_fragment_outputs_copy_to_subpass_inputs();
|
||||
const SPIRVariable *find_subpass_input_by_attachment_index(uint32_t index) const;
|
||||
const SPIRVariable *find_color_output_by_location(uint32_t location) const;
|
||||
|
||||
// A variant which takes two sets of name. The secondary is only used to verify there are no collisions,
|
||||
// but the set is not updated when we have found a new name.
|
||||
// Used primarily when adding block interface names.
|
||||
void add_variable(std::unordered_set<std::string> &variables_primary,
|
||||
const std::unordered_set<std::string> &variables_secondary, std::string &name);
|
||||
|
||||
void check_function_call_constraints(const uint32_t *args, uint32_t length);
|
||||
void handle_invalid_expression(uint32_t id);
|
||||
void find_static_extensions();
|
||||
|
||||
std::string emit_for_loop_initializers(const SPIRBlock &block);
|
||||
void emit_while_loop_initializers(const SPIRBlock &block);
|
||||
bool for_loop_initializers_are_same_type(const SPIRBlock &block);
|
||||
bool optimize_read_modify_write(const SPIRType &type, const std::string &lhs, const std::string &rhs);
|
||||
void fixup_image_load_store_access();
|
||||
|
||||
bool type_is_empty(const SPIRType &type);
|
||||
|
||||
virtual void declare_undefined_values();
|
||||
|
||||
bool can_use_io_location(spv::StorageClass storage, bool block);
|
||||
const Instruction *get_next_instruction_in_block(const Instruction &instr);
|
||||
static uint32_t mask_relevant_memory_semantics(uint32_t semantics);
|
||||
|
||||
std::string convert_half_to_string(const SPIRConstant &value, uint32_t col, uint32_t row);
|
||||
std::string convert_float_to_string(const SPIRConstant &value, uint32_t col, uint32_t row);
|
||||
std::string convert_double_to_string(const SPIRConstant &value, uint32_t col, uint32_t row);
|
||||
|
||||
std::string convert_separate_image_to_expression(uint32_t id);
|
||||
|
||||
// Builtins in GLSL are always specific signedness, but the SPIR-V can declare them
|
||||
// as either unsigned or signed.
|
||||
// Sometimes we will need to automatically perform casts on load and store to make this work.
|
||||
virtual void cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type);
|
||||
virtual void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type);
|
||||
void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr);
|
||||
bool unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id);
|
||||
void convert_non_uniform_expression(std::string &expr, uint32_t ptr_id);
|
||||
|
||||
void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id);
|
||||
void disallow_forwarding_in_expression_chain(const SPIRExpression &expr);
|
||||
|
||||
bool expression_is_constant_null(uint32_t id) const;
|
||||
bool expression_is_non_value_type_array(uint32_t ptr);
|
||||
virtual void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression);
|
||||
|
||||
uint32_t get_integer_width_for_instruction(const Instruction &instr) const;
|
||||
uint32_t get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *arguments, uint32_t length) const;
|
||||
|
||||
bool variable_is_lut(const SPIRVariable &var) const;
|
||||
|
||||
char current_locale_radix_character = '.';
|
||||
|
||||
void fixup_type_alias();
|
||||
void reorder_type_alias();
|
||||
|
||||
static const char *vector_swizzle(int vecsize, int index);
|
||||
|
||||
bool is_stage_output_location_masked(uint32_t location, uint32_t component) const;
|
||||
bool is_stage_output_builtin_masked(spv::BuiltIn builtin) const;
|
||||
bool is_stage_output_variable_masked(const SPIRVariable &var) const;
|
||||
bool is_stage_output_block_member_masked(const SPIRVariable &var, uint32_t index, bool strip_array) const;
|
||||
uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const;
|
||||
uint32_t get_declared_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const;
|
||||
std::unordered_set<LocationComponentPair, InternalHasher> masked_output_locations;
|
||||
std::unordered_set<uint32_t> masked_output_builtins;
|
||||
|
||||
private:
|
||||
void init();
|
||||
};
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright 2016-2021 Robert Konrad
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_HLSL_HPP
|
||||
|
||||
#include "spirv_glsl.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
// Interface which remaps vertex inputs to a fixed semantic name to make linking easier.
|
||||
struct HLSLVertexAttributeRemap
|
||||
{
|
||||
uint32_t location;
|
||||
std::string semantic;
|
||||
};
|
||||
// Specifying a root constant (d3d12) or push constant range (vulkan).
|
||||
//
|
||||
// `start` and `end` denotes the range of the root constant in bytes.
|
||||
// Both values need to be multiple of 4.
|
||||
struct RootConstants
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
|
||||
uint32_t binding;
|
||||
uint32_t space;
|
||||
};
|
||||
|
||||
// For finer control, decorations may be removed from specific resources instead with unset_decoration().
|
||||
enum HLSLBindingFlagBits
|
||||
{
|
||||
HLSL_BINDING_AUTO_NONE_BIT = 0,
|
||||
|
||||
// Push constant (root constant) resources will be declared as CBVs (b-space) without a register() declaration.
|
||||
// A register will be automatically assigned by the D3D compiler, but must therefore be reflected in D3D-land.
|
||||
// Push constants do not normally have a DecorationBinding set, but if they do, this can be used to ignore it.
|
||||
HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0,
|
||||
|
||||
// cbuffer resources will be declared as CBVs (b-space) without a register() declaration.
|
||||
// A register will be automatically assigned, but must be reflected in D3D-land.
|
||||
HLSL_BINDING_AUTO_CBV_BIT = 1 << 1,
|
||||
|
||||
// All SRVs (t-space) will be declared without a register() declaration.
|
||||
HLSL_BINDING_AUTO_SRV_BIT = 1 << 2,
|
||||
|
||||
// All UAVs (u-space) will be declared without a register() declaration.
|
||||
HLSL_BINDING_AUTO_UAV_BIT = 1 << 3,
|
||||
|
||||
// All samplers (s-space) will be declared without a register() declaration.
|
||||
HLSL_BINDING_AUTO_SAMPLER_BIT = 1 << 4,
|
||||
|
||||
// No resources will be declared with register().
|
||||
HLSL_BINDING_AUTO_ALL = 0x7fffffff
|
||||
};
|
||||
using HLSLBindingFlags = uint32_t;
|
||||
|
||||
// By matching stage, desc_set and binding for a SPIR-V resource,
|
||||
// register bindings are set based on whether the HLSL resource is a
|
||||
// CBV, UAV, SRV or Sampler. A single binding in SPIR-V might contain multiple
|
||||
// resource types, e.g. COMBINED_IMAGE_SAMPLER, and SRV/Sampler bindings will be used respectively.
|
||||
// On SM 5.0 and lower, register_space is ignored.
|
||||
//
|
||||
// To remap a push constant block which does not have any desc_set/binding associated with it,
|
||||
// use ResourceBindingPushConstant{DescriptorSet,Binding} as values for desc_set/binding.
|
||||
// For deeper control of push constants, set_root_constant_layouts() can be used instead.
|
||||
struct HLSLResourceBinding
|
||||
{
|
||||
spv::ExecutionModel stage = spv::ExecutionModelMax;
|
||||
uint32_t desc_set = 0;
|
||||
uint32_t binding = 0;
|
||||
|
||||
struct Binding
|
||||
{
|
||||
uint32_t register_space = 0;
|
||||
uint32_t register_binding = 0;
|
||||
} cbv, uav, srv, sampler;
|
||||
};
|
||||
|
||||
class CompilerHLSL : public CompilerGLSL
|
||||
{
|
||||
public:
|
||||
struct Options
|
||||
{
|
||||
uint32_t shader_model = 30; // TODO: map ps_4_0_level_9_0,... somehow
|
||||
|
||||
// Allows the PointSize builtin, and ignores it, as PointSize is not supported in HLSL.
|
||||
bool point_size_compat = false;
|
||||
|
||||
// Allows the PointCoord builtin, returns float2(0.5, 0.5), as PointCoord is not supported in HLSL.
|
||||
bool point_coord_compat = false;
|
||||
|
||||
// If true, the backend will assume that VertexIndex and InstanceIndex will need to apply
|
||||
// a base offset, and you will need to fill in a cbuffer with offsets.
|
||||
// Set to false if you know you will never use base instance or base vertex
|
||||
// functionality as it might remove an internal cbuffer.
|
||||
bool support_nonzero_base_vertex_base_instance = false;
|
||||
|
||||
// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used.
|
||||
// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead.
|
||||
// Alternatively, use set_hlsl_force_storage_buffer_as_uav to specify individually.
|
||||
bool force_storage_buffer_as_uav = false;
|
||||
|
||||
// Forces any storage image type marked as NonWritable to be considered an SRV instead.
|
||||
// For this to work with function call parameters, NonWritable must be considered to be part of the type system
|
||||
// so that NonWritable image arguments are also translated to Texture rather than RWTexture.
|
||||
bool nonwritable_uav_texture_as_srv = false;
|
||||
|
||||
// Enables native 16-bit types. Needs SM 6.2.
|
||||
// Uses half/int16_t/uint16_t instead of min16* types.
|
||||
// Also adds support for 16-bit load-store from (RW)ByteAddressBuffer.
|
||||
bool enable_16bit_types = false;
|
||||
|
||||
// If matrices are used as IO variables, flatten the attribute declaration to use
|
||||
// TEXCOORD{N,N+1,N+2,...} rather than TEXCOORDN_{0,1,2,3}.
|
||||
// If add_vertex_attribute_remap is used and this feature is used,
|
||||
// the semantic name will be queried once per active location.
|
||||
bool flatten_matrix_vertex_input_semantics = false;
|
||||
};
|
||||
|
||||
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
|
||||
: CompilerGLSL(std::move(spirv_))
|
||||
{
|
||||
}
|
||||
|
||||
CompilerHLSL(const uint32_t *ir_, size_t size)
|
||||
: CompilerGLSL(ir_, size)
|
||||
{
|
||||
}
|
||||
|
||||
explicit CompilerHLSL(const ParsedIR &ir_)
|
||||
: CompilerGLSL(ir_)
|
||||
{
|
||||
}
|
||||
|
||||
explicit CompilerHLSL(ParsedIR &&ir_)
|
||||
: CompilerGLSL(std::move(ir_))
|
||||
{
|
||||
}
|
||||
|
||||
const Options &get_hlsl_options() const
|
||||
{
|
||||
return hlsl_options;
|
||||
}
|
||||
|
||||
void set_hlsl_options(const Options &opts)
|
||||
{
|
||||
hlsl_options = opts;
|
||||
}
|
||||
|
||||
// Optionally specify a custom root constant layout.
|
||||
//
|
||||
// Push constants ranges will be split up according to the
|
||||
// layout specified.
|
||||
void set_root_constant_layouts(std::vector<RootConstants> layout);
|
||||
|
||||
// Compiles and remaps vertex attributes at specific locations to a fixed semantic.
|
||||
// The default is TEXCOORD# where # denotes location.
|
||||
// Matrices are unrolled to vectors with notation ${SEMANTIC}_#, where # denotes row.
|
||||
// $SEMANTIC is either TEXCOORD# or a semantic name specified here.
|
||||
void add_vertex_attribute_remap(const HLSLVertexAttributeRemap &vertex_attributes);
|
||||
std::string compile() override;
|
||||
|
||||
// This is a special HLSL workaround for the NumWorkGroups builtin.
|
||||
// This does not exist in HLSL, so the calling application must create a dummy cbuffer in
|
||||
// which the application will store this builtin.
|
||||
// The cbuffer layout will be:
|
||||
// cbuffer SPIRV_Cross_NumWorkgroups : register(b#, space#) { uint3 SPIRV_Cross_NumWorkgroups_count; };
|
||||
// This must be called before compile().
|
||||
// The function returns 0 if NumWorkGroups builtin is not statically used in the shader from the current entry point.
|
||||
// If non-zero, this returns the variable ID of a cbuffer which corresponds to
|
||||
// the cbuffer declared above. By default, no binding or descriptor set decoration is set,
|
||||
// so the calling application should declare explicit bindings on this ID before calling compile().
|
||||
VariableID remap_num_workgroups_builtin();
|
||||
|
||||
// Controls how resource bindings are declared in the output HLSL.
|
||||
void set_resource_binding_flags(HLSLBindingFlags flags);
|
||||
|
||||
// resource is a resource binding to indicate the HLSL CBV, SRV, UAV or sampler binding
|
||||
// to use for a particular SPIR-V description set
|
||||
// and binding. If resource bindings are provided,
|
||||
// is_hlsl_resource_binding_used() will return true after calling ::compile() if
|
||||
// the set/binding combination was used by the HLSL code.
|
||||
void add_hlsl_resource_binding(const HLSLResourceBinding &resource);
|
||||
bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
|
||||
|
||||
// Controls which storage buffer bindings will be forced to be declared as UAVs.
|
||||
void set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint32_t binding);
|
||||
|
||||
private:
|
||||
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
|
||||
std::string image_type_hlsl_modern(const SPIRType &type, uint32_t id);
|
||||
std::string image_type_hlsl_legacy(const SPIRType &type, uint32_t id);
|
||||
void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override;
|
||||
void emit_hlsl_entry_point();
|
||||
void emit_header() override;
|
||||
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_builtin_inputs_in_struct();
|
||||
void emit_builtin_outputs_in_struct();
|
||||
void emit_texture_op(const Instruction &i, bool sparse) override;
|
||||
void emit_instruction(const Instruction &instruction) override;
|
||||
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
|
||||
uint32_t count) override;
|
||||
void emit_buffer_block(const SPIRVariable &type) override;
|
||||
void emit_push_constant_block(const SPIRVariable &var) override;
|
||||
void emit_uniform(const SPIRVariable &var) override;
|
||||
void emit_modern_uniform(const SPIRVariable &var);
|
||||
void emit_legacy_uniform(const SPIRVariable &var);
|
||||
void emit_specialization_constants_and_structs();
|
||||
void emit_composite_constants();
|
||||
void emit_fixup() override;
|
||||
std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override;
|
||||
std::string layout_for_member(const SPIRType &type, uint32_t index) override;
|
||||
std::string to_interpolation_qualifiers(const Bitset &flags) override;
|
||||
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;
|
||||
bool emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0) override;
|
||||
std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override;
|
||||
std::string to_sampler_expression(uint32_t id);
|
||||
std::string to_resource_binding(const SPIRVariable &var);
|
||||
std::string to_resource_binding_sampler(const SPIRVariable &var);
|
||||
std::string to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t set);
|
||||
std::string to_initializer_expression(const SPIRVariable &var) 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_access_chain(const Instruction &instruction);
|
||||
void emit_load(const Instruction &instruction);
|
||||
void read_access_chain(std::string *expr, const std::string &lhs, const SPIRAccessChain &chain);
|
||||
void read_access_chain_struct(const std::string &lhs, const SPIRAccessChain &chain);
|
||||
void read_access_chain_array(const std::string &lhs, const SPIRAccessChain &chain);
|
||||
void write_access_chain(const SPIRAccessChain &chain, uint32_t value, const SmallVector<uint32_t> &composite_chain);
|
||||
void write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value,
|
||||
const SmallVector<uint32_t> &composite_chain);
|
||||
void write_access_chain_array(const SPIRAccessChain &chain, uint32_t value,
|
||||
const SmallVector<uint32_t> &composite_chain);
|
||||
std::string write_access_chain_value(uint32_t value, const SmallVector<uint32_t> &composite_chain, bool enclose);
|
||||
void emit_store(const Instruction &instruction);
|
||||
void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op);
|
||||
void emit_subgroup_op(const Instruction &i) override;
|
||||
void emit_block_hints(const SPIRBlock &block) override;
|
||||
|
||||
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier,
|
||||
uint32_t base_offset = 0) override;
|
||||
|
||||
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
||||
void replace_illegal_names() override;
|
||||
|
||||
bool is_hlsl_force_storage_buffer_as_uav(ID id) const;
|
||||
|
||||
Options hlsl_options;
|
||||
|
||||
// TODO: Refactor this to be more similar to MSL, maybe have some common system in place?
|
||||
bool requires_op_fmod = false;
|
||||
bool requires_fp16_packing = false;
|
||||
bool requires_uint2_packing = false;
|
||||
bool requires_explicit_fp16_packing = false;
|
||||
bool requires_unorm8_packing = false;
|
||||
bool requires_snorm8_packing = false;
|
||||
bool requires_unorm16_packing = false;
|
||||
bool requires_snorm16_packing = false;
|
||||
bool requires_bitfield_insert = false;
|
||||
bool requires_bitfield_extract = false;
|
||||
bool requires_inverse_2x2 = false;
|
||||
bool requires_inverse_3x3 = false;
|
||||
bool requires_inverse_4x4 = false;
|
||||
bool requires_scalar_reflect = false;
|
||||
bool requires_scalar_refract = false;
|
||||
bool requires_scalar_faceforward = false;
|
||||
|
||||
struct TextureSizeVariants
|
||||
{
|
||||
// MSVC 2013 workaround.
|
||||
TextureSizeVariants()
|
||||
{
|
||||
srv = 0;
|
||||
for (auto &unorm : uav)
|
||||
for (auto &u : unorm)
|
||||
u = 0;
|
||||
}
|
||||
uint64_t srv;
|
||||
uint64_t uav[3][4];
|
||||
} required_texture_size_variants;
|
||||
|
||||
void require_texture_query_variant(uint32_t var_id);
|
||||
void emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav,
|
||||
const char *type_qualifier);
|
||||
|
||||
enum TextureQueryVariantDim
|
||||
{
|
||||
Query1D = 0,
|
||||
Query1DArray,
|
||||
Query2D,
|
||||
Query2DArray,
|
||||
Query3D,
|
||||
QueryBuffer,
|
||||
QueryCube,
|
||||
QueryCubeArray,
|
||||
Query2DMS,
|
||||
Query2DMSArray,
|
||||
QueryDimCount
|
||||
};
|
||||
|
||||
enum TextureQueryVariantType
|
||||
{
|
||||
QueryTypeFloat = 0,
|
||||
QueryTypeInt = 16,
|
||||
QueryTypeUInt = 32,
|
||||
QueryTypeCount = 3
|
||||
};
|
||||
|
||||
enum BitcastType
|
||||
{
|
||||
TypeNormal,
|
||||
TypePackUint2x32,
|
||||
TypeUnpackUint64
|
||||
};
|
||||
|
||||
BitcastType get_bitcast_type(uint32_t result_type, uint32_t op0);
|
||||
|
||||
void emit_builtin_variables();
|
||||
bool require_output = false;
|
||||
bool require_input = false;
|
||||
SmallVector<HLSLVertexAttributeRemap> remap_vertex_attributes;
|
||||
|
||||
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;
|
||||
HLSLBindingFlags resource_binding_flags = 0;
|
||||
|
||||
// Custom root constant layout, which should be emitted
|
||||
// when translating push constant ranges.
|
||||
std::vector<RootConstants> root_constants_layout;
|
||||
|
||||
void validate_shader_model();
|
||||
|
||||
std::string get_unique_identifier();
|
||||
uint32_t unique_identifier_count = 0;
|
||||
|
||||
std::unordered_map<StageSetBinding, std::pair<HLSLResourceBinding, bool>, InternalHasher> resource_bindings;
|
||||
void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding);
|
||||
|
||||
std::unordered_set<SetBindingPair, InternalHasher> force_uav_buffer_bindings;
|
||||
|
||||
// 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;
|
||||
};
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2018-2021 Arm Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_PARSER_HPP
|
||||
|
||||
#include "spirv_cross_parsed_ir.hpp"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
Parser(const uint32_t *spirv_data, size_t word_count);
|
||||
Parser(std::vector<uint32_t> spirv);
|
||||
|
||||
void parse();
|
||||
|
||||
ParsedIR &get_parsed_ir()
|
||||
{
|
||||
return ir;
|
||||
}
|
||||
|
||||
private:
|
||||
ParsedIR ir;
|
||||
SPIRFunction *current_function = nullptr;
|
||||
SPIRBlock *current_block = nullptr;
|
||||
|
||||
void parse(const Instruction &instr);
|
||||
const uint32_t *stream(const Instruction &instr) const;
|
||||
|
||||
template <typename T, typename... P>
|
||||
T &set(uint32_t id, P &&... args)
|
||||
{
|
||||
ir.add_typed_id(static_cast<Types>(T::type), id);
|
||||
auto &var = variant_set<T>(ir.ids[id], std::forward<P>(args)...);
|
||||
var.self = id;
|
||||
return var;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T &get(uint32_t id)
|
||||
{
|
||||
return variant_get<T>(ir.ids[id]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *maybe_get(uint32_t id)
|
||||
{
|
||||
if (ir.ids[id].get_type() == static_cast<Types>(T::type))
|
||||
return &get<T>(id);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T &get(uint32_t id) const
|
||||
{
|
||||
return variant_get<T>(ir.ids[id]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T *maybe_get(uint32_t id) const
|
||||
{
|
||||
if (ir.ids[id].get_type() == T::type)
|
||||
return &get<T>(id);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This must be an ordered data structure so we always pick the same type aliases.
|
||||
SmallVector<uint32_t> global_struct_cache;
|
||||
SmallVector<std::pair<uint32_t, uint32_t>> forward_pointer_fixups;
|
||||
|
||||
bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
|
||||
bool variable_storage_is_aliased(const SPIRVariable &v) const;
|
||||
};
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2018-2021 Bradley Austin Davis
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define SPIRV_CROSS_REFLECT_HPP
|
||||
|
||||
#include "spirv_glsl.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace simple_json
|
||||
{
|
||||
class Stream;
|
||||
}
|
||||
|
||||
namespace SPIRV_CROSS_NAMESPACE
|
||||
{
|
||||
class CompilerReflection : public CompilerGLSL
|
||||
{
|
||||
using Parent = CompilerGLSL;
|
||||
|
||||
public:
|
||||
explicit CompilerReflection(std::vector<uint32_t> spirv_)
|
||||
: Parent(std::move(spirv_))
|
||||
{
|
||||
options.vulkan_semantics = true;
|
||||
}
|
||||
|
||||
CompilerReflection(const uint32_t *ir_, size_t word_count)
|
||||
: Parent(ir_, word_count)
|
||||
{
|
||||
options.vulkan_semantics = true;
|
||||
}
|
||||
|
||||
explicit CompilerReflection(const ParsedIR &ir_)
|
||||
: CompilerGLSL(ir_)
|
||||
{
|
||||
options.vulkan_semantics = true;
|
||||
}
|
||||
|
||||
explicit CompilerReflection(ParsedIR &&ir_)
|
||||
: CompilerGLSL(std::move(ir_))
|
||||
{
|
||||
options.vulkan_semantics = true;
|
||||
}
|
||||
|
||||
void set_format(const std::string &format);
|
||||
std::string compile() override;
|
||||
|
||||
private:
|
||||
static std::string execution_model_to_str(spv::ExecutionModel model);
|
||||
|
||||
void emit_entry_points();
|
||||
void emit_types();
|
||||
void emit_resources();
|
||||
void emit_specialization_constants();
|
||||
|
||||
void emit_type(uint32_t type_id, bool &emitted_open_tag);
|
||||
void emit_type_member(const SPIRType &type, uint32_t index);
|
||||
void emit_type_member_qualifiers(const SPIRType &type, uint32_t index);
|
||||
void emit_type_array(const SPIRType &type);
|
||||
void emit_resources(const char *tag, const SmallVector<Resource> &resources);
|
||||
bool type_is_reference(const SPIRType &type) const;
|
||||
|
||||
std::string to_member_name(const SPIRType &type, uint32_t index) const;
|
||||
|
||||
std::shared_ptr<simple_json::Stream> json_stream;
|
||||
};
|
||||
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user