Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
glslang
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
glslang
Commits
1061accf
Commit
1061accf
authored
Nov 01, 2016
by
John Kessenich
Committed by
GitHub
Nov 01, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #562 from TiemoJung/io_map_control_publish
HLSL -> Spir-V: Resource mapping handler
parents
909b8afa
c2016a52
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
297 additions
and
156 deletions
+297
-156
spv.register.autoassign.rangetest.frag.out
Test/baseResults/spv.register.autoassign.rangetest.frag.out
+0
-4
ShaderLang.cpp
glslang/MachineIndependent/ShaderLang.cpp
+2
-2
iomapper.cpp
glslang/MachineIndependent/iomapper.cpp
+261
-147
iomapper.h
glslang/MachineIndependent/iomapper.h
+1
-1
ShaderLang.h
glslang/Public/ShaderLang.h
+33
-2
No files found.
Test/baseResults/spv.register.autoassign.rangetest.frag.out
View file @
1061accf
...
@@ -2,10 +2,6 @@ spv.register.autoassign.rangetest.frag
...
@@ -2,10 +2,6 @@ spv.register.autoassign.rangetest.frag
Linked fragment stage:
Linked fragment stage:
INTERNAL ERROR: mapped binding out of range: g_tScene
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tScene
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tSamp
INTERNAL ERROR: mapped binding out of range: g_tScene
INTERNAL ERROR: mapped binding out of range: g_tScene
...
...
glslang/MachineIndependent/ShaderLang.cpp
View file @
1061accf
...
@@ -1716,7 +1716,7 @@ void TProgram::dumpReflection() { reflection->dump(); }
...
@@ -1716,7 +1716,7 @@ void TProgram::dumpReflection() { reflection->dump(); }
//
//
// I/O mapping implementation.
// I/O mapping implementation.
//
//
bool
TProgram
::
mapIO
()
bool
TProgram
::
mapIO
(
TIoMapResolver
*
resolver
)
{
{
if
(
!
linked
||
ioMapper
)
if
(
!
linked
||
ioMapper
)
return
false
;
return
false
;
...
@@ -1725,7 +1725,7 @@ bool TProgram::mapIO()
...
@@ -1725,7 +1725,7 @@ bool TProgram::mapIO()
for
(
int
s
=
0
;
s
<
EShLangCount
;
++
s
)
{
for
(
int
s
=
0
;
s
<
EShLangCount
;
++
s
)
{
if
(
intermediate
[
s
])
{
if
(
intermediate
[
s
])
{
if
(
!
ioMapper
->
addStage
((
EShLanguage
)
s
,
*
intermediate
[
s
],
*
infoSink
))
if
(
!
ioMapper
->
addStage
((
EShLanguage
)
s
,
*
intermediate
[
s
],
*
infoSink
,
resolver
))
return
false
;
return
false
;
}
}
}
}
...
...
glslang/MachineIndependent/iomapper.cpp
View file @
1061accf
...
@@ -61,177 +61,278 @@
...
@@ -61,177 +61,278 @@
// c. implicit dead bindings are left un-bound.
// c. implicit dead bindings are left un-bound.
//
//
namespace
glslang
{
// Map of IDs to bindings
namespace
glslang
{
typedef
std
::
unordered_map
<
unsigned
int
,
int
>
TBindingMap
;
typedef
std
::
unordered_set
<
int
>
TUsedBindings
;
struct
TVarEntryInfo
{
int
id
;
TIntermSymbol
*
symbol
;
bool
live
;
int
newBinding
;
int
newSet
;
// This traverses the AST to determine which bindings are used, and which are implicit
struct
TOrderById
// (for subsequent auto-numbering)
{
class
TBindingTraverser
:
public
TLiveTraverser
{
inline
bool
operator
()(
const
TVarEntryInfo
&
l
,
const
TVarEntryInfo
&
r
)
public
:
{
TBindingTraverser
(
const
TIntermediate
&
i
,
TBindingMap
&
bindingMap
,
TUsedBindings
&
usedBindings
,
return
l
.
id
<
r
.
id
;
bool
traverseDeadCode
=
false
)
:
}
TLiveTraverser
(
i
,
traverseDeadCode
,
true
,
true
,
false
),
};
bindingMap
(
bindingMap
),
usedBindings
(
usedBindings
)
{
}
protected
:
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
{
if
(
base
->
getQualifier
().
storage
==
EvqUniform
)
addUniform
(
*
base
);
}
// Return the right binding base given the variable type.
struct
TOrderByPriority
int
getBindingBase
(
const
TType
&
type
)
{
{
if
(
type
.
getBasicType
()
==
EbtSampler
)
{
// ordering:
const
TSampler
&
sampler
=
type
.
getSampler
();
// 1) has both binding and set
if
(
sampler
.
isPureSampler
())
// 2) has binding but no set
return
intermediate
.
getShiftSamplerBinding
();
// 3) has no binding but set
if
(
sampler
.
isTexture
())
// 4) has no binding and no set
return
intermediate
.
getShiftTextureBinding
();
inline
bool
operator
()(
const
TVarEntryInfo
&
l
,
const
TVarEntryInfo
&
r
)
{
const
TQualifier
&
lq
=
l
.
symbol
->
getQualifier
();
const
TQualifier
&
rq
=
r
.
symbol
->
getQualifier
();
// simple rules:
// has binding gives 2 points
// has set gives 1 point
// who has the most points is more important.
int
lPoints
=
(
lq
.
hasBinding
()
?
2
:
0
)
+
(
lq
.
hasSet
()
?
1
:
0
);
int
rPoints
=
(
rq
.
hasBinding
()
?
2
:
0
)
+
(
rq
.
hasSet
()
?
1
:
0
);
if
(
lPoints
==
rPoints
)
return
l
.
id
<
r
.
id
;
return
lPoints
>
rPoints
;
}
}
};
};
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
return
intermediate
.
getShiftUboBinding
();
return
-
1
;
// not a type with a binding
}
// Mark a given base symbol ID as being bound to 'binding'
void
markBinding
(
const
TIntermSymbol
&
base
,
int
binding
)
{
bindingMap
[
base
.
getId
()]
=
binding
;
if
(
binding
>=
0
)
{
typedef
std
::
vector
<
TVarEntryInfo
>
TVarLiveMap
;
// const TType& type = base.getType();
const
unsigned
int
size
=
1
;
// type.isArray() ? type.getCumulativeArraySize() : 1;
for
(
unsigned
int
offset
=
0
;
offset
<
size
;
++
offset
)
class
TVarGatherTraverser
:
public
TLiveTraverser
usedBindings
.
insert
(
binding
+
offset
);
{
}
public
:
}
TVarGatherTraverser
(
const
TIntermediate
&
i
,
TVarLiveMap
&
vars
,
bool
traverseDeadCode
)
:
TLiveTraverser
(
i
,
traverseDeadCode
,
true
,
true
,
false
)
// Mark the bindings that are given explicitly, and set ones that need
,
varLiveList
(
vars
)
// implicit bindings to -1 for a subsequent pass. (Can't happen in this
// pass because explicit bindings in dead code reserve the location).
virtual
void
addUniform
(
TIntermSymbol
&
base
)
{
{
// Skip ones we've already seen.
}
if
(
bindingMap
.
find
(
base
.
getId
())
!=
bindingMap
.
end
())
return
;
const
TType
&
type
=
base
.
getType
();
const
int
bindingBase
=
getBindingBase
(
type
);
// Return if it's not a type we bind
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
if
(
bindingBase
==
-
1
)
{
return
;
if
(
base
->
getQualifier
().
storage
==
EvqUniform
)
{
TVarEntryInfo
ent
=
{
base
->
getId
(),
base
,
!
traverseAll
};
if
(
type
.
getQualifier
().
hasBinding
())
{
TVarLiveMap
::
iterator
at
=
std
::
lower_bound
(
varLiveList
.
begin
(),
varLiveList
.
end
(),
ent
,
TVarEntryInfo
::
TOrderById
());
// It has a binding: keep that one.
if
(
at
!=
varLiveList
.
end
()
&&
at
->
id
==
ent
.
id
)
markBinding
(
base
,
type
.
getQualifier
().
layoutBinding
+
bindingBase
);
at
->
live
=
at
->
live
||
!
traverseAll
;
// update live state
}
else
if
(
!
traverseAll
)
{
else
// Mark it as something we need to dynamically create a binding for,
varLiveList
.
insert
(
at
,
ent
);
// only if we're walking just the live code. We don't auto-number
// in dead code.
markBinding
(
base
,
-
1
);
}
}
}
}
TBindingMap
&
bindingMap
;
private
:
T
UsedBindings
&
usedBindings
;
T
VarLiveMap
&
varLiveList
;
};
};
class
TVarSetTraverser
:
public
TLiveTraverser
// This traverses the AST and applies binding maps it's given.
{
class
TIoMappingTraverser
:
public
TBindingTraverser
{
public
:
public
:
TIoMappingTraverser
(
TIntermediate
&
i
,
TBindingMap
&
bindingMap
,
TUsedBindings
&
usedBindings
,
TVarSetTraverser
(
const
TIntermediate
&
i
,
const
TVarLiveMap
&
vars
)
TInfoSink
&
infoSink
,
bool
traverseDeadCode
)
:
:
TLiveTraverser
(
i
,
true
,
true
,
true
,
false
)
TBindingTraverser
(
i
,
bindingMap
,
usedBindings
,
traverseDeadCode
),
,
varLiveList
(
vars
)
infoSink
(
infoSink
),
assignError
(
false
)
{
}
bool
success
()
const
{
return
!
assignError
;
}
protected
:
unsigned
checkBindingRange
(
const
TIntermSymbol
&
base
,
unsigned
binding
)
{
{
if
(
binding
>=
TQualifier
::
layoutBindingEnd
)
{
TString
err
=
"mapped binding out of range: "
;
err
+=
base
.
getName
();
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
assignError
=
true
;
return
0
;
}
return
binding
;
}
}
void
addUniform
(
TIntermSymbol
&
base
)
override
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
{
{
// Skip things we don't intend to bind.
TVarEntryInfo
ent
=
{
base
->
getId
()
};
if
(
bindingMap
.
find
(
base
.
getId
())
==
bindingMap
.
end
())
TVarLiveMap
::
const_iterator
at
=
std
::
lower_bound
(
varLiveList
.
begin
(),
varLiveList
.
end
(),
ent
,
TVarEntryInfo
::
TOrderById
());
if
(
at
==
varLiveList
.
end
())
return
;
return
;
if
(
!
(
at
->
id
==
ent
.
id
))
const
int
existingBinding
=
bindingMap
[
base
.
getId
()];
// Apply existing binding, if we were given one or already made one up.
if
(
existingBinding
!=
-
1
)
{
base
.
getWritableType
().
getQualifier
().
layoutBinding
=
checkBindingRange
(
base
,
existingBinding
);
return
;
return
;
}
if
(
intermediate
.
getAutoMapBindings
())
{
if
(
at
->
newBinding
!=
-
1
)
// Otherwise, find a free spot for it.
base
->
getWritableType
().
getQualifier
().
layoutBinding
=
at
->
newBinding
;
const
int
freeBinding
=
getFreeBinding
(
base
.
getType
(),
getBindingBase
(
base
.
getType
()));
if
(
at
->
newSet
!=
-
1
)
base
->
getWritableType
().
getQualifier
().
layoutSet
=
at
->
newSet
;
}
private
:
const
TVarLiveMap
&
varLiveList
;
};
markBinding
(
base
,
freeBinding
);
struct
TResolverAdaptor
base
.
getWritableType
().
getQualifier
().
layoutBinding
=
checkBindingRange
(
base
,
freeBinding
);
{
TResolverAdaptor
(
EShLanguage
s
,
TIoMapResolver
&
r
,
TInfoSink
&
i
,
bool
&
e
)
:
resolver
(
r
)
,
stage
(
s
)
,
infoSink
(
i
)
,
error
(
e
)
{
}
inline
void
operator
()(
TVarEntryInfo
&
ent
)
{
bool
isValid
=
resolver
.
validateBinding
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
if
(
isValid
)
{
ent
.
newBinding
=
resolver
.
resolveBinding
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
ent
.
newSet
=
resolver
.
resolveSet
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
if
(
ent
.
newBinding
!=
-
1
)
{
if
(
ent
.
newBinding
>=
TQualifier
::
layoutBindingEnd
)
{
TString
err
=
"mapped binding out of range: "
+
ent
.
symbol
->
getName
();
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
error
=
true
;
}
}
if
(
ent
.
newSet
!=
-
1
)
{
if
(
ent
.
newSet
>=
TQualifier
::
layoutSetEnd
)
{
TString
err
=
"mapped set out of range: "
+
ent
.
symbol
->
getName
();
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
error
=
true
;
}
}
}
else
{
TString
errorMsg
=
"Invalid binding: "
+
ent
.
symbol
->
getName
();
infoSink
.
info
.
message
(
EPrefixInternalError
,
errorMsg
.
c_str
());
error
=
true
;
}
}
}
}
EShLanguage
stage
;
TIoMapResolver
&
resolver
;
TInfoSink
&
infoSink
;
bool
&
error
;
};
// Search for N free consecutive binding slots in [base, base+required).
/*
// E.g, if we want to reserve consecutive bindings for flattened arrays.
* Basic implementation of glslang::TIoMapResolver that replaces the
bool
hasNFreeSlots
(
int
base
,
int
required
)
{
* previous offset behaviour.
for
(
int
binding
=
base
;
binding
<
(
base
+
required
);
++
binding
)
* It does the same, uses the offsets for th corresponding uniform
if
(
usedBindings
.
find
(
binding
)
!=
usedBindings
.
end
())
* types. Also respects the EOptionAutoMapBindings flag and binds
return
false
;
* them if needed.
*/
return
true
;
struct
TDefaultIoResolver
:
public
glslang
::
TIoMapResolver
{
int
baseSamplerBinding
;
int
baseTextureBinding
;
int
baseUboBinding
;
bool
doAutoMapping
;
typedef
std
::
vector
<
int
>
TSlotSet
;
typedef
std
::
unordered_map
<
int
,
TSlotSet
>
TSlotSetMap
;
TSlotSetMap
slots
;
TSlotSet
::
iterator
findSlot
(
int
set
,
int
slot
)
{
return
std
::
lower_bound
(
slots
[
set
].
begin
(),
slots
[
set
].
end
(),
slot
);
}
bool
checkEmpty
(
int
set
,
int
slot
)
{
TSlotSet
::
iterator
at
=
findSlot
(
set
,
slot
);
return
!
(
at
!=
slots
[
set
].
end
()
&&
*
at
==
slot
);
}
int
reserveSlot
(
int
set
,
int
slot
)
{
TSlotSet
::
iterator
at
=
findSlot
(
set
,
slot
);
slots
[
set
].
insert
(
at
,
slot
);
return
slot
;
}
int
getFreeSlot
(
int
set
,
int
base
)
{
TSlotSet
::
iterator
at
=
findSlot
(
set
,
base
);
if
(
at
==
slots
[
set
].
end
())
return
reserveSlot
(
set
,
base
);
// look in locksteps, if they not match, then there is a free slot
for
(;
at
!=
slots
[
set
].
end
();
++
at
,
++
base
)
if
(
*
at
!=
base
)
break
;
return
reserveSlot
(
set
,
base
);
}
bool
validateBinding
(
EShLanguage
stage
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
/*is_live*/
)
override
{
if
(
type
.
getQualifier
().
hasBinding
())
{
int
set
;
if
(
type
.
getQualifier
().
hasSet
())
set
=
type
.
getQualifier
().
layoutSet
;
else
set
=
0
;
if
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
)
{
const
glslang
::
TSampler
&
sampler
=
type
.
getSampler
();
if
(
sampler
.
isPureSampler
())
return
checkEmpty
(
set
,
baseSamplerBinding
+
type
.
getQualifier
().
layoutBinding
);
if
(
sampler
.
isTexture
())
return
checkEmpty
(
set
,
baseTextureBinding
+
type
.
getQualifier
().
layoutBinding
);
}
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
return
checkEmpty
(
set
,
baseUboBinding
+
type
.
getQualifier
().
layoutBinding
);
}
}
return
true
;
// Find a free binding spot
}
int
getFreeBinding
(
const
TType
&
,
int
nextBinding
)
{
int
resolveBinding
(
EShLanguage
stage
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
is_live
)
override
while
(
!
hasNFreeSlots
(
nextBinding
,
1
))
{
++
nextBinding
;
int
set
;
if
(
type
.
getQualifier
().
hasSet
())
return
nextBinding
;
set
=
type
.
getQualifier
().
layoutSet
;
else
set
=
0
;
if
(
type
.
getQualifier
().
hasBinding
())
{
if
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
)
{
const
glslang
::
TSampler
&
sampler
=
type
.
getSampler
();
if
(
sampler
.
isPureSampler
())
return
reserveSlot
(
set
,
baseSamplerBinding
+
type
.
getQualifier
().
layoutBinding
);
if
(
sampler
.
isTexture
())
return
reserveSlot
(
set
,
baseTextureBinding
+
type
.
getQualifier
().
layoutBinding
);
}
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
return
reserveSlot
(
set
,
baseUboBinding
+
type
.
getQualifier
().
layoutBinding
);
}
else
if
(
is_live
&&
doAutoMapping
)
{
// find free slot, the caller did make sure it passes all vars with binding
// first and now all are passed that do not have a binding and needs one
if
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
)
{
const
glslang
::
TSampler
&
sampler
=
type
.
getSampler
();
if
(
sampler
.
isPureSampler
())
return
getFreeSlot
(
set
,
baseSamplerBinding
);
if
(
sampler
.
isTexture
())
return
getFreeSlot
(
set
,
baseTextureBinding
);
}
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
return
getFreeSlot
(
set
,
baseUboBinding
);
}
}
private
:
return
-
1
;
bool
assignError
;
// true if there was an error assigning the bindings
}
TInfoSink
&
infoSink
;
int
resolveSet
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
/*is_live*/
)
override
{
if
(
type
.
getQualifier
().
hasSet
())
return
type
.
getQualifier
().
layoutSet
;
return
0
;
}
};
};
// Map I/O variables to provided offsets, and make bindings for
// Map I/O variables to provided offsets, and make bindings for
// unbound but live variables.
// unbound but live variables.
//
//
// Returns false if the input is too malformed to do this.
// Returns false if the input is too malformed to do this.
bool
TIoMapper
::
addStage
(
EShLanguage
,
TIntermediate
&
intermediate
,
TInfoSink
&
infoSink
)
bool
TIoMapper
::
addStage
(
EShLanguage
stage
,
TIntermediate
&
intermediate
,
TInfoSink
&
infoSink
,
TIoMapResolver
*
resolver
)
{
{
// Trivial return if there is nothing to do.
// Trivial return if there is nothing to do.
if
(
intermediate
.
getShiftSamplerBinding
()
==
0
&&
if
(
intermediate
.
getShiftSamplerBinding
()
==
0
&&
intermediate
.
getShiftTextureBinding
()
==
0
&&
intermediate
.
getShiftTextureBinding
()
==
0
&&
intermediate
.
getShiftUboBinding
()
==
0
&&
intermediate
.
getShiftUboBinding
()
==
0
&&
intermediate
.
getAutoMapBindings
()
==
false
)
intermediate
.
getAutoMapBindings
()
==
false
&&
resolver
==
NULL
)
return
true
;
return
true
;
if
(
intermediate
.
getNumEntryPoints
()
!=
1
||
intermediate
.
isRecursive
())
if
(
intermediate
.
getNumEntryPoints
()
!=
1
||
intermediate
.
isRecursive
())
...
@@ -241,30 +342,43 @@ bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate, TInfoSink& in
...
@@ -241,30 +342,43 @@ bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate, TInfoSink& in
if
(
root
==
nullptr
)
if
(
root
==
nullptr
)
return
false
;
return
false
;
// The lifetime of this data spans several passes.
// if no resolver is provided, use the default resolver with the given shifts and auto map settings
TBindingMap
bindingMap
;
TDefaultIoResolver
defaultResolver
;
TUsedBindings
usedBindings
;
if
(
resolver
==
NULL
)
{
defaultResolver
.
baseSamplerBinding
=
intermediate
.
getShiftSamplerBinding
();
defaultResolver
.
baseTextureBinding
=
intermediate
.
getShiftTextureBinding
();
defaultResolver
.
baseUboBinding
=
intermediate
.
getShiftUboBinding
();
defaultResolver
.
doAutoMapping
=
intermediate
.
getAutoMapBindings
();
TBindingTraverser
it_binding_all
(
intermediate
,
bindingMap
,
usedBindings
,
true
);
resolver
=
&
defaultResolver
;
TBindingTraverser
it_binding_live
(
intermediate
,
bindingMap
,
usedBindings
,
false
);
}
TIoMappingTraverser
it_iomap
(
intermediate
,
bindingMap
,
usedBindings
,
infoSink
,
true
);
// Traverse all (live+dead) code to find explicit bindings, so we can avoid those.
TVarLiveMap
varMap
;
root
->
traverse
(
&
it_binding_all
);
TVarGatherTraverser
iter_binding_all
(
intermediate
,
varMap
,
true
);
TVarGatherTraverser
iter_binding_live
(
intermediate
,
varMap
,
false
);
// Traverse just live code to find things that need implicit bindings.
root
->
traverse
(
&
iter_binding_all
);
it_binding_live
.
pushFunction
(
intermediate
.
getEntryPointMangledName
().
c_str
());
it
er
_binding_live
.
pushFunction
(
intermediate
.
getEntryPointMangledName
().
c_str
());
while
(
!
it
_binding_live
.
functions
.
empty
())
{
while
(
!
iter
_binding_live
.
functions
.
empty
())
{
TIntermNode
*
function
=
it_binding_live
.
functions
.
back
();
TIntermNode
*
function
=
it
er
_binding_live
.
functions
.
back
();
it_binding_live
.
functions
.
pop_back
();
it
er
_binding_live
.
functions
.
pop_back
();
function
->
traverse
(
&
it_binding_live
);
function
->
traverse
(
&
it
er
_binding_live
);
}
}
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
// Bind everything that needs a binding and doesn't have one.
std
::
sort
(
varMap
.
begin
(),
varMap
.
end
(),
TVarEntryInfo
::
TOrderByPriority
());
root
->
traverse
(
&
it_iomap
);
bool
hadError
=
false
;
return
it_iomap
.
success
();
TResolverAdaptor
doResolve
(
stage
,
*
resolver
,
infoSink
,
hadError
);
std
::
for_each
(
varMap
.
begin
(),
varMap
.
end
(),
doResolve
);
if
(
!
hadError
)
{
// sort by id again, so we can use lower bound to find entries
std
::
sort
(
varMap
.
begin
(),
varMap
.
end
(),
TVarEntryInfo
::
TOrderById
());
TVarSetTraverser
iter_iomap
(
intermediate
,
varMap
);
root
->
traverse
(
&
iter_iomap
);
}
return
!
hadError
;
}
}
}
// end namespace glslang
}
// end namespace glslang
glslang/MachineIndependent/iomapper.h
View file @
1061accf
...
@@ -55,7 +55,7 @@ public:
...
@@ -55,7 +55,7 @@ public:
virtual
~
TIoMapper
()
{}
virtual
~
TIoMapper
()
{}
// grow the reflection stage by stage
// grow the reflection stage by stage
bool
addStage
(
EShLanguage
,
TIntermediate
&
,
TInfoSink
&
);
bool
addStage
(
EShLanguage
,
TIntermediate
&
,
TInfoSink
&
,
TIoMapResolver
*
);
};
};
}
// end namespace glslang
}
// end namespace glslang
...
...
glslang/Public/ShaderLang.h
View file @
1061accf
...
@@ -445,7 +445,36 @@ private:
...
@@ -445,7 +445,36 @@ private:
class
TReflection
;
class
TReflection
;
class
TIoMapper
;
class
TIoMapper
;
// Make one TProgram per set of shaders that will get linked together. Add all
// 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
// and resolveSet are invoked to resolve the binding and descriptor
// set index respectively.
// Invocations happen in a particular order:
// 1) var with binding and set already defined
// 2) var with binding but no set defined
// 3) var with set but no binding defined
// 4) var with no binding and no set defined
//
// 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 ok.
// Basic idea is to do aliasing binding checks with this.
virtual
bool
validateBinding
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
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
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
// Should return a value >= 0 if the current set should be overriden.
// Return -1 if the current set (including no set) should be kept.
virtual
int
resolveSet
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
};
// 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()
// the shaders that are to be linked together. After calling shader.parse()
// for all shaders, call link().
// for all shaders, call link().
//
//
...
@@ -485,7 +514,9 @@ public:
...
@@ -485,7 +514,9 @@ public:
void
dumpReflection
();
void
dumpReflection
();
// I/O mapping: apply base offsets and map live unbound variables
// I/O mapping: apply base offsets and map live unbound variables
bool
mapIO
();
// If resolver is not provided it uses the previous approach
// and respects auto assignment and offsets.
bool
mapIO
(
TIoMapResolver
*
resolver
=
NULL
);
protected
:
protected
:
bool
linkStage
(
EShLanguage
,
EShMessages
);
bool
linkStage
(
EShLanguage
,
EShMessages
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment