mirror of
https://github.com/RPCS3/glslang.git
synced 2024-11-23 11:19:40 +00:00
HLSL: Refactor attribute implementation.
- make it sharable with GLSL - correct the case insensitivity - remove the map; queries are not needed, all entries need processing - make it easier to build bottom up (will help GLSL parsing) - support semantic checking and reporting - allow front-end dependent semantics and attribute name mapping
This commit is contained in:
parent
e349af7e20
commit
e18fd20d5c
@ -129,8 +129,9 @@ protected:
|
||||
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
|
||||
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
|
||||
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
|
||||
spv::SelectionControlMask TranslateSelectionControl(glslang::TSelectionControl) const;
|
||||
spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) const;
|
||||
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
|
||||
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
|
||||
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&) const;
|
||||
spv::StorageClass TranslateStorageClass(const glslang::TType&);
|
||||
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
|
||||
spv::Id getSampledType(const glslang::TSampler&);
|
||||
@ -748,26 +749,34 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
|
||||
}
|
||||
}
|
||||
|
||||
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(glslang::TSelectionControl selectionControl) const
|
||||
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const
|
||||
{
|
||||
switch (selectionControl) {
|
||||
case glslang::ESelectionControlNone: return spv::SelectionControlMaskNone;
|
||||
case glslang::ESelectionControlFlatten: return spv::SelectionControlFlattenMask;
|
||||
case glslang::ESelectionControlDontFlatten: return spv::SelectionControlDontFlattenMask;
|
||||
default: return spv::SelectionControlMaskNone;
|
||||
}
|
||||
if (selectionNode.getFlatten())
|
||||
return spv::SelectionControlFlattenMask;
|
||||
if (selectionNode.getDontFlatten())
|
||||
return spv::SelectionControlDontFlattenMask;
|
||||
return spv::SelectionControlMaskNone;
|
||||
}
|
||||
|
||||
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const
|
||||
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const
|
||||
{
|
||||
switch (loopControl) {
|
||||
case glslang::ELoopControlNone: return spv::LoopControlMaskNone;
|
||||
case glslang::ELoopControlUnroll: return spv::LoopControlUnrollMask;
|
||||
case glslang::ELoopControlDontUnroll: return spv::LoopControlDontUnrollMask;
|
||||
// TODO: DependencyInfinite
|
||||
// TODO: DependencyLength
|
||||
default: return spv::LoopControlMaskNone;
|
||||
}
|
||||
if (switchNode.getFlatten())
|
||||
return spv::SelectionControlFlattenMask;
|
||||
if (switchNode.getDontFlatten())
|
||||
return spv::SelectionControlDontFlattenMask;
|
||||
return spv::SelectionControlMaskNone;
|
||||
}
|
||||
|
||||
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode) const
|
||||
{
|
||||
spv::LoopControlMask control = spv::LoopControlMaskNone;
|
||||
|
||||
if (loopNode.getDontUnroll())
|
||||
control = control | spv::LoopControlDontUnrollMask;
|
||||
if (loopNode.getUnroll())
|
||||
control = control | spv::LoopControlUnrollMask;
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
// Translate glslang type to SPIR-V storage class.
|
||||
@ -2026,7 +2035,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
||||
node->getCondition()->traverse(this);
|
||||
|
||||
// Selection control:
|
||||
const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
|
||||
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
|
||||
|
||||
// make an "if" based on the value created by the condition
|
||||
spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), control, builder);
|
||||
@ -2068,7 +2077,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
|
||||
spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
|
||||
|
||||
// Selection control:
|
||||
const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
|
||||
const spv::SelectionControlMask control = TranslateSwitchControl(*node);
|
||||
|
||||
// browse the children to sort out code segments
|
||||
int defaultSegment = -1;
|
||||
@ -2128,7 +2137,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
||||
builder.createBranch(&blocks.head);
|
||||
|
||||
// Loop control:
|
||||
const spv::LoopControlMask control = TranslateLoopControl(node->getLoopControl());
|
||||
const spv::LoopControlMask control = TranslateLoopControl(*node);
|
||||
|
||||
// TODO: dependency length
|
||||
|
||||
|
@ -1,20 +1,20 @@
|
||||
hlsl.numthreads.comp
|
||||
Shader version: 500
|
||||
local_size = (4, 4, 2)
|
||||
local_size = (1, 4, 8)
|
||||
0:? Sequence
|
||||
0:4 Function Definition: main(vu3; ( temp void)
|
||||
0:4 Function Parameters:
|
||||
0:4 'tid' ( in 3-component vector of uint)
|
||||
0:9 Function Definition: @main_aux1(vu3; ( temp void)
|
||||
0:9 Function Definition: @main_aux2(vu3; ( temp void)
|
||||
0:9 Function Parameters:
|
||||
0:9 'tid' ( in 3-component vector of uint)
|
||||
0:9 Function Definition: main_aux1( ( temp void)
|
||||
0:9 Function Definition: main_aux2( ( temp void)
|
||||
0:9 Function Parameters:
|
||||
0:? Sequence
|
||||
0:9 move second child to first child ( temp 3-component vector of uint)
|
||||
0:? 'tid' ( temp 3-component vector of uint)
|
||||
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
|
||||
0:9 Function Call: @main_aux1(vu3; ( temp void)
|
||||
0:9 Function Call: @main_aux2(vu3; ( temp void)
|
||||
0:? 'tid' ( temp 3-component vector of uint)
|
||||
0:? Linker Objects
|
||||
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
|
||||
@ -24,21 +24,21 @@ Linked compute stage:
|
||||
|
||||
|
||||
Shader version: 500
|
||||
local_size = (4, 4, 2)
|
||||
local_size = (1, 4, 8)
|
||||
0:? Sequence
|
||||
0:4 Function Definition: main(vu3; ( temp void)
|
||||
0:4 Function Parameters:
|
||||
0:4 'tid' ( in 3-component vector of uint)
|
||||
0:9 Function Definition: @main_aux1(vu3; ( temp void)
|
||||
0:9 Function Definition: @main_aux2(vu3; ( temp void)
|
||||
0:9 Function Parameters:
|
||||
0:9 'tid' ( in 3-component vector of uint)
|
||||
0:9 Function Definition: main_aux1( ( temp void)
|
||||
0:9 Function Definition: main_aux2( ( temp void)
|
||||
0:9 Function Parameters:
|
||||
0:? Sequence
|
||||
0:9 move second child to first child ( temp 3-component vector of uint)
|
||||
0:? 'tid' ( temp 3-component vector of uint)
|
||||
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
|
||||
0:9 Function Call: @main_aux1(vu3; ( temp void)
|
||||
0:9 Function Call: @main_aux2(vu3; ( temp void)
|
||||
0:? 'tid' ( temp 3-component vector of uint)
|
||||
0:? Linker Objects
|
||||
0:? 'tid' ( in 3-component vector of uint GlobalInvocationID)
|
||||
@ -50,13 +50,13 @@ local_size = (4, 4, 2)
|
||||
Capability Shader
|
||||
1: ExtInstImport "GLSL.std.450"
|
||||
MemoryModel Logical GLSL450
|
||||
EntryPoint GLCompute 4 "main_aux1" 18
|
||||
ExecutionMode 4 LocalSize 4 4 2
|
||||
EntryPoint GLCompute 4 "main_aux2" 18
|
||||
ExecutionMode 4 LocalSize 1 4 8
|
||||
Source HLSL 500
|
||||
Name 4 "main_aux1"
|
||||
Name 4 "main_aux2"
|
||||
Name 11 "main(vu3;"
|
||||
Name 10 "tid"
|
||||
Name 14 "@main_aux1(vu3;"
|
||||
Name 14 "@main_aux2(vu3;"
|
||||
Name 13 "tid"
|
||||
Name 16 "tid"
|
||||
Name 18 "tid"
|
||||
@ -70,7 +70,7 @@ local_size = (4, 4, 2)
|
||||
9: TypeFunction 2 8(ptr)
|
||||
17: TypePointer Input 7(ivec3)
|
||||
18(tid): 17(ptr) Variable Input
|
||||
4(main_aux1): 2 Function None 3
|
||||
4(main_aux2): 2 Function None 3
|
||||
5: Label
|
||||
16(tid): 8(ptr) Variable Function
|
||||
20(param): 8(ptr) Variable Function
|
||||
@ -78,7 +78,7 @@ local_size = (4, 4, 2)
|
||||
Store 16(tid) 19
|
||||
21: 7(ivec3) Load 16(tid)
|
||||
Store 20(param) 21
|
||||
22: 2 FunctionCall 14(@main_aux1(vu3;) 20(param)
|
||||
22: 2 FunctionCall 14(@main_aux2(vu3;) 20(param)
|
||||
Return
|
||||
FunctionEnd
|
||||
11(main(vu3;): 2 Function None 9
|
||||
@ -86,7 +86,7 @@ local_size = (4, 4, 2)
|
||||
12: Label
|
||||
Return
|
||||
FunctionEnd
|
||||
14(@main_aux1(vu3;): 2 Function None 9
|
||||
14(@main_aux2(vu3;): 2 Function None 9
|
||||
13(tid): 8(ptr) FunctionParameter
|
||||
15: Label
|
||||
Return
|
||||
|
@ -4,11 +4,8 @@ void main(uint3 tid : SV_DispatchThreadID )
|
||||
{
|
||||
}
|
||||
|
||||
[numTHreaDs(4,4,2)] // case insensitive
|
||||
void main_aux1(uint3 tid : SV_DispatchThreadID )
|
||||
[numthreads(1,4,8)]
|
||||
void main_aux2(uint3 tid : SV_DispatchThreadID )
|
||||
{
|
||||
}
|
||||
|
||||
[numthreads(1,4,8)]
|
||||
void main_aux2(uint3 tid : SV_DispatchThreadID );
|
||||
|
||||
|
@ -9,6 +9,7 @@ endif(WIN32)
|
||||
set(SOURCES
|
||||
MachineIndependent/glslang.y
|
||||
MachineIndependent/glslang_tab.cpp
|
||||
MachineIndependent/attribute.cpp
|
||||
MachineIndependent/Constant.cpp
|
||||
MachineIndependent/iomapper.cpp
|
||||
MachineIndependent/InfoSink.cpp
|
||||
@ -51,6 +52,7 @@ set(HEADERS
|
||||
Include/revision.h
|
||||
Include/ShHandle.h
|
||||
Include/Types.h
|
||||
MachineIndependent/attribute.h
|
||||
MachineIndependent/glslang_tab.cpp.h
|
||||
MachineIndependent/gl_types.h
|
||||
MachineIndependent/Initialize.h
|
||||
|
@ -37,6 +37,9 @@
|
||||
#ifndef _CONSTANT_UNION_INCLUDED_
|
||||
#define _CONSTANT_UNION_INCLUDED_
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/BaseTypes.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TConstUnion {
|
||||
|
@ -819,7 +819,7 @@ public:
|
||||
virtual glslang::TIntermMethod* getAsMethodNode() { return 0; }
|
||||
virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; }
|
||||
virtual glslang::TIntermBranch* getAsBranchNode() { return 0; }
|
||||
virtual glslang::TIntermLoop* getAsLoopNode() { return 0; }
|
||||
virtual glslang::TIntermLoop* getAsLoopNode() { return 0; }
|
||||
|
||||
virtual const glslang::TIntermTyped* getAsTyped() const { return 0; }
|
||||
virtual const glslang::TIntermOperator* getAsOperator() const { return 0; }
|
||||
@ -832,7 +832,7 @@ public:
|
||||
virtual const glslang::TIntermMethod* getAsMethodNode() const { return 0; }
|
||||
virtual const glslang::TIntermSymbol* getAsSymbolNode() const { return 0; }
|
||||
virtual const glslang::TIntermBranch* getAsBranchNode() const { return 0; }
|
||||
virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; }
|
||||
virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; }
|
||||
virtual ~TIntermNode() { }
|
||||
|
||||
protected:
|
||||
@ -885,24 +885,6 @@ protected:
|
||||
TType type;
|
||||
};
|
||||
|
||||
//
|
||||
// Selection control hints
|
||||
//
|
||||
enum TSelectionControl {
|
||||
ESelectionControlNone,
|
||||
ESelectionControlFlatten,
|
||||
ESelectionControlDontFlatten,
|
||||
};
|
||||
|
||||
//
|
||||
// Loop control hints
|
||||
//
|
||||
enum TLoopControl {
|
||||
ELoopControlNone,
|
||||
ELoopControlUnroll,
|
||||
ELoopControlDontUnroll,
|
||||
};
|
||||
|
||||
//
|
||||
// Handle for, do-while, and while loops.
|
||||
//
|
||||
@ -913,26 +895,30 @@ public:
|
||||
test(aTest),
|
||||
terminal(aTerminal),
|
||||
first(testFirst),
|
||||
control(ELoopControlNone)
|
||||
unroll(false),
|
||||
dontUnroll(false)
|
||||
{ }
|
||||
|
||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||
virtual const TIntermLoop* getAsLoopNode() const { return this; }
|
||||
virtual TIntermLoop* getAsLoopNode() { return this; }
|
||||
virtual const TIntermLoop* getAsLoopNode() const { return this; }
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
TIntermNode* getBody() const { return body; }
|
||||
TIntermTyped* getTest() const { return test; }
|
||||
TIntermTyped* getTerminal() const { return terminal; }
|
||||
bool testFirst() const { return first; }
|
||||
|
||||
void setLoopControl(TLoopControl c) { control = c; }
|
||||
TLoopControl getLoopControl() const { return control; }
|
||||
void setUnroll() { unroll = true; }
|
||||
void setDontUnroll() { dontUnroll = true; }
|
||||
bool getUnroll() const { return unroll; }
|
||||
bool getDontUnroll() const { return dontUnroll; }
|
||||
|
||||
protected:
|
||||
TIntermNode* body; // code to loop over
|
||||
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
|
||||
TIntermTyped* terminal; // exists for for-loops
|
||||
bool first; // true for while and for, not for do-while
|
||||
TLoopControl control; // loop control hint
|
||||
bool unroll; // true if unroll requested
|
||||
bool dontUnroll; // true if request to not unroll
|
||||
};
|
||||
|
||||
//
|
||||
@ -1343,22 +1329,29 @@ protected:
|
||||
class TIntermSelection : public TIntermTyped {
|
||||
public:
|
||||
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
|
||||
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
|
||||
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB),
|
||||
flatten(false), dontFlatten(false) {}
|
||||
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
|
||||
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
|
||||
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB),
|
||||
flatten(false), dontFlatten(false) {}
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
virtual TIntermTyped* getCondition() const { return condition; }
|
||||
virtual TIntermNode* getTrueBlock() const { return trueBlock; }
|
||||
virtual TIntermNode* getFalseBlock() const { return falseBlock; }
|
||||
virtual TIntermSelection* getAsSelectionNode() { return this; }
|
||||
virtual const TIntermSelection* getAsSelectionNode() const { return this; }
|
||||
void setSelectionControl(TSelectionControl c) { control = c; }
|
||||
TSelectionControl getSelectionControl() const { return control; }
|
||||
|
||||
void setFlatten() { flatten = true; }
|
||||
void setDontFlatten() { dontFlatten = true; }
|
||||
bool getFlatten() const { return flatten; }
|
||||
bool getDontFlatten() const { return dontFlatten; }
|
||||
|
||||
protected:
|
||||
TIntermTyped* condition;
|
||||
TIntermNode* trueBlock;
|
||||
TIntermNode* falseBlock;
|
||||
TSelectionControl control; // selection control hint
|
||||
bool flatten; // true if flatten requested
|
||||
bool dontFlatten; // true if requested to not flatten
|
||||
};
|
||||
|
||||
//
|
||||
@ -1369,18 +1362,24 @@ protected:
|
||||
//
|
||||
class TIntermSwitch : public TIntermNode {
|
||||
public:
|
||||
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b), control(ESelectionControlNone) { }
|
||||
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b),
|
||||
flatten(false), dontFlatten(false) {}
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
virtual TIntermNode* getCondition() const { return condition; }
|
||||
virtual TIntermAggregate* getBody() const { return body; }
|
||||
virtual TIntermSwitch* getAsSwitchNode() { return this; }
|
||||
virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
|
||||
void setSelectionControl(TSelectionControl c) { control = c; }
|
||||
TSelectionControl getSelectionControl() const { return control; }
|
||||
|
||||
void setFlatten() { flatten = true; }
|
||||
void setDontFlatten() { dontFlatten = true; }
|
||||
bool getFlatten() const { return flatten; }
|
||||
bool getDontFlatten() const { return dontFlatten; }
|
||||
|
||||
protected:
|
||||
TIntermTyped* condition;
|
||||
TIntermAggregate* body;
|
||||
TSelectionControl control; // selection control hint
|
||||
bool flatten; // true if flatten requested
|
||||
bool dontFlatten; // true if requested to not flatten
|
||||
};
|
||||
|
||||
enum TVisit
|
||||
|
@ -1614,7 +1614,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
|
||||
//
|
||||
// Returns the selection node created.
|
||||
//
|
||||
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc, TSelectionControl control)
|
||||
TIntermSelection* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
|
||||
{
|
||||
//
|
||||
// Don't prune the false path for compile-time constants; it's needed
|
||||
@ -1623,7 +1623,6 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair no
|
||||
|
||||
TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
|
||||
node->setLoc(loc);
|
||||
node->setSelectionControl(control);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -1666,12 +1665,13 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type,
|
||||
//
|
||||
// Returns the selection node created, or nullptr if one could not be.
|
||||
//
|
||||
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc, TSelectionControl control)
|
||||
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock,
|
||||
const TSourceLoc& loc)
|
||||
{
|
||||
// If it's void, go to the if-then-else selection()
|
||||
if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
|
||||
TIntermNodePair pair = { trueBlock, falseBlock };
|
||||
return addSelection(cond, pair, loc, control);
|
||||
return addSelection(cond, pair, loc);
|
||||
}
|
||||
|
||||
//
|
||||
@ -1909,11 +1909,11 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool
|
||||
//
|
||||
// Create while and do-while loop nodes.
|
||||
//
|
||||
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
|
||||
TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst,
|
||||
const TSourceLoc& loc)
|
||||
{
|
||||
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node->setLoc(loc);
|
||||
node->setLoopControl(control);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -1921,11 +1921,11 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
|
||||
//
|
||||
// Create a for-loop sequence.
|
||||
//
|
||||
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
|
||||
TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test,
|
||||
TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node)
|
||||
{
|
||||
TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node = new TIntermLoop(body, test, terminal, testFirst);
|
||||
node->setLoc(loc);
|
||||
node->setLoopControl(control);
|
||||
|
||||
// make a sequence of the initializer and statement, but try to reuse the
|
||||
// aggregate already created for whatever is in the initializer, if there is one
|
||||
|
86
glslang/MachineIndependent/attribute.cpp
Normal file
86
glslang/MachineIndependent/attribute.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
//
|
||||
// Copyright (C) 2017 LunarG, Inc.
|
||||
// Copyright (C) 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 Google, Inc., 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.
|
||||
//
|
||||
|
||||
#include "attribute.h"
|
||||
#include "../Include/intermediate.h"
|
||||
#include "ParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// extract integers out of attribute arguments stored in attribute aggregate
|
||||
bool TAttributeArgs::getInt(int& value, int argNum) const
|
||||
{
|
||||
const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
|
||||
|
||||
if (intConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = intConst->getIConst();
|
||||
return true;
|
||||
};
|
||||
|
||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
|
||||
{
|
||||
const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
|
||||
|
||||
if (stringConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = *stringConst->getSConst();
|
||||
|
||||
// Convenience.
|
||||
if (convertToLower)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper to get attribute const union. Returns nullptr on failure.
|
||||
const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
|
||||
{
|
||||
if (argNum >= args->getSequence().size())
|
||||
return nullptr;
|
||||
|
||||
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||
if (constVal == nullptr || constVal->getType() != basicType)
|
||||
return nullptr;
|
||||
|
||||
return constVal;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
97
glslang/MachineIndependent/attribute.h
Normal file
97
glslang/MachineIndependent/attribute.h
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// Copyright (C) 2017 LunarG, Inc.
|
||||
// Copyright (C) 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 _ATTRIBUTE_INCLUDED_
|
||||
#define _ATTRIBUTE_INCLUDED_
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/ConstantUnion.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
enum TAttributeType {
|
||||
EatNone,
|
||||
EatAllow_uav_condition,
|
||||
EatBranch,
|
||||
EatCall,
|
||||
EatDomain,
|
||||
EatEarlyDepthStencil,
|
||||
EatFastOpt,
|
||||
EatFlatten,
|
||||
EatForceCase,
|
||||
EatInstance,
|
||||
EatMaxTessFactor,
|
||||
EatNumThreads,
|
||||
EatMaxVertexCount,
|
||||
EatOutputControlPoints,
|
||||
EatOutputTopology,
|
||||
EatPartitioning,
|
||||
EatPatchConstantFunc,
|
||||
EatPatchSize,
|
||||
EatUnroll,
|
||||
EatLoop,
|
||||
EatBinding,
|
||||
EatGlobalBinding,
|
||||
EatLocation,
|
||||
EatInputAttachment,
|
||||
EatBuiltIn,
|
||||
EatPushConstant,
|
||||
EatConstantId
|
||||
};
|
||||
|
||||
class TIntermAggregate;
|
||||
|
||||
struct TAttributeArgs {
|
||||
TAttributeType name;
|
||||
TIntermAggregate* args;
|
||||
|
||||
// Obtain attribute as integer
|
||||
// Return false if it cannot be obtained
|
||||
bool getInt(int& value, int argNum = 0) const;
|
||||
|
||||
// Obtain attribute as string, with optional to-lower transform
|
||||
// Return false if it cannot be obtained
|
||||
bool getString(TString& value, int argNum = 0, bool convertToLower = true) const;
|
||||
|
||||
protected:
|
||||
const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
|
||||
};
|
||||
|
||||
typedef TList<TAttributeArgs> TAttributes;
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _ATTRIBUTE_INCLUDED_
|
@ -420,8 +420,8 @@ public:
|
||||
TIntermAggregate* makeAggregate(const TSourceLoc&);
|
||||
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
|
||||
bool areAllChildConst(TIntermAggregate* aggrNode);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
|
||||
TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
|
||||
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
|
||||
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
|
||||
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
|
||||
@ -439,8 +439,9 @@ public:
|
||||
TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
|
||||
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
|
||||
const TSourceLoc&, TIntermLoop*&);
|
||||
TIntermBranch* addBranch(TOperator, const TSourceLoc&);
|
||||
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
|
||||
template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);
|
||||
|
@ -247,7 +247,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{"hlsl.matrixindex.frag", "main"},
|
||||
{"hlsl.nonstaticMemberFunction.frag", "main"},
|
||||
{"hlsl.numericsuffixes.frag", "main"},
|
||||
{"hlsl.numthreads.comp", "main_aux1"},
|
||||
{"hlsl.numthreads.comp", "main_aux2"},
|
||||
{"hlsl.overload.frag", "PixelShaderFunction"},
|
||||
{"hlsl.opaque-type-bug.frag", "main"},
|
||||
{"hlsl.params.default.frag", "main"},
|
||||
|
@ -34,157 +34,73 @@
|
||||
//
|
||||
|
||||
#include "hlslAttributes.h"
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include "hlslParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
// Map the given string to an attribute enum from TAttributeType,
|
||||
// or EatNone if invalid.
|
||||
TAttributeType TAttributeMap::attributeFromName(const TString& nameSpace, const TString& name)
|
||||
TAttributeType HlslParseContext::attributeFromName(const TString& nameSpace, const TString& name) const
|
||||
{
|
||||
// These are case insensitive.
|
||||
TString lowername(name);
|
||||
std::transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);
|
||||
TString lowernameSpace(nameSpace);
|
||||
std::transform(lowernameSpace.begin(), lowernameSpace.end(), lowernameSpace.begin(), ::tolower);
|
||||
|
||||
// handle names within a namespace
|
||||
|
||||
if (lowernameSpace == "vk") {
|
||||
if (lowername == "input_attachment_index")
|
||||
if (nameSpace == "vk") {
|
||||
if (name == "input_attachment_index")
|
||||
return EatInputAttachment;
|
||||
else if (lowername == "location")
|
||||
else if (name == "location")
|
||||
return EatLocation;
|
||||
else if (lowername == "binding")
|
||||
else if (name == "binding")
|
||||
return EatBinding;
|
||||
else if (lowername == "global_cbuffer_binding")
|
||||
else if (name == "global_cbuffer_binding")
|
||||
return EatGlobalBinding;
|
||||
else if (lowername == "builtin")
|
||||
else if (name == "builtin")
|
||||
return EatBuiltIn;
|
||||
else if (lowername == "constant_id")
|
||||
else if (name == "constant_id")
|
||||
return EatConstantId;
|
||||
else if (lowername == "push_constant")
|
||||
else if (name == "push_constant")
|
||||
return EatPushConstant;
|
||||
} else if (lowernameSpace.size() > 0)
|
||||
} else if (nameSpace.size() > 0)
|
||||
return EatNone;
|
||||
|
||||
// handle names with no namespace
|
||||
|
||||
if (lowername == "allow_uav_condition")
|
||||
if (name == "allow_uav_condition")
|
||||
return EatAllow_uav_condition;
|
||||
else if (lowername == "branch")
|
||||
else if (name == "branch")
|
||||
return EatBranch;
|
||||
else if (lowername == "call")
|
||||
else if (name == "call")
|
||||
return EatCall;
|
||||
else if (lowername == "domain")
|
||||
else if (name == "domain")
|
||||
return EatDomain;
|
||||
else if (lowername == "earlydepthstencil")
|
||||
else if (name == "earlydepthstencil")
|
||||
return EatEarlyDepthStencil;
|
||||
else if (lowername == "fastopt")
|
||||
else if (name == "fastopt")
|
||||
return EatFastOpt;
|
||||
else if (lowername == "flatten")
|
||||
else if (name == "flatten")
|
||||
return EatFlatten;
|
||||
else if (lowername == "forcecase")
|
||||
else if (name == "forcecase")
|
||||
return EatForceCase;
|
||||
else if (lowername == "instance")
|
||||
else if (name == "instance")
|
||||
return EatInstance;
|
||||
else if (lowername == "maxtessfactor")
|
||||
else if (name == "maxtessfactor")
|
||||
return EatMaxTessFactor;
|
||||
else if (lowername == "maxvertexcount")
|
||||
else if (name == "maxvertexcount")
|
||||
return EatMaxVertexCount;
|
||||
else if (lowername == "numthreads")
|
||||
else if (name == "numthreads")
|
||||
return EatNumThreads;
|
||||
else if (lowername == "outputcontrolpoints")
|
||||
else if (name == "outputcontrolpoints")
|
||||
return EatOutputControlPoints;
|
||||
else if (lowername == "outputtopology")
|
||||
else if (name == "outputtopology")
|
||||
return EatOutputTopology;
|
||||
else if (lowername == "partitioning")
|
||||
else if (name == "partitioning")
|
||||
return EatPartitioning;
|
||||
else if (lowername == "patchconstantfunc")
|
||||
else if (name == "patchconstantfunc")
|
||||
return EatPatchConstantFunc;
|
||||
else if (lowername == "unroll")
|
||||
else if (name == "unroll")
|
||||
return EatUnroll;
|
||||
else if (lowername == "loop")
|
||||
else if (name == "loop")
|
||||
return EatLoop;
|
||||
else
|
||||
return EatNone;
|
||||
}
|
||||
|
||||
// Look up entry, inserting if it's not there, and if name is a valid attribute name
|
||||
// as known by attributeFromName.
|
||||
TAttributeType TAttributeMap::setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value)
|
||||
{
|
||||
if (name == nullptr)
|
||||
return EatNone;
|
||||
|
||||
const TAttributeType attr = attributeFromName(nameSpace, *name);
|
||||
|
||||
if (attr != EatNone)
|
||||
attributes[attr] = value;
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
// Look up entry (const version), and return aggregate node. This cannot change the map.
|
||||
const TIntermAggregate* TAttributeMap::operator[](TAttributeType attr) const
|
||||
{
|
||||
const auto entry = attributes.find(attr);
|
||||
|
||||
return (entry == attributes.end()) ? nullptr : entry->second;
|
||||
}
|
||||
|
||||
// True if entry exists in map (even if value is nullptr)
|
||||
bool TAttributeMap::contains(TAttributeType attr) const
|
||||
{
|
||||
return attributes.find(attr) != attributes.end();
|
||||
}
|
||||
|
||||
// extract integers out of attribute arguments stored in attribute aggregate
|
||||
bool TAttributeMap::getInt(TAttributeType attr, int& value, int argNum) const
|
||||
{
|
||||
const TConstUnion* intConst = getConstUnion(attr, EbtInt, argNum);
|
||||
|
||||
if (intConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = intConst->getIConst();
|
||||
return true;
|
||||
};
|
||||
|
||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||
bool TAttributeMap::getString(TAttributeType attr, TString& value, int argNum, bool convertToLower) const
|
||||
{
|
||||
const TConstUnion* stringConst = getConstUnion(attr, EbtString, argNum);
|
||||
|
||||
if (stringConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = *stringConst->getSConst();
|
||||
|
||||
// Convenience.
|
||||
if (convertToLower)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper to get attribute const union. Returns nullptr on failure.
|
||||
const TConstUnion* TAttributeMap::getConstUnion(TAttributeType attr, TBasicType basicType, int argNum) const
|
||||
{
|
||||
const TIntermAggregate* attrAgg = (*this)[attr];
|
||||
if (attrAgg == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (argNum >= int(attrAgg->getSequence().size()))
|
||||
return nullptr;
|
||||
|
||||
const TConstUnion* constVal = &attrAgg->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||
if (constVal == nullptr || constVal->getType() != basicType)
|
||||
return nullptr;
|
||||
|
||||
return constVal;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
@ -38,93 +38,22 @@
|
||||
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include "../glslang/MachineIndependent/attribute.h"
|
||||
#include "../glslang/MachineIndependent/SymbolTable.h"
|
||||
#include "hlslScanContext.h"
|
||||
#include "../glslang/Include/Common.h"
|
||||
|
||||
namespace glslang {
|
||||
enum TAttributeType {
|
||||
EatNone,
|
||||
EatAllow_uav_condition,
|
||||
EatBranch,
|
||||
EatCall,
|
||||
EatDomain,
|
||||
EatEarlyDepthStencil,
|
||||
EatFastOpt,
|
||||
EatFlatten,
|
||||
EatForceCase,
|
||||
EatInstance,
|
||||
EatMaxTessFactor,
|
||||
EatNumThreads,
|
||||
EatMaxVertexCount,
|
||||
EatOutputControlPoints,
|
||||
EatOutputTopology,
|
||||
EatPartitioning,
|
||||
EatPatchConstantFunc,
|
||||
EatPatchSize,
|
||||
EatUnroll,
|
||||
EatLoop,
|
||||
EatBinding,
|
||||
EatGlobalBinding,
|
||||
EatLocation,
|
||||
EatInputAttachment,
|
||||
EatBuiltIn,
|
||||
EatPushConstant,
|
||||
EatConstantId
|
||||
};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
// Allow use of TAttributeType enum in hash_map without calling code having to cast.
|
||||
template <> struct hash<glslang::TAttributeType> {
|
||||
std::size_t operator()(glslang::TAttributeType attr) const {
|
||||
return std::hash<int>()(int(attr));
|
||||
}
|
||||
};
|
||||
} // end namespace std
|
||||
|
||||
namespace glslang {
|
||||
class TIntermAggregate;
|
||||
|
||||
class TAttributeMap {
|
||||
public:
|
||||
int size() const { return (int)attributes.size(); }
|
||||
|
||||
// Search for and potentially add the attribute into the map. Return the
|
||||
// attribute type enum for it, if found, else EatNone.
|
||||
TAttributeType setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value);
|
||||
|
||||
// Const lookup: search for (but do not modify) the attribute in the map.
|
||||
const TIntermAggregate* operator[](TAttributeType) const;
|
||||
|
||||
// True if entry exists in map (even if value is nullptr)
|
||||
bool contains(TAttributeType) const;
|
||||
|
||||
// Obtain attribute as integer
|
||||
bool getInt(TAttributeType attr, int& value, int argNum = 0) const;
|
||||
|
||||
// Obtain attribute as string, with optional to-lower transform
|
||||
bool getString(TAttributeType attr, TString& value, int argNum = 0, bool convertToLower = true) const;
|
||||
|
||||
protected:
|
||||
// Helper to get attribute const union
|
||||
const TConstUnion* getConstUnion(TAttributeType attr, TBasicType, int argNum) const;
|
||||
|
||||
// Find an attribute enum given its name.
|
||||
static TAttributeType attributeFromName(const TString& nameSpace, const TString& name);
|
||||
|
||||
std::unordered_map<TAttributeType, TIntermAggregate*> attributes;
|
||||
};
|
||||
|
||||
class TFunctionDeclarator {
|
||||
public:
|
||||
TFunctionDeclarator() : function(nullptr), body(nullptr) { }
|
||||
TSourceLoc loc;
|
||||
TFunction* function;
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
TVector<HlslToken>* body;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
|
||||
#endif // HLSLATTRIBUTES_H_
|
||||
|
@ -396,6 +396,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
|
||||
if (peekTokenClass(EHTokLeftParen)) {
|
||||
// looks like function parameters
|
||||
|
||||
// merge in the attributes into the return type
|
||||
parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType, true);
|
||||
|
||||
// Potentially rename shader entry point function. No-op most of the time.
|
||||
parseContext.renameShaderFunction(fullName);
|
||||
|
||||
@ -423,7 +426,13 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
|
||||
parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
|
||||
}
|
||||
} else {
|
||||
// A variable declaration. Fix the storage qualifier if it's a global.
|
||||
// A variable declaration.
|
||||
|
||||
// merge in the attributes, the first time around, into the shared type
|
||||
if (! declarator_list)
|
||||
parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType);
|
||||
|
||||
// Fix the storage qualifier if it's a global.
|
||||
if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
|
||||
declaredType.getQualifier().storage = EvqUniform;
|
||||
|
||||
@ -536,13 +545,16 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
|
||||
bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
|
||||
{
|
||||
node = nullptr;
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
|
||||
// fully_specified_type
|
||||
TType type;
|
||||
if (! acceptFullySpecifiedType(type, attributes))
|
||||
return false;
|
||||
|
||||
if (attributes.size() > 0)
|
||||
parseContext.warn(token.loc, "attributes don't apply to control declaration", "", "");
|
||||
|
||||
// filter out type casts
|
||||
if (peekTokenClass(EHTokLeftParen)) {
|
||||
recedeToken();
|
||||
@ -578,12 +590,12 @@ bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
|
||||
// : type_specifier
|
||||
// | type_qualifier type_specifier
|
||||
//
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes)
|
||||
{
|
||||
TIntermNode* nodeList = nullptr;
|
||||
return acceptFullySpecifiedType(type, nodeList, attributes);
|
||||
}
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributeMap& attributes, bool forbidDeclarators)
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators)
|
||||
{
|
||||
// type_qualifier
|
||||
TQualifier qualifier;
|
||||
@ -608,7 +620,7 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
|
||||
parseContext.mergeQualifiers(type.getQualifier(), qualifier);
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(attributes, type);
|
||||
parseContext.transferTypeAttributes(token.loc, attributes, type);
|
||||
|
||||
// further, it can create an anonymous instance of the block
|
||||
// (cbuffer and tbuffer don't consume the next identifier, and
|
||||
@ -633,9 +645,6 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
|
||||
qualifier.builtIn = type.getQualifier().builtIn;
|
||||
|
||||
type.getQualifier() = qualifier;
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(attributes, type);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2335,7 +2344,7 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
|
||||
// struct_declaration
|
||||
|
||||
// attributes
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
acceptAttributes(attributes);
|
||||
|
||||
bool declarator_list = false;
|
||||
@ -2346,6 +2355,9 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
|
||||
expected("member type");
|
||||
return false;
|
||||
}
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(token.loc, attributes, memberType);
|
||||
|
||||
// struct_declarator COMMA struct_declarator ...
|
||||
bool functionDefinitionAccepted = false;
|
||||
@ -2542,7 +2554,7 @@ bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTy
|
||||
bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
|
||||
{
|
||||
// attributes
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
acceptAttributes(attributes);
|
||||
|
||||
// fully_specified_type
|
||||
@ -2550,6 +2562,9 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
|
||||
if (! acceptFullySpecifiedType(*type, attributes))
|
||||
return false;
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(token.loc, attributes, *type);
|
||||
|
||||
// identifier
|
||||
HlslToken idToken;
|
||||
acceptIdentifier(idToken);
|
||||
@ -3386,7 +3401,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
|
||||
statement = nullptr;
|
||||
|
||||
// attributes
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
acceptAttributes(attributes);
|
||||
|
||||
// attributed_statement
|
||||
@ -3458,7 +3473,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
|
||||
// | PATCHCONSTANTFUNC
|
||||
// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
|
||||
//
|
||||
void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
|
||||
void HlslGrammar::acceptAttributes(TAttributes& attributes)
|
||||
{
|
||||
// For now, accept the [ XXX(X) ] syntax, but drop all but
|
||||
// numthreads, which is used to set the CS local size.
|
||||
@ -3529,9 +3544,16 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
|
||||
return;
|
||||
}
|
||||
|
||||
// Add any values we found into the attribute map. This accepts
|
||||
// (and ignores) values not mapping to a known TAttributeType;
|
||||
attributes.setAttribute(nameSpace, attributeToken.string, expressions);
|
||||
// Add any values we found into the attribute map.
|
||||
if (attributeToken.string != nullptr) {
|
||||
TAttributeType attributeType = parseContext.attributeFromName(nameSpace, *attributeToken.string);
|
||||
if (attributeType == EatNone)
|
||||
parseContext.warn(attributeToken.loc, "unrecognized attribute", attributeToken.string->c_str(), "");
|
||||
else {
|
||||
TAttributeArgs attributeArgs = { attributeType, expressions };
|
||||
attributes.push_back(attributeArgs);
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@ -3539,12 +3561,10 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
|
||||
// : IF LEFT_PAREN expression RIGHT_PAREN statement
|
||||
// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
|
||||
//
|
||||
bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes)
|
||||
{
|
||||
TSourceLoc loc = token.loc;
|
||||
|
||||
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
|
||||
|
||||
// IF
|
||||
if (! acceptTokenClass(EHTokIf))
|
||||
return false;
|
||||
@ -3582,7 +3602,9 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
|
||||
}
|
||||
|
||||
// Put the pieces together
|
||||
statement = intermediate.addSelection(condition, thenElse, loc, control);
|
||||
statement = intermediate.addSelection(condition, thenElse, loc);
|
||||
parseContext.handleSelectionAttributes(loc, statement->getAsSelectionNode(), attributes);
|
||||
|
||||
parseContext.popScope();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
@ -3592,13 +3614,11 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
|
||||
// switch_statement
|
||||
// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
|
||||
//
|
||||
bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes)
|
||||
{
|
||||
// SWITCH
|
||||
TSourceLoc loc = token.loc;
|
||||
|
||||
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
|
||||
|
||||
if (! acceptTokenClass(EHTokSwitch))
|
||||
return false;
|
||||
|
||||
@ -3618,7 +3638,8 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
if (statementOkay)
|
||||
statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr, control);
|
||||
statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr,
|
||||
attributes);
|
||||
|
||||
parseContext.popSwitchSequence();
|
||||
parseContext.popScope();
|
||||
@ -3632,7 +3653,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
|
||||
// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
|
||||
//
|
||||
// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
|
||||
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes)
|
||||
{
|
||||
TSourceLoc loc = token.loc;
|
||||
TIntermTyped* condition = nullptr;
|
||||
@ -3642,9 +3663,8 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
|
||||
// WHILE or DO or FOR
|
||||
advanceToken();
|
||||
|
||||
const TLoopControl control = parseContext.handleLoopControl(attributes);
|
||||
|
||||
TIntermLoop* loopNode = nullptr;
|
||||
switch (loop) {
|
||||
case EHTokWhile:
|
||||
// so that something declared in the condition is scoped to the lifetime
|
||||
@ -3670,9 +3690,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
parseContext.popScope();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
|
||||
|
||||
return true;
|
||||
loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc);
|
||||
statement = loopNode;
|
||||
break;
|
||||
|
||||
case EHTokDo:
|
||||
parseContext.nestLooping(); // this only needs to work right if no errors
|
||||
@ -3703,9 +3723,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
parseContext.unnestLooping();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
|
||||
|
||||
return true;
|
||||
loopNode = intermediate.addLoop(statement, condition, 0, false, loc);
|
||||
statement = loopNode;
|
||||
break;
|
||||
|
||||
case EHTokFor:
|
||||
{
|
||||
@ -3747,18 +3767,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
return false;
|
||||
}
|
||||
|
||||
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control);
|
||||
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, loopNode);
|
||||
|
||||
parseContext.popScope();
|
||||
parseContext.unnestLooping();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
parseContext.handleLoopAttributes(loc, loopNode, attributes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// jump_statement
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TAttributeMap;
|
||||
class TFunctionDeclarator;
|
||||
|
||||
// Should just be the grammar aspect of HLSL.
|
||||
@ -71,8 +70,8 @@ namespace glslang {
|
||||
bool acceptControlDeclaration(TIntermNode*& node);
|
||||
bool acceptSamplerDeclarationDX9(TType&);
|
||||
bool acceptSamplerState();
|
||||
bool acceptFullySpecifiedType(TType&, const TAttributeMap&);
|
||||
bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributeMap&, bool forbidDeclarators = false);
|
||||
bool acceptFullySpecifiedType(TType&, const TAttributes&);
|
||||
bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributes&, bool forbidDeclarators = false);
|
||||
bool acceptQualifier(TQualifier&);
|
||||
bool acceptLayoutQualifierList(TQualifier&);
|
||||
bool acceptType(TType&);
|
||||
@ -117,10 +116,10 @@ namespace glslang {
|
||||
bool acceptScopedCompoundStatement(TIntermNode*&);
|
||||
bool acceptStatement(TIntermNode*&);
|
||||
bool acceptNestedStatement(TIntermNode*&);
|
||||
void acceptAttributes(TAttributeMap&);
|
||||
bool acceptSelectionStatement(TIntermNode*&, const TAttributeMap&);
|
||||
bool acceptSwitchStatement(TIntermNode*&, const TAttributeMap&);
|
||||
bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&);
|
||||
void acceptAttributes(TAttributes&);
|
||||
bool acceptSelectionStatement(TIntermNode*&, const TAttributes&);
|
||||
bool acceptSwitchStatement(TIntermNode*&, const TAttributes&);
|
||||
bool acceptIterationStatement(TIntermNode*&, const TAttributes&);
|
||||
bool acceptJumpStatement(TIntermNode*&);
|
||||
bool acceptCaseLabel(TIntermNode*&);
|
||||
bool acceptDefaultLabel(TIntermNode*&);
|
||||
|
@ -1620,7 +1620,7 @@ void HlslParseContext::addStructBufferHiddenCounterParam(const TSourceLoc& loc,
|
||||
// Returns an aggregate of parameter-symbol nodes.
|
||||
//
|
||||
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
|
||||
const TAttributeMap& attributes,
|
||||
const TAttributes& attributes,
|
||||
TIntermNode*& entryPointTree)
|
||||
{
|
||||
currentCaller = function.getMangledName();
|
||||
@ -1717,189 +1717,217 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
|
||||
}
|
||||
|
||||
// Handle all [attrib] attribute for the shader entry point
|
||||
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributeMap& attributes)
|
||||
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributes& attributes)
|
||||
{
|
||||
// Handle entry-point function attributes
|
||||
const TIntermAggregate* numThreads = attributes[EatNumThreads];
|
||||
if (numThreads != nullptr) {
|
||||
const TIntermSequence& sequence = numThreads->getSequence();
|
||||
|
||||
for (int lid = 0; lid < int(sequence.size()); ++lid)
|
||||
intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
}
|
||||
|
||||
// MaxVertexCount
|
||||
if (attributes.contains(EatMaxVertexCount)) {
|
||||
int maxVertexCount;
|
||||
|
||||
if (! attributes.getInt(EatMaxVertexCount, maxVertexCount)) {
|
||||
error(loc, "invalid maxvertexcount", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(maxVertexCount))
|
||||
error(loc, "cannot change previously set maxvertexcount attribute", "", "");
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatNumThreads:
|
||||
{
|
||||
const TIntermSequence& sequence = it->args->getSequence();
|
||||
for (int lid = 0; lid < int(sequence.size()); ++lid)
|
||||
intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
break;
|
||||
}
|
||||
}
|
||||
case EatMaxVertexCount:
|
||||
{
|
||||
int maxVertexCount;
|
||||
|
||||
// Handle [patchconstantfunction("...")]
|
||||
if (attributes.contains(EatPatchConstantFunc)) {
|
||||
TString pcfName;
|
||||
if (! attributes.getString(EatPatchConstantFunc, pcfName, 0, false)) {
|
||||
error(loc, "invalid patch constant function", "", "");
|
||||
} else {
|
||||
patchConstantFunctionName = pcfName;
|
||||
if (! it->getInt(maxVertexCount)) {
|
||||
error(loc, "invalid maxvertexcount", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(maxVertexCount))
|
||||
error(loc, "cannot change previously set maxvertexcount attribute", "", "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle [domain("...")]
|
||||
if (attributes.contains(EatDomain)) {
|
||||
TString domainStr;
|
||||
if (! attributes.getString(EatDomain, domainStr)) {
|
||||
error(loc, "invalid domain", "", "");
|
||||
} else {
|
||||
TLayoutGeometry domain = ElgNone;
|
||||
|
||||
if (domainStr == "tri") {
|
||||
domain = ElgTriangles;
|
||||
} else if (domainStr == "quad") {
|
||||
domain = ElgQuads;
|
||||
} else if (domainStr == "isoline") {
|
||||
domain = ElgIsolines;
|
||||
case EatPatchConstantFunc:
|
||||
{
|
||||
TString pcfName;
|
||||
if (! it->getString(pcfName, 0, false)) {
|
||||
error(loc, "invalid patch constant function", "", "");
|
||||
} else {
|
||||
error(loc, "unsupported domain type", domainStr.c_str(), "");
|
||||
}
|
||||
|
||||
if (language == EShLangTessEvaluation) {
|
||||
if (! intermediate.setInputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
} else {
|
||||
if (! intermediate.setOutputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
patchConstantFunctionName = pcfName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle [outputtopology("...")]
|
||||
if (attributes.contains(EatOutputTopology)) {
|
||||
TString topologyStr;
|
||||
if (! attributes.getString(EatOutputTopology, topologyStr)) {
|
||||
error(loc, "invalid outputtopology", "", "");
|
||||
} else {
|
||||
TVertexOrder vertexOrder = EvoNone;
|
||||
TLayoutGeometry primitive = ElgNone;
|
||||
|
||||
if (topologyStr == "point") {
|
||||
intermediate.setPointMode();
|
||||
} else if (topologyStr == "line") {
|
||||
primitive = ElgIsolines;
|
||||
} else if (topologyStr == "triangle_cw") {
|
||||
vertexOrder = EvoCw;
|
||||
primitive = ElgTriangles;
|
||||
} else if (topologyStr == "triangle_ccw") {
|
||||
vertexOrder = EvoCcw;
|
||||
primitive = ElgTriangles;
|
||||
case EatDomain:
|
||||
{
|
||||
// Handle [domain("...")]
|
||||
TString domainStr;
|
||||
if (! it->getString(domainStr)) {
|
||||
error(loc, "invalid domain", "", "");
|
||||
} else {
|
||||
error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
|
||||
}
|
||||
TLayoutGeometry domain = ElgNone;
|
||||
|
||||
if (vertexOrder != EvoNone) {
|
||||
if (! intermediate.setVertexOrder(vertexOrder)) {
|
||||
error(loc, "cannot change previously set outputtopology",
|
||||
TQualifier::getVertexOrderString(vertexOrder), "");
|
||||
if (domainStr == "tri") {
|
||||
domain = ElgTriangles;
|
||||
} else if (domainStr == "quad") {
|
||||
domain = ElgQuads;
|
||||
} else if (domainStr == "isoline") {
|
||||
domain = ElgIsolines;
|
||||
} else {
|
||||
error(loc, "unsupported domain type", domainStr.c_str(), "");
|
||||
}
|
||||
|
||||
if (language == EShLangTessEvaluation) {
|
||||
if (! intermediate.setInputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
} else {
|
||||
if (! intermediate.setOutputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
}
|
||||
}
|
||||
if (primitive != ElgNone)
|
||||
intermediate.setOutputPrimitive(primitive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle [partitioning("...")]
|
||||
if (attributes.contains(EatPartitioning)) {
|
||||
TString partitionStr;
|
||||
if (! attributes.getString(EatPartitioning, partitionStr)) {
|
||||
error(loc, "invalid partitioning", "", "");
|
||||
} else {
|
||||
TVertexSpacing partitioning = EvsNone;
|
||||
|
||||
if (partitionStr == "integer") {
|
||||
partitioning = EvsEqual;
|
||||
} else if (partitionStr == "fractional_even") {
|
||||
partitioning = EvsFractionalEven;
|
||||
} else if (partitionStr == "fractional_odd") {
|
||||
partitioning = EvsFractionalOdd;
|
||||
//} else if (partition == "pow2") { // TODO: currently nothing to map this to.
|
||||
case EatOutputTopology:
|
||||
{
|
||||
// Handle [outputtopology("...")]
|
||||
TString topologyStr;
|
||||
if (! it->getString(topologyStr)) {
|
||||
error(loc, "invalid outputtopology", "", "");
|
||||
} else {
|
||||
error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
|
||||
}
|
||||
TVertexOrder vertexOrder = EvoNone;
|
||||
TLayoutGeometry primitive = ElgNone;
|
||||
|
||||
if (! intermediate.setVertexSpacing(partitioning))
|
||||
error(loc, "cannot change previously set partitioning",
|
||||
TQualifier::getVertexSpacingString(partitioning), "");
|
||||
if (topologyStr == "point") {
|
||||
intermediate.setPointMode();
|
||||
} else if (topologyStr == "line") {
|
||||
primitive = ElgIsolines;
|
||||
} else if (topologyStr == "triangle_cw") {
|
||||
vertexOrder = EvoCw;
|
||||
primitive = ElgTriangles;
|
||||
} else if (topologyStr == "triangle_ccw") {
|
||||
vertexOrder = EvoCcw;
|
||||
primitive = ElgTriangles;
|
||||
} else {
|
||||
error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
|
||||
}
|
||||
|
||||
if (vertexOrder != EvoNone) {
|
||||
if (! intermediate.setVertexOrder(vertexOrder)) {
|
||||
error(loc, "cannot change previously set outputtopology",
|
||||
TQualifier::getVertexOrderString(vertexOrder), "");
|
||||
}
|
||||
}
|
||||
if (primitive != ElgNone)
|
||||
intermediate.setOutputPrimitive(primitive);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case EatPartitioning:
|
||||
{
|
||||
// Handle [partitioning("...")]
|
||||
TString partitionStr;
|
||||
if (! it->getString(partitionStr)) {
|
||||
error(loc, "invalid partitioning", "", "");
|
||||
} else {
|
||||
TVertexSpacing partitioning = EvsNone;
|
||||
|
||||
if (partitionStr == "integer") {
|
||||
partitioning = EvsEqual;
|
||||
} else if (partitionStr == "fractional_even") {
|
||||
partitioning = EvsFractionalEven;
|
||||
} else if (partitionStr == "fractional_odd") {
|
||||
partitioning = EvsFractionalOdd;
|
||||
//} else if (partition == "pow2") { // TODO: currently nothing to map this to.
|
||||
} else {
|
||||
error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
|
||||
}
|
||||
|
||||
// Handle [outputcontrolpoints("...")]
|
||||
if (attributes.contains(EatOutputControlPoints)) {
|
||||
int ctrlPoints;
|
||||
if (! attributes.getInt(EatOutputControlPoints, ctrlPoints)) {
|
||||
error(loc, "invalid outputcontrolpoints", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(ctrlPoints)) {
|
||||
error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
|
||||
if (! intermediate.setVertexSpacing(partitioning))
|
||||
error(loc, "cannot change previously set partitioning",
|
||||
TQualifier::getVertexSpacingString(partitioning), "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EatOutputControlPoints:
|
||||
{
|
||||
// Handle [outputcontrolpoints("...")]
|
||||
int ctrlPoints;
|
||||
if (! it->getInt(ctrlPoints)) {
|
||||
error(loc, "invalid outputcontrolpoints", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(ctrlPoints)) {
|
||||
error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EatBuiltIn:
|
||||
case EatLocation:
|
||||
// tolerate these because of dual use of entrypoint and type attributes
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to entry point", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the given type with any type-like attribute information in the
|
||||
// attributes.
|
||||
void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, TType& type)
|
||||
void HlslParseContext::transferTypeAttributes(const TSourceLoc& loc, const TAttributes& attributes, TType& type,
|
||||
bool allowEntry)
|
||||
{
|
||||
if (attributes.size() == 0)
|
||||
return;
|
||||
|
||||
// location
|
||||
int value;
|
||||
if (attributes.getInt(EatLocation, value))
|
||||
type.getQualifier().layoutLocation = value;
|
||||
|
||||
// binding
|
||||
if (attributes.getInt(EatBinding, value)) {
|
||||
type.getQualifier().layoutBinding = value;
|
||||
type.getQualifier().layoutSet = 0;
|
||||
}
|
||||
|
||||
// set
|
||||
if (attributes.getInt(EatBinding, value, 1))
|
||||
type.getQualifier().layoutSet = value;
|
||||
|
||||
// global cbuffer binding
|
||||
if (attributes.getInt(EatGlobalBinding, value))
|
||||
globalUniformBinding = value;
|
||||
|
||||
// global cbuffer binding
|
||||
if (attributes.getInt(EatGlobalBinding, value, 1))
|
||||
globalUniformSet = value;
|
||||
|
||||
// input attachment
|
||||
if (attributes.getInt(EatInputAttachment, value))
|
||||
type.getQualifier().layoutAttachment = value;
|
||||
|
||||
// PointSize built-in
|
||||
TString builtInString;
|
||||
if (attributes.getString(EatBuiltIn, builtInString, 0, false)) {
|
||||
if (builtInString == "PointSize")
|
||||
type.getQualifier().builtIn = EbvPointSize;
|
||||
}
|
||||
|
||||
// push_constant
|
||||
if (attributes.contains(EatPushConstant))
|
||||
type.getQualifier().layoutPushConstant = true;
|
||||
|
||||
// specialization constant
|
||||
if (attributes.getInt(EatConstantId, value)) {
|
||||
TSourceLoc loc;
|
||||
loc.init();
|
||||
setSpecConstantId(loc, type.getQualifier(), value);
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatLocation:
|
||||
// location
|
||||
if (it->getInt(value))
|
||||
type.getQualifier().layoutLocation = value;
|
||||
break;
|
||||
case EatBinding:
|
||||
// binding
|
||||
if (it->getInt(value)) {
|
||||
type.getQualifier().layoutBinding = value;
|
||||
type.getQualifier().layoutSet = 0;
|
||||
}
|
||||
// set
|
||||
if (it->getInt(value, 1))
|
||||
type.getQualifier().layoutSet = value;
|
||||
break;
|
||||
case EatGlobalBinding:
|
||||
// global cbuffer binding
|
||||
if (it->getInt(value))
|
||||
globalUniformBinding = value;
|
||||
// global cbuffer binding
|
||||
if (it->getInt(value, 1))
|
||||
globalUniformSet = value;
|
||||
break;
|
||||
case EatInputAttachment:
|
||||
// input attachment
|
||||
if (it->getInt(value))
|
||||
type.getQualifier().layoutAttachment = value;
|
||||
break;
|
||||
case EatBuiltIn:
|
||||
// PointSize built-in
|
||||
if (it->getString(builtInString, 0, false)) {
|
||||
if (builtInString == "PointSize")
|
||||
type.getQualifier().builtIn = EbvPointSize;
|
||||
}
|
||||
break;
|
||||
case EatPushConstant:
|
||||
// push_constant
|
||||
type.getQualifier().layoutPushConstant = true;
|
||||
break;
|
||||
case EatConstantId:
|
||||
// specialization constant
|
||||
if (it->getInt(value)) {
|
||||
TSourceLoc loc;
|
||||
loc.init();
|
||||
setSpecConstantId(loc, type.getQualifier(), value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (! allowEntry)
|
||||
warn(loc, "attribute does not apply to a type", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1936,7 +1964,7 @@ void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, T
|
||||
// a subtree that creates the entry point.
|
||||
//
|
||||
TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction,
|
||||
const TAttributeMap& attributes)
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
// Return true if this is a tessellation patch constant function input to a domain shader.
|
||||
const auto isDsPcfInput = [this](const TType& type) {
|
||||
@ -8792,29 +8820,75 @@ bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayout
|
||||
}
|
||||
|
||||
//
|
||||
// Selection hints
|
||||
// Selection attributes
|
||||
//
|
||||
TSelectionControl HlslParseContext::handleSelectionControl(const TAttributeMap& attributes) const
|
||||
void HlslParseContext::handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection* selection,
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
if (attributes.contains(EatFlatten))
|
||||
return ESelectionControlFlatten;
|
||||
else if (attributes.contains(EatBranch))
|
||||
return ESelectionControlDontFlatten;
|
||||
else
|
||||
return ESelectionControlNone;
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to a selection", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Switch attributes
|
||||
//
|
||||
void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch* selection,
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to a switch", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop hints
|
||||
//
|
||||
TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes) const
|
||||
void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
if (attributes.contains(EatUnroll))
|
||||
return ELoopControlUnroll;
|
||||
else if (attributes.contains(EatLoop))
|
||||
return ELoopControlDontUnroll;
|
||||
else
|
||||
return ELoopControlNone;
|
||||
if (loop == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatUnroll:
|
||||
loop->setUnroll();
|
||||
break;
|
||||
case EatLoop:
|
||||
loop->setDontUnroll();
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to a loop", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@ -8959,7 +9033,7 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn
|
||||
// into a switch node.
|
||||
//
|
||||
TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression,
|
||||
TIntermAggregate* lastStatements, TSelectionControl control)
|
||||
TIntermAggregate* lastStatements, const TAttributes& attributes)
|
||||
{
|
||||
wrapupSwitchSubsequence(lastStatements, nullptr);
|
||||
|
||||
@ -8986,7 +9060,7 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
|
||||
|
||||
TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
|
||||
switchNode->setLoc(loc);
|
||||
switchNode->setSelectionControl(control);
|
||||
handleSwitchAttributes(loc, switchNode, attributes);
|
||||
|
||||
return switchNode;
|
||||
}
|
||||
|
@ -38,12 +38,12 @@
|
||||
|
||||
#include "../glslang/MachineIndependent/parseVersions.h"
|
||||
#include "../glslang/MachineIndependent/ParseHelper.h"
|
||||
#include "../glslang/MachineIndependent/attribute.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TAttributeMap; // forward declare
|
||||
class TFunctionDeclarator;
|
||||
|
||||
class HlslParseContext : public TParseContextBase {
|
||||
@ -80,10 +80,10 @@ public:
|
||||
bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
||||
void assignToInterface(TVariable& variable);
|
||||
void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
|
||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
|
||||
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
|
||||
void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&);
|
||||
void transferTypeAttributes(const TAttributeMap&, TType&);
|
||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributes&, TIntermNode*& entryPointTree);
|
||||
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributes&);
|
||||
void handleEntryPointAttributes(const TSourceLoc&, const TAttributes&);
|
||||
void transferTypeAttributes(const TSourceLoc&, const TAttributes&, TType&, bool allowEntry = false);
|
||||
void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
|
||||
void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
|
||||
void remapNonEntryPointIO(TFunction& function);
|
||||
@ -163,7 +163,7 @@ public:
|
||||
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
|
||||
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
|
||||
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
|
||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, TSelectionControl control);
|
||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, const TAttributes&);
|
||||
|
||||
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
||||
|
||||
@ -203,10 +203,11 @@ public:
|
||||
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
|
||||
|
||||
// Determine selection control from attributes
|
||||
TSelectionControl handleSelectionControl(const TAttributeMap& attributes) const;
|
||||
void handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection*, const TAttributes& attributes);
|
||||
void handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch*, const TAttributes& attributes);
|
||||
|
||||
// Determine loop control from attributes
|
||||
TLoopControl handleLoopControl(const TAttributeMap& attributes) const;
|
||||
void handleLoopAttributes(const TSourceLoc& loc, TIntermLoop*, const TAttributes& attributes);
|
||||
|
||||
// Share struct buffer deep types
|
||||
void shareStructBufferType(TType&);
|
||||
@ -217,6 +218,8 @@ public:
|
||||
// Obtain the sampler return type of the given sampler in retType.
|
||||
void getTextureReturnType(const TSampler& sampler, TType& retType) const;
|
||||
|
||||
TAttributeType attributeFromName(const TString& nameSpace, const TString& name) const;
|
||||
|
||||
protected:
|
||||
struct TFlattenData {
|
||||
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),
|
||||
|
Loading…
Reference in New Issue
Block a user