dep/reshadefx: Update to 7bdfb03
This commit is contained in:
@ -16,6 +16,8 @@ namespace reshadefx
|
||||
/// </summary>
|
||||
class codegen
|
||||
{
|
||||
friend class parser;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Virtual destructor to guarantee that memory of the implementations deriving from this interface is properly destroyed.
|
||||
@ -23,12 +25,21 @@ namespace reshadefx
|
||||
virtual ~codegen() {}
|
||||
|
||||
/// <summary>
|
||||
/// Writes result of the code generation to the specified <paramref name="module"/>.
|
||||
/// Gets the module describing the generated code.
|
||||
/// </summary>
|
||||
/// <param name="module">Target module to fill.</param>
|
||||
virtual void write_result(module &module) = 0;
|
||||
const effect_module &module() const { return _module; }
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Finalizes and returns the generated code for the entire module (all entry points).
|
||||
/// </summary>
|
||||
virtual std::basic_string<char> finalize_code() const = 0;
|
||||
/// <summary>
|
||||
/// Finalizes and returns the generated code for the specified entry point (and no other entry points).
|
||||
/// </summary>
|
||||
/// <param name="entry_point_name">Name of the entry point function to generate code for.</param>
|
||||
virtual std::basic_string<char> finalize_code_for_entry_point(const std::string &entry_point_name) const = 0;
|
||||
|
||||
protected:
|
||||
/// <summary>
|
||||
/// An opaque ID referring to a SSA value or basic block.
|
||||
/// </summary>
|
||||
@ -40,14 +51,14 @@ namespace reshadefx
|
||||
/// <param name="loc">Source location matching this definition (for debugging).</param>
|
||||
/// <param name="info">Description of the type.</param>
|
||||
/// <returns>New SSA ID of the type.</returns>
|
||||
virtual id define_struct(const location &loc, struct_info &info) = 0;
|
||||
virtual id define_struct(const location &loc, struct_type &info) = 0;
|
||||
/// <summary>
|
||||
/// Defines a new texture binding.
|
||||
/// </summary>
|
||||
/// <param name="loc">Source location matching this definition (for debugging).</param>
|
||||
/// <param name="info">Description of the texture object.</param>
|
||||
/// <returns>New SSA ID of the binding.</returns>
|
||||
virtual id define_texture(const location &loc, texture_info &info) = 0;
|
||||
virtual id define_texture(const location &loc, texture &info) = 0;
|
||||
/// <summary>
|
||||
/// Defines a new sampler binding.
|
||||
/// </summary>
|
||||
@ -55,7 +66,7 @@ namespace reshadefx
|
||||
/// <param name="tex_info">Description of the texture this sampler object references.</param>
|
||||
/// <param name="info">Description of the sampler object.</param>
|
||||
/// <returns>New SSA ID of the binding.</returns>
|
||||
virtual id define_sampler(const location &loc, const texture_info &tex_info, sampler_info &info) = 0;
|
||||
virtual id define_sampler(const location &loc, const texture &tex_info, sampler &info) = 0;
|
||||
/// <summary>
|
||||
/// Defines a new storage binding.
|
||||
/// </summary>
|
||||
@ -63,14 +74,14 @@ namespace reshadefx
|
||||
/// <param name="tex_info">Description of the texture this storage object references.</param>
|
||||
/// <param name="info">Description of the storage object.</param>
|
||||
/// <returns>New SSA ID of the binding.</returns>
|
||||
virtual id define_storage(const location &loc, const texture_info &tex_info, storage_info &info) = 0;
|
||||
virtual id define_storage(const location &loc, const texture &tex_info, storage &info) = 0;
|
||||
/// <summary>
|
||||
/// Defines a new uniform variable.
|
||||
/// </summary>
|
||||
/// <param name="loc">Source location matching this definition (for debugging).</param>
|
||||
/// <param name="info">Description of the uniform variable.</param>
|
||||
/// <returns>New SSA ID of the variable.</returns>
|
||||
virtual id define_uniform(const location &loc, uniform_info &info) = 0;
|
||||
virtual id define_uniform(const location &loc, uniform &info) = 0;
|
||||
/// <summary>
|
||||
/// Defines a new variable.
|
||||
/// </summary>
|
||||
@ -82,26 +93,25 @@ namespace reshadefx
|
||||
/// <returns>New SSA ID of the variable.</returns>
|
||||
virtual id define_variable(const location &loc, const type &type, std::string name = std::string(), bool global = false, id initializer_value = 0) = 0;
|
||||
/// <summary>
|
||||
/// Defines a new function and its function parameters and make it current. Any code added after this call is added to this function.
|
||||
/// Defines a new function and its function parameters and make it current.
|
||||
/// Any code added after this call is added to this function.
|
||||
/// </summary>
|
||||
/// <param name="loc">Source location matching this definition (for debugging).</param>
|
||||
/// <param name="info">Description of the function.</param>
|
||||
/// <returns>New SSA ID of the function.</returns>
|
||||
virtual id define_function(const location &loc, function_info &info) = 0;
|
||||
virtual id define_function(const location &loc, function &info) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Defines a new effect technique.
|
||||
/// </summary>
|
||||
/// <param name="loc">Source location matching this definition (for debugging).</param>
|
||||
/// <param name="info">Description of the technique.</param>
|
||||
void define_technique(technique_info &&info) { _module.techniques.push_back(std::move(info)); }
|
||||
void define_technique(technique &&info) { _module.techniques.push_back(std::move(info)); }
|
||||
/// <summary>
|
||||
/// Makes a function a shader entry point.
|
||||
/// </summary>
|
||||
/// <param name="function">Function to use as entry point. May be overwritten to point to a new unique function for this entry point.</param>
|
||||
/// <param name="type">Shader type (vertex, pixel or compute shader).</param>
|
||||
/// <param name="num_threads">Number of local threads it this is a compute entry point.</param>
|
||||
virtual void define_entry_point(function_info &function, shader_type type, int num_threads[3] = nullptr) = 0;
|
||||
/// <param name="function">Function to use as entry point. May be overwritten to point to a new uniquely generated function.</param>
|
||||
virtual void define_entry_point(function &function) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the access chain and add a load operation to the output.
|
||||
@ -131,6 +141,19 @@ namespace reshadefx
|
||||
/// <param name="data">Actual constant data to convert into a SSA ID.</param>
|
||||
/// <returns>New SSA ID with the constant value.</returns>
|
||||
virtual id emit_constant(const type &type, const constant &data) = 0;
|
||||
id emit_constant(const type &data_type, uint32_t value)
|
||||
{
|
||||
// Create a constant value of the specified type
|
||||
constant data = {}; // Initialize to zero, so that components not set below still have a defined value for lookup via std::memcmp
|
||||
for (unsigned int i = 0; i < data_type.components(); ++i)
|
||||
{
|
||||
if (data_type.is_integral())
|
||||
data.as_uint[i] = value;
|
||||
else
|
||||
data.as_float[i] = static_cast<float>(value);
|
||||
}
|
||||
return emit_constant(data_type, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an unary operation to the output (built-in operation with one argument).
|
||||
@ -222,7 +245,7 @@ namespace reshadefx
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if code is currently added to a function.
|
||||
/// </summary>
|
||||
virtual bool is_in_function() const { return is_in_block(); }
|
||||
bool is_in_function() const { return _current_function != nullptr; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new basic block.
|
||||
@ -272,93 +295,96 @@ namespace reshadefx
|
||||
/// <param name="false_target">ID of the basic block to jump to when the condition is false.</param>
|
||||
/// <returns>ID of the current basic block.</returns>
|
||||
virtual id leave_block_and_branch_conditional(id condition, id true_target, id false_target) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Leaves the current function. Any code added after this call is added in the global scope.
|
||||
/// </summary>
|
||||
virtual void leave_function() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Recalculates sampler and storage bindings to take as little binding space as possible for each entry point.
|
||||
/// </summary>
|
||||
virtual void optimize_bindings();
|
||||
|
||||
/// <summary>
|
||||
/// Looks up an existing struct type.
|
||||
/// </summary>
|
||||
/// <param name="id">SSA ID of the type to find.</param>
|
||||
/// <returns>Reference to the struct description.</returns>
|
||||
const struct_info &get_struct(id id) const
|
||||
const struct_type &get_struct(id id) const
|
||||
{
|
||||
return *std::find_if(_structs.begin(), _structs.end(),
|
||||
[id](const auto &it) { return it.definition == id; });
|
||||
[id](const struct_type &info) { return info.id == id; });
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up an existing texture binding.
|
||||
/// </summary>
|
||||
/// <param name="id">SSA ID of the texture binding to find.</param>
|
||||
/// <returns>Reference to the texture description.</returns>
|
||||
texture_info &get_texture(id id)
|
||||
texture &get_texture(id id)
|
||||
{
|
||||
return *std::find_if(_module.textures.begin(), _module.textures.end(),
|
||||
[id](const auto &it) { return it.id == id; });
|
||||
[id](const texture &info) { return info.id == id; });
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up an existing sampler binding.
|
||||
/// </summary>
|
||||
/// <param name="id">SSA ID of the sampler binding to find.</param>
|
||||
/// <returns>Reference to the sampler description.</returns>
|
||||
const sampler_info &get_sampler(id id) const
|
||||
const sampler &get_sampler(id id) const
|
||||
{
|
||||
return *std::find_if(_module.samplers.begin(), _module.samplers.end(),
|
||||
[id](const auto &it) { return it.id == id; });
|
||||
[id](const sampler &info) { return info.id == id; });
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up an existing storage binding.
|
||||
/// </summary>
|
||||
/// <param name="id">SSA ID of the storage binding to find.</param>
|
||||
/// <returns>Reference to the storage description.</returns>
|
||||
const storage_info &get_storage(id id) const
|
||||
const storage &get_storage(id id) const
|
||||
{
|
||||
return *std::find_if(_module.storages.begin(), _module.storages.end(),
|
||||
[id](const auto &it) { return it.id == id; });
|
||||
[id](const storage &info) { return info.id == id; });
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up an existing function definition.
|
||||
/// </summary>
|
||||
/// <param name="id">SSA ID of the function variable to find.</param>
|
||||
/// <returns>Reference to the function description.</returns>
|
||||
function_info &get_function(id id)
|
||||
function &get_function(id id)
|
||||
{
|
||||
return *std::find_if(_functions.begin(), _functions.end(),
|
||||
[id](const auto &it) { return it->definition == id; })->get();
|
||||
[id](const std::unique_ptr<function> &info) { return info->id == id; })->get();
|
||||
}
|
||||
function &get_function(const std::string &unique_name)
|
||||
{
|
||||
return *std::find_if(_functions.begin(), _functions.end(),
|
||||
[&unique_name](const std::unique_ptr<function> &info) { return info->unique_name == unique_name; })->get();
|
||||
}
|
||||
|
||||
protected:
|
||||
id make_id() { return _next_id++; }
|
||||
|
||||
static uint32_t align_up(uint32_t size, uint32_t alignment)
|
||||
{
|
||||
alignment -= 1;
|
||||
return ((size + alignment) & ~alignment);
|
||||
}
|
||||
static uint32_t align_up(uint32_t size, uint32_t alignment, uint32_t elements)
|
||||
{
|
||||
return align_up(size, alignment) * (elements - 1) + size;
|
||||
}
|
||||
effect_module _module;
|
||||
std::vector<struct_type> _structs;
|
||||
std::vector<std::unique_ptr<function>> _functions;
|
||||
|
||||
reshadefx::module _module;
|
||||
std::vector<struct_info> _structs;
|
||||
std::vector<std::unique_ptr<function_info>> _functions;
|
||||
id _next_id = 1;
|
||||
id _last_block = 0;
|
||||
id _current_block = 0;
|
||||
function *_current_function = nullptr;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a back-end implementation for GLSL code generation.
|
||||
/// </summary>
|
||||
/// <param name="version">GLSL version to insert at the beginning of the file.</param>
|
||||
/// <param name="gles">Generate GLSL ES code instead of core OpenGL.</param>
|
||||
/// <param name="vulkan_semantics">Generate GLSL for OpenGL or for Vulkan.</param>
|
||||
/// <param name="debug_info">Whether to append debug information like line directives to the generated code.</param>
|
||||
/// <param name="uniforms_to_spec_constants">Whether to convert uniform variables to specialization constants.</param>
|
||||
/// <param name="enable_16bit_types">Use real 16-bit types for the minimum precision types "min16int", "min16uint" and "min16float".</param>
|
||||
/// <param name="flip_vert_y">Insert code to flip the Y component of the output position in vertex shaders.</param>
|
||||
codegen *create_codegen_glsl(bool gles, bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types = false, bool flip_vert_y = false);
|
||||
codegen *create_codegen_glsl(unsigned version, bool gles, bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types = false, bool flip_vert_y = false);
|
||||
/// <summary>
|
||||
/// Creates a back-end implementation for HLSL code generation.
|
||||
/// </summary>
|
||||
|
||||
@ -15,7 +15,7 @@ namespace reshadefx
|
||||
/// </summary>
|
||||
struct type
|
||||
{
|
||||
enum datatype : uint8_t
|
||||
enum datatype : uint32_t
|
||||
{
|
||||
t_void,
|
||||
t_bool,
|
||||
@ -101,6 +101,8 @@ namespace reshadefx
|
||||
bool is_function() const { return base == t_function; }
|
||||
|
||||
bool is_array() const { return array_length != 0; }
|
||||
bool is_bounded_array() const { return is_array() && array_length != 0xFFFFFFFF; }
|
||||
bool is_unbounded_array() const { return array_length == 0xFFFFFFFF; }
|
||||
bool is_scalar() const { return is_numeric() && !is_matrix() && !is_vector() && !is_array(); }
|
||||
bool is_vector() const { return is_numeric() && rows > 1 && cols == 1; }
|
||||
bool is_matrix() const { return is_numeric() && rows >= 1 && cols > 1; }
|
||||
@ -109,27 +111,27 @@ namespace reshadefx
|
||||
unsigned int components() const { return rows * cols; }
|
||||
unsigned int texture_dimension() const { return base >= t_texture1d && base <= t_storage3d_float ? ((base - t_texture1d) % 3) + 1 : 0; }
|
||||
|
||||
friend inline bool operator==(const type &lhs, const type &rhs)
|
||||
friend bool operator==(const type &lhs, const type &rhs)
|
||||
{
|
||||
return lhs.base == rhs.base && lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.array_length == rhs.array_length && lhs.definition == rhs.definition;
|
||||
return lhs.base == rhs.base && lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.array_length == rhs.array_length && lhs.struct_definition == rhs.struct_definition;
|
||||
}
|
||||
friend inline bool operator!=(const type &lhs, const type &rhs)
|
||||
friend bool operator!=(const type &lhs, const type &rhs)
|
||||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
// Underlying base type ('int', 'float', ...)
|
||||
datatype base = t_void;
|
||||
datatype base : 8;
|
||||
// Number of rows if this is a vector type
|
||||
unsigned int rows = 0;
|
||||
uint32_t rows : 4;
|
||||
// Number of columns if this is a matrix type
|
||||
unsigned int cols = 0;
|
||||
uint32_t cols : 4;
|
||||
// Bit mask of all the qualifiers decorating the type
|
||||
unsigned int qualifiers = 0;
|
||||
// Negative if an unsized array, otherwise the number of elements if this is an array type
|
||||
int array_length = 0;
|
||||
uint32_t qualifiers : 16;
|
||||
// Number of elements if this is an array type, 0xFFFFFFFF if it is an unsized array
|
||||
uint32_t array_length;
|
||||
// ID of the matching struct if this is a struct type
|
||||
uint32_t definition = 0;
|
||||
uint32_t struct_definition;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@ -168,8 +170,8 @@ namespace reshadefx
|
||||
|
||||
op_type op;
|
||||
reshadefx::type from, to;
|
||||
uint32_t index = 0;
|
||||
signed char swizzle[4] = {};
|
||||
uint32_t index;
|
||||
signed char swizzle[4];
|
||||
};
|
||||
|
||||
uint32_t base = 0;
|
||||
|
||||
@ -7,14 +7,48 @@
|
||||
|
||||
#include "effect_expression.hpp"
|
||||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace reshadefx
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of supported texture types.
|
||||
/// Describes an annotation attached to a variable.
|
||||
/// </summary>
|
||||
enum class texture_type
|
||||
struct annotation
|
||||
{
|
||||
reshadefx::type type = {};
|
||||
std::string name;
|
||||
reshadefx::constant value = {};
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a struct member or parameter.
|
||||
/// </summary>
|
||||
struct member_type
|
||||
{
|
||||
reshadefx::type type = {};
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
std::string semantic;
|
||||
reshadefx::location location;
|
||||
bool has_default_value = false;
|
||||
reshadefx::constant default_value = {};
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a struct type defined in effect code.
|
||||
/// </summary>
|
||||
struct struct_type
|
||||
{
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
std::vector<member_type> member_list;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Available texture types.
|
||||
/// </summary>
|
||||
enum class texture_type : uint8_t
|
||||
{
|
||||
texture_1d = 1,
|
||||
texture_2d = 2,
|
||||
@ -22,9 +56,9 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A list of supported texture formats.
|
||||
/// Available texture formats.
|
||||
/// </summary>
|
||||
enum class texture_format
|
||||
enum class texture_format : uint8_t
|
||||
{
|
||||
unknown,
|
||||
|
||||
@ -46,9 +80,46 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A filtering type used for texture lookups.
|
||||
/// Describes the properties of a <see cref="texture"/> object.
|
||||
/// </summary>
|
||||
enum class filter_mode
|
||||
struct texture_desc
|
||||
{
|
||||
uint32_t width = 1;
|
||||
uint32_t height = 1;
|
||||
uint16_t depth = 1;
|
||||
uint16_t levels = 1;
|
||||
texture_type type = texture_type::texture_2d;
|
||||
texture_format format = texture_format::rgba8;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a texture object defined in effect code.
|
||||
/// </summary>
|
||||
struct texture : texture_desc
|
||||
{
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
std::string semantic;
|
||||
std::vector<annotation> annotations;
|
||||
bool render_target = false;
|
||||
bool storage_access = false;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes the binding of a <see cref="texture"/> object.
|
||||
/// </summary>
|
||||
struct texture_binding
|
||||
{
|
||||
uint32_t binding = 0;
|
||||
std::string texture_name;
|
||||
bool srgb = false;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Texture filtering modes available for texture sampling operations.
|
||||
/// </summary>
|
||||
enum class filter_mode : uint8_t
|
||||
{
|
||||
min_mag_mip_point = 0,
|
||||
min_mag_point_mip_linear = 0x1,
|
||||
@ -57,13 +128,14 @@ namespace reshadefx
|
||||
min_linear_mag_mip_point = 0x10,
|
||||
min_linear_mag_point_mip_linear = 0x11,
|
||||
min_mag_linear_mip_point = 0x14,
|
||||
min_mag_mip_linear = 0x15
|
||||
min_mag_mip_linear = 0x15,
|
||||
anisotropic = 0x55
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies behavior of sampling with texture coordinates outside an image.
|
||||
/// Sampling behavior at texture coordinates outside the bounds of a texture resource.
|
||||
/// </summary>
|
||||
enum class texture_address_mode
|
||||
enum class texture_address_mode : uint8_t
|
||||
{
|
||||
wrap = 1,
|
||||
mirror = 2,
|
||||
@ -72,9 +144,117 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies RGB or alpha blending operations.
|
||||
/// Describes the properties of a <see cref="sampler"/> object.
|
||||
/// </summary>
|
||||
enum class pass_blend_op : uint8_t
|
||||
struct sampler_desc
|
||||
{
|
||||
filter_mode filter = filter_mode::min_mag_mip_linear;
|
||||
texture_address_mode address_u = texture_address_mode::clamp;
|
||||
texture_address_mode address_v = texture_address_mode::clamp;
|
||||
texture_address_mode address_w = texture_address_mode::clamp;
|
||||
float min_lod = -3.402823466e+38f;
|
||||
float max_lod = +3.402823466e+38f; // FLT_MAX
|
||||
float lod_bias = 0.0f;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a texture sampler object defined in effect code.
|
||||
/// </summary>
|
||||
struct sampler : sampler_desc
|
||||
{
|
||||
reshadefx::type type = {};
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
std::string texture_name;
|
||||
std::vector<annotation> annotations;
|
||||
bool srgb = false;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes the binding of a <see cref="sampler"/> object.
|
||||
/// </summary>
|
||||
struct sampler_binding : sampler_desc
|
||||
{
|
||||
uint32_t binding = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes the properties of a <see cref="storage"/> object.
|
||||
/// </summary>
|
||||
struct storage_desc
|
||||
{
|
||||
uint16_t level = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a texture storage object defined in effect code.
|
||||
/// </summary>
|
||||
struct storage : storage_desc
|
||||
{
|
||||
reshadefx::type type = {};
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
std::string texture_name;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes the binding of a <see cref="storage"/> object.
|
||||
/// </summary>
|
||||
struct storage_binding : storage_desc
|
||||
{
|
||||
uint32_t binding = 0;
|
||||
std::string texture_name;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a uniform variable defined in effect code.
|
||||
/// </summary>
|
||||
struct uniform
|
||||
{
|
||||
reshadefx::type type = {};
|
||||
std::string name;
|
||||
uint32_t size = 0;
|
||||
uint32_t offset = 0;
|
||||
std::vector<annotation> annotations;
|
||||
bool has_initializer_value = false;
|
||||
reshadefx::constant initializer_value = {};
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Type of a shader entry point.
|
||||
/// </summary>
|
||||
enum class shader_type
|
||||
{
|
||||
unknown,
|
||||
vertex,
|
||||
pixel,
|
||||
compute
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes a function defined in effect code.
|
||||
/// </summary>
|
||||
struct function
|
||||
{
|
||||
reshadefx::type return_type = {};
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
std::string return_semantic;
|
||||
std::vector<member_type> parameter_list;
|
||||
shader_type type = shader_type::unknown;
|
||||
int num_threads[3] = {};
|
||||
std::vector<uint32_t> referenced_samplers;
|
||||
std::vector<uint32_t> referenced_storages;
|
||||
std::vector<uint32_t> referenced_functions;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Color or alpha blending operations.
|
||||
/// </summary>
|
||||
enum class blend_op : uint8_t
|
||||
{
|
||||
add = 1,
|
||||
subtract,
|
||||
@ -84,9 +264,9 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies blend factors, which modulate values between the pixel shader output and render target.
|
||||
/// Blend factors in color or alpha blending operations, which modulate values between the pixel shader output and render target.
|
||||
/// </summary>
|
||||
enum class pass_blend_factor : uint8_t
|
||||
enum class blend_factor : uint8_t
|
||||
{
|
||||
zero = 0,
|
||||
one = 1,
|
||||
@ -101,9 +281,9 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the stencil operations that can be performed during depth-stencil testing.
|
||||
/// Stencil operations that can be performed during depth-stencil testing.
|
||||
/// </summary>
|
||||
enum class pass_stencil_op : uint8_t
|
||||
enum class stencil_op : uint8_t
|
||||
{
|
||||
zero = 0,
|
||||
keep,
|
||||
@ -116,9 +296,9 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Specifies comparison options for depth-stencil testing.
|
||||
/// Comparison operations for depth-stencil testing.
|
||||
/// </summary>
|
||||
enum class pass_stencil_func : uint8_t
|
||||
enum class stencil_func : uint8_t
|
||||
{
|
||||
never,
|
||||
less,
|
||||
@ -143,205 +323,70 @@ namespace reshadefx
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A struct type defined in the effect code.
|
||||
/// Describes a render pass with all its state info.
|
||||
/// </summary>
|
||||
struct struct_info
|
||||
{
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
std::vector<struct struct_member_info> member_list;
|
||||
uint32_t definition = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A struct field defined in the effect code.
|
||||
/// </summary>
|
||||
struct struct_member_info
|
||||
{
|
||||
reshadefx::type type;
|
||||
std::string name;
|
||||
std::string semantic;
|
||||
reshadefx::location location;
|
||||
uint32_t definition = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// An annotation attached to a variable.
|
||||
/// </summary>
|
||||
struct annotation
|
||||
{
|
||||
reshadefx::type type;
|
||||
std::string name;
|
||||
reshadefx::constant value;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A texture defined in the effect code.
|
||||
/// </summary>
|
||||
struct texture_info
|
||||
{
|
||||
uint32_t id = 0;
|
||||
uint32_t binding = 0;
|
||||
std::string name;
|
||||
std::string semantic;
|
||||
std::string unique_name;
|
||||
std::vector<annotation> annotations;
|
||||
texture_type type = texture_type::texture_2d;
|
||||
uint32_t width = 1;
|
||||
uint32_t height = 1;
|
||||
uint16_t depth = 1;
|
||||
uint16_t levels = 1;
|
||||
texture_format format = texture_format::rgba8;
|
||||
bool render_target = false;
|
||||
bool storage_access = false;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A texture sampler defined in the effect code.
|
||||
/// </summary>
|
||||
struct sampler_info
|
||||
{
|
||||
uint32_t id = 0;
|
||||
uint32_t binding = 0;
|
||||
uint32_t texture_binding = 0;
|
||||
std::string name;
|
||||
reshadefx::type type;
|
||||
std::string unique_name;
|
||||
std::string texture_name;
|
||||
std::vector<annotation> annotations;
|
||||
filter_mode filter = filter_mode::min_mag_mip_linear;
|
||||
texture_address_mode address_u = texture_address_mode::clamp;
|
||||
texture_address_mode address_v = texture_address_mode::clamp;
|
||||
texture_address_mode address_w = texture_address_mode::clamp;
|
||||
float min_lod = -3.402823466e+38f;
|
||||
float max_lod = +3.402823466e+38f; // FLT_MAX
|
||||
float lod_bias = 0.0f;
|
||||
uint8_t srgb = false;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A texture storage object defined in the effect code.
|
||||
/// </summary>
|
||||
struct storage_info
|
||||
{
|
||||
uint32_t id = 0;
|
||||
uint32_t binding = 0;
|
||||
std::string name;
|
||||
reshadefx::type type;
|
||||
std::string unique_name;
|
||||
std::string texture_name;
|
||||
uint16_t level = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// An uniform variable defined in the effect code.
|
||||
/// </summary>
|
||||
struct uniform_info
|
||||
{
|
||||
std::string name;
|
||||
reshadefx::type type;
|
||||
uint32_t size = 0;
|
||||
uint32_t offset = 0;
|
||||
std::vector<annotation> annotations;
|
||||
bool has_initializer_value = false;
|
||||
reshadefx::constant initializer_value;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Type of a shader entry point.
|
||||
/// </summary>
|
||||
enum class shader_type
|
||||
{
|
||||
vs,
|
||||
ps,
|
||||
cs,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A shader entry point function.
|
||||
/// </summary>
|
||||
struct entry_point
|
||||
{
|
||||
std::string name;
|
||||
shader_type type;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A function defined in the effect code.
|
||||
/// </summary>
|
||||
struct function_info
|
||||
{
|
||||
uint32_t definition;
|
||||
std::string name;
|
||||
std::string unique_name;
|
||||
reshadefx::type return_type;
|
||||
std::string return_semantic;
|
||||
std::vector<struct_member_info> parameter_list;
|
||||
std::unordered_set<uint32_t> referenced_samplers;
|
||||
std::unordered_set<uint32_t> referenced_storages;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A render pass with all its state info.
|
||||
/// </summary>
|
||||
struct pass_info
|
||||
struct pass
|
||||
{
|
||||
std::string name;
|
||||
std::string render_target_names[8] = {};
|
||||
std::string vs_entry_point;
|
||||
std::string ps_entry_point;
|
||||
std::string cs_entry_point;
|
||||
uint8_t generate_mipmaps = true;
|
||||
uint8_t clear_render_targets = false;
|
||||
uint8_t srgb_write_enable = false;
|
||||
uint8_t blend_enable[8] = { false, false, false, false, false, false, false, false };
|
||||
uint8_t stencil_enable = false;
|
||||
uint8_t color_write_mask[8] = { 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF };
|
||||
bool generate_mipmaps = true;
|
||||
bool clear_render_targets = false;
|
||||
bool blend_enable[8] = { false, false, false, false, false, false, false, false };
|
||||
blend_factor source_color_blend_factor[8] = { blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one };
|
||||
blend_factor dest_color_blend_factor[8] = { blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero };
|
||||
blend_op color_blend_op[8] = { blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add };
|
||||
blend_factor source_alpha_blend_factor[8] = { blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one };
|
||||
blend_factor dest_alpha_blend_factor[8] = { blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero };
|
||||
blend_op alpha_blend_op[8] = { blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add };
|
||||
bool srgb_write_enable = false;
|
||||
uint8_t render_target_write_mask[8] = { 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF };
|
||||
bool stencil_enable = false;
|
||||
uint8_t stencil_read_mask = 0xFF;
|
||||
uint8_t stencil_write_mask = 0xFF;
|
||||
pass_blend_op blend_op[8] = { pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add };
|
||||
pass_blend_op blend_op_alpha[8] = { pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add };
|
||||
pass_blend_factor src_blend[8] = { pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one };
|
||||
pass_blend_factor dest_blend[8] = { pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero };
|
||||
pass_blend_factor src_blend_alpha[8] = { pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one };
|
||||
pass_blend_factor dest_blend_alpha[8] = { pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero };
|
||||
pass_stencil_func stencil_comparison_func = pass_stencil_func::always;
|
||||
uint32_t stencil_reference_value = 0;
|
||||
pass_stencil_op stencil_op_pass = pass_stencil_op::keep;
|
||||
pass_stencil_op stencil_op_fail = pass_stencil_op::keep;
|
||||
pass_stencil_op stencil_op_depth_fail = pass_stencil_op::keep;
|
||||
uint32_t num_vertices = 3;
|
||||
stencil_func stencil_comparison_func = stencil_func::always;
|
||||
stencil_op stencil_pass_op = stencil_op::keep;
|
||||
stencil_op stencil_fail_op = stencil_op::keep;
|
||||
stencil_op stencil_depth_fail_op = stencil_op::keep;
|
||||
primitive_topology topology = primitive_topology::triangle_list;
|
||||
uint32_t stencil_reference_value = 0;
|
||||
uint32_t num_vertices = 3;
|
||||
uint32_t viewport_width = 0;
|
||||
uint32_t viewport_height = 0;
|
||||
uint32_t viewport_dispatch_z = 1;
|
||||
std::vector<sampler_info> samplers;
|
||||
std::vector<storage_info> storages;
|
||||
|
||||
// Bindings specific for the code generation target (in case of combined texture and sampler, 'texture_bindings' and 'sampler_bindings' will be the same size and point to the same bindings, otherwise they are independent)
|
||||
std::vector<texture_binding> texture_bindings;
|
||||
std::vector<sampler_binding> sampler_bindings;
|
||||
std::vector<storage_binding> storage_bindings;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A collection of passes that make up an effect.
|
||||
/// </summary>
|
||||
struct technique_info
|
||||
struct technique
|
||||
{
|
||||
std::string name;
|
||||
std::vector<pass_info> passes;
|
||||
std::vector<pass> passes;
|
||||
std::vector<annotation> annotations;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// In-memory representation of an effect file.
|
||||
/// </summary>
|
||||
struct module
|
||||
struct effect_module
|
||||
{
|
||||
std::vector<char> code;
|
||||
std::vector<std::pair<std::string, shader_type>> entry_points;
|
||||
|
||||
std::vector<entry_point> entry_points;
|
||||
std::vector<texture_info> textures;
|
||||
std::vector<sampler_info> samplers;
|
||||
std::vector<storage_info> storages;
|
||||
std::vector<uniform_info> uniforms, spec_constants;
|
||||
std::vector<technique_info> techniques;
|
||||
std::vector<texture> textures;
|
||||
std::vector<sampler> samplers;
|
||||
std::vector<storage> storages;
|
||||
|
||||
std::vector<uniform> uniforms;
|
||||
std::vector<uniform> spec_constants;
|
||||
std::vector<technique> techniques;
|
||||
|
||||
uint32_t total_uniform_size = 0;
|
||||
uint32_t num_texture_bindings = 0;
|
||||
|
||||
@ -58,14 +58,14 @@ namespace reshadefx
|
||||
bool peek_multary_op(unsigned int &precedence) const;
|
||||
bool accept_assignment_op();
|
||||
|
||||
void parse_top(bool &parse_success);
|
||||
bool parse_top(bool &parse_success);
|
||||
bool parse_struct();
|
||||
bool parse_function(type type, std::string name);
|
||||
bool parse_function(type type, std::string name, shader_type stype, int num_threads[3]);
|
||||
bool parse_variable(type type, std::string name, bool global = false);
|
||||
bool parse_technique();
|
||||
bool parse_technique_pass(pass_info &info);
|
||||
bool parse_technique_pass(pass &info);
|
||||
bool parse_type(type &type);
|
||||
bool parse_array_size(type &type);
|
||||
bool parse_array_length(type &type);
|
||||
bool parse_expression(expression &expression);
|
||||
bool parse_expression_unary(expression &expression);
|
||||
bool parse_expression_multary(expression &expression, unsigned int precedence = 0);
|
||||
@ -74,15 +74,16 @@ namespace reshadefx
|
||||
bool parse_statement(bool scoped);
|
||||
bool parse_statement_block(bool scoped);
|
||||
|
||||
codegen *_codegen = nullptr;
|
||||
std::string _errors;
|
||||
|
||||
token _token, _token_next, _token_backup;
|
||||
std::unique_ptr<class lexer> _lexer;
|
||||
size_t _lexer_backup_offset = 0;
|
||||
class codegen *_codegen = nullptr;
|
||||
|
||||
token _token;
|
||||
token _token_next;
|
||||
token _token_backup;
|
||||
|
||||
std::vector<uint32_t> _loop_break_target_stack;
|
||||
std::vector<uint32_t> _loop_continue_target_stack;
|
||||
reshadefx::function_info *_current_function = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
@ -154,17 +154,16 @@ namespace reshadefx
|
||||
void expand_macro(const std::string &name, const macro ¯o, const std::vector<std::string> &arguments);
|
||||
void create_macro_replacement_list(macro ¯o);
|
||||
|
||||
bool _success = true;
|
||||
include_file_exists_callback _file_exists_cb;
|
||||
include_read_file_callback _read_file_cb;
|
||||
std::string _output, _errors;
|
||||
|
||||
std::string _current_token_raw_data;
|
||||
reshadefx::token _token;
|
||||
location _output_location;
|
||||
std::vector<input_level> _input_stack;
|
||||
size_t _next_input_index = 0;
|
||||
size_t _current_input_index = 0;
|
||||
reshadefx::token _token;
|
||||
std::string _current_token_raw_data;
|
||||
reshadefx::location _output_location;
|
||||
|
||||
std::vector<if_level> _if_stack;
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ namespace reshadefx
|
||||
uint32_t id = 0;
|
||||
reshadefx::type type = {};
|
||||
reshadefx::constant constant = {};
|
||||
const reshadefx::function_info *function = nullptr;
|
||||
const reshadefx::function *function = nullptr;
|
||||
};
|
||||
struct scoped_symbol : symbol
|
||||
{
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace reshadefx
|
||||
{
|
||||
@ -246,7 +247,7 @@ namespace reshadefx
|
||||
};
|
||||
std::string literal_as_string;
|
||||
|
||||
inline operator tokenid() const { return id; }
|
||||
operator tokenid() const { return id; }
|
||||
|
||||
static std::string id_to_name(tokenid id);
|
||||
};
|
||||
|
||||
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
@ -3,16 +3,16 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "effect_lexer.hpp"
|
||||
#include "effect_codegen.hpp"
|
||||
#include <cmath> // fmod
|
||||
#include "effect_expression.hpp"
|
||||
#include <cmath> // std::fmod
|
||||
#include <cassert>
|
||||
#include <cstring> // memcpy, memset
|
||||
#include <algorithm> // std::min, std::max
|
||||
#include <cstring> // std::memcpy, std::memset
|
||||
#include <algorithm> // std::max, std::min
|
||||
|
||||
reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
|
||||
{
|
||||
type result = { std::max(lhs.base, rhs.base) };
|
||||
type result;
|
||||
result.base = std::max(lhs.base, rhs.base);
|
||||
|
||||
// Non-numeric types cannot be vectors or matrices
|
||||
if (!result.is_numeric())
|
||||
@ -35,11 +35,14 @@ reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
|
||||
// Some qualifiers propagate to the result
|
||||
result.qualifiers = (lhs.qualifiers & type::q_precise) | (rhs.qualifiers & type::q_precise);
|
||||
|
||||
// In case this is a structure, assume they are the same
|
||||
result.definition = rhs.definition;
|
||||
assert(lhs.definition == rhs.definition || lhs.definition == 0);
|
||||
// Cannot merge array types, assume no arrays
|
||||
result.array_length = 0;
|
||||
assert(lhs.array_length == 0 && rhs.array_length == 0);
|
||||
|
||||
// In case this is a structure, assume they are the same
|
||||
result.struct_definition = rhs.struct_definition;
|
||||
assert(lhs.struct_definition == rhs.struct_definition || lhs.struct_definition == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -48,101 +51,101 @@ std::string reshadefx::type::description() const
|
||||
std::string result;
|
||||
switch (base)
|
||||
{
|
||||
case reshadefx::type::t_void:
|
||||
case t_void:
|
||||
result = "void";
|
||||
break;
|
||||
case reshadefx::type::t_bool:
|
||||
case t_bool:
|
||||
result = "bool";
|
||||
break;
|
||||
case reshadefx::type::t_min16int:
|
||||
case t_min16int:
|
||||
result = "min16int";
|
||||
break;
|
||||
case reshadefx::type::t_int:
|
||||
case t_int:
|
||||
result = "int";
|
||||
break;
|
||||
case reshadefx::type::t_min16uint:
|
||||
case t_min16uint:
|
||||
result = "min16uint";
|
||||
break;
|
||||
case reshadefx::type::t_uint:
|
||||
case t_uint:
|
||||
result = "uint";
|
||||
break;
|
||||
case reshadefx::type::t_min16float:
|
||||
case t_min16float:
|
||||
result = "min16float";
|
||||
break;
|
||||
case reshadefx::type::t_float:
|
||||
case t_float:
|
||||
result = "float";
|
||||
break;
|
||||
case reshadefx::type::t_string:
|
||||
case t_string:
|
||||
result = "string";
|
||||
break;
|
||||
case reshadefx::type::t_struct:
|
||||
case t_struct:
|
||||
result = "struct";
|
||||
break;
|
||||
case reshadefx::type::t_texture1d:
|
||||
case t_texture1d:
|
||||
result = "texture1D";
|
||||
break;
|
||||
case reshadefx::type::t_texture2d:
|
||||
case t_texture2d:
|
||||
result = "texture2D";
|
||||
break;
|
||||
case reshadefx::type::t_texture3d:
|
||||
case t_texture3d:
|
||||
result = "texture3D";
|
||||
break;
|
||||
case reshadefx::type::t_sampler1d_int:
|
||||
case t_sampler1d_int:
|
||||
result = "sampler1D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler2d_int:
|
||||
case t_sampler2d_int:
|
||||
result = "sampler2D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler3d_int:
|
||||
case t_sampler3d_int:
|
||||
result = "sampler3D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler1d_uint:
|
||||
case t_sampler1d_uint:
|
||||
result = "sampler1D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler2d_uint:
|
||||
case t_sampler2d_uint:
|
||||
result = "sampler2D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler3d_uint:
|
||||
case t_sampler3d_uint:
|
||||
result = "sampler3D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler1d_float:
|
||||
case t_sampler1d_float:
|
||||
result = "sampler1D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler2d_float:
|
||||
case t_sampler2d_float:
|
||||
result = "sampler2D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler3d_float:
|
||||
case t_sampler3d_float:
|
||||
result = "sampler3D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage1d_int:
|
||||
case t_storage1d_int:
|
||||
result = "storage1D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage2d_int:
|
||||
case t_storage2d_int:
|
||||
result = "storage2D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage3d_int:
|
||||
case t_storage3d_int:
|
||||
result = "storage3D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage1d_uint:
|
||||
case t_storage1d_uint:
|
||||
result = "storage1D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage2d_uint:
|
||||
case t_storage2d_uint:
|
||||
result = "storage2D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage3d_uint:
|
||||
case t_storage3d_uint:
|
||||
result = "storage3D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage1d_float:
|
||||
case t_storage1d_float:
|
||||
result = "storage1D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage2d_float:
|
||||
case t_storage2d_float:
|
||||
result = "storage2D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage3d_float:
|
||||
case t_storage3d_float:
|
||||
result = "storage3D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_function:
|
||||
result = "function";
|
||||
case t_function:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -157,7 +160,7 @@ std::string reshadefx::type::description() const
|
||||
if (is_array())
|
||||
{
|
||||
result += '[';
|
||||
if (array_length > 0)
|
||||
if (is_bounded_array())
|
||||
result += std::to_string(array_length);
|
||||
result += ']';
|
||||
}
|
||||
@ -179,7 +182,7 @@ void reshadefx::expression::reset_to_lvalue(const reshadefx::location &loc, uint
|
||||
type.qualifiers |= type::q_const;
|
||||
|
||||
// Strip away global variable qualifiers
|
||||
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared);
|
||||
type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
|
||||
}
|
||||
void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint32_t in_base, const reshadefx::type &in_type)
|
||||
{
|
||||
@ -192,7 +195,7 @@ void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint
|
||||
chain.clear();
|
||||
|
||||
// Strip away global variable qualifiers
|
||||
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared);
|
||||
type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
|
||||
}
|
||||
|
||||
void reshadefx::expression::reset_to_rvalue_constant(const reshadefx::location &loc, bool data)
|
||||
@ -290,7 +293,7 @@ void reshadefx::expression::add_cast_operation(const reshadefx::type &cast_type)
|
||||
constant.as_float[i] = static_cast<float>(constant.as_int[i]);
|
||||
};
|
||||
|
||||
for (auto &element : constant.array_data)
|
||||
for (struct constant &element : constant.array_data)
|
||||
cast_constant(element, type, cast_type);
|
||||
|
||||
cast_constant(constant, type, cast_type);
|
||||
@ -320,7 +323,7 @@ void reshadefx::expression::add_dynamic_index_access(uint32_t index_expression)
|
||||
assert(!is_constant); // Cannot have dynamic indexing into constant in SPIR-V
|
||||
assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
|
||||
|
||||
auto prev_type = type;
|
||||
struct type prev_type = type;
|
||||
|
||||
if (type.is_array())
|
||||
{
|
||||
@ -342,11 +345,11 @@ void reshadefx::expression::add_constant_index_access(unsigned int index)
|
||||
{
|
||||
assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
|
||||
|
||||
auto prev_type = type;
|
||||
struct type prev_type = type;
|
||||
|
||||
if (type.is_array())
|
||||
{
|
||||
assert(type.array_length < 0 || index < static_cast<unsigned int>(type.array_length));
|
||||
assert(index < type.array_length);
|
||||
|
||||
type.array_length = 0;
|
||||
}
|
||||
@ -389,7 +392,7 @@ void reshadefx::expression::add_swizzle_access(const signed char swizzle[4], uns
|
||||
{
|
||||
assert(type.is_numeric() && !type.is_array());
|
||||
|
||||
const auto prev_type = type;
|
||||
const struct type prev_type = type;
|
||||
|
||||
type.rows = length;
|
||||
type.cols = 1;
|
||||
|
||||
@ -18,7 +18,7 @@ enum token_type
|
||||
};
|
||||
|
||||
// Lookup table which translates a given char to a token type
|
||||
static const unsigned type_lookup[256] = {
|
||||
static const unsigned int s_type_lookup[256] = {
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SPACE,
|
||||
'\n', SPACE, SPACE, SPACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
@ -35,7 +35,7 @@ static const unsigned type_lookup[256] = {
|
||||
};
|
||||
|
||||
// Lookup tables which translate a given string literal to a token and backwards
|
||||
static const std::unordered_map<tokenid, std::string_view> token_lookup = {
|
||||
static const std::unordered_map<tokenid, std::string_view> s_token_lookup = {
|
||||
{ tokenid::end_of_file, "end of file" },
|
||||
{ tokenid::exclaim, "!" },
|
||||
{ tokenid::hash, "#" },
|
||||
@ -205,7 +205,7 @@ static const std::unordered_map<tokenid, std::string_view> token_lookup = {
|
||||
{ tokenid::storage2d, "storage2D" },
|
||||
{ tokenid::storage3d, "storage3D" },
|
||||
};
|
||||
static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
|
||||
static const std::unordered_map<std::string_view, tokenid> s_keyword_lookup = {
|
||||
{ "asm", tokenid::reserved },
|
||||
{ "asm_fragment", tokenid::reserved },
|
||||
{ "auto", tokenid::reserved },
|
||||
@ -439,7 +439,7 @@ static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
|
||||
{ "volatile", tokenid::volatile_ },
|
||||
{ "while", tokenid::while_ }
|
||||
};
|
||||
static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup = {
|
||||
static const std::unordered_map<std::string_view, tokenid> s_pp_directive_lookup = {
|
||||
{ "define", tokenid::hash_def },
|
||||
{ "undef", tokenid::hash_undef },
|
||||
{ "if", tokenid::hash_if },
|
||||
@ -454,15 +454,15 @@ static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup =
|
||||
{ "include", tokenid::hash_include },
|
||||
};
|
||||
|
||||
static inline bool is_octal_digit(char c)
|
||||
static bool is_octal_digit(char c)
|
||||
{
|
||||
return static_cast<unsigned>(c - '0') < 8;
|
||||
}
|
||||
static inline bool is_decimal_digit(char c)
|
||||
static bool is_decimal_digit(char c)
|
||||
{
|
||||
return static_cast<unsigned>(c - '0') < 10;
|
||||
}
|
||||
static inline bool is_hexadecimal_digit(char c)
|
||||
static bool is_hexadecimal_digit(char c)
|
||||
{
|
||||
return is_decimal_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
@ -504,8 +504,8 @@ static long long octal_to_decimal(long long n)
|
||||
|
||||
std::string reshadefx::token::id_to_name(tokenid id)
|
||||
{
|
||||
const auto it = token_lookup.find(id);
|
||||
if (it != token_lookup.end())
|
||||
const auto it = s_token_lookup.find(id);
|
||||
if (it != s_token_lookup.end())
|
||||
return std::string(it->second);
|
||||
return "unknown";
|
||||
}
|
||||
@ -526,7 +526,7 @@ next_token:
|
||||
assert(_cur <= _end);
|
||||
|
||||
// Do a character type lookup for the current character
|
||||
switch (type_lookup[uint8_t(*_cur)])
|
||||
switch (s_type_lookup[uint8_t(*_cur)])
|
||||
{
|
||||
case 0xFF: // EOF
|
||||
tok.id = tokenid::end_of_file;
|
||||
@ -635,7 +635,7 @@ next_token:
|
||||
tok.id = tokenid::minus;
|
||||
break;
|
||||
case '.':
|
||||
if (type_lookup[uint8_t(_cur[1])] == DIGIT)
|
||||
if (s_type_lookup[uint8_t(_cur[1])] == DIGIT)
|
||||
parse_numeric_literal(tok);
|
||||
else if (_cur[1] == '.' && _cur[2] == '.')
|
||||
tok.id = tokenid::ellipsis,
|
||||
@ -805,7 +805,7 @@ void reshadefx::lexer::skip_space()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type_lookup[uint8_t(*_cur)] == SPACE)
|
||||
if (s_type_lookup[uint8_t(*_cur)] == SPACE)
|
||||
skip(1);
|
||||
else
|
||||
break;
|
||||
@ -841,7 +841,7 @@ void reshadefx::lexer::parse_identifier(token &tok) const
|
||||
auto *const begin = _cur, *end = begin;
|
||||
|
||||
// Skip to the end of the identifier sequence
|
||||
while (type_lookup[uint8_t(*end)] == IDENT || type_lookup[uint8_t(*end)] == DIGIT)
|
||||
while (s_type_lookup[uint8_t(*end)] == IDENT || s_type_lookup[uint8_t(*end)] == DIGIT)
|
||||
end++;
|
||||
|
||||
tok.id = tokenid::identifier;
|
||||
@ -852,8 +852,8 @@ void reshadefx::lexer::parse_identifier(token &tok) const
|
||||
if (_ignore_keywords)
|
||||
return;
|
||||
|
||||
if (const auto it = keyword_lookup.find(tok.literal_as_string);
|
||||
it != keyword_lookup.end())
|
||||
if (const auto it = s_keyword_lookup.find(tok.literal_as_string);
|
||||
it != s_keyword_lookup.end())
|
||||
tok.id = it->second;
|
||||
}
|
||||
bool reshadefx::lexer::parse_pp_directive(token &tok)
|
||||
@ -862,8 +862,8 @@ bool reshadefx::lexer::parse_pp_directive(token &tok)
|
||||
skip_space(); // Skip any space between the '#' and directive
|
||||
parse_identifier(tok);
|
||||
|
||||
if (const auto it = pp_directive_lookup.find(tok.literal_as_string);
|
||||
it != pp_directive_lookup.end())
|
||||
if (const auto it = s_pp_directive_lookup.find(tok.literal_as_string);
|
||||
it != s_pp_directive_lookup.end())
|
||||
{
|
||||
tok.id = it->second;
|
||||
return true;
|
||||
@ -999,6 +999,9 @@ void reshadefx::lexer::parse_string_literal(token &tok, bool escape)
|
||||
|
||||
tok.id = tokenid::string_literal;
|
||||
tok.length = end - begin + 1;
|
||||
|
||||
// Free up unused memory
|
||||
tok.literal_as_string.shrink_to_fit();
|
||||
}
|
||||
void reshadefx::lexer::parse_numeric_literal(token &tok) const
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,8 +5,8 @@
|
||||
|
||||
#include "effect_lexer.hpp"
|
||||
#include "effect_preprocessor.hpp"
|
||||
#include <cstdio> // fclose, fopen, fread, fseek
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <algorithm> // std::find_if
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -52,7 +52,7 @@ enum macro_replacement
|
||||
macro_replacement_stringize = '\xFE',
|
||||
};
|
||||
|
||||
static const int precedence_lookup[] = {
|
||||
static const int s_precedence_lookup[] = {
|
||||
0, 1, 2, 3, 4, // bitwise operators
|
||||
5, 6, 7, 7, 7, 7, // logical operators
|
||||
8, 8, // left shift, right shift
|
||||
@ -61,9 +61,8 @@ static const int precedence_lookup[] = {
|
||||
11, 11, 11, 11 // unary operators
|
||||
};
|
||||
|
||||
static bool read_file(const std::string &path, std::string &data, reshadefx::preprocessor::include_read_file_callback &cb)
|
||||
static bool read_file(const std::string &path, std::string &file_data, reshadefx::preprocessor::include_read_file_callback &cb)
|
||||
{
|
||||
std::string file_data;
|
||||
if (!cb(path, file_data))
|
||||
return false;
|
||||
|
||||
@ -77,29 +76,33 @@ static bool read_file(const std::string &path, std::string &data, reshadefx::pre
|
||||
static_cast<unsigned char>(file_data[2]) == 0xbf)
|
||||
file_data.erase(0, 3);
|
||||
|
||||
data = std::move(file_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reshadefx::preprocessor::stdfs_read_file_callback(const std::string &path, std::string &data)
|
||||
{
|
||||
std::ifstream file(std::filesystem::path(path), std::ios::binary);
|
||||
if (!file)
|
||||
return false;
|
||||
// Read file contents into memory
|
||||
const std::filesystem::path fspath(path);
|
||||
#ifndef _WIN32
|
||||
FILE *const file = fopen(fspath.c_str(), "rb");
|
||||
#else
|
||||
FILE *const file = _wfsopen(fspath.generic_wstring().c_str(), L"rb", SH_DENYWR);
|
||||
#endif
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
|
||||
// Read file contents into memory
|
||||
std::error_code ec;
|
||||
const uintmax_t file_size = std::filesystem::file_size(path, ec);
|
||||
if (ec)
|
||||
return false;
|
||||
fseek(file, 0, SEEK_END);
|
||||
const size_t file_size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
data.reserve(file_size + 1);
|
||||
data.resize(static_cast<size_t>(file_size), '\0');
|
||||
if (!file.read(data.data(), file_size))
|
||||
return false;
|
||||
const size_t file_size_read = fread(data.data(), 1, file_size, file);
|
||||
|
||||
// No longer need to have a handle open to the file, since all data was read, so can safely close it
|
||||
fclose(file);
|
||||
|
||||
if (file_size_read != file_size)
|
||||
return false;
|
||||
|
||||
// No longer need to have a handle open to the file, since all data was read, so can safely close it
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,7 +159,8 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
|
||||
// Enforce all input strings to end with a line feed
|
||||
assert(!source_code.empty() && source_code.back() == '\n');
|
||||
|
||||
_success = true; // Clear success flag before parsing a new string
|
||||
// Only consider new errors added below for the success of this call
|
||||
const size_t errors_offset = _errors.length();
|
||||
|
||||
// Give this push a name, so that lexer location starts at a new line
|
||||
// This is necessary in case this string starts with a preprocessor directive, since the lexer only reports those as such if they appear at the beginning of a new line
|
||||
@ -164,15 +168,15 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
|
||||
push(std::move(source_code), path.empty() ? "unknown" : path);
|
||||
parse();
|
||||
|
||||
return _success;
|
||||
return _errors.find(": preprocessor error: ", errors_offset) == std::string::npos;
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> reshadefx::preprocessor::included_files() const
|
||||
{
|
||||
std::vector<std::filesystem::path> files;
|
||||
files.reserve(_file_cache.size());
|
||||
for (const auto &it : _file_cache)
|
||||
files.push_back(std::filesystem::u8path(it.first));
|
||||
for (const std::pair<std::string, std::string> &cache_entry : _file_cache)
|
||||
files.push_back(std::filesystem::u8path(cache_entry.first));
|
||||
return files;
|
||||
}
|
||||
std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_macro_definitions() const
|
||||
@ -189,12 +193,19 @@ std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_m
|
||||
|
||||
void reshadefx::preprocessor::error(const location &location, const std::string &message)
|
||||
{
|
||||
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor error: " + message + '\n';
|
||||
_success = false; // Unset success flag
|
||||
_errors += location.source;
|
||||
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
|
||||
_errors += ": preprocessor error: ";
|
||||
_errors += message;
|
||||
_errors += '\n';
|
||||
}
|
||||
void reshadefx::preprocessor::warning(const location &location, const std::string &message)
|
||||
{
|
||||
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor warning: " + message + '\n';
|
||||
_errors += location.source;
|
||||
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
|
||||
_errors += ": preprocessor warning: ";
|
||||
_errors += message;
|
||||
_errors += '\n';
|
||||
}
|
||||
|
||||
void reshadefx::preprocessor::push(std::string input, const std::string &name)
|
||||
@ -357,32 +368,32 @@ void reshadefx::preprocessor::parse()
|
||||
{
|
||||
case tokenid::hash_if:
|
||||
parse_if();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_ifdef:
|
||||
parse_ifdef();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_ifndef:
|
||||
parse_ifndef();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_else:
|
||||
parse_else();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_elif:
|
||||
parse_elif();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_endif:
|
||||
parse_endif();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
default:
|
||||
@ -511,11 +522,18 @@ void reshadefx::preprocessor::parse_if()
|
||||
level.pp_token = _token;
|
||||
level.input_index = _current_input_index;
|
||||
|
||||
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
|
||||
level.value = evaluate_expression();
|
||||
|
||||
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
|
||||
level.skipping = parent_skipping || !level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
|
||||
level.value = evaluate_expression();
|
||||
level.skipping = !level.value;
|
||||
}
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
}
|
||||
@ -528,16 +546,23 @@ void reshadefx::preprocessor::parse_ifdef()
|
||||
if (!expect(tokenid::identifier))
|
||||
return;
|
||||
|
||||
level.value = is_defined(_token.literal_as_string);
|
||||
|
||||
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
|
||||
level.skipping = parent_skipping || !level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.value = is_defined(_token.literal_as_string);
|
||||
level.skipping = !level.value;
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
// Only add to used macro list if this #ifdef is active and the macro was not defined before
|
||||
if (!parent_skipping)
|
||||
// Only add to used macro list if this #ifdef is active and the macro was not defined before
|
||||
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
|
||||
_used_macros.emplace(_token.literal_as_string);
|
||||
}
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
}
|
||||
void reshadefx::preprocessor::parse_ifndef()
|
||||
{
|
||||
@ -548,16 +573,23 @@ void reshadefx::preprocessor::parse_ifndef()
|
||||
if (!expect(tokenid::identifier))
|
||||
return;
|
||||
|
||||
level.value = !is_defined(_token.literal_as_string);
|
||||
|
||||
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
|
||||
level.skipping = parent_skipping || !level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.value = !is_defined(_token.literal_as_string);
|
||||
level.skipping = !level.value;
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
// Only add to used macro list if this #ifndef is active and the macro was not defined before
|
||||
if (!parent_skipping)
|
||||
// Only add to used macro list if this #ifndef is active and the macro was not defined before
|
||||
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
|
||||
_used_macros.emplace(_token.literal_as_string);
|
||||
}
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
}
|
||||
void reshadefx::preprocessor::parse_elif()
|
||||
{
|
||||
@ -573,10 +605,19 @@ void reshadefx::preprocessor::parse_elif()
|
||||
level.input_index = _current_input_index;
|
||||
|
||||
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
|
||||
const bool condition_result = evaluate_expression();
|
||||
level.skipping = parent_skipping || level.value || !condition_result;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool condition_result = evaluate_expression();
|
||||
level.skipping = level.value || !condition_result;
|
||||
|
||||
if (!level.value) level.value = condition_result;
|
||||
if (!level.value)
|
||||
level.value = condition_result;
|
||||
}
|
||||
}
|
||||
void reshadefx::preprocessor::parse_else()
|
||||
{
|
||||
@ -591,16 +632,25 @@ void reshadefx::preprocessor::parse_else()
|
||||
level.input_index = _current_input_index;
|
||||
|
||||
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
|
||||
level.skipping = parent_skipping || level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.skipping = parent_skipping || level.value;
|
||||
|
||||
if (!level.value) level.value = true;
|
||||
if (!level.value)
|
||||
level.value = true;
|
||||
}
|
||||
}
|
||||
void reshadefx::preprocessor::parse_endif()
|
||||
{
|
||||
if (_if_stack.empty())
|
||||
error(_token.location, "missing #if for #endif");
|
||||
else
|
||||
_if_stack.pop_back();
|
||||
return error(_token.location, "missing #if for #endif");
|
||||
|
||||
_if_stack.pop_back();
|
||||
}
|
||||
|
||||
void reshadefx::preprocessor::parse_error()
|
||||
@ -927,8 +977,8 @@ bool reshadefx::preprocessor::evaluate_expression()
|
||||
break;
|
||||
|
||||
if (left_associative ?
|
||||
(precedence_lookup[op] > precedence_lookup[prev_op]) :
|
||||
(precedence_lookup[op] >= precedence_lookup[prev_op]))
|
||||
(s_precedence_lookup[op] > s_precedence_lookup[prev_op]) :
|
||||
(s_precedence_lookup[op] >= s_precedence_lookup[prev_op]))
|
||||
break;
|
||||
|
||||
stack_index--;
|
||||
@ -1016,9 +1066,13 @@ bool reshadefx::preprocessor::evaluate_expression()
|
||||
BINARY_OPERATION(-);
|
||||
break;
|
||||
case op_modulo:
|
||||
if (stack[stack_index - 1] == 0)
|
||||
return error(_token.location, "right operand of '%' is zero"), 0;
|
||||
BINARY_OPERATION(%);
|
||||
break;
|
||||
case op_divide:
|
||||
if (stack[stack_index - 1] == 0)
|
||||
return error(_token.location, "division by zero"), 0;
|
||||
BINARY_OPERATION(/);
|
||||
break;
|
||||
case op_multiply:
|
||||
@ -1068,12 +1122,24 @@ bool reshadefx::preprocessor::evaluate_identifier_as_macro()
|
||||
push(escape_string(file_stem.u8string()));
|
||||
return true;
|
||||
}
|
||||
if (_token.literal_as_string == "__FILE_STEM_HASH__")
|
||||
{
|
||||
const std::filesystem::path file_stem = std::filesystem::u8path(_token.location.source).stem();
|
||||
push(std::to_string(std::hash<std::string>()(file_stem.u8string()) & 0xFFFFFFFF));
|
||||
return true;
|
||||
}
|
||||
if (_token.literal_as_string == "__FILE_NAME__")
|
||||
{
|
||||
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
|
||||
push(escape_string(file_name.u8string()));
|
||||
return true;
|
||||
}
|
||||
if (_token.literal_as_string == "__FILE_NAME_HASH__")
|
||||
{
|
||||
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
|
||||
push(std::to_string(std::hash<std::string>()(file_name.u8string()) & 0xFFFFFFFF));
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto it = _macros.find(_token.literal_as_string);
|
||||
if (it == _macros.end())
|
||||
|
||||
@ -13,25 +13,23 @@
|
||||
#include <algorithm> // std::upper_bound, std::sort
|
||||
#include <functional> // std::greater
|
||||
|
||||
enum class intrinsic_id : uint32_t
|
||||
enum class intrinsic_id
|
||||
{
|
||||
#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) name##i,
|
||||
#include "effect_symbol_table_intrinsics.inl"
|
||||
};
|
||||
|
||||
struct intrinsic
|
||||
struct intrinsic : reshadefx::function
|
||||
{
|
||||
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types) : id(id)
|
||||
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types)
|
||||
{
|
||||
function.name = name;
|
||||
function.return_type = ret_type;
|
||||
function.parameter_list.reserve(arg_types.size());
|
||||
function::return_type = ret_type;
|
||||
function::id = static_cast<uint32_t>(id);
|
||||
function::name = name;
|
||||
function::parameter_list.reserve(arg_types.size());
|
||||
for (const reshadefx::type &arg_type : arg_types)
|
||||
function.parameter_list.push_back({ arg_type });
|
||||
function::parameter_list.push_back({ arg_type });
|
||||
}
|
||||
|
||||
intrinsic_id id;
|
||||
reshadefx::function_info function;
|
||||
};
|
||||
|
||||
#define void { reshadefx::type::t_void }
|
||||
@ -130,48 +128,17 @@ static const intrinsic s_intrinsics[] =
|
||||
#undef uint2
|
||||
#undef uint3
|
||||
#undef uint4
|
||||
#undef float1
|
||||
#undef float
|
||||
#undef float2
|
||||
#undef float3
|
||||
#undef float4
|
||||
#undef float2x2
|
||||
#undef float3x3
|
||||
#undef float4x4
|
||||
#undef out_float
|
||||
#undef out_float2
|
||||
#undef out_float3
|
||||
#undef out_float4
|
||||
#undef sampler1d_int
|
||||
#undef sampler2d_int
|
||||
#undef sampler3d_int
|
||||
#undef sampler1d_uint
|
||||
#undef sampler2d_uint
|
||||
#undef sampler3d_uint
|
||||
#undef sampler1d_float4
|
||||
#undef sampler2d_float4
|
||||
#undef sampler3d_float4
|
||||
#undef storage1d_int
|
||||
#undef storage2d_int
|
||||
#undef storage3d_int
|
||||
#undef storage1d_uint
|
||||
#undef storage2d_uint
|
||||
#undef storage3d_uint
|
||||
#undef storage1d_float4
|
||||
#undef storage2d_float4
|
||||
#undef storage3d_float4
|
||||
#undef inout_storage1d_int
|
||||
#undef inout_storage2d_int
|
||||
#undef inout_storage3d_int
|
||||
#undef inout_storage1d_uint
|
||||
#undef inout_storage2d_uint
|
||||
#undef inout_storage3d_uint
|
||||
|
||||
unsigned int reshadefx::type::rank(const type &src, const type &dst)
|
||||
{
|
||||
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.array_length > 0 && dst.array_length > 0))
|
||||
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.is_bounded_array() && dst.is_bounded_array()))
|
||||
return 0; // Arrays of different sizes are not compatible
|
||||
if (src.is_struct() || dst.is_struct())
|
||||
return src.definition == dst.definition ? 32 : 0; // Structs are only compatible if they are the same type
|
||||
return src.struct_definition == dst.struct_definition ? 32 : 0; // Structs are only compatible if they are the same type
|
||||
if (!src.is_numeric() || !dst.is_numeric())
|
||||
return src.base == dst.base && src.rows == dst.rows && src.cols == dst.cols ? 32 : 0; // Numeric values are not compatible with other types
|
||||
if (src.is_matrix() && (!dst.is_matrix() || src.rows != dst.rows || src.cols != dst.cols))
|
||||
@ -181,7 +148,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
|
||||
// - Floating point has a higher rank than integer types
|
||||
// - Integer to floating point promotion has a higher rank than floating point to integer conversion
|
||||
// - Signed to unsigned integer conversion has a higher rank than unsigned to signed integer conversion
|
||||
static const int ranks[7][7] = {
|
||||
static const unsigned int ranks[7][7] = {
|
||||
{ 5, 4, 4, 4, 4, 4, 4 }, // bool
|
||||
{ 3, 5, 5, 2, 2, 4, 4 }, // min16int
|
||||
{ 3, 5, 5, 2, 2, 4, 4 }, // int
|
||||
@ -194,7 +161,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
|
||||
assert(src.base > 0 && src.base <= 7); // bool - float
|
||||
assert(dst.base > 0 && dst.base <= 7);
|
||||
|
||||
const int rank = ranks[src.base - 1][dst.base - 1] << 2;
|
||||
const unsigned int rank = ranks[src.base - 1][dst.base - 1] << 2;
|
||||
|
||||
if ((src.is_scalar() && dst.is_vector()))
|
||||
return rank >> 1; // Scalar to vector promotion has a lower rank
|
||||
@ -284,7 +251,7 @@ bool reshadefx::symbol_table::insert_symbol(const std::string &name, const symbo
|
||||
{
|
||||
// Extract scope name
|
||||
scope.name = _current_scope.name.substr(0, pos += 2);
|
||||
const auto previous_scope_name = _current_scope.name.substr(pos);
|
||||
const std::string previous_scope_name = _current_scope.name.substr(pos);
|
||||
|
||||
// Insert symbol into this scope
|
||||
insert_sorted(_symbol_stack[previous_scope_name + name], scoped_symbol { symbol, scope });
|
||||
@ -335,7 +302,7 @@ reshadefx::scoped_symbol reshadefx::symbol_table::find_symbol(const std::string
|
||||
return result;
|
||||
}
|
||||
|
||||
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function_info *function1, const reshadefx::function_info *function2)
|
||||
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function *function1, const reshadefx::function *function2)
|
||||
{
|
||||
const size_t num_arguments = arguments.size();
|
||||
|
||||
@ -388,7 +355,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
{
|
||||
out_data.op = symbol_type::function;
|
||||
|
||||
const function_info *result = nullptr;
|
||||
const function *result = nullptr;
|
||||
unsigned int num_overloads = 0;
|
||||
unsigned int overload_namespace = scope.namespace_level;
|
||||
|
||||
@ -405,7 +372,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
it->scope.namespace_level > scope.namespace_level || (it->scope.namespace_level == scope.namespace_level && it->scope.name != scope.name))
|
||||
continue;
|
||||
|
||||
const function_info *const function = it->function;
|
||||
const function *const function = it->function;
|
||||
|
||||
if (function == nullptr)
|
||||
continue;
|
||||
@ -425,7 +392,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (arguments.size() != function->parameter_list.size())
|
||||
else if (arguments.size() > function->parameter_list.size() || (arguments.size() < function->parameter_list.size() && !function->parameter_list[arguments.size()].has_default_value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -453,18 +420,18 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
{
|
||||
for (const intrinsic &intrinsic : s_intrinsics)
|
||||
{
|
||||
if (intrinsic.function.name != name || intrinsic.function.parameter_list.size() != arguments.size())
|
||||
if (intrinsic.name != name || intrinsic.parameter_list.size() != arguments.size())
|
||||
continue;
|
||||
|
||||
// A new possibly-matching intrinsic function was found, compare it against the current result
|
||||
const int comparison = compare_functions(arguments, &intrinsic.function, result);
|
||||
const int comparison = compare_functions(arguments, &intrinsic, result);
|
||||
|
||||
if (comparison < 0) // The new function is a better match
|
||||
{
|
||||
out_data.op = symbol_type::intrinsic;
|
||||
out_data.id = static_cast<uint32_t>(intrinsic.id);
|
||||
out_data.type = intrinsic.function.return_type;
|
||||
out_data.function = &intrinsic.function;
|
||||
out_data.id = intrinsic.id;
|
||||
out_data.type = intrinsic.return_type;
|
||||
out_data.function = &intrinsic;
|
||||
result = out_data.function;
|
||||
num_overloads = 1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user