dep: Add reshadefx

This commit is contained in:
Stenzek
2023-08-13 14:03:17 +10:00
parent c01f249e0f
commit 8c638b4c78
24 changed files with 19519 additions and 0 deletions

View File

@ -0,0 +1,377 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_module.hpp"
#include <memory> // std::unique_ptr
#include <algorithm> // std::find_if
namespace reshadefx
{
/// <summary>
/// A SSA code generation back-end interface for the parser to call into.
/// </summary>
class codegen
{
public:
/// <summary>
/// Virtual destructor to guarantee that memory of the implementations deriving from this interface is properly destroyed.
/// </summary>
virtual ~codegen() {}
/// <summary>
/// Writes result of the code generation to the specified <paramref name="module"/>.
/// </summary>
/// <param name="module">Target module to fill.</param>
virtual void write_result(module &module) = 0;
public:
/// <summary>
/// An opaque ID referring to a SSA value or basic block.
/// </summary>
using id = uint32_t;
/// <summary>
/// Defines a new struct type.
/// </summary>
/// <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;
/// <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;
/// <summary>
/// Defines a new sampler binding.
/// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param>
/// <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;
/// <summary>
/// Defines a new storage binding.
/// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param>
/// <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;
/// <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;
/// <summary>
/// Defines a new variable.
/// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param>
/// <param name="type">Data type of the variable.</param>
/// <param name="name">Name of the variable.</param>
/// <param name="global"><c>true</c> if this variable is in global scope, <c>false</c> otherwise.</param>
/// <param name="initializer_value">SSA ID of an optional initializer value.</param>
/// <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.
/// </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;
/// <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)); }
/// <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;
/// <summary>
/// Resolves the access chain and add a load operation to the output.
/// </summary>
/// <param name="chain">Access chain pointing to the variable to load from.</param>
/// <param name="force_new_id">Set to <see langword="true"/> to force this to return a new SSA ID for l-value loads.</param>
/// <returns>New SSA ID with the loaded value.</returns>
virtual id emit_load(const expression &chain, bool force_new_id = false) = 0;
/// <summary>
/// Resolves the access chain and add a store operation to the output.
/// </summary>
/// <param name="chain">Access chain pointing to the variable to store to.</param>
/// <param name="value">SSA ID of the value to store.</param>
virtual void emit_store(const expression &chain, id value) = 0;
/// <summary>
/// Resolves the access chain, but do not add a load operation. This returns a pointer instead.
/// </summary>
/// <param name="chain">Access chain pointing to the variable to resolve.</param>
/// <param name="chain_index">Output value which is set to the index in the access chain up to which the access chain went.</param>
/// <returns>New SSA ID with a pointer to the value.</returns>
virtual id emit_access_chain(const expression &chain, size_t &chain_index) { chain_index = chain.chain.size(); return emit_load(chain); }
/// <summary>
/// Creates a SSA constant value.
/// </summary>
/// <param name="type">Data type of the constant.</param>
/// <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;
/// <summary>
/// Adds an unary operation to the output (built-in operation with one argument).
/// </summary>
/// <param name="loc">Source location matching this operation (for debugging).</param>
/// <param name="op">Unary operator to use.</param>
/// <param name="type">Data type of the input value.</param>
/// <param name="val">SSA ID of value to perform the operation on.</param>
/// <returns>New SSA ID with the result of the operation.</returns>
virtual id emit_unary_op(const location &loc, tokenid op, const type &type, id val) = 0;
/// <summary>
/// Adds a binary operation to the output (built-in operation with two arguments).
/// </summary>
/// <param name="loc">Source location matching this operation (for debugging).</param>
/// <param name="op">Binary operator to use.</param>
/// <param name="res_type">Data type of the result.</param>
/// <param name="type">Data type of the input values.</param>
/// <param name="lhs">SSA ID of the value on the left-hand side of the binary operation.</param>
/// <param name="rhs">SSA ID of the value on the right-hand side of the binary operation.</param>
/// <returns>New SSA ID with the result of the operation.</returns>
virtual id emit_binary_op(const location &loc, tokenid op, const type &res_type, const type &type, id lhs, id rhs) = 0;
id emit_binary_op(const location &loc, tokenid op, const type &type, id lhs, id rhs) { return emit_binary_op(loc, op, type, type, lhs, rhs); }
/// <summary>
/// Adds a ternary operation to the output (built-in operation with three arguments).
/// </summary>
/// <param name="loc">Source location matching this operation (for debugging).</param>
/// <param name="op">Ternary operator to use.</param>
/// <param name="type">Data type of the input values.</param>
/// <param name="condition">SSA ID of the condition value of the ternary operation.</param>
/// <param name="true_value">SSA ID of the first value of the ternary operation.</param>
/// <param name="false_value">SSA ID of the second value of the ternary operation.</param>
/// <returns>New SSA ID with the result of the operation.</returns>
virtual id emit_ternary_op(const location &loc, tokenid op, const type &type, id condition, id true_value, id false_value) = 0;
/// <summary>
/// Adds a function call to the output.
/// </summary>
/// <param name="loc">Source location matching this operation (for debugging).</param>
/// <param name="function">SSA ID of the function to call.</param>
/// <param name="res_type">Data type of the call result.</param>
/// <param name="args">List of SSA IDs representing the call arguments.</param>
/// <returns>New SSA ID with the result of the function call.</returns>
virtual id emit_call(const location &loc, id function, const type &res_type, const std::vector<expression> &args) = 0;
/// <summary>
/// Adds an intrinsic function call to the output.
/// </summary>
/// <param name="loc">Source location matching this operation (for debugging).</param>
/// <param name="function">Intrinsic to call.</param>
/// <param name="res_type">Data type of the call result.</param>
/// <param name="args">List of SSA IDs representing the call arguments.</param>
/// <returns>New SSA ID with the result of the function call.</returns>
virtual id emit_call_intrinsic(const location &loc, id function, const type &res_type, const std::vector<expression> &args) = 0;
/// <summary>
/// Adds a type constructor call to the output.
/// </summary>
/// <param name="type">Data type to construct.</param>
/// <param name="args">List of SSA IDs representing the scalar constructor arguments.</param>
/// <returns>New SSA ID with the constructed value.</returns>
virtual id emit_construct(const location &loc, const type &type, const std::vector<expression> &args) = 0;
/// <summary>
/// Adds a structured branch control flow to the output.
/// </summary>
/// <param name="loc">Source location matching this branch (for debugging).</param>
/// <param name="flags">0 - default, 1 - flatten, 2 - do not flatten</param>
virtual void emit_if(const location &loc, id condition_value, id condition_block, id true_statement_block, id false_statement_block, unsigned int flags) = 0;
/// <summary>
/// Adds a branch control flow with a SSA phi operation to the output.
/// </summary>
/// <param name="loc">Source location matching this branch (for debugging).</param>
/// <returns>New SSA ID with the result of the phi operation.</returns>
virtual id emit_phi(const location &loc, id condition_value, id condition_block, id true_value, id true_statement_block, id false_value, id false_statement_block, const type &type) = 0;
/// <summary>
/// Adds a structured loop control flow to the output.
/// </summary>
/// <param name="loc">Source location matching this loop (for debugging).</param>
/// <param name="flags">0 - default, 1 - unroll, 2 - do not unroll</param>
virtual void emit_loop(const location &loc, id condition_value, id prev_block, id header_block, id condition_block, id loop_block, id continue_block, unsigned int flags) = 0;
/// <summary>
/// Adds a structured switch control flow to the output.
/// </summary>
/// <param name="loc">Source location matching this switch (for debugging).</param>
/// <param name="flags">0 - default, 1 - flatten, 2 - do not flatten</param>
virtual void emit_switch(const location &loc, id selector_value, id selector_block, id default_label, id default_block, const std::vector<id> &case_literal_and_labels, const std::vector<id> &case_blocks, unsigned int flags) = 0;
/// <summary>
/// Returns <see langword="true"/> if code is currently added to a basic block.
/// </summary>
bool is_in_block() const { return _current_block != 0; }
/// <summary>
/// Returns <see langword="true"/> if code is currently added to a function.
/// </summary>
virtual bool is_in_function() const { return is_in_block(); }
/// <summary>
/// Creates a new basic block.
/// </summary>
/// <returns>New ID of the basic block.</returns>
virtual id create_block() { return make_id(); }
/// <summary>
/// Overwrites the current block ID.
/// </summary>
/// <param name="id">ID of the block to make current.</param>
/// <returns>ID of the previous basic block.</returns>
virtual id set_block(id id) = 0;
/// <summary>
/// Creates a new basic block and make it current.
/// </summary>
/// <param name="id">ID of the basic block to create and make current.</param>
virtual void enter_block(id id) = 0;
/// <summary>
/// Returns from the current basic block and kill the shader invocation.
/// </summary>
/// <returns>ID of the current basic block.</returns>
virtual id leave_block_and_kill() = 0;
/// <summary>
/// Returns from the current basic block and hand control flow over to the function call side.
/// </summary>
/// <param name="value">Optional SSA ID of a return value.</param>
/// <returns>ID of the current basic block.</returns>
virtual id leave_block_and_return(id value = 0) = 0;
/// <summary>
/// Diverges the current control flow and enter a switch.
/// </summary>
/// <param name="value">SSA ID of the selector value to decide the switch path.</param>
/// <returns>ID of the current basic block.</returns>
virtual id leave_block_and_switch(id value, id default_target) = 0;
/// <summary>
/// Diverges the current control flow and jump to the specified target block.
/// </summary>
/// <param name="target">ID of the basic block to jump to.</param>
/// <param name="is_continue">Set to <see langword="true"/> if this corresponds to a loop continue statement.</param>
/// <returns>ID of the current basic block.</returns>
virtual id leave_block_and_branch(id target, unsigned int loop_flow = 0) = 0;
/// <summary>
/// Diverges the current control flow and jump to one of the specified target blocks, depending on the condition.
/// </summary>
/// <param name="condition">SSA ID of a value used to choose which path to take.</param>
/// <param name="true_target">ID of the basic block to jump to when the condition is true.</param>
/// <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>
/// 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
{
return *std::find_if(_structs.begin(), _structs.end(),
[id](const auto &it) { return it.definition == 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)
{
return *std::find_if(_module.textures.begin(), _module.textures.end(),
[id](const auto &it) { return it.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
{
return *std::find_if(_module.samplers.begin(), _module.samplers.end(),
[id](const auto &it) { return it.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
{
return *std::find_if(_module.storages.begin(), _module.storages.end(),
[id](const auto &it) { return it.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)
{
return *std::find_if(_functions.begin(), _functions.end(),
[id](const auto &it) { return it->definition == id; })->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;
}
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;
};
/// <summary>
/// Creates a back-end implementation for GLSL code generation.
/// </summary>
/// <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 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>
/// <param name="shader_model">The HLSL shader model version (e.g. 30, 41, 50, 60, ...)</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>
codegen *create_codegen_hlsl(unsigned int shader_model, bool debug_info, bool uniforms_to_spec_constants);
/// <summary>
/// Creates a back-end implementation for SPIR-V code generation.
/// </summary>
/// <param name="vulkan_semantics">Generate SPIR-V 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_spirv(bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types = false, bool flip_vert_y = false);
}

View File

@ -0,0 +1,249 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_token.hpp"
namespace reshadefx
{
/// <summary>
/// Structure which encapsulates a parsed value type
/// </summary>
struct type
{
enum datatype : uint8_t
{
t_void,
t_bool,
t_min16int,
t_int,
t_min16uint,
t_uint,
t_min16float,
t_float,
t_string,
t_struct,
t_texture1d,
t_texture2d,
t_texture3d,
t_sampler1d_int,
t_sampler2d_int,
t_sampler3d_int,
t_sampler1d_uint,
t_sampler2d_uint,
t_sampler3d_uint,
t_sampler1d_float,
t_sampler2d_float,
t_sampler3d_float,
t_storage1d_int,
t_storage2d_int,
t_storage3d_int,
t_storage1d_uint,
t_storage2d_uint,
t_storage3d_uint,
t_storage1d_float,
t_storage2d_float,
t_storage3d_float,
t_function,
};
enum qualifier : uint32_t
{
q_extern = 1 << 0,
q_static = 1 << 1,
q_uniform = 1 << 2,
q_volatile = 1 << 3,
q_precise = 1 << 4,
q_groupshared = 1 << 14,
q_in = 1 << 5,
q_out = 1 << 6,
q_inout = q_in | q_out,
q_const = 1 << 8,
q_linear = 1 << 10,
q_noperspective = 1 << 11,
q_centroid = 1 << 12,
q_nointerpolation = 1 << 13,
};
/// <summary>
/// Gets the result type of an operation involving the two input types.
/// </summary>
static type merge(const type &lhs, const type &rhs);
/// <summary>
/// Calculates the ranking between two types which can be used to select the best matching function overload. The higher the rank, the better the match. A value of zero indicates that the types are not compatible.
/// </summary>
static unsigned int rank(const type &src, const type &dst);
/// <summary>
/// Returns a human-readable description of this type definition.
/// </summary>
std::string description() const;
bool has(qualifier x) const { return (qualifiers & x) == x; }
bool is_void() const { return base == t_void; }
bool is_boolean() const { return base == t_bool; }
bool is_numeric() const { return base >= t_bool && base <= t_float; }
bool is_integral() const { return (base >= t_bool && base <= t_uint) || (base >= t_sampler1d_int && base <= t_sampler3d_uint) || (base >= t_storage1d_int && base <= t_storage3d_uint); }
bool is_floating_point() const { return base == t_min16float || base == t_float || (base >= t_sampler1d_float && base <= t_sampler3d_float) || (base >= t_storage1d_float && base <= t_storage3d_float); }
bool is_signed() const { return base == t_min16int || base == t_int || (base >= t_sampler1d_int && base <= t_sampler3d_int) || (base >= t_storage1d_int && base <= t_storage3d_int) || is_floating_point(); }
bool is_unsigned() const { return base == t_min16uint || base == t_uint || (base >= t_sampler1d_uint && base <= t_sampler3d_uint) || (base >= t_storage1d_uint && base <= t_storage3d_uint); }
bool is_struct() const { return base == t_struct; }
bool is_object() const { return is_texture() || is_sampler() || is_storage(); }
bool is_texture() const { return base >= t_texture1d && base <= t_texture3d; }
bool is_sampler() const { return base >= t_sampler1d_int && base <= t_sampler3d_float; }
bool is_storage() const { return base >= t_storage1d_int && base <= t_storage3d_float; }
bool is_function() const { return base == t_function; }
bool is_array() const { return array_length != 0; }
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; }
unsigned int precision() const { return base == t_min16int || base == t_min16uint || base == t_min16float ? 16 : 32; }
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)
{
return lhs.base == rhs.base && lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.array_length == rhs.array_length && lhs.definition == rhs.definition;
}
friend inline bool operator!=(const type &lhs, const type &rhs)
{
return !operator==(lhs, rhs);
}
// Underlying base type ('int', 'float', ...)
datatype base = t_void;
// Number of rows if this is a vector type
unsigned int rows = 0;
// Number of columns if this is a matrix type
unsigned int cols = 0;
// 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;
// ID of the matching struct if this is a struct type
uint32_t definition = 0;
};
/// <summary>
/// Structure which encapsulates a parsed constant value
/// </summary>
struct constant
{
union
{
float as_float[16];
int32_t as_int[16];
uint32_t as_uint[16];
};
// Optional string associated with this constant
std::string string_data;
// Optional additional elements if this is an array constant
std::vector<constant> array_data;
};
/// <summary>
/// Structures which keeps track of the access chain of an expression
/// </summary>
struct expression
{
struct operation
{
enum op_type
{
op_cast,
op_member,
op_dynamic_index,
op_constant_index,
op_swizzle,
};
op_type op;
reshadefx::type from, to;
uint32_t index = 0;
signed char swizzle[4] = {};
};
uint32_t base = 0;
reshadefx::type type = {};
reshadefx::constant constant = {};
bool is_lvalue = false;
bool is_constant = false;
reshadefx::location location;
std::vector<operation> chain;
/// <summary>
/// Initializes the expression to a l-value.
/// </summary>
/// <param name="loc">Code location of the expression.</param>
/// <param name="base">SSA ID of the l-value.</param>
/// <param name="type">Value type of the expression result.</param>
void reset_to_lvalue(const reshadefx::location &loc, uint32_t base, const reshadefx::type &type);
/// <summary>
/// Initializes the expression to a r-value.
/// </summary>
/// <param name="loc">Code location of the expression.</param>
/// <param name="base">SSA ID of the r-value.</param>
/// <param name="type">Value type of the expression result.</param>
void reset_to_rvalue(const reshadefx::location &loc, uint32_t base, const reshadefx::type &type);
/// <summary>
/// Initializes the expression to a constant value.
/// </summary>
/// <param name="loc">Code location of the constant expression.</param>
/// <param name="data">Constant value to initialize to.</param>
void reset_to_rvalue_constant(const reshadefx::location &loc, bool data);
void reset_to_rvalue_constant(const reshadefx::location &loc, float data);
void reset_to_rvalue_constant(const reshadefx::location &loc, int32_t data);
void reset_to_rvalue_constant(const reshadefx::location &loc, uint32_t data);
void reset_to_rvalue_constant(const reshadefx::location &loc, std::string data);
void reset_to_rvalue_constant(const reshadefx::location &loc, reshadefx::constant data, const reshadefx::type &type);
/// <summary>
/// Adds a cast operation to the current access chain.
/// </summary>
/// <param name="type">Type to cast the expression to.</param>
void add_cast_operation(const reshadefx::type &type);
/// <summary>
/// Adds a structure member lookup to the current access chain.
/// </summary>
/// <param name="index">Index of the member to dereference.</param>
/// <param name="type">Value type of the member.</param>
void add_member_access(unsigned int index, const reshadefx::type &type);
/// <summary>
/// Adds an index operation to the current access chain.
/// </summary>
/// <param name="index_expression">SSA ID of the indexing value.</param>
void add_dynamic_index_access(uint32_t index_expression);
/// <summary>
/// Adds an constant index operation to the current access chain.
/// </summary>
/// <param name="index">Constant indexing value.</param>
void add_constant_index_access(unsigned int index);
/// <summary>
/// Adds a swizzle operation to the current access chain.
/// </summary>
/// <param name="swizzle">Swizzle for each component. -1 = unused, 0 = x, 1 = y, 2 = z, 3 = w.</param>
/// <param name="length">Number of components in the swizzle. The maximum is 4.</param>
void add_swizzle_access(const signed char swizzle[4], unsigned int length);
/// <summary>
/// Applies an unary operation to this constant expression.
/// </summary>
/// <param name="op">Unary operator to apply.</param>
bool evaluate_constant_expression(reshadefx::tokenid op);
/// <summary>
/// Applies a binary operation to this constant expression.
/// </summary>
/// <param name="op">Binary operator to apply.</param>
/// <param name="rhs">Constant value to use as right-hand side of the binary operation.</param>
bool evaluate_constant_expression(reshadefx::tokenid op, const reshadefx::constant &rhs);
};
}

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_token.hpp"
namespace reshadefx
{
/// <summary>
/// A lexical analyzer for C-like languages.
/// </summary>
class lexer
{
public:
explicit lexer(
std::string input,
bool ignore_comments = true,
bool ignore_whitespace = true,
bool ignore_pp_directives = true,
bool ignore_line_directives = false,
bool ignore_keywords = false,
bool escape_string_literals = true,
const location &start_location = location()) :
_input(std::move(input)),
_cur_location(start_location),
_ignore_comments(ignore_comments),
_ignore_whitespace(ignore_whitespace),
_ignore_pp_directives(ignore_pp_directives),
_ignore_line_directives(ignore_line_directives),
_ignore_keywords(ignore_keywords),
_escape_string_literals(escape_string_literals)
{
_cur = _input.data();
_end = _cur + _input.size();
}
lexer(const lexer &lexer) { operator=(lexer); }
lexer &operator=(const lexer &lexer)
{
_input = lexer._input;
_cur_location = lexer._cur_location;
reset_to_offset(lexer._cur - lexer._input.data());
_end = _input.data() + _input.size();
_ignore_comments = lexer._ignore_comments;
_ignore_whitespace = lexer._ignore_whitespace;
_ignore_pp_directives = lexer._ignore_pp_directives;
_ignore_keywords = lexer._ignore_keywords;
_escape_string_literals = lexer._escape_string_literals;
_ignore_line_directives = lexer._ignore_line_directives;
return *this;
}
/// <summary>
/// Gets the current position in the input string.
/// </summary>
size_t input_offset() const { return _cur - _input.data(); }
/// <summary>
/// Gets the input string this lexical analyzer works on.
/// </summary>
/// <returns>Constant reference to the input string.</returns>
const std::string &input_string() const { return _input; }
/// <summary>
/// Performs lexical analysis on the input string and return the next token in sequence.
/// </summary>
/// <returns>Next token from the input string.</returns>
token lex();
/// <summary>
/// Advances to the next token that is not whitespace.
/// </summary>
void skip_space();
/// <summary>
/// Advances to the next new line, ignoring all tokens.
/// </summary>
void skip_to_next_line();
/// <summary>
/// Resets position to the specified <paramref name="offset"/>.
/// </summary>
/// <param name="offset">Offset in characters from the start of the input string.</param>
void reset_to_offset(size_t offset);
private:
/// <summary>
/// Skips an arbitrary amount of characters in the input string.
/// </summary>
/// <param name="length">Number of input characters to skip.</param>
void skip(size_t length);
void parse_identifier(token &tok) const;
bool parse_pp_directive(token &tok);
void parse_string_literal(token &tok, bool escape);
void parse_numeric_literal(token &tok) const;
std::string _input;
location _cur_location;
const std::string::value_type *_cur, *_end;
bool _ignore_comments;
bool _ignore_whitespace;
bool _ignore_pp_directives;
bool _ignore_line_directives;
bool _ignore_keywords;
bool _escape_string_literals;
};
}

View File

@ -0,0 +1,350 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_expression.hpp"
#include <unordered_set>
namespace reshadefx
{
/// <summary>
/// A list of supported texture types.
/// </summary>
enum class texture_type
{
texture_1d = 1,
texture_2d = 2,
texture_3d = 3
};
/// <summary>
/// A list of supported texture formats.
/// </summary>
enum class texture_format
{
unknown,
r8,
r16,
r16f,
r32i,
r32u,
r32f,
rg8,
rg16,
rg16f,
rg32f,
rgba8,
rgba16,
rgba16f,
rgba32f,
rgb10a2
};
/// <summary>
/// A filtering type used for texture lookups.
/// </summary>
enum class filter_mode
{
min_mag_mip_point = 0,
min_mag_point_mip_linear = 0x1,
min_point_mag_linear_mip_point = 0x4,
min_point_mag_mip_linear = 0x5,
min_linear_mag_mip_point = 0x10,
min_linear_mag_point_mip_linear = 0x11,
min_mag_linear_mip_point = 0x14,
min_mag_mip_linear = 0x15
};
/// <summary>
/// Specifies behavior of sampling with texture coordinates outside an image.
/// </summary>
enum class texture_address_mode
{
wrap = 1,
mirror = 2,
clamp = 3,
border = 4
};
/// <summary>
/// Specifies RGB or alpha blending operations.
/// </summary>
enum class pass_blend_op : uint8_t
{
add = 1,
subtract,
reverse_subtract,
min,
max
};
/// <summary>
/// Specifies blend factors, which modulate values between the pixel shader output and render target.
/// </summary>
enum class pass_blend_factor : uint8_t
{
zero = 0,
one = 1,
source_color,
one_minus_source_color,
dest_color,
one_minus_dest_color,
source_alpha,
one_minus_source_alpha,
dest_alpha,
one_minus_dest_alpha
};
/// <summary>
/// Specifies the stencil operations that can be performed during depth-stencil testing.
/// </summary>
enum class pass_stencil_op : uint8_t
{
zero = 0,
keep,
replace,
increment_saturate,
decrement_saturate,
invert,
increment,
decrement
};
/// <summary>
/// Specifies comparison options for depth-stencil testing.
/// </summary>
enum class pass_stencil_func : uint8_t
{
never,
less,
equal,
less_equal,
greater,
not_equal,
greater_equal,
always
};
/// <summary>
/// Specifies the possible primitives.
/// </summary>
enum class primitive_topology : uint8_t
{
point_list = 1,
line_list,
line_strip,
triangle_list,
triangle_strip
};
/// <summary>
/// A struct type defined in the effect code.
/// </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
{
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 };
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;
primitive_topology topology = primitive_topology::triangle_list;
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;
};
/// <summary>
/// A collection of passes that make up an effect.
/// </summary>
struct technique_info
{
std::string name;
std::vector<pass_info> passes;
std::vector<annotation> annotations;
};
/// <summary>
/// In-memory representation of an effect file.
/// </summary>
struct module
{
std::vector<char> code;
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;
uint32_t total_uniform_size = 0;
uint32_t num_texture_bindings = 0;
uint32_t num_sampler_bindings = 0;
uint32_t num_storage_bindings = 0;
};
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_symbol_table.hpp"
#include <memory> // std::unique_ptr
namespace reshadefx
{
/// <summary>
/// A parser for the ReShade FX shader language.
/// </summary>
class parser : symbol_table
{
public:
// Define constructor explicitly because lexer class is not included here
parser();
~parser();
/// <summary>
/// Parses the provided input string.
/// </summary>
/// <param name="source">String to analyze.</param>
/// <param name="backend">Code generation implementation to use.</param>
/// <returns><see langword="true"/> if parsing was successfull, <see langword="false"/> otherwise.</returns>
bool parse(std::string source, class codegen *backend);
/// <summary>
/// Gets the list of error messages.
/// </summary>
const std::string &errors() const { return _errors; }
private:
void error(const location &location, unsigned int code, const std::string &message);
void warning(const location &location, unsigned int code, const std::string &message);
void backup();
void restore();
bool peek(char tok) const { return _token_next.id == static_cast<tokenid>(tok); }
bool peek(tokenid tokid) const { return _token_next.id == tokid; }
void consume();
void consume_until(char tok) { return consume_until(static_cast<tokenid>(tok)); }
void consume_until(tokenid tokid);
bool accept(char tok) { return accept(static_cast<tokenid>(tok)); }
bool accept(tokenid tokid);
bool expect(char tok) { return expect(static_cast<tokenid>(tok)); }
bool expect(tokenid tokid);
bool accept_symbol(std::string &identifier, scoped_symbol &symbol);
bool accept_type_class(type &type);
bool accept_type_qualifiers(type &type);
bool accept_unary_op();
bool accept_postfix_op();
bool peek_multary_op(unsigned int &precedence) const;
bool accept_assignment_op();
void parse_top(bool &parse_success);
bool parse_struct();
bool parse_function(type type, std::string name);
bool parse_variable(type type, std::string name, bool global = false);
bool parse_technique();
bool parse_technique_pass(pass_info &info);
bool parse_type(type &type);
bool parse_array_size(type &type);
bool parse_expression(expression &expression);
bool parse_expression_unary(expression &expression);
bool parse_expression_multary(expression &expression, unsigned int precedence = 0);
bool parse_expression_assignment(expression &expression);
bool parse_annotations(std::vector<annotation> &annotations);
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;
std::vector<uint32_t> _loop_break_target_stack;
std::vector<uint32_t> _loop_continue_target_stack;
reshadefx::function_info *_current_function = nullptr;
};
}

View File

@ -0,0 +1,166 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_token.hpp"
#include <memory> // std::unique_ptr
#include <filesystem>
#include <unordered_map>
#include <unordered_set>
namespace reshadefx
{
/// <summary>
/// A C-style preprocessor implementation.
/// </summary>
class preprocessor
{
public:
struct macro
{
std::string replacement_list;
std::vector<std::string> parameters;
bool is_predefined = false;
bool is_variadic = false;
bool is_function_like = false;
};
// Define constructor explicitly because lexer class is not included here
preprocessor();
~preprocessor();
/// <summary>
/// Adds an include directory to the list of search paths used when resolving #include directives.
/// </summary>
/// <param name="path">Path to the directory to add.</param>
void add_include_path(const std::filesystem::path &path);
/// <summary>
/// Adds a new macro definition. This is equal to appending '#define name macro' to this preprocessor instance.
/// </summary>
/// <param name="name">Name of the macro to define.</param>
/// <param name="macro">Definition of the macro function or value.</param>
/// <returns></returns>
bool add_macro_definition(const std::string &name, const macro &macro);
/// <summary>
/// Adds a new macro value definition. This is equal to appending '#define name macro' to this preprocessor instance.
/// </summary>
/// <param name="name">Name of the macro to define.</param>
/// <param name="value">Value to define that macro to.</param>
/// <returns></returns>
bool add_macro_definition(const std::string &name, std::string value = "1")
{
return add_macro_definition(name, macro { std::move(value), {}, true });
}
/// <summary>
/// Opens the specified file, parses its contents and appends them to the output.
/// </summary>
/// <param name="path">Path to the file to parse.</param>
/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>
bool append_file(const std::filesystem::path &path);
/// <summary>
/// Parses the specified string and appends it to the output.
/// </summary>
/// <param name="source_code">String to parse.</param>
/// <param name="path">Optional file path to identify this string with.</param>
/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>
bool append_string(std::string source_code, const std::filesystem::path &path = std::filesystem::path());
/// <summary>
/// Gets the list of error messages.
/// </summary>
const std::string &errors() const { return _errors; }
/// <summary>
/// Gets the current pre-processed output string.
/// </summary>
const std::string &output() const { return _output; }
/// <summary>
/// Gets a list of all included files.
/// </summary>
std::vector<std::filesystem::path> included_files() const;
/// <summary>
/// Gets a list of all defines that were used in #ifdef and #ifndef lines.
/// </summary>
std::vector<std::pair<std::string, std::string>> used_macro_definitions() const;
/// <summary>
/// Gets a list of pragma directives that occured.
/// </summary>
std::vector<std::pair<std::string, std::string>> used_pragma_directives() const { return _used_pragmas; }
private:
struct if_level
{
bool value;
bool skipping;
token pp_token;
size_t input_index;
};
struct input_level
{
std::string name;
std::unique_ptr<class lexer> lexer;
token next_token;
std::unordered_set<std::string> hidden_macros;
};
void error(const location &location, const std::string &message);
void warning(const location &location, const std::string &message);
void push(std::string input, const std::string &name = std::string());
bool peek(tokenid tokid) const;
void consume();
void consume_until(tokenid tokid);
bool accept(tokenid tokid, bool ignore_whitespace = true);
bool expect(tokenid tokid);
void parse();
void parse_def();
void parse_undef();
void parse_if();
void parse_ifdef();
void parse_ifndef();
void parse_elif();
void parse_else();
void parse_endif();
void parse_error();
void parse_warning();
void parse_pragma();
void parse_include();
bool evaluate_expression();
bool evaluate_identifier_as_macro();
bool is_defined(const std::string &name) const;
void expand_macro(const std::string &name, const macro &macro, const std::vector<std::string> &arguments);
void create_macro_replacement_list(macro &macro);
bool _success = true;
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;
std::vector<if_level> _if_stack;
unsigned short _recursion_count = 0;
std::unordered_set<std::string> _used_macros;
std::unordered_map<std::string, macro> _macros;
std::vector<std::filesystem::path> _include_paths;
std::unordered_map<std::string, std::string> _file_cache;
std::vector<std::pair<std::string, std::string>> _used_pragmas;
};
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include "effect_module.hpp"
#include <unordered_map> // Used for symbol lookup table
namespace reshadefx
{
/// <summary>
/// A scope encapsulating symbols.
/// </summary>
struct scope
{
std::string name;
uint32_t level, namespace_level;
};
/// <summary>
/// Enumeration of all possible symbol types.
/// </summary>
enum class symbol_type
{
invalid,
variable,
constant,
function,
intrinsic,
structure,
};
/// <summary>
/// A single symbol in the symbol table.
/// </summary>
struct symbol
{
symbol_type op = symbol_type::invalid;
uint32_t id = 0;
reshadefx::type type = {};
reshadefx::constant constant = {};
const reshadefx::function_info *function = nullptr;
};
struct scoped_symbol : symbol
{
struct scope scope; // Store scope together with symbol data
};
/// <summary>
/// A symbol table managing a list of scopes and symbols.
/// </summary>
class symbol_table
{
public:
symbol_table();
/// <summary>
/// Enters a new scope as child of the current one.
/// </summary>
void enter_scope();
/// <summary>
/// Enters a new namespace as child of the current one.
/// </summary>
void enter_namespace(const std::string &name);
/// <summary>
/// Leaves the current scope and enter the parent one.
/// </summary>
void leave_scope();
/// <summary>
/// Leaves the current namespace and enter the parent one.
/// </summary>
void leave_namespace();
/// <summary>
/// Gets the current scope the symbol table operates in.
/// </summary>
const scope &current_scope() const { return _current_scope; }
/// <summary>
/// Inserts an new symbol in the symbol table.
/// Returns <see langword="false"/> if a symbol by that name and type already exists.
/// </summary>
bool insert_symbol(const std::string &name, const symbol &symbol, bool global = false);
/// <summary>
/// Looks for an existing symbol with the specified <paramref name="name"/>.
/// </summary>
scoped_symbol find_symbol(const std::string &name) const;
scoped_symbol find_symbol(const std::string &name, const scope &scope, bool exclusive) const;
/// <summary>
/// Searches for the best function or intrinsic overload matching the argument list.
/// </summary>
bool resolve_function_call(const std::string &name, const std::vector<expression> &args, const scope &scope, symbol &data, bool &ambiguous) const;
private:
scope _current_scope;
// Lookup table from name to matching symbols
std::unordered_map<std::string, std::vector<scoped_symbol>> _symbol_stack;
};
}

View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include <string>
#include <vector>
namespace reshadefx
{
/// <summary>
/// Structure which keeps track of a code location.
/// </summary>
struct location
{
location() : line(1), column(1) {}
explicit location(uint32_t line, uint32_t column = 1) : line(line), column(column) {}
explicit location(std::string source, uint32_t line, uint32_t column = 1) : source(std::move(source)), line(line), column(column) {}
std::string source;
uint32_t line, column;
};
/// <summary>
/// A collection of identifiers for various possible tokens.
/// </summary>
enum class tokenid
{
unknown = -1,
end_of_file = 0,
end_of_line = '\n',
// operators
space = ' ',
exclaim = '!',
hash = '#',
dollar = '$',
percent = '%',
ampersand = '&',
parenthesis_open = '(',
parenthesis_close = ')',
star = '*',
plus = '+',
comma = ',',
minus = '-',
dot = '.',
slash = '/',
colon = ':',
semicolon = ';',
less = '<',
equal = '=',
greater = '>',
question = '?',
at = '@',
bracket_open = '[',
backslash = '\\',
bracket_close = ']',
caret = '^',
brace_open = '{',
pipe = '|',
brace_close = '}',
tilde = '~',
exclaim_equal = 256 /* != */,
percent_equal /* %= */,
ampersand_ampersand /* && */,
ampersand_equal /* &= */,
star_equal /* *= */,
plus_plus /* ++*/,
plus_equal /* += */,
minus_minus /* -- */,
minus_equal /* -= */,
arrow /* -> */,
ellipsis /* ... */,
slash_equal /* /= */,
colon_colon /* :: */,
less_less_equal /* <<= */,
less_less /* << */,
less_equal /* <= */,
equal_equal /* == */,
greater_greater_equal /* >>= */,
greater_greater /* >> */,
greater_equal /* >= */,
caret_equal /* ^= */,
pipe_equal /* |= */,
pipe_pipe /* || */,
// identifiers
reserved,
identifier,
// literals
true_literal,
false_literal,
int_literal,
uint_literal,
float_literal,
double_literal,
string_literal,
// keywords
namespace_,
struct_,
technique,
pass,
for_,
while_,
do_,
if_,
else_,
switch_,
case_,
default_,
break_,
continue_,
return_,
discard_,
extern_,
static_,
uniform_,
volatile_,
precise,
groupshared,
in,
out,
inout,
const_,
linear,
noperspective,
centroid,
nointerpolation,
void_,
bool_,
bool2,
bool3,
bool4,
bool2x2,
bool2x3,
bool2x4,
bool3x2,
bool3x3,
bool3x4,
bool4x2,
bool4x3,
bool4x4,
int_,
int2,
int3,
int4,
int2x2,
int2x3,
int2x4,
int3x2,
int3x3,
int3x4,
int4x2,
int4x3,
int4x4,
min16int,
min16int2,
min16int3,
min16int4,
uint_,
uint2,
uint3,
uint4,
uint2x2,
uint2x3,
uint2x4,
uint3x2,
uint3x3,
uint3x4,
uint4x2,
uint4x3,
uint4x4,
min16uint,
min16uint2,
min16uint3,
min16uint4,
float_,
float2,
float3,
float4,
float2x2,
float2x3,
float2x4,
float3x2,
float3x3,
float3x4,
float4x2,
float4x3,
float4x4,
min16float,
min16float2,
min16float3,
min16float4,
vector,
matrix,
string_,
texture1d,
texture2d,
texture3d,
sampler1d,
sampler2d,
sampler3d,
storage1d,
storage2d,
storage3d,
// preprocessor directives
hash_def,
hash_undef,
hash_if,
hash_ifdef,
hash_ifndef,
hash_else,
hash_elif,
hash_endif,
hash_error,
hash_warning,
hash_pragma,
hash_include,
hash_unknown,
single_line_comment,
multi_line_comment,
};
/// <summary>
/// A structure describing a single token in the input string.
/// </summary>
struct token
{
tokenid id;
reshadefx::location location;
size_t offset, length;
union
{
int literal_as_int;
unsigned int literal_as_uint;
float literal_as_float;
double literal_as_double;
};
std::string literal_as_string;
inline operator tokenid() const { return id; }
static std::string id_to_name(tokenid id);
};
}