Path: blob/master/dep/reshadefx/include/effect_codegen.hpp
4246 views
/*1* Copyright (C) 2014 Patrick Mours2* SPDX-License-Identifier: BSD-3-Clause3*/45#pragma once67#include "effect_module.hpp"8#include <memory> // std::unique_ptr9#include <algorithm> // std::find_if1011namespace reshadefx12{13/// <summary>14/// A SSA code generation back-end interface for the parser to call into.15/// </summary>16class codegen17{18friend class parser;1920public:21/// <summary>22/// Virtual destructor to guarantee that memory of the implementations deriving from this interface is properly destroyed.23/// </summary>24virtual ~codegen() {}2526/// <summary>27/// Gets the module describing the generated code.28/// </summary>29const effect_module &module() const { return _module; }3031/// <summary>32/// Finalizes and returns the generated code for the entire module (all entry points).33/// </summary>34virtual std::basic_string<char> finalize_code() const = 0;35/// <summary>36/// Finalizes and returns the generated code for the specified entry point (and no other entry points).37/// </summary>38/// <param name="entry_point_name">Name of the entry point function to generate code for.</param>39virtual std::basic_string<char> finalize_code_for_entry_point(const std::string &entry_point_name) const = 0;4041protected:42/// <summary>43/// An opaque ID referring to a SSA value or basic block.44/// </summary>45using id = uint32_t;4647/// <summary>48/// Defines a new struct type.49/// </summary>50/// <param name="loc">Source location matching this definition (for debugging).</param>51/// <param name="info">Description of the type.</param>52/// <returns>New SSA ID of the type.</returns>53virtual id define_struct(const location &loc, struct_type &info) = 0;54/// <summary>55/// Defines a new texture binding.56/// </summary>57/// <param name="loc">Source location matching this definition (for debugging).</param>58/// <param name="info">Description of the texture object.</param>59/// <returns>New SSA ID of the binding.</returns>60virtual id define_texture(const location &loc, texture &info) = 0;61/// <summary>62/// Defines a new sampler binding.63/// </summary>64/// <param name="loc">Source location matching this definition (for debugging).</param>65/// <param name="tex_info">Description of the texture this sampler object references.</param>66/// <param name="info">Description of the sampler object.</param>67/// <returns>New SSA ID of the binding.</returns>68virtual id define_sampler(const location &loc, const texture &tex_info, sampler &info) = 0;69/// <summary>70/// Defines a new storage binding.71/// </summary>72/// <param name="loc">Source location matching this definition (for debugging).</param>73/// <param name="tex_info">Description of the texture this storage object references.</param>74/// <param name="info">Description of the storage object.</param>75/// <returns>New SSA ID of the binding.</returns>76virtual id define_storage(const location &loc, const texture &tex_info, storage &info) = 0;77/// <summary>78/// Defines a new uniform variable.79/// </summary>80/// <param name="loc">Source location matching this definition (for debugging).</param>81/// <param name="info">Description of the uniform variable.</param>82/// <returns>New SSA ID of the variable.</returns>83virtual id define_uniform(const location &loc, uniform &info) = 0;84/// <summary>85/// Defines a new variable.86/// </summary>87/// <param name="loc">Source location matching this definition (for debugging).</param>88/// <param name="type">Data type of the variable.</param>89/// <param name="name">Name of the variable.</param>90/// <param name="global"><c>true</c> if this variable is in global scope, <c>false</c> otherwise.</param>91/// <param name="initializer_value">SSA ID of an optional initializer value.</param>92/// <returns>New SSA ID of the variable.</returns>93virtual id define_variable(const location &loc, const type &type, std::string name = std::string(), bool global = false, id initializer_value = 0) = 0;94/// <summary>95/// Defines a new function and its function parameters and make it current.96/// Any code added after this call is added to this function.97/// </summary>98/// <param name="loc">Source location matching this definition (for debugging).</param>99/// <param name="info">Description of the function.</param>100/// <returns>New SSA ID of the function.</returns>101virtual id define_function(const location &loc, function &info) = 0;102103/// <summary>104/// Defines a new effect technique.105/// </summary>106/// <param name="loc">Source location matching this definition (for debugging).</param>107/// <param name="info">Description of the technique.</param>108void define_technique(technique &&info) { _module.techniques.push_back(std::move(info)); }109/// <summary>110/// Makes a function a shader entry point.111/// </summary>112/// <param name="function">Function to use as entry point. May be overwritten to point to a new uniquely generated function.</param>113virtual void define_entry_point(function &function) = 0;114115/// <summary>116/// Resolves the access chain and add a load operation to the output.117/// </summary>118/// <param name="chain">Access chain pointing to the variable to load from.</param>119/// <param name="force_new_id">Set to <see langword="true"/> to force this to return a new SSA ID for l-value loads.</param>120/// <returns>New SSA ID with the loaded value.</returns>121virtual id emit_load(const expression &chain, bool force_new_id = false) = 0;122/// <summary>123/// Resolves the access chain and add a store operation to the output.124/// </summary>125/// <param name="chain">Access chain pointing to the variable to store to.</param>126/// <param name="value">SSA ID of the value to store.</param>127virtual void emit_store(const expression &chain, id value) = 0;128/// <summary>129/// Resolves the access chain, but do not add a load operation. This returns a pointer instead.130/// </summary>131/// <param name="chain">Access chain pointing to the variable to resolve.</param>132/// <param name="chain_index">Output value which is set to the index in the access chain up to which the access chain went.</param>133/// <returns>New SSA ID with a pointer to the value.</returns>134virtual id emit_access_chain(const expression &chain, size_t &chain_index) { chain_index = chain.chain.size(); return emit_load(chain); }135136/// <summary>137/// Creates a SSA constant value.138/// </summary>139/// <param name="type">Data type of the constant.</param>140/// <param name="data">Actual constant data to convert into a SSA ID.</param>141/// <returns>New SSA ID with the constant value.</returns>142virtual id emit_constant(const type &type, const constant &data) = 0;143id emit_constant(const type &data_type, uint32_t value)144{145// Create a constant value of the specified type146constant data = {}; // Initialize to zero, so that components not set below still have a defined value for lookup via std::memcmp147for (unsigned int i = 0; i < data_type.components(); ++i)148{149if (data_type.is_integral())150data.as_uint[i] = value;151else152data.as_float[i] = static_cast<float>(value);153}154return emit_constant(data_type, data);155}156157/// <summary>158/// Adds an unary operation to the output (built-in operation with one argument).159/// </summary>160/// <param name="loc">Source location matching this operation (for debugging).</param>161/// <param name="op">Unary operator to use.</param>162/// <param name="type">Data type of the input value.</param>163/// <param name="val">SSA ID of value to perform the operation on.</param>164/// <returns>New SSA ID with the result of the operation.</returns>165virtual id emit_unary_op(const location &loc, tokenid op, const type &type, id val) = 0;166/// <summary>167/// Adds a binary operation to the output (built-in operation with two arguments).168/// </summary>169/// <param name="loc">Source location matching this operation (for debugging).</param>170/// <param name="op">Binary operator to use.</param>171/// <param name="res_type">Data type of the result.</param>172/// <param name="type">Data type of the input values.</param>173/// <param name="lhs">SSA ID of the value on the left-hand side of the binary operation.</param>174/// <param name="rhs">SSA ID of the value on the right-hand side of the binary operation.</param>175/// <returns>New SSA ID with the result of the operation.</returns>176virtual id emit_binary_op(const location &loc, tokenid op, const type &res_type, const type &type, id lhs, id rhs) = 0;177id 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); }178/// <summary>179/// Adds a ternary operation to the output (built-in operation with three arguments).180/// </summary>181/// <param name="loc">Source location matching this operation (for debugging).</param>182/// <param name="op">Ternary operator to use.</param>183/// <param name="type">Data type of the input values.</param>184/// <param name="condition">SSA ID of the condition value of the ternary operation.</param>185/// <param name="true_value">SSA ID of the first value of the ternary operation.</param>186/// <param name="false_value">SSA ID of the second value of the ternary operation.</param>187/// <returns>New SSA ID with the result of the operation.</returns>188virtual id emit_ternary_op(const location &loc, tokenid op, const type &type, id condition, id true_value, id false_value) = 0;189/// <summary>190/// Adds a function call to the output.191/// </summary>192/// <param name="loc">Source location matching this operation (for debugging).</param>193/// <param name="function">SSA ID of the function to call.</param>194/// <param name="res_type">Data type of the call result.</param>195/// <param name="args">List of SSA IDs representing the call arguments.</param>196/// <returns>New SSA ID with the result of the function call.</returns>197virtual id emit_call(const location &loc, id function, const type &res_type, const std::vector<expression> &args) = 0;198/// <summary>199/// Adds an intrinsic function call to the output.200/// </summary>201/// <param name="loc">Source location matching this operation (for debugging).</param>202/// <param name="function">Intrinsic to call.</param>203/// <param name="res_type">Data type of the call result.</param>204/// <param name="args">List of SSA IDs representing the call arguments.</param>205/// <returns>New SSA ID with the result of the function call.</returns>206virtual id emit_call_intrinsic(const location &loc, id function, const type &res_type, const std::vector<expression> &args) = 0;207/// <summary>208/// Adds a type constructor call to the output.209/// </summary>210/// <param name="type">Data type to construct.</param>211/// <param name="args">List of SSA IDs representing the scalar constructor arguments.</param>212/// <returns>New SSA ID with the constructed value.</returns>213virtual id emit_construct(const location &loc, const type &type, const std::vector<expression> &args) = 0;214215/// <summary>216/// Adds a structured branch control flow to the output.217/// </summary>218/// <param name="loc">Source location matching this branch (for debugging).</param>219/// <param name="flags">0 - default, 1 - flatten, 2 - do not flatten</param>220virtual void emit_if(const location &loc, id condition_value, id condition_block, id true_statement_block, id false_statement_block, unsigned int flags) = 0;221/// <summary>222/// Adds a branch control flow with a SSA phi operation to the output.223/// </summary>224/// <param name="loc">Source location matching this branch (for debugging).</param>225/// <returns>New SSA ID with the result of the phi operation.</returns>226virtual 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;227/// <summary>228/// Adds a structured loop control flow to the output.229/// </summary>230/// <param name="loc">Source location matching this loop (for debugging).</param>231/// <param name="flags">0 - default, 1 - unroll, 2 - do not unroll</param>232virtual 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;233/// <summary>234/// Adds a structured switch control flow to the output.235/// </summary>236/// <param name="loc">Source location matching this switch (for debugging).</param>237/// <param name="flags">0 - default, 1 - flatten, 2 - do not flatten</param>238virtual 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;239240/// <summary>241/// Returns <see langword="true"/> if code is currently added to a basic block.242/// </summary>243bool is_in_block() const { return _current_block != 0; }244/// <summary>245/// Returns <see langword="true"/> if code is currently added to a function.246/// </summary>247bool is_in_function() const { return _current_function != nullptr; }248249/// <summary>250/// Creates a new basic block.251/// </summary>252/// <returns>New ID of the basic block.</returns>253virtual id create_block() { return make_id(); }254/// <summary>255/// Overwrites the current block ID.256/// </summary>257/// <param name="id">ID of the block to make current.</param>258/// <returns>ID of the previous basic block.</returns>259virtual id set_block(id id) = 0;260/// <summary>261/// Creates a new basic block and make it current.262/// </summary>263/// <param name="id">ID of the basic block to create and make current.</param>264virtual void enter_block(id id) = 0;265/// <summary>266/// Returns from the current basic block and kill the shader invocation.267/// </summary>268/// <returns>ID of the current basic block.</returns>269virtual id leave_block_and_kill() = 0;270/// <summary>271/// Returns from the current basic block and hand control flow over to the function call side.272/// </summary>273/// <param name="value">Optional SSA ID of a return value.</param>274/// <returns>ID of the current basic block.</returns>275virtual id leave_block_and_return(id value = 0) = 0;276/// <summary>277/// Diverges the current control flow and enter a switch.278/// </summary>279/// <param name="value">SSA ID of the selector value to decide the switch path.</param>280/// <returns>ID of the current basic block.</returns>281virtual id leave_block_and_switch(id value, id default_target) = 0;282/// <summary>283/// Diverges the current control flow and jump to the specified target block.284/// </summary>285/// <param name="target">ID of the basic block to jump to.</param>286/// <param name="is_continue">Set to <see langword="true"/> if this corresponds to a loop continue statement.</param>287/// <returns>ID of the current basic block.</returns>288virtual id leave_block_and_branch(id target, unsigned int loop_flow = 0) = 0;289/// <summary>290/// Diverges the current control flow and jump to one of the specified target blocks, depending on the condition.291/// </summary>292/// <param name="condition">SSA ID of a value used to choose which path to take.</param>293/// <param name="true_target">ID of the basic block to jump to when the condition is true.</param>294/// <param name="false_target">ID of the basic block to jump to when the condition is false.</param>295/// <returns>ID of the current basic block.</returns>296virtual id leave_block_and_branch_conditional(id condition, id true_target, id false_target) = 0;297298/// <summary>299/// Leaves the current function. Any code added after this call is added in the global scope.300/// </summary>301virtual void leave_function() = 0;302303/// <summary>304/// Recalculates sampler and storage bindings to take as little binding space as possible for each entry point.305/// </summary>306virtual void optimize_bindings();307308/// <summary>309/// Looks up an existing struct type.310/// </summary>311/// <param name="id">SSA ID of the type to find.</param>312/// <returns>Reference to the struct description.</returns>313const struct_type &get_struct(id id) const314{315return *std::find_if(_structs.begin(), _structs.end(),316[id](const struct_type &info) { return info.id == id; });317}318/// <summary>319/// Looks up an existing texture binding.320/// </summary>321/// <param name="id">SSA ID of the texture binding to find.</param>322/// <returns>Reference to the texture description.</returns>323texture &get_texture(id id)324{325return *std::find_if(_module.textures.begin(), _module.textures.end(),326[id](const texture &info) { return info.id == id; });327}328/// <summary>329/// Looks up an existing sampler binding.330/// </summary>331/// <param name="id">SSA ID of the sampler binding to find.</param>332/// <returns>Reference to the sampler description.</returns>333const sampler &get_sampler(id id) const334{335return *std::find_if(_module.samplers.begin(), _module.samplers.end(),336[id](const sampler &info) { return info.id == id; });337}338/// <summary>339/// Looks up an existing storage binding.340/// </summary>341/// <param name="id">SSA ID of the storage binding to find.</param>342/// <returns>Reference to the storage description.</returns>343const storage &get_storage(id id) const344{345return *std::find_if(_module.storages.begin(), _module.storages.end(),346[id](const storage &info) { return info.id == id; });347}348/// <summary>349/// Looks up an existing function definition.350/// </summary>351/// <param name="id">SSA ID of the function variable to find.</param>352/// <returns>Reference to the function description.</returns>353function &get_function(id id)354{355return *std::find_if(_functions.begin(), _functions.end(),356[id](const std::unique_ptr<function> &info) { return info->id == id; })->get();357}358function &get_function(const std::string &unique_name)359{360return *std::find_if(_functions.begin(), _functions.end(),361[&unique_name](const std::unique_ptr<function> &info) { return info->unique_name == unique_name; })->get();362}363364id make_id() { return _next_id++; }365366effect_module _module;367std::vector<struct_type> _structs;368std::vector<std::unique_ptr<function>> _functions;369370id _next_id = 1;371id _last_block = 0;372id _current_block = 0;373function *_current_function = nullptr;374};375376/// <summary>377/// Creates a back-end implementation for GLSL code generation.378/// </summary>379/// <param name="version">GLSL version to insert at the beginning of the file.</param>380/// <param name="gles">Generate GLSL ES code instead of core OpenGL.</param>381/// <param name="vulkan_semantics">Generate GLSL for OpenGL or for Vulkan.</param>382/// <param name="debug_info">Whether to append debug information like line directives to the generated code.</param>383/// <param name="uniforms_to_spec_constants">Whether to convert uniform variables to specialization constants.</param>384/// <param name="enable_16bit_types">Use real 16-bit types for the minimum precision types "min16int", "min16uint" and "min16float".</param>385/// <param name="flip_vert_y">Insert code to flip the Y component of the output position in vertex shaders.</param>386codegen *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);387/// <summary>388/// Creates a back-end implementation for HLSL code generation.389/// </summary>390/// <param name="shader_model">The HLSL shader model version (e.g. 30, 41, 50, 60, ...)</param>391/// <param name="debug_info">Whether to append debug information like line directives to the generated code.</param>392/// <param name="uniforms_to_spec_constants">Whether to convert uniform variables to specialization constants.</param>393codegen *create_codegen_hlsl(unsigned int shader_model, bool debug_info, bool uniforms_to_spec_constants);394/// <summary>395/// Creates a back-end implementation for SPIR-V code generation.396/// </summary>397/// <param name="vulkan_semantics">Generate SPIR-V for OpenGL or for Vulkan.</param>398/// <param name="debug_info">Whether to append debug information like line directives to the generated code.</param>399/// <param name="uniforms_to_spec_constants">Whether to convert uniform variables to specialization constants.</param>400/// <param name="enable_16bit_types">Use real 16-bit types for the minimum precision types "min16int", "min16uint" and "min16float".</param>401/// <param name="flip_vert_y">Insert code to flip the Y component of the output position in vertex shaders.</param>402codegen *create_codegen_spirv(bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types = false, bool flip_vert_y = false);403}404405406