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
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
284 additions
and
143 deletions
+284
-143
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
+249
-135
iomapper.h
glslang/MachineIndependent/iomapper.h
+1
-1
ShaderLang.h
glslang/Public/ShaderLang.h
+32
-1
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
...
@@ -64,174 +64,275 @@
...
@@ -64,174 +64,275 @@
namespace
glslang
{
namespace
glslang
{
// Map of IDs to bindings
struct
TVarEntryInfo
typedef
std
::
unordered_map
<
unsigned
int
,
int
>
TBindingMap
;
{
typedef
std
::
unordered_set
<
int
>
TUsedBindings
;
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'
typedef
std
::
vector
<
TVarEntryInfo
>
TVarLiveMap
;
void
markBinding
(
const
TIntermSymbol
&
base
,
int
binding
)
{
bindingMap
[
base
.
getId
()]
=
binding
;
class
TVarGatherTraverser
:
public
TLiveTraverser
{
public
:
TVarGatherTraverser
(
const
TIntermediate
&
i
,
TVarLiveMap
&
vars
,
bool
traverseDeadCode
)
:
TLiveTraverser
(
i
,
traverseDeadCode
,
true
,
true
,
false
)
,
varLiveList
(
vars
)
{
}
if
(
binding
>=
0
)
{
// const TType& type = base.getType();
const
unsigned
int
size
=
1
;
// type.isArray() ? type.getCumulativeArraySize() : 1;
for
(
unsigned
int
offset
=
0
;
offset
<
size
;
++
offset
)
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
usedBindings
.
insert
(
binding
+
offset
);
{
if
(
base
->
getQualifier
().
storage
==
EvqUniform
)
{
TVarEntryInfo
ent
=
{
base
->
getId
(),
base
,
!
traverseAll
};
TVarLiveMap
::
iterator
at
=
std
::
lower_bound
(
varLiveList
.
begin
(),
varLiveList
.
end
(),
ent
,
TVarEntryInfo
::
TOrderById
());
if
(
at
!=
varLiveList
.
end
()
&&
at
->
id
==
ent
.
id
)
at
->
live
=
at
->
live
||
!
traverseAll
;
// update live state
else
varLiveList
.
insert
(
at
,
ent
);
}
}
}
}
// Mark the bindings that are given explicitly, and set ones that need
private
:
// implicit bindings to -1 for a subsequent pass. (Can't happen in this
TVarLiveMap
&
varLiveList
;
// pass because explicit bindings in dead code reserve the location).
};
virtual
void
addUniform
(
TIntermSymbol
&
base
)
class
TVarSetTraverser
:
public
TLiveTraverser
{
public
:
TVarSetTraverser
(
const
TIntermediate
&
i
,
const
TVarLiveMap
&
vars
)
:
TLiveTraverser
(
i
,
true
,
true
,
true
,
false
)
,
varLiveList
(
vars
)
{
{
// 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
)
{
TVarEntryInfo
ent
=
{
base
->
getId
()
};
TVarLiveMap
::
const_iterator
at
=
std
::
lower_bound
(
varLiveList
.
begin
(),
varLiveList
.
end
(),
ent
,
TVarEntryInfo
::
TOrderById
());
if
(
at
==
varLiveList
.
end
())
return
;
if
(
!
(
at
->
id
==
ent
.
id
))
return
;
return
;
if
(
type
.
getQualifier
().
hasBinding
())
{
if
(
at
->
newBinding
!=
-
1
)
// It has a binding: keep that one.
base
->
getWritableType
().
getQualifier
().
layoutBinding
=
at
->
newBinding
;
markBinding
(
base
,
type
.
getQualifier
().
layoutBinding
+
bindingBase
);
if
(
at
->
newSet
!=
-
1
)
}
else
if
(
!
traverseAll
)
{
base
->
getWritableType
().
getQualifier
().
layoutSet
=
at
->
newSet
;
// Mark it as something we need to dynamically create a binding for,
// only if we're walking just the live code. We don't auto-number
// in dead code.
markBinding
(
base
,
-
1
);
}
}
}
TBindingMap
&
bindingMap
;
private
:
TUsedBindings
&
usedBindings
;
const
TVarLiveMap
&
varLiveList
;
};
};
struct
TResolverAdaptor
// This traverses the AST and applies binding maps it's given.
{
class
TIoMappingTraverser
:
public
TBindingTraverser
{
TResolverAdaptor
(
EShLanguage
s
,
TIoMapResolver
&
r
,
TInfoSink
&
i
,
bool
&
e
)
public
:
:
resolver
(
r
)
TIoMappingTraverser
(
TIntermediate
&
i
,
TBindingMap
&
bindingMap
,
TUsedBindings
&
usedBindings
,
,
stage
(
s
)
TInfoSink
&
infoSink
,
bool
traverseDeadCode
)
:
,
infoSink
(
i
)
TBindingTraverser
(
i
,
bindingMap
,
usedBindings
,
traverseDeadCode
),
,
error
(
e
)
infoSink
(
infoSink
),
{
assignError
(
false
)
}
{
}
inline
void
operator
()(
TVarEntryInfo
&
ent
)
bool
success
()
const
{
return
!
assignError
;
}
protected
:
unsigned
checkBindingRange
(
const
TIntermSymbol
&
base
,
unsigned
binding
)
{
{
if
(
binding
>=
TQualifier
::
layoutBindingEnd
)
{
bool
isValid
=
resolver
.
validateBinding
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
TString
err
=
"mapped binding out of range: "
;
if
(
isValid
)
{
err
+=
base
.
getName
();
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
);
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
if
(
ent
.
newBinding
!=
-
1
)
{
assignError
=
true
;
if
(
ent
.
newBinding
>=
TQualifier
::
layoutBindingEnd
)
{
TString
err
=
"mapped binding out of range: "
+
ent
.
symbol
->
getName
();
return
0
;
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
();
return
binding
;
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
;
};
void
addUniform
(
TIntermSymbol
&
base
)
override
/*
* Basic implementation of glslang::TIoMapResolver that replaces the
* previous offset behaviour.
* It does the same, uses the offsets for th corresponding uniform
* types. Also respects the EOptionAutoMapBindings flag and binds
* them if needed.
*/
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
)
{
{
// Skip things we don't intend to bind.
return
std
::
lower_bound
(
slots
[
set
].
begin
(),
slots
[
set
].
end
(),
slot
);
if
(
bindingMap
.
find
(
base
.
getId
())
==
bindingMap
.
end
())
return
;
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
;
}
}
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
(
intermediate
.
getAutoMapBindings
())
{
if
(
sampler
.
isTexture
())
// Otherwise, find a free spot for it.
return
checkEmpty
(
set
,
baseTextureBinding
+
type
.
getQualifier
().
layoutBinding
);
const
int
freeBinding
=
getFreeBinding
(
base
.
getType
(),
getBindingBase
(
base
.
getType
()));
}
markBinding
(
base
,
freeBinding
);
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
base
.
getWritableType
().
getQualifier
().
layoutBinding
=
checkBindingRange
(
base
,
free
Binding
);
return
checkEmpty
(
set
,
baseUboBinding
+
type
.
getQualifier
().
layout
Binding
);
}
}
return
true
;
}
}
int
resolveBinding
(
EShLanguage
stage
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
is_live
)
override
{
int
set
;
if
(
type
.
getQualifier
().
hasSet
())
set
=
type
.
getQualifier
().
layoutSet
;
else
set
=
0
;
// Search for N free consecutive binding slots in [base, base+required).
if
(
type
.
getQualifier
().
hasBinding
())
{
// E.g, if we want to reserve consecutive bindings for flattened arrays.
if
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
)
{
bool
hasNFreeSlots
(
int
base
,
int
required
)
{
const
glslang
::
TSampler
&
sampler
=
type
.
getSampler
();
for
(
int
binding
=
base
;
binding
<
(
base
+
required
);
++
binding
)
if
(
sampler
.
isPureSampler
())
if
(
usedBindings
.
find
(
binding
)
!=
usedBindings
.
end
())
return
reserveSlot
(
set
,
baseSamplerBinding
+
type
.
getQualifier
().
layoutBinding
);
return
false
;
return
true
;
if
(
sampler
.
isTexture
())
return
reserveSlot
(
set
,
baseTextureBinding
+
type
.
getQualifier
().
layoutBinding
);
}
}
// Find a free binding spot
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
int
getFreeBinding
(
const
TType
&
,
int
nextBinding
)
{
return
reserveSlot
(
set
,
baseUboBinding
+
type
.
getQualifier
().
layoutBinding
);
while
(
!
hasNFreeSlots
(
nextBinding
,
1
))
}
else
if
(
is_live
&&
doAutoMapping
)
{
++
nextBinding
;
// 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
);
return
nextBinding
;
if
(
sampler
.
isTexture
())
return
getFreeSlot
(
set
,
baseTextureBinding
);
}
}
private
:
if
(
type
.
getQualifier
().
isUniformOrBuffer
())
bool
assignError
;
// true if there was an error assigning the bindings
return
getFreeSlot
(
set
,
baseUboBinding
);
TInfoSink
&
infoSink
;
}
return
-
1
;
}
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,6 +445,35 @@ private:
...
@@ -445,6 +445,35 @@ private:
class
TReflection
;
class
TReflection
;
class
TIoMapper
;
class
TIoMapper
;
// 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
// 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