glslang/glslang/Public/ShaderLang.h
Chow f4b2ba2c27 Reflection will crash when the VS input symbol defines the same name with FS output symbol
[PURPOSE]:
The current process design for Uniform / Block / Pipe IO symbols reflection (during program linking) is as following :

1.1 using a global mapper called 'TNameToIndex' to store all the relationship of name (of symbols) to their indexes (in their own MapIndexToReflection vectors).

1.2 TNameToIndex mapper will be used during program linking and helps to check and merge duplicate symbols within each stage ( Uniform, Block and Pipe IO)

1.3 Different types of symbols will have their own index mapping storage. All those symbols will share TNameToIndex as a general searching mapper.

1.4 Only IN in first stage and OUT in last stage will be dealed within traversing functions.

Now, here we meet those problems:

2.1 In and Out variables for pipelines are mapping to different MapIndexToReflection vector (ioItems), but they may still have same names within the general symbol search mapper : TNameToIndex.

2.2 Then, when there are same symbols of IN in VS and OUT in FS, TNameToIndex could not tell the difference because it only stores one local index for one symbol (1:1) as a pair of KeyValue.

[What fixed]:

Seperate I/O from other symbols like Uniform and Block (it is wrong to keep them all in TNameToIndex), and save in new searching mappers called pipeInNameToIndex and pipeOutNameToIndex.

Expose new top-level functions defined as getReflectionPipeIOIndex and getPipeIOIndex for users who need to query Pipe I/O information (As they may reach those things through getUniformIndex and getReflectionIndex now, which is a confused way.)

As there are 2 mappers for above symbols, users needs to input second argument when they wanna reach those pipe I/O parameters, that's also why we need to modify GET functions either.

[Test Case]:

The shader is as following:

######### VS ############
layout(location = 0) in vec4 g_position;
layout(location = 1) in vec4 g_color;
out StageData {
vec4 color;
} g_vs_out;
void main() {
gl_Position = g_position;
g_vs_out.color = g_color;
}

########### FS #############
in StageData {
vec4 color;
} g_fs_in;
layout(location = 0) out vec4 g_color;
void main() {
g_color = g_fs_in.color;
}
2019-09-18 14:04:29 +08:00

901 lines
37 KiB
C++
Executable File

//
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
// Copyright (C) 2013-2016 LunarG, Inc.
// Copyright (C) 2015-2018 Google, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#ifndef _COMPILER_INTERFACE_INCLUDED_
#define _COMPILER_INTERFACE_INCLUDED_
#include "../Include/ResourceLimits.h"
#include "../MachineIndependent/Versions.h"
#include <cstring>
#include <vector>
#ifdef _WIN32
#define C_DECL __cdecl
//#ifdef SH_EXPORTING
// #define SH_IMPORT_EXPORT __declspec(dllexport)
//#else
// #define SH_IMPORT_EXPORT __declspec(dllimport)
//#endif
#define SH_IMPORT_EXPORT
#else
#define SH_IMPORT_EXPORT
#define C_DECL
#endif
//
// This is the platform independent interface between an OGL driver
// and the shading language compiler/linker.
//
#ifdef __cplusplus
extern "C" {
#endif
// This should always increase, as some paths to do not consume
// a more major number.
// It should increment by one when new functionality is added.
#define GLSLANG_MINOR_VERSION 13
//
// Call before doing any other compiler/linker operations.
//
// (Call once per process, not once per thread.)
//
SH_IMPORT_EXPORT int ShInitialize();
//
// Call this at process shutdown to clean up memory.
//
SH_IMPORT_EXPORT int ShFinalize();
//
// Types of languages the compiler can consume.
//
typedef enum {
EShLangVertex,
EShLangTessControl,
EShLangTessEvaluation,
EShLangGeometry,
EShLangFragment,
EShLangCompute,
EShLangRayGenNV,
EShLangIntersectNV,
EShLangAnyHitNV,
EShLangClosestHitNV,
EShLangMissNV,
EShLangCallableNV,
EShLangTaskNV,
EShLangMeshNV,
EShLangCount,
} EShLanguage; // would be better as stage, but this is ancient now
typedef enum {
EShLangVertexMask = (1 << EShLangVertex),
EShLangTessControlMask = (1 << EShLangTessControl),
EShLangTessEvaluationMask = (1 << EShLangTessEvaluation),
EShLangGeometryMask = (1 << EShLangGeometry),
EShLangFragmentMask = (1 << EShLangFragment),
EShLangComputeMask = (1 << EShLangCompute),
EShLangRayGenNVMask = (1 << EShLangRayGenNV),
EShLangIntersectNVMask = (1 << EShLangIntersectNV),
EShLangAnyHitNVMask = (1 << EShLangAnyHitNV),
EShLangClosestHitNVMask = (1 << EShLangClosestHitNV),
EShLangMissNVMask = (1 << EShLangMissNV),
EShLangCallableNVMask = (1 << EShLangCallableNV),
EShLangTaskNVMask = (1 << EShLangTaskNV),
EShLangMeshNVMask = (1 << EShLangMeshNV),
} EShLanguageMask;
namespace glslang {
class TType;
typedef enum {
EShSourceNone,
EShSourceGlsl, // GLSL, includes ESSL (OpenGL ES GLSL)
EShSourceHlsl, // HLSL
} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead
typedef enum {
EShClientNone, // use when there is no client, e.g. for validation
EShClientVulkan,
EShClientOpenGL,
} EShClient;
typedef enum {
EShTargetNone,
EShTargetSpv, // SPIR-V (preferred spelling)
EshTargetSpv = EShTargetSpv, // legacy spelling
} EShTargetLanguage;
typedef enum {
EShTargetVulkan_1_0 = (1 << 22), // Vulkan 1.0
EShTargetVulkan_1_1 = (1 << 22) | (1 << 12), // Vulkan 1.1
EShTargetOpenGL_450 = 450, // OpenGL
} EShTargetClientVersion;
typedef EShTargetClientVersion EshTargetClientVersion;
typedef enum {
EShTargetSpv_1_0 = (1 << 16), // SPIR-V 1.0
EShTargetSpv_1_1 = (1 << 16) | (1 << 8), // SPIR-V 1.1
EShTargetSpv_1_2 = (1 << 16) | (2 << 8), // SPIR-V 1.2
EShTargetSpv_1_3 = (1 << 16) | (3 << 8), // SPIR-V 1.3
EShTargetSpv_1_4 = (1 << 16) | (4 << 8), // SPIR-V 1.4
EShTargetSpv_1_5 = (1 << 16) | (5 << 8), // SPIR-V 1.5
} EShTargetLanguageVersion;
struct TInputLanguage {
EShSource languageFamily; // redundant information with other input, this one overrides when not EShSourceNone
EShLanguage stage; // redundant information with other input, this one overrides when not EShSourceNone
EShClient dialect;
int dialectVersion; // version of client's language definition, not the client (when not EShClientNone)
};
struct TClient {
EShClient client;
EShTargetClientVersion version; // version of client itself (not the client's input dialect)
};
struct TTarget {
EShTargetLanguage language;
EShTargetLanguageVersion version; // version to target, if SPIR-V, defined by "word 1" of the SPIR-V header
bool hlslFunctionality1; // can target hlsl_functionality1 extension(s)
};
// All source/client/target versions and settings.
// Can override previous methods of setting, when items are set here.
// Expected to grow, as more are added, rather than growing parameter lists.
struct TEnvironment {
TInputLanguage input; // definition of the input language
TClient client; // what client is the overall compilation being done for?
TTarget target; // what to generate
};
const char* StageName(EShLanguage);
} // end namespace glslang
//
// Types of output the linker will create.
//
typedef enum {
EShExVertexFragment,
EShExFragment
} EShExecutable;
//
// Optimization level for the compiler.
//
typedef enum {
EShOptNoGeneration,
EShOptNone,
EShOptSimple, // Optimizations that can be done quickly
EShOptFull, // Optimizations that will take more time
} EShOptimizationLevel;
//
// Texture and Sampler transformation mode.
//
typedef enum {
EShTexSampTransKeep, // keep textures and samplers as is (default)
EShTexSampTransUpgradeTextureRemoveSampler, // change texture w/o embeded sampler into sampled texture and throw away all samplers
} EShTextureSamplerTransformMode;
//
// Message choices for what errors and warnings are given.
//
enum EShMessages {
EShMsgDefault = 0, // default is to give all required errors and extra warnings
EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input
EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification
EShMsgAST = (1 << 2), // print the AST intermediate representation
EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation
EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V
EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor
EShMsgReadHlsl = (1 << 6), // use HLSL parsing rules and semantics
EShMsgCascadingErrors = (1 << 7), // get cascading errors; risks error-recovery issues, instead of an early exit
EShMsgKeepUncalled = (1 << 8), // for testing, don't eliminate uncalled functions
EShMsgHlslOffsets = (1 << 9), // allow block offsets to follow HLSL rules instead of GLSL rules
EShMsgDebugInfo = (1 << 10), // save debug information
EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL
EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages
EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (right now only for samplers)
EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table
};
//
// Options for building reflection
//
typedef enum {
EShReflectionDefault = 0, // default is original behaviour before options were added
EShReflectionStrictArraySuffix = (1 << 0), // reflection will follow stricter rules for array-of-structs suffixes
EShReflectionBasicArraySuffix = (1 << 1), // arrays of basic types will be appended with [0] as in GL reflection
EShReflectionIntermediateIO = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader
EShReflectionSeparateBuffers = (1 << 3), // buffer variables and buffer blocks are reflected separately
EShReflectionAllBlockVariables = (1 << 4), // reflect all variables in blocks, even if they are inactive
EShReflectionUnwrapIOBlocks = (1 << 5), // unwrap input/output blocks the same as with uniform blocks
} EShReflectionOptions;
//
// Build a table for bindings. This can be used for locating
// attributes, uniforms, globals, etc., as needed.
//
typedef struct {
const char* name;
int binding;
} ShBinding;
typedef struct {
int numBindings;
ShBinding* bindings; // array of bindings
} ShBindingTable;
//
// ShHandle held by but opaque to the driver. It is allocated,
// managed, and de-allocated by the compiler/linker. It's contents
// are defined by and used by the compiler and linker. For example,
// symbol table information and object code passed from the compiler
// to the linker can be stored where ShHandle points.
//
// If handle creation fails, 0 will be returned.
//
typedef void* ShHandle;
//
// Driver calls these to create and destroy compiler/linker
// objects.
//
SH_IMPORT_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int debugOptions); // one per shader
SH_IMPORT_EXPORT ShHandle ShConstructLinker(const EShExecutable, int debugOptions); // one per shader pair
SH_IMPORT_EXPORT ShHandle ShConstructUniformMap(); // one per uniform namespace (currently entire program object)
SH_IMPORT_EXPORT void ShDestruct(ShHandle);
//
// The return value of ShCompile is boolean, non-zero indicating
// success.
//
// The info-log should be written by ShCompile into
// ShHandle, so it can answer future queries.
//
SH_IMPORT_EXPORT int ShCompile(
const ShHandle,
const char* const shaderStrings[],
const int numStrings,
const int* lengths,
const EShOptimizationLevel,
const TBuiltInResource *resources,
int debugOptions,
int defaultVersion = 110, // use 100 for ES environment, overridden by #version in shader
bool forwardCompatible = false, // give errors for use of deprecated features
EShMessages messages = EShMsgDefault // warnings and errors
);
SH_IMPORT_EXPORT int ShLinkExt(
const ShHandle, // linker object
const ShHandle h[], // compiler objects to link together
const int numHandles);
//
// ShSetEncrpytionMethod is a place-holder for specifying
// how source code is encrypted.
//
SH_IMPORT_EXPORT void ShSetEncryptionMethod(ShHandle);
//
// All the following return 0 if the information is not
// available in the object passed down, or the object is bad.
//
SH_IMPORT_EXPORT const char* ShGetInfoLog(const ShHandle);
SH_IMPORT_EXPORT const void* ShGetExecutable(const ShHandle);
SH_IMPORT_EXPORT int ShSetVirtualAttributeBindings(const ShHandle, const ShBindingTable*); // to detect user aliasing
SH_IMPORT_EXPORT int ShSetFixedAttributeBindings(const ShHandle, const ShBindingTable*); // to force any physical mappings
//
// Tell the linker to never assign a vertex attribute to this list of physical attributes
//
SH_IMPORT_EXPORT int ShExcludeAttributes(const ShHandle, int *attributes, int count);
//
// Returns the location ID of the named uniform.
// Returns -1 if error.
//
SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char* name);
#ifdef __cplusplus
} // end extern "C"
#endif
////////////////////////////////////////////////////////////////////////////////////////////
//
// Deferred-Lowering C++ Interface
// -----------------------------------
//
// Below is a new alternate C++ interface, which deprecates the above
// opaque handle-based interface.
//
// The below is further designed to handle multiple compilation units per stage, where
// the intermediate results, including the parse tree, are preserved until link time,
// rather than the above interface which is designed to have each compilation unit
// lowered at compile time. In the above model, linking occurs on the lowered results,
// whereas in this model intra-stage linking can occur at the parse tree
// (treeRoot in TIntermediate) level, and then a full stage can be lowered.
//
#include <list>
#include <string>
#include <utility>
class TCompiler;
class TInfoSink;
namespace glslang {
const char* GetEsslVersionString();
const char* GetGlslVersionString();
int GetKhronosToolId();
class TIntermediate;
class TProgram;
class TPoolAllocator;
// Call this exactly once per process before using anything else
bool InitializeProcess();
// Call once per process to tear down everything
void FinalizeProcess();
// Resource type for IO resolver
enum TResourceType {
EResSampler,
EResTexture,
EResImage,
EResUbo,
EResSsbo,
EResUav,
EResCount
};
// Make one TShader per shader that you will link into a program. Then
// - provide the shader through setStrings() or setStringsWithLengths()
// - optionally call setEnv*(), see below for more detail
// - optionally use setPreamble() to set a special shader string that will be
// processed before all others but won't affect the validity of #version
// - call parse(): source language and target environment must be selected
// either by correct setting of EShMessages sent to parse(), or by
// explicitly calling setEnv*()
// - query the info logs
//
// N.B.: Does not yet support having the same TShader instance being linked into
// multiple programs.
//
// N.B.: Destruct a linked program *before* destructing the shaders linked into it.
//
class TShader {
public:
explicit TShader(EShLanguage);
virtual ~TShader();
void setStrings(const char* const* s, int n);
void setStringsWithLengths(const char* const* s, const int* l, int n);
void setStringsWithLengthsAndNames(
const char* const* s, const int* l, const char* const* names, int n);
void setPreamble(const char* s) { preamble = s; }
void setEntryPoint(const char* entryPoint);
void setSourceEntryPoint(const char* sourceEntryPointName);
void addProcesses(const std::vector<std::string>&);
// IO resolver binding data: see comments in ShaderLang.cpp
void setShiftBinding(TResourceType res, unsigned int base);
void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding
void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set);
void setResourceSetBinding(const std::vector<std::string>& base);
void setAutoMapBindings(bool map);
void setAutoMapLocations(bool map);
void addUniformLocationOverride(const char* name, int loc);
void setUniformLocationBase(int base);
void setInvertY(bool invert);
#ifdef ENABLE_HLSL
void setHlslIoMapping(bool hlslIoMap);
void setFlattenUniformArrays(bool flatten);
#endif
void setNoStorageFormat(bool useUnknownFormat);
void setNanMinMaxClamp(bool nanMinMaxClamp);
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode);
// For setting up the environment (cleared to nothingness in the constructor).
// These must be called so that parsing is done for the right source language and
// target environment, either indirectly through TranslateEnvironment() based on
// EShMessages et. al., or directly by the user.
//
// setEnvInput: The input source language and stage. If generating code for a
// specific client, the input client semantics to use and the
// version of the that client's input semantics to use, otherwise
// use EShClientNone and version of 0, e.g. for validation mode.
// Note 'version' does not describe the target environment,
// just the version of the source dialect to compile under.
//
// See the definitions of TEnvironment, EShSource, EShLanguage,
// and EShClient for choices and more detail.
//
// setEnvClient: The client that will be hosting the execution, and it's version.
// Note 'version' is not the version of the languages involved, but
// the version of the client environment.
// Use EShClientNone and version of 0 if there is no client, e.g.
// for validation mode.
//
// See EShTargetClientVersion for choices.
//
// setEnvTarget: The language to translate to when generating code, and that
// language's version.
// Use EShTargetNone and version of 0 if there is no client, e.g.
// for validation mode.
//
void setEnvInput(EShSource lang, EShLanguage envStage, EShClient client, int version)
{
environment.input.languageFamily = lang;
environment.input.stage = envStage;
environment.input.dialect = client;
environment.input.dialectVersion = version;
}
void setEnvClient(EShClient client, EShTargetClientVersion version)
{
environment.client.client = client;
environment.client.version = version;
}
void setEnvTarget(EShTargetLanguage lang, EShTargetLanguageVersion version)
{
environment.target.language = lang;
environment.target.version = version;
}
#ifdef ENABLE_HLSL
void setEnvTargetHlslFunctionality1() { environment.target.hlslFunctionality1 = true; }
bool getEnvTargetHlslFunctionality1() const { return environment.target.hlslFunctionality1; }
#else
bool getEnvTargetHlslFunctionality1() const { return false; }
#endif
// Interface to #include handlers.
//
// To support #include, a client of Glslang does the following:
// 1. Call setStringsWithNames to set the source strings and associated
// names. For example, the names could be the names of the files
// containing the shader sources.
// 2. Call parse with an Includer.
//
// When the Glslang parser encounters an #include directive, it calls
// the Includer's include method with the requested include name
// together with the current string name. The returned IncludeResult
// contains the fully resolved name of the included source, together
// with the source text that should replace the #include directive
// in the source stream. After parsing that source, Glslang will
// release the IncludeResult object.
class Includer {
public:
// An IncludeResult contains the resolved name and content of a source
// inclusion.
struct IncludeResult {
IncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength, void* userData) :
headerName(headerName), headerData(headerData), headerLength(headerLength), userData(userData) { }
// For a successful inclusion, the fully resolved name of the requested
// include. For example, in a file system-based includer, full resolution
// should convert a relative path name into an absolute path name.
// For a failed inclusion, this is an empty string.
const std::string headerName;
// The content and byte length of the requested inclusion. The
// Includer producing this IncludeResult retains ownership of the
// storage.
// For a failed inclusion, the header
// field points to a string containing error details.
const char* const headerData;
const size_t headerLength;
// Include resolver's context.
void* userData;
protected:
IncludeResult& operator=(const IncludeResult&);
IncludeResult();
};
// For both include methods below:
//
// Resolves an inclusion request by name, current source name,
// and include depth.
// On success, returns an IncludeResult containing the resolved name
// and content of the include.
// On failure, returns a nullptr, or an IncludeResult
// with an empty string for the headerName and error details in the
// header field.
// The Includer retains ownership of the contents
// of the returned IncludeResult value, and those contents must
// remain valid until the releaseInclude method is called on that
// IncludeResult object.
//
// Note "local" vs. "system" is not an "either/or": "local" is an
// extra thing to do over "system". Both might get called, as per
// the C++ specification.
// For the "system" or <>-style includes; search the "system" paths.
virtual IncludeResult* includeSystem(const char* /*headerName*/,
const char* /*includerName*/,
size_t /*inclusionDepth*/) { return nullptr; }
// For the "local"-only aspect of a "" include. Should not search in the
// "system" paths, because on returning a failure, the parser will
// call includeSystem() to look in the "system" locations.
virtual IncludeResult* includeLocal(const char* /*headerName*/,
const char* /*includerName*/,
size_t /*inclusionDepth*/) { return nullptr; }
// Signals that the parser will no longer use the contents of the
// specified IncludeResult.
virtual void releaseInclude(IncludeResult*) = 0;
virtual ~Includer() {}
};
// Fail all Includer searches
class ForbidIncluder : public Includer {
public:
virtual void releaseInclude(IncludeResult*) override { }
};
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
bool forwardCompatible, EShMessages, Includer&);
bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
bool forwardCompatible, EShMessages messages)
{
TShader::ForbidIncluder includer;
return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer);
}
// Equivalent to parse() without a default profile and without forcing defaults.
bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages)
{
return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages);
}
bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages,
Includer& includer)
{
return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages, includer);
}
// NOTE: Doing just preprocessing to obtain a correct preprocessed shader string
// is not an officially supported or fully working path.
bool preprocess(const TBuiltInResource* builtInResources,
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
bool forwardCompatible, EShMessages message, std::string* outputString,
Includer& includer);
const char* getInfoLog();
const char* getInfoDebugLog();
EShLanguage getStage() const { return stage; }
TIntermediate* getIntermediate() const { return intermediate; }
protected:
TPoolAllocator* pool;
EShLanguage stage;
TCompiler* compiler;
TIntermediate* intermediate;
TInfoSink* infoSink;
// strings and lengths follow the standard for glShaderSource:
// strings is an array of numStrings pointers to string data.
// lengths can be null, but if not it is an array of numStrings
// integers containing the length of the associated strings.
// if lengths is null or lengths[n] < 0 the associated strings[n] is
// assumed to be null-terminated.
// stringNames is the optional names for all the strings. If stringNames
// is null, then none of the strings has name. If a certain element in
// stringNames is null, then the corresponding string does not have name.
const char* const* strings;
const int* lengths;
const char* const* stringNames;
const char* preamble;
int numStrings;
// a function in the source string can be renamed FROM this TO the name given in setEntryPoint.
std::string sourceEntryPointName;
TEnvironment environment;
friend class TProgram;
private:
TShader& operator=(TShader&);
};
#ifndef GLSLANG_WEB
//
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
//
// Data needed for just a single object at the granularity exchanged by the reflection API
class TObjectReflection {
public:
TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex);
const TType* getType() const { return type; }
int getBinding() const;
void dump() const;
static TObjectReflection badReflection() { return TObjectReflection(); }
std::string name;
int offset;
int glDefineType;
int size; // data size in bytes for a block, array size for a (non-block) object that's an array
int index;
int counterIndex;
int numMembers;
int arrayStride; // stride of an array variable
int topLevelArrayStride; // stride of the top-level variable in a storage buffer member
EShLanguageMask stages;
protected:
TObjectReflection()
: offset(-1), glDefineType(-1), size(-1), index(-1), counterIndex(-1), numMembers(-1), arrayStride(0),
topLevelArrayStride(0), stages(EShLanguageMask(0)), type(nullptr)
{
}
const TType* type;
};
class TReflection;
class TIoMapper;
struct TVarEntryInfo;
// Allows to customize the binding layout after linking.
// All used uniform variables will invoke at least validateBinding.
// If validateBinding returned true then the other resolveBinding,
// resolveSet, and resolveLocation are invoked to resolve the binding
// and descriptor set index respectively.
//
// Invocations happen in a particular order:
// 1) all shader inputs
// 2) all shader outputs
// 3) all uniforms with binding and set already defined
// 4) all uniforms with binding but no set defined
// 5) all uniforms with set but no binding defined
// 6) all uniforms with no binding and no set defined
//
// mapIO will use this resolver in two phases. The first
// phase is a notification phase, calling the corresponging
// notifiy callbacks, this phase ends with a call to endNotifications.
// Phase two starts directly after the call to endNotifications
// and calls all other callbacks to validate and to get the
// bindings, sets, locations, component and color indices.
//
// NOTE: that still limit checks are applied to bindings and sets
// and may result in an error.
class TIoMapResolver
{
public:
virtual ~TIoMapResolver() {}
// Should return true if the resulting/current binding would be okay.
// Basic idea is to do aliasing binding checks with this.
virtual bool validateBinding(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return a value >= 0 if the current binding should be overridden.
// Return -1 if the current binding (including no binding) should be kept.
virtual int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return a value >= 0 if the current set should be overridden.
// Return -1 if the current set (including no set) should be kept.
virtual int resolveSet(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return a value >= 0 if the current location should be overridden.
// Return -1 if the current location (including no location) should be kept.
virtual int resolveUniformLocation(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return true if the resulting/current setup would be okay.
// Basic idea is to do aliasing checks and reject invalid semantic names.
virtual bool validateInOut(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return a value >= 0 if the current location should be overridden.
// Return -1 if the current location (including no location) should be kept.
virtual int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return a value >= 0 if the current component index should be overridden.
// Return -1 if the current component index (including no index) should be kept.
virtual int resolveInOutComponent(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Should return a value >= 0 if the current color index should be overridden.
// Return -1 if the current color index (including no index) should be kept.
virtual int resolveInOutIndex(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Notification of a uniform variable
virtual void notifyBinding(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Notification of a in or out variable
virtual void notifyInOut(EShLanguage stage, TVarEntryInfo& ent) = 0;
// Called by mapIO when it starts its notify pass for the given stage
virtual void beginNotifications(EShLanguage stage) = 0;
// Called by mapIO when it has finished the notify pass
virtual void endNotifications(EShLanguage stage) = 0;
// Called by mipIO when it starts its resolve pass for the given stage
virtual void beginResolve(EShLanguage stage) = 0;
// Called by mapIO when it has finished the resolve pass
virtual void endResolve(EShLanguage stage) = 0;
// Called by mapIO when it starts its symbol collect for teh given stage
virtual void beginCollect(EShLanguage stage) = 0;
// Called by mapIO when it has finished the symbol collect
virtual void endCollect(EShLanguage stage) = 0;
// Called by TSlotCollector to resolve storage locations or bindings
virtual void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0;
// Called by TSlotCollector to resolve resource locations or bindings
virtual void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0;
// Called by mapIO.addStage to set shader stage mask to mark a stage be added to this pipeline
virtual void addStage(EShLanguage stage) = 0;
};
#endif // GLSLANG_WEB
// Make one TProgram per set of shaders that will get linked together. Add all
// the shaders that are to be linked together. After calling shader.parse()
// for all shaders, call link().
//
// N.B.: Destruct a linked program *before* destructing the shaders linked into it.
//
class TProgram {
public:
TProgram();
virtual ~TProgram();
void addShader(TShader* shader) { stages[shader->stage].push_back(shader); }
// Link Validation interface
bool link(EShMessages);
const char* getInfoLog();
const char* getInfoDebugLog();
TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; }
#ifndef GLSLANG_WEB
// Reflection Interface
// call first, to do liveness analysis, index mapping, etc.; returns false on failure
bool buildReflection(int opts = EShReflectionDefault);
unsigned getLocalSize(int dim) const; // return dim'th local size
int getReflectionIndex(const char *name) const;
int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const;
int getNumUniformVariables() const;
const TObjectReflection& getUniform(int index) const;
int getNumUniformBlocks() const;
const TObjectReflection& getUniformBlock(int index) const;
int getNumPipeInputs() const;
const TObjectReflection& getPipeInput(int index) const;
int getNumPipeOutputs() const;
const TObjectReflection& getPipeOutput(int index) const;
int getNumBufferVariables() const;
const TObjectReflection& getBufferVariable(int index) const;
int getNumBufferBlocks() const;
const TObjectReflection& getBufferBlock(int index) const;
int getNumAtomicCounters() const;
const TObjectReflection& getAtomicCounter(int index) const;
// Legacy Reflection Interface - expressed in terms of above interface
// can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveUniformVariables() const { return getNumUniformVariables(); }
// can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
int getNumLiveUniformBlocks() const { return getNumUniformBlocks(); }
// can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
int getNumLiveAttributes() const { return getNumPipeInputs(); }
// can be used for glGetUniformIndices()
int getUniformIndex(const char *name) const { return getReflectionIndex(name); }
int getPipeIOIndex(const char *name, const bool inOrOut) const
{ return getReflectionPipeIOIndex(name, inOrOut); }
// can be used for "name" part of glGetActiveUniform()
const char *getUniformName(int index) const { return getUniform(index).name.c_str(); }
// returns the binding number
int getUniformBinding(int index) const { return getUniform(index).getBinding(); }
// returns Shaders Stages where a Uniform is present
EShLanguageMask getUniformStages(int index) const { return getUniform(index).stages; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformBlockIndex(int index) const { return getUniform(index).index; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
int getUniformType(int index) const { return getUniform(index).glDefineType; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformBufferOffset(int index) const { return getUniform(index).offset; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
int getUniformArraySize(int index) const { return getUniform(index).size; }
// returns a TType*
const TType *getUniformTType(int index) const { return getUniform(index).getType(); }
// can be used for glGetActiveUniformBlockName()
const char *getUniformBlockName(int index) const { return getUniformBlock(index).name.c_str(); }
// can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformBlockSize(int index) const { return getUniformBlock(index).size; }
// returns the block binding number
int getUniformBlockBinding(int index) const { return getUniformBlock(index).getBinding(); }
// returns block index of associated counter.
int getUniformBlockCounterIndex(int index) const { return getUniformBlock(index).counterIndex; }
// returns a TType*
const TType *getUniformBlockTType(int index) const { return getUniformBlock(index).getType(); }
// can be used for glGetActiveAttrib()
const char *getAttributeName(int index) const { return getPipeInput(index).name.c_str(); }
// can be used for glGetActiveAttrib()
int getAttributeType(int index) const { return getPipeInput(index).glDefineType; }
// returns a TType*
const TType *getAttributeTType(int index) const { return getPipeInput(index).getType(); }
void dumpReflection();
// I/O mapping: apply base offsets and map live unbound variables
// If resolver is not provided it uses the previous approach
// and respects auto assignment and offsets.
bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr);
#endif
protected:
bool linkStage(EShLanguage, EShMessages);
TPoolAllocator* pool;
std::list<TShader*> stages[EShLangCount];
TIntermediate* intermediate[EShLangCount];
bool newedIntermediate[EShLangCount]; // track which intermediate were "new" versus reusing a singleton unit in a stage
TInfoSink* infoSink;
#ifndef GLSLANG_WEB
TReflection* reflection;
#endif
bool linked;
private:
TProgram(TProgram&);
TProgram& operator=(TProgram&);
};
} // end namespace glslang
#endif // _COMPILER_INTERFACE_INCLUDED_