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
f04f1f93
Unverified
Commit
f04f1f93
authored
Jul 29, 2019
by
John Kessenich
Committed by
GitHub
Jul 29, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1857 from Roy-AMD/automapping-opengl-location
Automapping opengl location
parents
7fc86834
03a93ae1
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1059 additions
and
400 deletions
+1059
-400
ShaderLang.cpp
glslang/MachineIndependent/ShaderLang.cpp
+11
-9
iomapper.cpp
glslang/MachineIndependent/iomapper.cpp
+790
-374
iomapper.h
glslang/MachineIndependent/iomapper.h
+234
-3
ShaderLang.h
glslang/Public/ShaderLang.h
+24
-14
No files found.
glslang/MachineIndependent/ShaderLang.cpp
View file @
f04f1f93
...
@@ -1852,7 +1852,7 @@ const char* TShader::getInfoDebugLog()
...
@@ -1852,7 +1852,7 @@ const char* TShader::getInfoDebugLog()
return
infoSink
->
debug
.
c_str
();
return
infoSink
->
debug
.
c_str
();
}
}
TProgram
::
TProgram
()
:
reflection
(
0
),
ioMapper
(
nullptr
),
linked
(
false
)
TProgram
::
TProgram
()
:
reflection
(
0
),
linked
(
false
)
{
{
pool
=
new
TPoolAllocator
;
pool
=
new
TPoolAllocator
;
infoSink
=
new
TInfoSink
;
infoSink
=
new
TInfoSink
;
...
@@ -1864,7 +1864,6 @@ TProgram::TProgram() : reflection(0), ioMapper(nullptr), linked(false)
...
@@ -1864,7 +1864,6 @@ TProgram::TProgram() : reflection(0), ioMapper(nullptr), linked(false)
TProgram
::~
TProgram
()
TProgram
::~
TProgram
()
{
{
delete
ioMapper
;
delete
infoSink
;
delete
infoSink
;
delete
reflection
;
delete
reflection
;
...
@@ -2035,21 +2034,24 @@ void TProgram::dumpReflection() { if (reflection != nullptr) reflection->dump();
...
@@ -2035,21 +2034,24 @@ void TProgram::dumpReflection() { if (reflection != nullptr) reflection->dump();
//
//
// I/O mapping implementation.
// I/O mapping implementation.
//
//
bool
TProgram
::
mapIO
(
TIoMapResolver
*
resolv
er
)
bool
TProgram
::
mapIO
(
TIoMapResolver
*
pResolver
,
TIoMapper
*
pIoMapp
er
)
{
{
if
(
!
linked
||
ioMapper
)
if
(
!
linked
)
return
false
;
return
false
;
TIoMapper
*
ioMapper
=
nullptr
;
ioMapper
=
new
TIoMapper
;
TIoMapper
defaultIOMapper
;
if
(
pIoMapper
==
nullptr
)
ioMapper
=
&
defaultIOMapper
;
else
ioMapper
=
pIoMapper
;
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
,
r
esolver
))
if
(
!
ioMapper
->
addStage
((
EShLanguage
)
s
,
*
intermediate
[
s
],
*
infoSink
,
pR
esolver
))
return
false
;
return
false
;
}
}
}
}
return
true
;
return
ioMapper
->
doMap
(
pResolver
,
*
infoSink
)
;
}
}
}
// end namespace glslang
}
// end namespace glslang
glslang/MachineIndependent/iomapper.cpp
View file @
f04f1f93
...
@@ -35,14 +35,9 @@
...
@@ -35,14 +35,9 @@
#include "../Include/Common.h"
#include "../Include/Common.h"
#include "../Include/InfoSink.h"
#include "../Include/InfoSink.h"
#include "iomapper.h"
#include "LiveTraverser.h"
#include "localintermediate.h"
#include "gl_types.h"
#include "gl_types.h"
#include "iomapper.h"
#include <unordered_set>
#include <unordered_map>
//
//
// Map IO bindings.
// Map IO bindings.
...
@@ -61,60 +56,9 @@
...
@@ -61,60 +56,9 @@
// c. implicit dead bindings are left un-bound.
// c. implicit dead bindings are left un-bound.
//
//
namespace
glslang
{
namespace
glslang
{
struct
TVarEntryInfo
class
TVarGatherTraverser
:
public
TLiveTraverser
{
{
int
id
;
TIntermSymbol
*
symbol
;
bool
live
;
int
newBinding
;
int
newSet
;
int
newLocation
;
int
newComponent
;
int
newIndex
;
struct
TOrderById
{
inline
bool
operator
()(
const
TVarEntryInfo
&
l
,
const
TVarEntryInfo
&
r
)
{
return
l
.
id
<
r
.
id
;
}
};
struct
TOrderByPriority
{
// ordering:
// 1) has both binding and set
// 2) has binding but no set
// 3) has no binding but set
// 4) has no binding and no set
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
;
}
};
};
typedef
std
::
vector
<
TVarEntryInfo
>
TVarLiveMap
;
class
TVarGatherTraverser
:
public
TLiveTraverser
{
public
:
public
:
TVarGatherTraverser
(
const
TIntermediate
&
i
,
bool
traverseDeadCode
,
TVarLiveMap
&
inList
,
TVarLiveMap
&
outList
,
TVarLiveMap
&
uniformList
)
TVarGatherTraverser
(
const
TIntermediate
&
i
,
bool
traverseDeadCode
,
TVarLiveMap
&
inList
,
TVarLiveMap
&
outList
,
TVarLiveMap
&
uniformList
)
:
TLiveTraverser
(
i
,
traverseDeadCode
,
true
,
true
,
false
)
:
TLiveTraverser
(
i
,
traverseDeadCode
,
true
,
true
,
false
)
...
@@ -124,7 +68,6 @@ public:
...
@@ -124,7 +68,6 @@ public:
{
{
}
}
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
{
{
TVarLiveMap
*
target
=
nullptr
;
TVarLiveMap
*
target
=
nullptr
;
...
@@ -134,14 +77,15 @@ public:
...
@@ -134,14 +77,15 @@ public:
target
=
&
outputList
;
target
=
&
outputList
;
else
if
(
base
->
getQualifier
().
isUniformOrBuffer
()
&&
!
base
->
getQualifier
().
layoutPushConstant
)
else
if
(
base
->
getQualifier
().
isUniformOrBuffer
()
&&
!
base
->
getQualifier
().
layoutPushConstant
)
target
=
&
uniformList
;
target
=
&
uniformList
;
if
(
target
)
{
if
(
target
)
{
TVarEntryInfo
ent
=
{
base
->
getId
(),
base
,
!
traverseAll
};
TVarEntryInfo
ent
=
{
base
->
getId
(),
base
,
!
traverseAll
};
TVarLiveMap
::
iterator
at
=
std
::
lower_bound
(
target
->
begin
(),
target
->
end
(),
ent
,
TVarEntryInfo
::
TOrderById
());
ent
.
stage
=
intermediate
.
getStage
();
if
(
at
!=
target
->
end
()
&&
at
->
id
==
ent
.
id
)
TVarLiveMap
::
iterator
at
=
target
->
find
(
at
->
live
=
at
->
live
||
!
traverseAll
;
// update live state
ent
.
symbol
->
getName
());
// std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
if
(
at
!=
target
->
end
()
&&
at
->
second
.
id
==
ent
.
id
)
at
->
second
.
live
=
at
->
second
.
live
||
!
traverseAll
;
// update live state
else
else
target
->
insert
(
at
,
ent
)
;
(
*
target
)[
ent
.
symbol
->
getName
()]
=
ent
;
}
}
}
}
...
@@ -162,9 +106,7 @@ public:
...
@@ -162,9 +106,7 @@ public:
{
{
}
}
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
{
virtual
void
visitSymbol
(
TIntermSymbol
*
base
)
{
const
TVarLiveMap
*
source
;
const
TVarLiveMap
*
source
;
if
(
base
->
getQualifier
().
storage
==
EvqVaryingIn
)
if
(
base
->
getQualifier
().
storage
==
EvqVaryingIn
)
source
=
&
inputList
;
source
=
&
inputList
;
...
@@ -176,23 +118,23 @@ public:
...
@@ -176,23 +118,23 @@ public:
return
;
return
;
TVarEntryInfo
ent
=
{
base
->
getId
()
};
TVarEntryInfo
ent
=
{
base
->
getId
()
};
TVarLiveMap
::
const_iterator
at
=
s
td
::
lower_bound
(
source
->
begin
(),
source
->
end
(),
ent
,
TVarEntryInfo
::
TOrderById
());
TVarLiveMap
::
const_iterator
at
=
s
ource
->
find
(
base
->
getName
());
if
(
at
==
source
->
end
())
if
(
at
==
source
->
end
())
return
;
return
;
if
(
at
->
id
!=
ent
.
id
)
if
(
at
->
second
.
id
!=
ent
.
id
)
return
;
return
;
if
(
at
->
newBinding
!=
-
1
)
if
(
at
->
second
.
newBinding
!=
-
1
)
base
->
getWritableType
().
getQualifier
().
layoutBinding
=
at
->
newBinding
;
base
->
getWritableType
().
getQualifier
().
layoutBinding
=
at
->
second
.
newBinding
;
if
(
at
->
newSet
!=
-
1
)
if
(
at
->
second
.
newSet
!=
-
1
)
base
->
getWritableType
().
getQualifier
().
layoutSet
=
at
->
newSet
;
base
->
getWritableType
().
getQualifier
().
layoutSet
=
at
->
second
.
newSet
;
if
(
at
->
newLocation
!=
-
1
)
if
(
at
->
second
.
newLocation
!=
-
1
)
base
->
getWritableType
().
getQualifier
().
layoutLocation
=
at
->
newLocation
;
base
->
getWritableType
().
getQualifier
().
layoutLocation
=
at
->
second
.
newLocation
;
if
(
at
->
newComponent
!=
-
1
)
if
(
at
->
second
.
newComponent
!=
-
1
)
base
->
getWritableType
().
getQualifier
().
layoutComponent
=
at
->
newComponent
;
base
->
getWritableType
().
getQualifier
().
layoutComponent
=
at
->
second
.
newComponent
;
if
(
at
->
newIndex
!=
-
1
)
if
(
at
->
second
.
newIndex
!=
-
1
)
base
->
getWritableType
().
getQualifier
().
layoutIndex
=
at
->
newIndex
;
base
->
getWritableType
().
getQualifier
().
layoutIndex
=
at
->
second
.
newIndex
;
}
}
private
:
private
:
...
@@ -210,10 +152,12 @@ struct TNotifyUniformAdaptor
...
@@ -210,10 +152,12 @@ struct TNotifyUniformAdaptor
,
resolver
(
r
)
,
resolver
(
r
)
{
{
}
}
inline
void
operator
()(
TVarEntryInfo
&
ent
)
inline
void
operator
()(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
entKey
)
{
{
resolver
.
notifyBinding
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
resolver
.
notifyBinding
(
stage
,
ent
Key
.
second
);
}
}
private
:
private
:
TNotifyUniformAdaptor
&
operator
=
(
TNotifyUniformAdaptor
&
);
TNotifyUniformAdaptor
&
operator
=
(
TNotifyUniformAdaptor
&
);
};
};
...
@@ -227,44 +171,41 @@ struct TNotifyInOutAdaptor
...
@@ -227,44 +171,41 @@ struct TNotifyInOutAdaptor
,
resolver
(
r
)
,
resolver
(
r
)
{
{
}
}
inline
void
operator
()(
TVarEntryInfo
&
ent
)
inline
void
operator
()(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
entKey
)
{
{
resolver
.
notifyInOut
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
resolver
.
notifyInOut
(
stage
,
ent
Key
.
second
);
}
}
private
:
private
:
TNotifyInOutAdaptor
&
operator
=
(
TNotifyInOutAdaptor
&
);
TNotifyInOutAdaptor
&
operator
=
(
TNotifyInOutAdaptor
&
);
};
};
struct
TResolverUniformAdaptor
struct
TResolverUniformAdaptor
{
{
TResolverUniformAdaptor
(
EShLanguage
s
,
TIoMapResolver
&
r
,
TInfoSink
&
i
,
bool
&
e
)
TResolverUniformAdaptor
(
EShLanguage
s
,
TIoMapResolver
&
r
,
TInfoSink
&
i
,
bool
&
e
,
TIntermediate
&
interm
)
:
stage
(
s
)
:
stage
(
s
)
,
resolver
(
r
)
,
resolver
(
r
)
,
infoSink
(
i
)
,
infoSink
(
i
)
,
error
(
e
)
,
error
(
e
)
,
intermediate
(
interm
)
{
{
}
}
inline
void
operator
()(
TVarEntryInfo
&
ent
)
inline
void
operator
()(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
entKey
)
{
{
TVarEntryInfo
&
ent
=
entKey
.
second
;
ent
.
newLocation
=
-
1
;
ent
.
newLocation
=
-
1
;
ent
.
newComponent
=
-
1
;
ent
.
newComponent
=
-
1
;
ent
.
newBinding
=
-
1
;
ent
.
newBinding
=
-
1
;
ent
.
newSet
=
-
1
;
ent
.
newSet
=
-
1
;
ent
.
newIndex
=
-
1
;
ent
.
newIndex
=
-
1
;
const
bool
isValid
=
resolver
.
validateBinding
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
const
bool
isValid
=
resolver
.
validateBinding
(
stage
,
ent
);
ent
.
live
);
if
(
isValid
)
{
if
(
isValid
)
{
ent
.
newBinding
=
resolver
.
resolveBinding
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
resolver
.
resolveBinding
(
stage
,
ent
);
ent
.
live
);
resolver
.
resolveSet
(
stage
,
ent
);
ent
.
newSet
=
resolver
.
resolveSet
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
resolver
.
resolveUniformLocation
(
stage
,
ent
);
ent
.
newLocation
=
resolver
.
resolveUniformLocation
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
if
(
ent
.
newBinding
!=
-
1
)
{
if
(
ent
.
newBinding
!=
-
1
)
{
if
(
ent
.
newBinding
>=
int
(
TQualifier
::
layoutBindingEnd
))
{
if
(
ent
.
newBinding
>=
int
(
TQualifier
::
layoutBindingEnd
))
{
TString
err
=
"mapped binding out of range: "
+
ent
.
symbol
->
getName
()
;
TString
err
=
"mapped binding out of range: "
+
ent
Key
.
first
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
error
=
true
;
error
=
true
;
...
@@ -272,64 +213,52 @@ struct TResolverUniformAdaptor
...
@@ -272,64 +213,52 @@ struct TResolverUniformAdaptor
}
}
if
(
ent
.
newSet
!=
-
1
)
{
if
(
ent
.
newSet
!=
-
1
)
{
if
(
ent
.
newSet
>=
int
(
TQualifier
::
layoutSetEnd
))
{
if
(
ent
.
newSet
>=
int
(
TQualifier
::
layoutSetEnd
))
{
TString
err
=
"mapped set out of range: "
+
ent
.
symbol
->
getName
()
;
TString
err
=
"mapped set out of range: "
+
ent
Key
.
first
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
error
=
true
;
error
=
true
;
}
}
}
}
}
else
{
}
else
{
TString
errorMsg
=
"Invalid binding: "
+
ent
.
symbol
->
getName
()
;
TString
errorMsg
=
"Invalid binding: "
+
ent
Key
.
first
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
errorMsg
.
c_str
());
infoSink
.
info
.
message
(
EPrefixInternalError
,
errorMsg
.
c_str
());
error
=
true
;
error
=
true
;
}
}
}
}
inline
void
setStage
(
EShLanguage
s
)
{
stage
=
s
;
}
EShLanguage
stage
;
EShLanguage
stage
;
TIoMapResolver
&
resolver
;
TIoMapResolver
&
resolver
;
TInfoSink
&
infoSink
;
TInfoSink
&
infoSink
;
bool
&
error
;
bool
&
error
;
TIntermediate
&
intermediate
;
private
:
private
:
TResolverUniformAdaptor
&
operator
=
(
TResolverUniformAdaptor
&
);
TResolverUniformAdaptor
&
operator
=
(
TResolverUniformAdaptor
&
);
};
};
struct
TResolverInOutAdaptor
struct
TResolverInOutAdaptor
{
{
TResolverInOutAdaptor
(
EShLanguage
s
,
TIoMapResolver
&
r
,
TInfoSink
&
i
,
bool
&
e
)
TResolverInOutAdaptor
(
EShLanguage
s
,
TIoMapResolver
&
r
,
TInfoSink
&
i
,
bool
&
e
,
TIntermediate
&
interm
)
:
stage
(
s
)
:
stage
(
s
)
,
resolver
(
r
)
,
resolver
(
r
)
,
infoSink
(
i
)
,
infoSink
(
i
)
,
error
(
e
)
,
error
(
e
)
,
intermediate
(
interm
)
{
{
}
}
inline
void
operator
()(
TVarEntryInfo
&
ent
)
inline
void
operator
()(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
entKey
)
{
{
TVarEntryInfo
&
ent
=
entKey
.
second
;
ent
.
newLocation
=
-
1
;
ent
.
newLocation
=
-
1
;
ent
.
newComponent
=
-
1
;
ent
.
newComponent
=
-
1
;
ent
.
newBinding
=
-
1
;
ent
.
newBinding
=
-
1
;
ent
.
newSet
=
-
1
;
ent
.
newSet
=
-
1
;
ent
.
newIndex
=
-
1
;
ent
.
newIndex
=
-
1
;
const
bool
isValid
=
resolver
.
validateInOut
(
stage
,
const
bool
isValid
=
resolver
.
validateInOut
(
stage
,
ent
);
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
if
(
isValid
)
{
if
(
isValid
)
{
ent
.
newLocation
=
resolver
.
resolveInOutLocation
(
stage
,
resolver
.
resolveInOutLocation
(
stage
,
ent
);
ent
.
symbol
->
getName
().
c_str
(),
resolver
.
resolveInOutComponent
(
stage
,
ent
);
ent
.
symbol
->
getType
(),
resolver
.
resolveInOutIndex
(
stage
,
ent
);
ent
.
live
);
ent
.
newComponent
=
resolver
.
resolveInOutComponent
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
ent
.
newIndex
=
resolver
.
resolveInOutIndex
(
stage
,
ent
.
symbol
->
getName
().
c_str
(),
ent
.
symbol
->
getType
(),
ent
.
live
);
}
else
{
}
else
{
TString
errorMsg
;
TString
errorMsg
;
if
(
ent
.
symbol
->
getType
().
getQualifier
().
semanticName
!=
nullptr
)
{
if
(
ent
.
symbol
->
getType
().
getQualifier
().
semanticName
!=
nullptr
)
{
...
@@ -344,55 +273,164 @@ struct TResolverInOutAdaptor
...
@@ -344,55 +273,164 @@ struct TResolverInOutAdaptor
}
}
}
}
inline
void
setStage
(
EShLanguage
s
)
{
stage
=
s
;
}
EShLanguage
stage
;
EShLanguage
stage
;
TIoMapResolver
&
resolver
;
TIoMapResolver
&
resolver
;
TInfoSink
&
infoSink
;
TInfoSink
&
infoSink
;
bool
&
error
;
bool
&
error
;
TIntermediate
&
intermediate
;
private
:
private
:
TResolverInOutAdaptor
&
operator
=
(
TResolverInOutAdaptor
&
);
TResolverInOutAdaptor
&
operator
=
(
TResolverInOutAdaptor
&
);
};
};
// Base class for shared TIoMapResolver services, used by several derivations.
// The class is used for reserving explicit uniform locations and ubo/ssbo/opaque bindings
struct
TDefaultIoResolverBase
:
public
glslang
::
TIoMapResolver
struct
TSymbolValidater
{
{
TDefaultIoResolverBase
(
const
TIntermediate
&
intermediate
)
:
TSymbolValidater
(
TIoMapResolver
&
r
,
TInfoSink
&
i
,
TVarLiveMap
*
in
[
EShLangCount
],
TVarLiveMap
*
out
[
EShLangCount
],
intermediate
(
intermediate
),
TVarLiveMap
*
uniform
[
EShLangCount
],
bool
&
hadError
)
nextUniformLocation
(
intermediate
.
getUniformLocationBase
()),
:
preStage
(
EShLangCount
)
nextInputLocation
(
0
),
,
currentStage
(
EShLangCount
)
nextOutputLocation
(
0
)
,
nextStage
(
EShLangCount
)
{
}
,
resolver
(
r
)
,
infoSink
(
i
)
,
hadError
(
hadError
)
{
memcpy
(
inVarMaps
,
in
,
EShLangCount
*
(
sizeof
(
TVarLiveMap
*
)));
memcpy
(
outVarMaps
,
out
,
EShLangCount
*
(
sizeof
(
TVarLiveMap
*
)));
memcpy
(
uniformVarMap
,
uniform
,
EShLangCount
*
(
sizeof
(
TVarLiveMap
*
)));
}
int
getBaseBinding
(
TResourceType
res
,
unsigned
int
set
)
const
{
inline
void
operator
()(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
entKey
)
{
return
selectBaseBinding
(
intermediate
.
getShiftBinding
(
res
),
TVarEntryInfo
&
ent1
=
entKey
.
second
;
intermediate
.
getShiftBindingForSet
(
res
,
set
));
TIntermSymbol
*
base
=
ent1
.
symbol
;
const
TType
&
type
=
ent1
.
symbol
->
getType
();
const
TString
&
name
=
entKey
.
first
;
TString
mangleName1
,
mangleName2
;
type
.
appendMangledName
(
mangleName1
);
EShLanguage
stage
=
ent1
.
stage
;
if
(
currentStage
!=
stage
)
{
preStage
=
currentStage
;
currentStage
=
stage
;
nextStage
=
EShLangCount
;
for
(
int
i
=
currentStage
+
1
;
i
<
EShLangCount
;
i
++
)
{
if
(
inVarMaps
[
i
]
!=
nullptr
)
nextStage
=
static_cast
<
EShLanguage
>
(
i
);
}
}
}
if
(
base
->
getQualifier
().
storage
==
EvqVaryingIn
)
{
// validate stage in;
if
(
preStage
==
EShLangCount
)
return
;
if
(
outVarMaps
[
preStage
]
!=
nullptr
)
{
auto
ent2
=
outVarMaps
[
preStage
]
->
find
(
name
);
if
(
ent2
!=
outVarMaps
[
preStage
]
->
end
())
{
ent2
->
second
.
symbol
->
getType
().
appendMangledName
(
mangleName2
);
if
(
mangleName1
==
mangleName2
)
return
;
else
{
TString
err
=
"Invalid In/Out variable type : "
+
entKey
.
first
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
hadError
=
true
;
}
}
return
;
}
}
else
if
(
base
->
getQualifier
().
storage
==
EvqVaryingOut
)
{
// validate stage out;
if
(
nextStage
==
EShLangCount
)
return
;
if
(
outVarMaps
[
nextStage
]
!=
nullptr
)
{
auto
ent2
=
inVarMaps
[
nextStage
]
->
find
(
name
);
if
(
ent2
!=
inVarMaps
[
nextStage
]
->
end
())
{
ent2
->
second
.
symbol
->
getType
().
appendMangledName
(
mangleName2
);
if
(
mangleName1
==
mangleName2
)
return
;
else
{
TString
err
=
"Invalid In/Out variable type : "
+
entKey
.
first
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
hadError
=
true
;
}
}
return
;
}
}
else
if
(
base
->
getQualifier
().
isUniformOrBuffer
()
&&
!
base
->
getQualifier
().
layoutPushConstant
)
{
// validate uniform type;
for
(
int
i
=
0
;
i
<
EShLangCount
;
i
++
)
{
if
(
i
!=
currentStage
&&
outVarMaps
[
i
]
!=
nullptr
)
{
auto
ent2
=
uniformVarMap
[
i
]
->
find
(
name
);
if
(
ent2
!=
uniformVarMap
[
i
]
->
end
())
{
ent2
->
second
.
symbol
->
getType
().
appendMangledName
(
mangleName2
);
if
(
mangleName1
!=
mangleName2
)
{
TString
err
=
"Invalid Uniform variable type : "
+
entKey
.
first
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
err
.
c_str
());
hadError
=
true
;
}
mangleName2
.
clear
();
}
}
}
}
}
TVarLiveMap
*
inVarMaps
[
EShLangCount
],
*
outVarMaps
[
EShLangCount
],
*
uniformVarMap
[
EShLangCount
];
// Use for mark pre stage, to get more interface symbol information.
EShLanguage
preStage
,
currentStage
,
nextStage
;
// Use for mark current shader stage for resolver
TIoMapResolver
&
resolver
;
TInfoSink
&
infoSink
;
bool
&
hadError
;
const
std
::
vector
<
std
::
string
>&
getResourceSetBinding
()
const
{
return
intermediate
.
getResourceSetBinding
();
}
private
:
TSymbolValidater
&
operator
=
(
TSymbolValidater
&
);
};
bool
doAutoBindingMapping
()
const
{
return
intermediate
.
getAutoMapBindings
();
}
struct
TSlotCollector
{
bool
doAutoLocationMapping
()
const
{
return
intermediate
.
getAutoMapLocations
();
}
TSlotCollector
(
TIoMapResolver
&
r
,
TInfoSink
&
i
)
:
resolver
(
r
),
infoSink
(
i
)
{
}
typedef
std
::
vector
<
int
>
TSlotSet
;
inline
void
operator
()(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
entKey
)
{
typedef
std
::
unordered_map
<
int
,
TSlotSet
>
TSlotSetMap
;
resolver
.
reserverStorageSlot
(
entKey
.
second
,
infoSink
);
TSlotSetMap
slots
;
resolver
.
reserverResourceSlot
(
entKey
.
second
,
infoSink
);
}
TIoMapResolver
&
resolver
;
TInfoSink
&
infoSink
;
TSlotSet
::
iterator
findSlot
(
int
set
,
int
slot
)
private
:
{
TSlotCollector
&
operator
=
(
TSlotCollector
&
);
};
TDefaultIoResolverBase
::
TDefaultIoResolverBase
(
const
TIntermediate
&
intermediate
)
:
intermediate
(
intermediate
)
,
nextUniformLocation
(
intermediate
.
getUniformLocationBase
())
,
nextInputLocation
(
0
)
,
nextOutputLocation
(
0
)
{
memset
(
stageMask
,
false
,
sizeof
(
bool
)
*
(
EShLangCount
+
1
));
}
int
TDefaultIoResolverBase
::
getBaseBinding
(
TResourceType
res
,
unsigned
int
set
)
const
{
return
selectBaseBinding
(
intermediate
.
getShiftBinding
(
res
),
intermediate
.
getShiftBindingForSet
(
res
,
set
));
}
const
std
::
vector
<
std
::
string
>&
TDefaultIoResolverBase
::
getResourceSetBinding
()
const
{
return
intermediate
.
getResourceSetBinding
();
}
bool
TDefaultIoResolverBase
::
doAutoBindingMapping
()
const
{
return
intermediate
.
getAutoMapBindings
();
}
bool
TDefaultIoResolverBase
::
doAutoLocationMapping
()
const
{
return
intermediate
.
getAutoMapLocations
();
}
TDefaultIoResolverBase
::
TSlotSet
::
iterator
TDefaultIoResolverBase
::
findSlot
(
int
set
,
int
slot
)
{
return
std
::
lower_bound
(
slots
[
set
].
begin
(),
slots
[
set
].
end
(),
slot
);
return
std
::
lower_bound
(
slots
[
set
].
begin
(),
slots
[
set
].
end
(),
slot
);
}
}
bool
checkEmpty
(
int
set
,
int
slot
)
bool
TDefaultIoResolverBase
::
checkEmpty
(
int
set
,
int
slot
)
{
{
TSlotSet
::
iterator
at
=
findSlot
(
set
,
slot
);
TSlotSet
::
iterator
at
=
findSlot
(
set
,
slot
);
return
!
(
at
!=
slots
[
set
].
end
()
&&
*
at
==
slot
);
return
!
(
at
!=
slots
[
set
].
end
()
&&
*
at
==
slot
);
}
}
int
reserveSlot
(
int
set
,
int
slot
,
int
size
=
1
)
int
TDefaultIoResolverBase
::
reserveSlot
(
int
set
,
int
slot
,
int
size
)
{
{
TSlotSet
::
iterator
at
=
findSlot
(
set
,
slot
);
TSlotSet
::
iterator
at
=
findSlot
(
set
,
slot
);
// tolerate aliasing, by not double-recording aliases
// tolerate aliasing, by not double-recording aliases
// (policy about appropriateness of the alias is higher up)
// (policy about appropriateness of the alias is higher up)
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
...
@@ -400,16 +438,13 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver
...
@@ -400,16 +438,13 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver
at
=
slots
[
set
].
insert
(
at
,
slot
+
i
);
at
=
slots
[
set
].
insert
(
at
,
slot
+
i
);
++
at
;
++
at
;
}
}
return
slot
;
return
slot
;
}
}
int
getFreeSlot
(
int
set
,
int
base
,
int
size
=
1
)
int
TDefaultIoResolverBase
::
getFreeSlot
(
int
set
,
int
base
,
int
size
)
{
{
TSlotSet
::
iterator
at
=
findSlot
(
set
,
base
);
TSlotSet
::
iterator
at
=
findSlot
(
set
,
base
);
if
(
at
==
slots
[
set
].
end
())
if
(
at
==
slots
[
set
].
end
())
return
reserveSlot
(
set
,
base
,
size
);
return
reserveSlot
(
set
,
base
,
size
);
// look for a big enough gap
// look for a big enough gap
for
(;
at
!=
slots
[
set
].
end
();
++
at
)
{
for
(;
at
!=
slots
[
set
].
end
();
++
at
)
{
if
(
*
at
-
base
>=
size
)
if
(
*
at
-
base
>=
size
)
...
@@ -417,145 +452,442 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver
...
@@ -417,145 +452,442 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver
base
=
*
at
+
1
;
base
=
*
at
+
1
;
}
}
return
reserveSlot
(
set
,
base
,
size
);
return
reserveSlot
(
set
,
base
,
size
);
}
}
virtual
bool
validateBinding
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
/*is_live*/
)
override
=
0
;
virtual
int
resolveBinding
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
is_live
)
override
=
0
;
int
resolveSet
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
/*is_live*/
)
override
{
if
(
type
.
getQualifier
().
hasSet
())
return
type
.
getQualifier
().
layoutSet
;
int
TDefaultIoResolverBase
::
resolveSet
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
if
(
type
.
getQualifier
().
hasSet
())
{
return
ent
.
newSet
=
type
.
getQualifier
().
layoutSet
;
}
// If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
// If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
if
(
getResourceSetBinding
().
size
()
==
1
)
if
(
getResourceSetBinding
().
size
()
==
1
)
{
return
atoi
(
getResourceSetBinding
()[
0
].
c_str
());
return
ent
.
newSet
=
atoi
(
getResourceSetBinding
()[
0
].
c_str
());
return
0
;
}
}
int
resolveUniformLocation
(
EShLanguage
/*stage*/
,
const
char
*
name
,
const
glslang
::
TType
&
type
,
bool
/*is_live*/
)
override
return
ent
.
newSet
=
0
;
{
}
// kick out of not doing this
if
(
!
doAutoLocationMapping
())
return
-
1
;
int
TDefaultIoResolverBase
::
resolveUniformLocation
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
const
char
*
name
=
ent
.
symbol
->
getName
().
c_str
();
// kick out of not doing this
if
(
!
doAutoLocationMapping
())
{
return
ent
.
newLocation
=
-
1
;
}
// no locations added if already present, a built-in variable, a block, or an opaque
// no locations added if already present, a built-in variable, a block, or an opaque
if
(
type
.
getQualifier
().
hasLocation
()
||
type
.
isBuiltIn
()
||
if
(
type
.
getQualifier
().
hasLocation
()
||
type
.
isBuiltIn
()
||
type
.
getBasicType
()
==
EbtBlock
||
type
.
getBasicType
()
==
EbtBlock
||
type
.
getBasicType
()
==
EbtAtomicUint
||
(
type
.
containsOpaque
()
&&
intermediate
.
getSpv
().
openGl
==
0
))
{
type
.
getBasicType
()
==
EbtAtomicUint
||
return
ent
.
newLocation
=
-
1
;
(
type
.
containsOpaque
()
&&
intermediate
.
getSpv
().
openGl
==
0
))
}
return
-
1
;
// no locations on blocks of built-in variables
// no locations on blocks of built-in variables
if
(
type
.
isStruct
())
{
if
(
type
.
isStruct
())
{
if
(
type
.
getStruct
()
->
size
()
<
1
)
if
(
type
.
getStruct
()
->
size
()
<
1
)
{
return
-
1
;
return
ent
.
newLocation
=
-
1
;
if
((
*
type
.
getStruct
())[
0
].
type
->
isBuiltIn
())
}
return
-
1
;
if
((
*
type
.
getStruct
())[
0
].
type
->
isBuiltIn
())
{
return
ent
.
newLocation
=
-
1
;
}
}
}
int
location
=
intermediate
.
getUniformLocationOverride
(
name
);
int
location
=
intermediate
.
getUniformLocationOverride
(
name
);
if
(
location
!=
-
1
)
if
(
location
!=
-
1
)
{
return
location
;
return
ent
.
newLocation
=
location
;
}
location
=
nextUniformLocation
;
location
=
nextUniformLocation
;
nextUniformLocation
+=
TIntermediate
::
computeTypeUniformLocationSize
(
type
);
nextUniformLocation
+=
TIntermediate
::
computeTypeUniformLocationSize
(
type
);
return
ent
.
newLocation
=
location
;
}
return
location
;
int
TDefaultIoResolverBase
::
resolveInOutLocation
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
{
}
const
TType
&
type
=
ent
.
symbol
->
getType
();
bool
validateInOut
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
TType
&
/*type*/
,
bool
/*is_live*/
)
override
{
return
true
;
}
int
resolveInOutLocation
(
EShLanguage
stage
,
const
char
*
/*name*/
,
const
TType
&
type
,
bool
/*is_live*/
)
override
{
// kick out of not doing this
// kick out of not doing this
if
(
!
doAutoLocationMapping
())
if
(
!
doAutoLocationMapping
())
{
return
-
1
;
return
ent
.
newLocation
=
-
1
;
}
// no locations added if already present, or a built-in variable
// no locations added if already present, or a built-in variable
if
(
type
.
getQualifier
().
hasLocation
()
||
type
.
isBuiltIn
())
if
(
type
.
getQualifier
().
hasLocation
()
||
type
.
isBuiltIn
())
{
return
-
1
;
return
ent
.
newLocation
=
-
1
;
}
// no locations on blocks of built-in variables
// no locations on blocks of built-in variables
if
(
type
.
isStruct
())
{
if
(
type
.
isStruct
())
{
if
(
type
.
getStruct
()
->
size
()
<
1
)
if
(
type
.
getStruct
()
->
size
()
<
1
)
{
return
-
1
;
return
ent
.
newLocation
=
-
1
;
if
((
*
type
.
getStruct
())[
0
].
type
->
isBuiltIn
())
}
return
-
1
;
if
((
*
type
.
getStruct
())[
0
].
type
->
isBuiltIn
())
{
return
ent
.
newLocation
=
-
1
;
}
}
}
// point to the right input or output location counter
// point to the right input or output location counter
int
&
nextLocation
=
type
.
getQualifier
().
isPipeInput
()
?
nextInputLocation
:
nextOutputLocation
;
int
&
nextLocation
=
type
.
getQualifier
().
isPipeInput
()
?
nextInputLocation
:
nextOutputLocation
;
// Placeholder. This does not do proper cross-stage lining up, nor
// Placeholder. This does not do proper cross-stage lining up, nor
// work with mixed location/no-location declarations.
// work with mixed location/no-location declarations.
int
location
=
nextLocation
;
int
location
=
nextLocation
;
int
typeLocationSize
;
int
typeLocationSize
;
// Don’t take into account the outer-most array if the stage’s
// Don’t take into account the outer-most array if the stage’s
// interface is automatically an array.
// interface is automatically an array.
typeLocationSize
=
computeTypeLocationSize
(
type
,
stage
);
nextLocation
+=
typeLocationSize
;
return
ent
.
newLocation
=
location
;
}
int
TDefaultIoResolverBase
::
resolveInOutComponent
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
{
return
ent
.
newComponent
=
-
1
;
}
int
TDefaultIoResolverBase
::
resolveInOutIndex
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
{
return
ent
.
newIndex
=
-
1
;
}
uint32_t
TDefaultIoResolverBase
::
computeTypeLocationSize
(
const
TType
&
type
,
EShLanguage
stage
)
{
int
typeLocationSize
;
// Don’t take into account the outer-most array if the stage’s
// interface is automatically an array.
if
(
type
.
getQualifier
().
isArrayedIo
(
stage
))
{
if
(
type
.
getQualifier
().
isArrayedIo
(
stage
))
{
TType
elementType
(
type
,
0
);
TType
elementType
(
type
,
0
);
typeLocationSize
=
TIntermediate
::
computeTypeLocationSize
(
elementType
,
stage
);
typeLocationSize
=
TIntermediate
::
computeTypeLocationSize
(
elementType
,
stage
);
}
else
{
}
else
{
typeLocationSize
=
TIntermediate
::
computeTypeLocationSize
(
type
,
stage
);
typeLocationSize
=
TIntermediate
::
computeTypeLocationSize
(
type
,
stage
);
}
}
nextLocation
+=
typeLocationSize
;
return
typeLocationSize
;
}
return
location
;
//TDefaultGlslIoResolver
TResourceType
TDefaultGlslIoResolver
::
getResourceType
(
const
glslang
::
TType
&
type
)
{
if
(
isImageType
(
type
))
{
return
EResImage
;
}
}
int
resolveInOutComponent
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
TType
&
/*type*/
,
bool
/*is_live*/
)
override
if
(
isTextureType
(
type
))
{
{
return
EResTexture
;
return
-
1
;
}
}
int
resolveInOutIndex
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
TType
&
/*type*/
,
bool
/*is_live*/
)
override
if
(
isSsboType
(
type
))
{
{
return
EResSsbo
;
return
-
1
;
}
if
(
isSamplerType
(
type
))
{
return
EResSampler
;
}
}
if
(
isUboType
(
type
))
{
return
EResUbo
;
}
return
EResCount
;
}
void
notifyBinding
(
EShLanguage
,
const
char
*
/*name*/
,
const
TType
&
,
bool
/*is_live*/
)
override
{}
TDefaultGlslIoResolver
::
TDefaultGlslIoResolver
(
const
TIntermediate
&
intermediate
)
void
notifyInOut
(
EShLanguage
,
const
char
*
/*name*/
,
const
TType
&
,
bool
/*is_live*/
)
override
{}
:
TDefaultIoResolverBase
(
intermediate
)
void
endNotifications
(
EShLanguage
)
override
{}
,
preStage
(
EShLangCount
)
void
beginNotifications
(
EShLanguage
)
override
{}
,
currentStage
(
EShLangCount
)
void
beginResolve
(
EShLanguage
)
override
{}
{
}
void
endResolve
(
EShLanguage
)
override
{}
int
TDefaultGlslIoResolver
::
resolveInOutLocation
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
const
TString
&
name
=
ent
.
symbol
->
getName
();
if
(
currentStage
!=
stage
)
{
preStage
=
currentStage
;
currentStage
=
stage
;
}
// kick out of not doing this
if
(
!
doAutoLocationMapping
())
{
return
ent
.
newLocation
=
-
1
;
}
// expand the location to each element if the symbol is a struct or array
if
(
type
.
getQualifier
().
hasLocation
())
{
return
ent
.
newLocation
=
type
.
getQualifier
().
layoutLocation
;
}
// no locations added if already present, or a built-in variable
if
(
type
.
isBuiltIn
())
{
return
ent
.
newLocation
=
-
1
;
}
// no locations on blocks of built-in variables
if
(
type
.
isStruct
())
{
if
(
type
.
getStruct
()
->
size
()
<
1
)
{
return
ent
.
newLocation
=
-
1
;
}
if
((
*
type
.
getStruct
())[
0
].
type
->
isBuiltIn
())
{
return
ent
.
newLocation
=
-
1
;
}
}
int
typeLocationSize
=
computeTypeLocationSize
(
type
,
stage
);
int
location
=
type
.
getQualifier
().
layoutLocation
;
bool
hasLocation
=
false
;
EShLanguage
keyStage
(
EShLangCount
);
TStorageQualifier
storage
;
storage
=
EvqInOut
;
if
(
type
.
getQualifier
().
isPipeInput
())
{
// If this symbol is a input, search pre stage's out
keyStage
=
preStage
;
}
if
(
type
.
getQualifier
().
isPipeOutput
())
{
// If this symbol is a output, search next stage's in
keyStage
=
currentStage
;
}
// The in/out in current stage is not declared with location, but it is possible declared
// with explicit location in other stages, find the storageSlotMap firstly to check whether
// the in/out has location
int
resourceKey
=
buildStorageKey
(
keyStage
,
storage
);
if
(
!
storageSlotMap
[
resourceKey
].
empty
())
{
TVarSlotMap
::
iterator
iter
=
storageSlotMap
[
resourceKey
].
find
(
name
);
if
(
iter
!=
storageSlotMap
[
resourceKey
].
end
())
{
// If interface resource be found, set it has location and this symbol's new location
// equal the symbol's explicit location declarated in pre or next stage.
//
// vs: out vec4 a;
// fs: layout(..., location = 3,...) in vec4 a;
hasLocation
=
true
;
location
=
iter
->
second
;
// if we want deal like that:
// vs: layout(location=4) out vec4 a;
// out vec4 b;
//
// fs: in vec4 a;
// layout(location = 4) in vec4 b;
// we need retraverse the map.
}
if
(
!
hasLocation
)
{
// If interface resource note found, It's mean the location in two stage are both implicit declarat.
// So we should find a new slot for this interface.
//
// vs: out vec4 a;
// fs: in vec4 a;
location
=
getFreeSlot
(
resourceKey
,
0
,
typeLocationSize
);
storageSlotMap
[
resourceKey
][
name
]
=
location
;
}
}
else
{
// the first interface declarated in a program.
TVarSlotMap
varSlotMap
;
location
=
getFreeSlot
(
resourceKey
,
0
,
typeLocationSize
);
varSlotMap
[
name
]
=
location
;
storageSlotMap
[
resourceKey
]
=
varSlotMap
;
}
//Update location
return
ent
.
newLocation
=
location
;
}
protected
:
int
TDefaultGlslIoResolver
::
resolveUniformLocation
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
{
TDefaultIoResolverBase
(
TDefaultIoResolverBase
&
);
const
TType
&
type
=
ent
.
symbol
->
getType
();
TDefaultIoResolverBase
&
operator
=
(
TDefaultIoResolverBase
&
);
const
TString
&
name
=
ent
.
symbol
->
getName
();
// kick out of not doing this
if
(
!
doAutoLocationMapping
())
{
return
ent
.
newLocation
=
-
1
;
}
// expand the location to each element if the symbol is a struct or array
if
(
type
.
getQualifier
().
hasLocation
()
&&
(
type
.
isStruct
()
||
type
.
isArray
()))
{
return
ent
.
newLocation
=
type
.
getQualifier
().
layoutLocation
;
}
else
{
// no locations added if already present, a built-in variable, a block, or an opaque
if
(
type
.
getQualifier
().
hasLocation
()
||
type
.
isBuiltIn
()
||
type
.
getBasicType
()
==
EbtBlock
||
type
.
getBasicType
()
==
EbtAtomicUint
||
(
type
.
containsOpaque
()
&&
intermediate
.
getSpv
().
openGl
==
0
))
{
return
ent
.
newLocation
=
-
1
;
}
// no locations on blocks of built-in variables
if
(
type
.
isStruct
())
{
if
(
type
.
getStruct
()
->
size
()
<
1
)
{
return
ent
.
newLocation
=
-
1
;
}
if
((
*
type
.
getStruct
())[
0
].
type
->
isBuiltIn
())
{
return
ent
.
newLocation
=
-
1
;
}
}
}
int
location
=
intermediate
.
getUniformLocationOverride
(
name
.
c_str
());
if
(
location
!=
-
1
)
{
return
ent
.
newLocation
=
location
;
}
const
TIntermediate
&
intermediate
;
int
size
=
TIntermediate
::
computeTypeUniformLocationSize
(
type
);
int
nextUniformLocation
;
int
nextInputLocation
;
// The uniform in current stage is not declared with location, but it is possible declared
int
nextOutputLocation
;
// with explicit location in other stages, find the storageSlotMap firstly to check whether
// the uniform has location
bool
hasLocation
=
false
;
int
resourceKey
=
buildStorageKey
(
EShLangCount
,
EvqUniform
);
TVarSlotMap
&
slotMap
=
storageSlotMap
[
resourceKey
];
// Check dose shader program has uniform resource
if
(
!
slotMap
.
empty
())
{
// If uniform resource not empty, try find a same name uniform
TVarSlotMap
::
iterator
iter
=
slotMap
.
find
(
name
);
if
(
iter
!=
slotMap
.
end
())
{
// If uniform resource be found, set it has location and this symbol's new location
// equal the uniform's explicit location declarated in other stage.
//
// vs: uniform vec4 a;
// fs: layout(..., location = 3,...) uniform vec4 a;
hasLocation
=
true
;
location
=
iter
->
second
;
}
if
(
!
hasLocation
)
{
// No explicit location declaraten in other stage.
// So we should find a new slot for this uniform.
//
// vs: uniform vec4 a;
// fs: uniform vec4 a;
location
=
getFreeSlot
(
resourceKey
,
0
,
computeTypeLocationSize
(
type
,
currentStage
));
storageSlotMap
[
resourceKey
][
name
]
=
location
;
}
}
else
{
// the first uniform declarated in a program.
TVarSlotMap
varSlotMap
;
location
=
getFreeSlot
(
resourceKey
,
0
,
size
);
varSlotMap
[
name
]
=
location
;
storageSlotMap
[
resourceKey
]
=
varSlotMap
;
}
return
ent
.
newLocation
=
location
;
}
// Return descriptor set specific base if there is one, and the generic base otherwise.
int
TDefaultGlslIoResolver
::
resolveBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
{
int
selectBaseBinding
(
int
base
,
int
descriptorSetBase
)
const
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
return
descriptorSetBase
!=
-
1
?
descriptorSetBase
:
base
;
const
TString
&
name
=
ent
.
symbol
->
getName
();
// On OpenGL arrays of opaque types take a seperate binding for each element
int
numBindings
=
intermediate
.
getSpv
().
openGl
!=
0
&&
type
.
isSizedArray
()
?
type
.
getCumulativeArraySize
()
:
1
;
TResourceType
resource
=
getResourceType
(
type
);
// don't need to handle uniform symbol, it will be handled in resolveUniformLocation
if
(
resource
==
EResUbo
&&
type
.
getBasicType
()
!=
EbtBlock
)
{
return
ent
.
newBinding
=
-
1
;
}
// There is no 'set' qualifier in OpenGL shading language, each resource has its own
// binding name space, so remap the 'set' to resource type which make each resource
// binding is valid from 0 to MAX_XXRESOURCE_BINDINGS
int
set
=
resource
;
if
(
resource
<
EResCount
)
{
if
(
type
.
getQualifier
().
hasBinding
())
{
ent
.
newBinding
=
reserveSlot
(
set
,
getBaseBinding
(
resource
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
return
ent
.
newBinding
;
}
else
if
(
ent
.
live
&&
doAutoBindingMapping
())
{
// The resource in current stage is not declared with binding, but it is possible declared
// with explicit binding in other stages, find the resourceSlotMap firstly to check whether
// the resource has binding, don't need to allocate if it already has a binding
bool
hasBinding
=
false
;
if
(
!
resourceSlotMap
[
resource
].
empty
())
{
TVarSlotMap
::
iterator
iter
=
resourceSlotMap
[
resource
].
find
(
name
);
if
(
iter
!=
resourceSlotMap
[
resource
].
end
())
{
hasBinding
=
true
;
ent
.
newBinding
=
iter
->
second
;
}
}
}
if
(
!
hasBinding
)
{
TVarSlotMap
varSlotMap
;
// 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
int
binding
=
getFreeSlot
(
resource
,
getBaseBinding
(
resource
,
set
),
numBindings
);
varSlotMap
[
name
]
=
binding
;
resourceSlotMap
[
resource
]
=
varSlotMap
;
ent
.
newBinding
=
binding
;
}
return
ent
.
newBinding
;
}
}
return
ent
.
newBinding
=
-
1
;
}
static
int
getLayoutSet
(
const
glslang
::
TType
&
type
)
{
void
TDefaultGlslIoResolver
::
beginResolve
(
EShLanguage
stage
)
{
if
(
type
.
getQualifier
().
hasSet
())
// reset stage state
return
type
.
getQualifier
().
layoutSet
;
if
(
stage
==
EShLangCount
)
else
preStage
=
currentStage
=
stage
;
return
0
;
// update stage state
else
if
(
currentStage
!=
stage
)
{
preStage
=
currentStage
;
currentStage
=
stage
;
}
}
}
static
bool
isSamplerType
(
const
glslang
::
TType
&
type
)
{
void
TDefaultGlslIoResolver
::
endResolve
(
EShLanguage
/*stage*/
)
{
return
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
type
.
getSampler
().
isPureSampler
();
// TODO nothing
}
void
TDefaultGlslIoResolver
::
beginCollect
(
EShLanguage
stage
)
{
// reset stage state
if
(
stage
==
EShLangCount
)
preStage
=
currentStage
=
stage
;
// update stage state
else
if
(
currentStage
!=
stage
)
{
preStage
=
currentStage
;
currentStage
=
stage
;
}
}
}
static
bool
isTextureType
(
const
glslang
::
TType
&
type
)
{
void
TDefaultGlslIoResolver
::
endCollect
(
EShLanguage
/*stage*/
)
{
return
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
// TODO nothing
(
type
.
getSampler
().
isTexture
()
||
type
.
getSampler
().
isSubpass
()));
}
void
TDefaultGlslIoResolver
::
reserverStorageSlot
(
TVarEntryInfo
&
ent
,
TInfoSink
&
infoSink
)
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
const
TString
&
name
=
ent
.
symbol
->
getName
();
TStorageQualifier
storage
=
type
.
getQualifier
().
storage
;
EShLanguage
stage
(
EShLangCount
);
switch
(
storage
)
{
case
EvqUniform
:
if
(
type
.
getBasicType
()
!=
EbtBlock
&&
type
.
getQualifier
().
hasLocation
())
{
//
// Reserve the slots for the uniforms who has explicit location
int
storageKey
=
buildStorageKey
(
EShLangCount
,
EvqUniform
);
int
location
=
type
.
getQualifier
().
layoutLocation
;
TVarSlotMap
&
varSlotMap
=
storageSlotMap
[
storageKey
];
TVarSlotMap
::
iterator
iter
=
varSlotMap
.
find
(
name
);
if
(
iter
==
varSlotMap
.
end
())
{
int
numLocations
=
TIntermediate
::
computeTypeUniformLocationSize
(
type
);
reserveSlot
(
storageKey
,
location
,
numLocations
);
varSlotMap
[
name
]
=
location
;
}
else
{
// Allocate location by name for OpenGL driver, so the uniform in different
// stages should be declared with the same location
if
(
iter
->
second
!=
location
)
{
TString
errorMsg
=
"Invalid location: "
+
name
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
errorMsg
.
c_str
());
}
}
}
break
;
case
EvqVaryingIn
:
case
EvqVaryingOut
:
//
// Reserve the slots for the inout who has explicit location
if
(
type
.
getQualifier
().
hasLocation
())
{
stage
=
storage
==
EvqVaryingIn
?
preStage
:
stage
;
stage
=
storage
==
EvqVaryingOut
?
currentStage
:
stage
;
int
storageKey
=
buildStorageKey
(
stage
,
EvqInOut
);
int
location
=
type
.
getQualifier
().
layoutLocation
;
TVarSlotMap
&
varSlotMap
=
storageSlotMap
[
storageKey
];
TVarSlotMap
::
iterator
iter
=
varSlotMap
.
find
(
name
);
if
(
iter
==
varSlotMap
.
end
())
{
int
numLocations
=
TIntermediate
::
computeTypeUniformLocationSize
(
type
);
reserveSlot
(
storageKey
,
location
,
numLocations
);
varSlotMap
[
name
]
=
location
;
}
else
{
// Allocate location by name for OpenGL driver, so the uniform in different
// stages should be declared with the same location
if
(
iter
->
second
!=
location
)
{
TString
errorMsg
=
"Invalid location: "
+
name
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
errorMsg
.
c_str
());
}
}
}
}
break
;
default
:
break
;
}
}
static
bool
isUboType
(
const
glslang
::
TType
&
type
)
{
void
TDefaultGlslIoResolver
::
reserverResourceSlot
(
TVarEntryInfo
&
ent
,
TInfoSink
&
infoSink
)
{
return
type
.
getQualifier
().
storage
==
EvqUniform
;
const
TType
&
type
=
ent
.
symbol
->
getType
();
const
TString
&
name
=
ent
.
symbol
->
getName
();
int
resource
=
getResourceType
(
type
);
if
(
type
.
getQualifier
().
hasBinding
())
{
TVarSlotMap
&
varSlotMap
=
resourceSlotMap
[
resource
];
TVarSlotMap
::
iterator
iter
=
varSlotMap
.
find
(
name
);
int
binding
=
type
.
getQualifier
().
layoutBinding
;
if
(
iter
==
varSlotMap
.
end
())
{
// Reserve the slots for the ubo, ssbo and opaques who has explicit binding
int
numBindings
=
type
.
isSizedArray
()
?
type
.
getCumulativeArraySize
()
:
1
;
varSlotMap
[
name
]
=
binding
;
reserveSlot
(
resource
,
binding
,
numBindings
);
}
else
{
// Allocate binding by name for OpenGL driver, so the resource in different
// stages should be declared with the same binding
if
(
iter
->
second
!=
binding
)
{
TString
errorMsg
=
"Invalid binding: "
+
name
;
infoSink
.
info
.
message
(
EPrefixInternalError
,
errorMsg
.
c_str
());
}
}
};
}
}
}
//TDefaultGlslIoResolver end
/*
/*
* Basic implementation of glslang::TIoMapResolver that replaces the
* Basic implementation of glslang::TIoMapResolver that replaces the
...
@@ -567,66 +899,47 @@ protected:
...
@@ -567,66 +899,47 @@ protected:
/*
/*
* Default resolver
* Default resolver
*/
*/
struct
TDefaultIoResolver
:
public
TDefaultIoResolverBase
struct
TDefaultIoResolver
:
public
TDefaultIoResolverBase
{
{
TDefaultIoResolver
(
const
TIntermediate
&
intermediate
)
:
TDefaultIoResolverBase
(
intermediate
)
{
}
TDefaultIoResolver
(
const
TIntermediate
&
intermediate
)
:
TDefaultIoResolverBase
(
intermediate
)
{
}
bool
validateBinding
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
/*type*/
,
bool
/*is_live*/
)
override
bool
validateBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
/*ent*/
)
override
{
return
true
;
}
{
return
true
;
TResourceType
getResourceType
(
const
glslang
::
TType
&
type
)
override
{
if
(
isImageType
(
type
))
{
return
EResImage
;
}
if
(
isTextureType
(
type
))
{
return
EResTexture
;
}
if
(
isSsboType
(
type
))
{
return
EResSsbo
;
}
if
(
isSamplerType
(
type
))
{
return
EResSampler
;
}
if
(
isUboType
(
type
))
{
return
EResUbo
;
}
return
EResCount
;
}
}
int
resolveBinding
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
is_live
)
override
int
resolveBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
{
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
const
int
set
=
getLayoutSet
(
type
);
const
int
set
=
getLayoutSet
(
type
);
// On OpenGL arrays of opaque types take a seperate binding for each element
// On OpenGL arrays of opaque types take a seperate binding for each element
int
numBindings
=
intermediate
.
getSpv
().
openGl
!=
0
&&
type
.
isSizedArray
()
?
type
.
getCumulativeArraySize
()
:
1
;
int
numBindings
=
intermediate
.
getSpv
().
openGl
!=
0
&&
type
.
isSizedArray
()
?
type
.
getCumulativeArraySize
()
:
1
;
TResourceType
resource
=
getResourceType
(
type
);
if
(
resource
<
EResCount
)
{
if
(
type
.
getQualifier
().
hasBinding
())
{
if
(
type
.
getQualifier
().
hasBinding
())
{
if
(
isImageType
(
type
))
return
ent
.
newBinding
=
reserveSlot
(
return
reserveSlot
(
set
,
getBaseBinding
(
EResImage
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
set
,
getBaseBinding
(
resource
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
}
else
if
(
ent
.
live
&&
doAutoBindingMapping
())
{
if
(
isTextureType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResTexture
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
if
(
isSsboType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResSsbo
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
if
(
isSamplerType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResSampler
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
if
(
isUboType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResUbo
,
set
)
+
type
.
getQualifier
().
layoutBinding
,
numBindings
);
}
else
if
(
is_live
&&
doAutoBindingMapping
())
{
// find free slot, the caller did make sure it passes all vars with binding
// 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
// first and now all are passed that do not have a binding and needs one
return
ent
.
newBinding
=
getFreeSlot
(
set
,
getBaseBinding
(
resource
,
set
),
numBindings
);
if
(
isImageType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResImage
,
set
),
numBindings
);
if
(
isTextureType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResTexture
,
set
),
numBindings
);
if
(
isSsboType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResSsbo
,
set
),
numBindings
);
if
(
isSamplerType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResSampler
,
set
),
numBindings
);
if
(
isUboType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResUbo
,
set
),
numBindings
);
}
return
-
1
;
}
}
protected
:
static
bool
isImageType
(
const
glslang
::
TType
&
type
)
{
return
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
type
.
getSampler
().
isImage
();
}
}
return
ent
.
newBinding
=
-
1
;
static
bool
isSsboType
(
const
glslang
::
TType
&
type
)
{
return
type
.
getQualifier
().
storage
==
EvqBuffer
;
}
}
};
};
...
@@ -673,98 +986,65 @@ b - for constant buffer views (CBV)
...
@@ -673,98 +986,65 @@ b - for constant buffer views (CBV)
CBUFFER
CBUFFER
CONSTANTBUFFER
CONSTANTBUFFER
********************************************************************************/
********************************************************************************/
struct
TDefaultHlslIoResolver
:
public
TDefaultIoResolverBase
struct
TDefaultHlslIoResolver
:
public
TDefaultIoResolverBase
{
{
TDefaultHlslIoResolver
(
const
TIntermediate
&
intermediate
)
:
TDefaultIoResolverBase
(
intermediate
)
{
}
TDefaultHlslIoResolver
(
const
TIntermediate
&
intermediate
)
:
TDefaultIoResolverBase
(
intermediate
)
{
}
bool
validateBinding
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
/*type*/
,
bool
/*is_live*/
)
override
bool
validateBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
/*ent*/
)
override
{
return
true
;
}
{
return
true
;
TResourceType
getResourceType
(
const
glslang
::
TType
&
type
)
override
{
if
(
isUavType
(
type
))
{
return
EResUav
;
}
if
(
isSrvType
(
type
))
{
return
EResTexture
;
}
if
(
isSamplerType
(
type
))
{
return
EResSampler
;
}
if
(
isUboType
(
type
))
{
return
EResUbo
;
}
return
EResCount
;
}
}
int
resolveBinding
(
EShLanguage
/*stage*/
,
const
char
*
/*name*/
,
const
glslang
::
TType
&
type
,
bool
is_live
)
override
int
resolveBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
{
{
const
TType
&
type
=
ent
.
symbol
->
getType
();
const
int
set
=
getLayoutSet
(
type
);
const
int
set
=
getLayoutSet
(
type
);
TResourceType
resource
=
getResourceType
(
type
);
if
(
resource
<
EResCount
)
{
if
(
type
.
getQualifier
().
hasBinding
())
{
if
(
type
.
getQualifier
().
hasBinding
())
{
if
(
isUavType
(
type
))
return
ent
.
newBinding
=
reserveSlot
(
set
,
getBaseBinding
(
resource
,
set
)
+
type
.
getQualifier
().
layoutBinding
);
return
reserveSlot
(
set
,
getBaseBinding
(
EResUav
,
set
)
+
type
.
getQualifier
().
layoutBinding
);
}
else
if
(
ent
.
live
&&
doAutoBindingMapping
())
{
if
(
isSrvType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResTexture
,
set
)
+
type
.
getQualifier
().
layoutBinding
);
if
(
isSamplerType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResSampler
,
set
)
+
type
.
getQualifier
().
layoutBinding
);
if
(
isUboType
(
type
))
return
reserveSlot
(
set
,
getBaseBinding
(
EResUbo
,
set
)
+
type
.
getQualifier
().
layoutBinding
);
}
else
if
(
is_live
&&
doAutoBindingMapping
())
{
// find free slot, the caller did make sure it passes all vars with binding
// 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
// first and now all are passed that do not have a binding and needs one
return
ent
.
newBinding
=
getFreeSlot
(
set
,
getBaseBinding
(
resource
,
set
));
if
(
isUavType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResUav
,
set
));
if
(
isSrvType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResTexture
,
set
));
if
(
isSamplerType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResSampler
,
set
));
if
(
isUboType
(
type
))
return
getFreeSlot
(
set
,
getBaseBinding
(
EResUbo
,
set
));
}
}
return
-
1
;
}
protected
:
// Return true if this is a SRV (shader resource view) type:
static
bool
isSrvType
(
const
glslang
::
TType
&
type
)
{
return
isTextureType
(
type
)
||
type
.
getQualifier
().
storage
==
EvqBuffer
;
}
}
return
ent
.
newBinding
=
-
1
;
// Return true if this is a UAV (unordered access view) type:
static
bool
isUavType
(
const
glslang
::
TType
&
type
)
{
if
(
type
.
getQualifier
().
readonly
)
return
false
;
return
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
type
.
getSampler
().
isImage
())
||
(
type
.
getQualifier
().
storage
==
EvqBuffer
);
}
}
};
};
// 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
stage
,
TIntermediate
&
intermediate
,
TInfoSink
&
infoSink
,
TIoMapResolver
*
resolver
)
bool
TIoMapper
::
addStage
(
EShLanguage
stage
,
TIntermediate
&
intermediate
,
TInfoSink
&
infoSink
,
TIoMapResolver
*
resolver
)
{
{
bool
somethingToDo
=
!
intermediate
.
getResourceSetBinding
().
empty
()
||
intermediate
.
getAutoMapBindings
()
||
bool
somethingToDo
=
!
intermediate
.
getResourceSetBinding
().
empty
()
||
intermediate
.
getAutoMapBindings
()
||
intermediate
.
getAutoMapLocations
();
intermediate
.
getAutoMapLocations
();
for
(
int
res
=
0
;
res
<
EResCount
;
++
res
)
{
for
(
int
res
=
0
;
res
<
EResCount
;
++
res
)
{
somethingToDo
=
somethingToDo
||
somethingToDo
=
somethingToDo
||
(
intermediate
.
getShiftBinding
(
TResourceType
(
res
))
!=
0
)
||
(
intermediate
.
getShiftBinding
(
TResourceType
(
res
))
!=
0
)
||
intermediate
.
hasShiftBindingForSet
(
TResourceType
(
res
));
intermediate
.
hasShiftBindingForSet
(
TResourceType
(
res
));
}
}
if
(
!
somethingToDo
&&
resolver
==
nullptr
)
if
(
!
somethingToDo
&&
resolver
==
nullptr
)
return
true
;
return
true
;
if
(
intermediate
.
getNumEntryPoints
()
!=
1
||
intermediate
.
isRecursive
())
if
(
intermediate
.
getNumEntryPoints
()
!=
1
||
intermediate
.
isRecursive
())
return
false
;
return
false
;
TIntermNode
*
root
=
intermediate
.
getTreeRoot
();
TIntermNode
*
root
=
intermediate
.
getTreeRoot
();
if
(
root
==
nullptr
)
if
(
root
==
nullptr
)
return
false
;
return
false
;
// if no resolver is provided, use the default resolver with the given shifts and auto map settings
// if no resolver is provided, use the default resolver with the given shifts and auto map settings
TDefaultIoResolver
defaultResolver
(
intermediate
);
TDefaultIoResolver
defaultResolver
(
intermediate
);
TDefaultHlslIoResolver
defaultHlslResolver
(
intermediate
);
TDefaultHlslIoResolver
defaultHlslResolver
(
intermediate
);
if
(
resolver
==
nullptr
)
{
if
(
resolver
==
nullptr
)
{
// TODO: use a passed in IO mapper for this
// TODO: use a passed in IO mapper for this
if
(
intermediate
.
usingHlslIoMapping
())
if
(
intermediate
.
usingHlslIoMapping
())
...
@@ -772,47 +1052,183 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi
...
@@ -772,47 +1052,183 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi
else
else
resolver
=
&
defaultResolver
;
resolver
=
&
defaultResolver
;
}
}
resolver
->
addStage
(
stage
);
TVarLiveMap
inVarMap
,
outVarMap
,
uniformVarMap
;
TVarLiveMap
inVarMap
,
outVarMap
,
uniformVarMap
;
TVarLiveVector
inVector
,
outVector
,
uniformVector
;
TVarGatherTraverser
iter_binding_all
(
intermediate
,
true
,
inVarMap
,
outVarMap
,
uniformVarMap
);
TVarGatherTraverser
iter_binding_all
(
intermediate
,
true
,
inVarMap
,
outVarMap
,
uniformVarMap
);
TVarGatherTraverser
iter_binding_live
(
intermediate
,
false
,
inVarMap
,
outVarMap
,
uniformVarMap
);
TVarGatherTraverser
iter_binding_live
(
intermediate
,
false
,
inVarMap
,
outVarMap
,
uniformVarMap
);
root
->
traverse
(
&
iter_binding_all
);
root
->
traverse
(
&
iter_binding_all
);
iter_binding_live
.
pushFunction
(
intermediate
.
getEntryPointMangledName
().
c_str
());
iter_binding_live
.
pushFunction
(
intermediate
.
getEntryPointMangledName
().
c_str
());
while
(
!
iter_binding_live
.
functions
.
empty
())
{
while
(
!
iter_binding_live
.
functions
.
empty
())
{
TIntermNode
*
function
=
iter_binding_live
.
functions
.
back
();
TIntermNode
*
function
=
iter_binding_live
.
functions
.
back
();
iter_binding_live
.
functions
.
pop_back
();
iter_binding_live
.
functions
.
pop_back
();
function
->
traverse
(
&
iter_binding_live
);
function
->
traverse
(
&
iter_binding_live
);
}
}
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
std
::
sort
(
uniformVarMap
.
begin
(),
uniformVarMap
.
end
(),
TVarEntryInfo
::
TOrderByPriority
());
std
::
for_each
(
inVarMap
.
begin
(),
inVarMap
.
end
(),
[
&
inVector
](
TVarLivePair
p
)
{
inVector
.
push_back
(
p
);
});
std
::
sort
(
inVector
.
begin
(),
inVector
.
end
(),
[](
const
TVarLivePair
&
p1
,
const
TVarLivePair
&
p2
)
->
bool
{
return
TVarEntryInfo
::
TOrderByPriority
()(
p1
.
second
,
p2
.
second
);
});
std
::
for_each
(
outVarMap
.
begin
(),
outVarMap
.
end
(),
[
&
outVector
](
TVarLivePair
p
)
{
outVector
.
push_back
(
p
);
});
std
::
sort
(
outVector
.
begin
(),
outVector
.
end
(),
[](
const
TVarLivePair
&
p1
,
const
TVarLivePair
&
p2
)
->
bool
{
return
TVarEntryInfo
::
TOrderByPriority
()(
p1
.
second
,
p2
.
second
);
});
std
::
for_each
(
uniformVarMap
.
begin
(),
uniformVarMap
.
end
(),
[
&
uniformVector
](
TVarLivePair
p
)
{
uniformVector
.
push_back
(
p
);
});
std
::
sort
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
[](
const
TVarLivePair
&
p1
,
const
TVarLivePair
&
p2
)
->
bool
{
return
TVarEntryInfo
::
TOrderByPriority
()(
p1
.
second
,
p2
.
second
);
});
bool
hadError
=
false
;
bool
hadError
=
false
;
TNotifyInOutAdaptor
inOutNotify
(
stage
,
*
resolver
);
TNotifyInOutAdaptor
inOutNotify
(
stage
,
*
resolver
);
TNotifyUniformAdaptor
uniformNotify
(
stage
,
*
resolver
);
TNotifyUniformAdaptor
uniformNotify
(
stage
,
*
resolver
);
TResolverUniformAdaptor
uniformResolve
(
stage
,
*
resolver
,
infoSink
,
hadError
,
intermediate
);
TResolverUniformAdaptor
uniformResolve
(
stage
,
*
resolver
,
infoSink
,
hadError
);
TResolverInOutAdaptor
inOutResolve
(
stage
,
*
resolver
,
infoSink
,
hadError
,
intermediate
);
TResolverInOutAdaptor
inOutResolve
(
stage
,
*
resolver
,
infoSink
,
hadError
);
resolver
->
beginNotifications
(
stage
);
resolver
->
beginNotifications
(
stage
);
std
::
for_each
(
inV
arMap
.
begin
(),
inVarMap
.
end
(),
inOutNotify
);
std
::
for_each
(
inV
ector
.
begin
(),
inVector
.
end
(),
inOutNotify
);
std
::
for_each
(
outV
arMap
.
begin
(),
outVarMap
.
end
(),
inOutNotify
);
std
::
for_each
(
outV
ector
.
begin
(),
outVector
.
end
(),
inOutNotify
);
std
::
for_each
(
uniformV
arMap
.
begin
(),
uniformVarMap
.
end
(),
uniformNotify
);
std
::
for_each
(
uniformV
ector
.
begin
(),
uniformVector
.
end
(),
uniformNotify
);
resolver
->
endNotifications
(
stage
);
resolver
->
endNotifications
(
stage
);
resolver
->
beginResolve
(
stage
);
resolver
->
beginResolve
(
stage
);
std
::
for_each
(
inVarMap
.
begin
(),
inVarMap
.
end
(),
inOutResolve
);
std
::
for_each
(
inVector
.
begin
(),
inVector
.
end
(),
inOutResolve
);
std
::
for_each
(
outVarMap
.
begin
(),
outVarMap
.
end
(),
inOutResolve
);
std
::
for_each
(
inVector
.
begin
(),
inVector
.
end
(),
[
&
inVarMap
](
TVarLivePair
p
)
{
std
::
for_each
(
uniformVarMap
.
begin
(),
uniformVarMap
.
end
(),
uniformResolve
);
auto
at
=
inVarMap
.
find
(
p
.
second
.
symbol
->
getName
());
if
(
at
!=
inVarMap
.
end
())
at
->
second
=
p
.
second
;
});
std
::
for_each
(
outVector
.
begin
(),
outVector
.
end
(),
inOutResolve
);
std
::
for_each
(
outVector
.
begin
(),
outVector
.
end
(),
[
&
outVarMap
](
TVarLivePair
p
)
{
auto
at
=
outVarMap
.
find
(
p
.
second
.
symbol
->
getName
());
if
(
at
!=
outVarMap
.
end
())
at
->
second
=
p
.
second
;
});
std
::
for_each
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
uniformResolve
);
std
::
for_each
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
[
&
uniformVarMap
](
TVarLivePair
p
)
{
auto
at
=
uniformVarMap
.
find
(
p
.
second
.
symbol
->
getName
());
if
(
at
!=
uniformVarMap
.
end
())
at
->
second
=
p
.
second
;
});
resolver
->
endResolve
(
stage
);
resolver
->
endResolve
(
stage
);
if
(
!
hadError
)
{
if
(
!
hadError
)
{
// sort by id again, so we can use lower bound to find entries
std
::
sort
(
uniformVarMap
.
begin
(),
uniformVarMap
.
end
(),
TVarEntryInfo
::
TOrderById
());
TVarSetTraverser
iter_iomap
(
intermediate
,
inVarMap
,
outVarMap
,
uniformVarMap
);
TVarSetTraverser
iter_iomap
(
intermediate
,
inVarMap
,
outVarMap
,
uniformVarMap
);
root
->
traverse
(
&
iter_iomap
);
root
->
traverse
(
&
iter_iomap
);
}
}
return
!
hadError
;
}
// Map I/O variables to provided offsets, and make bindings for
// unbound but live variables.
//
// Returns false if the input is too malformed to do this.
bool
TGlslIoMapper
::
addStage
(
EShLanguage
stage
,
TIntermediate
&
intermediate
,
TInfoSink
&
infoSink
,
TIoMapResolver
*
resolver
)
{
bool
somethingToDo
=
!
intermediate
.
getResourceSetBinding
().
empty
()
||
intermediate
.
getAutoMapBindings
()
||
intermediate
.
getAutoMapLocations
();
for
(
int
res
=
0
;
res
<
EResCount
;
++
res
)
{
somethingToDo
=
somethingToDo
||
(
intermediate
.
getShiftBinding
(
TResourceType
(
res
))
!=
0
)
||
intermediate
.
hasShiftBindingForSet
(
TResourceType
(
res
));
}
if
(
!
somethingToDo
&&
resolver
==
nullptr
)
{
return
true
;
}
if
(
intermediate
.
getNumEntryPoints
()
!=
1
||
intermediate
.
isRecursive
())
{
return
false
;
}
TIntermNode
*
root
=
intermediate
.
getTreeRoot
();
if
(
root
==
nullptr
)
{
return
false
;
}
// if no resolver is provided, use the default resolver with the given shifts and auto map settings
TDefaultGlslIoResolver
defaultResolver
(
intermediate
);
if
(
resolver
==
nullptr
)
{
resolver
=
&
defaultResolver
;
}
resolver
->
addStage
(
stage
);
inVarMaps
[
stage
]
=
new
TVarLiveMap
,
outVarMaps
[
stage
]
=
new
TVarLiveMap
(),
uniformVarMap
[
stage
]
=
new
TVarLiveMap
();
TVarGatherTraverser
iter_binding_all
(
intermediate
,
true
,
*
inVarMaps
[
stage
],
*
outVarMaps
[
stage
],
*
uniformVarMap
[
stage
]);
TVarGatherTraverser
iter_binding_live
(
intermediate
,
false
,
*
inVarMaps
[
stage
],
*
outVarMaps
[
stage
],
*
uniformVarMap
[
stage
]);
root
->
traverse
(
&
iter_binding_all
);
iter_binding_live
.
pushFunction
(
intermediate
.
getEntryPointMangledName
().
c_str
());
while
(
!
iter_binding_live
.
functions
.
empty
())
{
TIntermNode
*
function
=
iter_binding_live
.
functions
.
back
();
iter_binding_live
.
functions
.
pop_back
();
function
->
traverse
(
&
iter_binding_live
);
}
TNotifyInOutAdaptor
inOutNotify
(
stage
,
*
resolver
);
TNotifyUniformAdaptor
uniformNotify
(
stage
,
*
resolver
);
// Resolve current stage input symbol location with previous stage output here,
// uniform symbol, ubo, ssbo and opaque symbols are per-program resource,
// will resolve uniform symbol location and ubo/ssbo/opaque binding in doMap()
resolver
->
beginNotifications
(
stage
);
std
::
for_each
(
inVarMaps
[
stage
]
->
begin
(),
inVarMaps
[
stage
]
->
end
(),
inOutNotify
);
std
::
for_each
(
outVarMaps
[
stage
]
->
begin
(),
outVarMaps
[
stage
]
->
end
(),
inOutNotify
);
std
::
for_each
(
uniformVarMap
[
stage
]
->
begin
(),
uniformVarMap
[
stage
]
->
end
(),
uniformNotify
);
resolver
->
endNotifications
(
stage
);
TSlotCollector
slotCollector
(
*
resolver
,
infoSink
);
resolver
->
beginCollect
(
stage
);
std
::
for_each
(
inVarMaps
[
stage
]
->
begin
(),
inVarMaps
[
stage
]
->
end
(),
slotCollector
);
std
::
for_each
(
outVarMaps
[
stage
]
->
begin
(),
outVarMaps
[
stage
]
->
end
(),
slotCollector
);
std
::
for_each
(
uniformVarMap
[
stage
]
->
begin
(),
uniformVarMap
[
stage
]
->
end
(),
slotCollector
);
resolver
->
endCollect
(
stage
);
intermediates
[
stage
]
=
&
intermediate
;
return
!
hadError
;
}
bool
TGlslIoMapper
::
doMap
(
TIoMapResolver
*
resolver
,
TInfoSink
&
infoSink
)
{
resolver
->
endResolve
(
EShLangCount
);
if
(
!
hadError
)
{
//Resolve uniform location, ubo/ssbo/opaque bindings across stages
TResolverUniformAdaptor
uniformResolve
(
EShLangCount
,
*
resolver
,
infoSink
,
hadError
);
TResolverInOutAdaptor
inOutResolve
(
EShLangCount
,
*
resolver
,
infoSink
,
hadError
);
TSymbolValidater
symbolValidater
(
*
resolver
,
infoSink
,
inVarMaps
,
outVarMaps
,
uniformVarMap
,
hadError
);
TVarLiveVector
uniformVector
;
resolver
->
beginResolve
(
EShLangCount
);
for
(
int
stage
=
EShLangVertex
;
stage
<
EShLangCount
;
stage
++
)
{
if
(
inVarMaps
[
stage
]
!=
nullptr
)
{
inOutResolve
.
setStage
(
EShLanguage
(
stage
));
std
::
for_each
(
inVarMaps
[
stage
]
->
begin
(),
inVarMaps
[
stage
]
->
end
(),
symbolValidater
);
std
::
for_each
(
inVarMaps
[
stage
]
->
begin
(),
inVarMaps
[
stage
]
->
end
(),
inOutResolve
);
std
::
for_each
(
outVarMaps
[
stage
]
->
begin
(),
outVarMaps
[
stage
]
->
end
(),
symbolValidater
);
std
::
for_each
(
outVarMaps
[
stage
]
->
begin
(),
outVarMaps
[
stage
]
->
end
(),
inOutResolve
);
}
if
(
uniformVarMap
[
stage
]
!=
nullptr
)
{
uniformResolve
.
setStage
(
EShLanguage
(
stage
));
// sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
std
::
for_each
(
uniformVarMap
[
stage
]
->
begin
(),
uniformVarMap
[
stage
]
->
end
(),
[
&
uniformVector
](
TVarLivePair
p
)
{
uniformVector
.
push_back
(
p
);
});
}
}
std
::
sort
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
[](
const
TVarLivePair
&
p1
,
const
TVarLivePair
&
p2
)
->
bool
{
return
TVarEntryInfo
::
TOrderByPriority
()(
p1
.
second
,
p2
.
second
);
});
std
::
for_each
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
symbolValidater
);
std
::
for_each
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
uniformResolve
);
std
::
sort
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
[](
const
TVarLivePair
&
p1
,
const
TVarLivePair
&
p2
)
->
bool
{
return
TVarEntryInfo
::
TOrderByPriority
()(
p1
.
second
,
p2
.
second
);
});
resolver
->
endResolve
(
EShLangCount
);
for
(
size_t
stage
=
0
;
stage
<
EShLangCount
;
stage
++
)
{
if
(
intermediates
[
stage
]
!=
nullptr
)
{
// traverse each stage, set new location to each input/output and unifom symbol, set new binding to
// ubo, ssbo and opaque symbols
TVarLiveMap
**
pUniformVarMap
=
uniformVarMap
;
std
::
for_each
(
uniformVector
.
begin
(),
uniformVector
.
end
(),
[
pUniformVarMap
,
stage
](
TVarLivePair
p
)
{
auto
at
=
pUniformVarMap
[
stage
]
->
find
(
p
.
second
.
symbol
->
getName
());
if
(
at
!=
pUniformVarMap
[
stage
]
->
end
())
at
->
second
=
p
.
second
;
});
TVarSetTraverser
iter_iomap
(
*
intermediates
[
stage
],
*
inVarMaps
[
stage
],
*
outVarMaps
[
stage
],
*
uniformVarMap
[
stage
]);
intermediates
[
stage
]
->
getTreeRoot
()
->
traverse
(
&
iter_iomap
);
}
}
return
!
hadError
;
return
!
hadError
;
}
else
{
return
false
;
}
}
}
}
// end namespace glslang
}
// end namespace glslang
glslang/MachineIndependent/iomapper.h
View file @
f04f1f93
...
@@ -36,8 +36,9 @@
...
@@ -36,8 +36,9 @@
#ifndef _IOMAPPER_INCLUDED
#ifndef _IOMAPPER_INCLUDED
#define _IOMAPPER_INCLUDED
#define _IOMAPPER_INCLUDED
#include "../Public/ShaderLang.h"
#include "LiveTraverser.h"
#include <unordered_map>
#include <unordered_set>
//
//
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
//
//
...
@@ -47,15 +48,245 @@ class TInfoSink;
...
@@ -47,15 +48,245 @@ class TInfoSink;
namespace
glslang
{
namespace
glslang
{
class
TIntermediate
;
class
TIntermediate
;
struct
TVarEntryInfo
{
int
id
;
TIntermSymbol
*
symbol
;
bool
live
;
int
newBinding
;
int
newSet
;
int
newLocation
;
int
newComponent
;
int
newIndex
;
EShLanguage
stage
;
struct
TOrderById
{
inline
bool
operator
()(
const
TVarEntryInfo
&
l
,
const
TVarEntryInfo
&
r
)
{
return
l
.
id
<
r
.
id
;
}
};
struct
TOrderByPriority
{
// ordering:
// 1) has both binding and set
// 2) has binding but no set
// 3) has no binding but set
// 4) has no binding and no set
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
;
}
};
};
// Base class for shared TIoMapResolver services, used by several derivations.
struct
TDefaultIoResolverBase
:
public
glslang
::
TIoMapResolver
{
public
:
TDefaultIoResolverBase
(
const
TIntermediate
&
intermediate
);
typedef
std
::
vector
<
int
>
TSlotSet
;
typedef
std
::
unordered_map
<
int
,
TSlotSet
>
TSlotSetMap
;
// grow the reflection stage by stage
void
notifyBinding
(
EShLanguage
,
TVarEntryInfo
&
/*ent*/
)
override
{}
void
notifyInOut
(
EShLanguage
,
TVarEntryInfo
&
/*ent*/
)
override
{}
void
beginNotifications
(
EShLanguage
)
override
{}
void
endNotifications
(
EShLanguage
)
override
{}
void
beginResolve
(
EShLanguage
)
override
{}
void
endResolve
(
EShLanguage
)
override
{}
void
beginCollect
(
EShLanguage
)
override
{}
void
endCollect
(
EShLanguage
)
override
{}
void
reserverResourceSlot
(
TVarEntryInfo
&
/*ent*/
,
TInfoSink
&
/*infoSink*/
)
override
{}
void
reserverStorageSlot
(
TVarEntryInfo
&
/*ent*/
,
TInfoSink
&
/*infoSink*/
)
override
{}
int
getBaseBinding
(
TResourceType
res
,
unsigned
int
set
)
const
;
const
std
::
vector
<
std
::
string
>&
getResourceSetBinding
()
const
;
virtual
TResourceType
getResourceType
(
const
glslang
::
TType
&
type
)
=
0
;
bool
doAutoBindingMapping
()
const
;
bool
doAutoLocationMapping
()
const
;
TSlotSet
::
iterator
findSlot
(
int
set
,
int
slot
);
bool
checkEmpty
(
int
set
,
int
slot
);
bool
validateInOut
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
/*ent*/
)
override
{
return
true
;
};
int
reserveSlot
(
int
set
,
int
slot
,
int
size
=
1
);
int
getFreeSlot
(
int
set
,
int
base
,
int
size
=
1
);
int
resolveSet
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
;
int
resolveUniformLocation
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
;
int
resolveInOutLocation
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
override
;
int
resolveInOutComponent
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
;
int
resolveInOutIndex
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
;
void
addStage
(
EShLanguage
stage
)
override
{
if
(
stage
<
EShLangCount
)
stageMask
[
stage
]
=
true
;
};
uint32_t
computeTypeLocationSize
(
const
TType
&
type
,
EShLanguage
stage
);
TSlotSetMap
slots
;
protected
:
TDefaultIoResolverBase
(
TDefaultIoResolverBase
&
);
TDefaultIoResolverBase
&
operator
=
(
TDefaultIoResolverBase
&
);
const
TIntermediate
&
intermediate
;
int
nextUniformLocation
;
int
nextInputLocation
;
int
nextOutputLocation
;
bool
stageMask
[
EShLangCount
+
1
];
// Return descriptor set specific base if there is one, and the generic base otherwise.
int
selectBaseBinding
(
int
base
,
int
descriptorSetBase
)
const
{
return
descriptorSetBase
!=
-
1
?
descriptorSetBase
:
base
;
}
static
int
getLayoutSet
(
const
glslang
::
TType
&
type
)
{
if
(
type
.
getQualifier
().
hasSet
())
return
type
.
getQualifier
().
layoutSet
;
else
return
0
;
}
static
bool
isSamplerType
(
const
glslang
::
TType
&
type
)
{
return
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
type
.
getSampler
().
isPureSampler
();
}
static
bool
isTextureType
(
const
glslang
::
TType
&
type
)
{
return
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
(
type
.
getSampler
().
isTexture
()
||
type
.
getSampler
().
isSubpass
()));
}
static
bool
isUboType
(
const
glslang
::
TType
&
type
)
{
return
type
.
getQualifier
().
storage
==
EvqUniform
;
}
static
bool
isImageType
(
const
glslang
::
TType
&
type
)
{
return
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
type
.
getSampler
().
isImage
();
}
static
bool
isSsboType
(
const
glslang
::
TType
&
type
)
{
return
type
.
getQualifier
().
storage
==
EvqBuffer
;
}
// Return true if this is a SRV (shader resource view) type:
static
bool
isSrvType
(
const
glslang
::
TType
&
type
)
{
return
isTextureType
(
type
)
||
type
.
getQualifier
().
storage
==
EvqBuffer
;
}
// Return true if this is a UAV (unordered access view) type:
static
bool
isUavType
(
const
glslang
::
TType
&
type
)
{
if
(
type
.
getQualifier
().
readonly
)
return
false
;
return
(
type
.
getBasicType
()
==
glslang
::
EbtSampler
&&
type
.
getSampler
().
isImage
())
||
(
type
.
getQualifier
().
storage
==
EvqBuffer
);
}
};
// Defaulf I/O resolver for OpenGL
struct
TDefaultGlslIoResolver
:
public
TDefaultIoResolverBase
{
public
:
typedef
std
::
map
<
TString
,
int
>
TVarSlotMap
;
// <resourceName, location/binding>
typedef
std
::
map
<
int
,
TVarSlotMap
>
TSlotMap
;
// <resourceKey, TVarSlotMap>
TDefaultGlslIoResolver
(
const
TIntermediate
&
intermediate
);
bool
validateBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
/*ent*/
)
override
{
return
true
;
};
TResourceType
getResourceType
(
const
glslang
::
TType
&
type
)
override
;
int
resolveInOutLocation
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
override
;
int
resolveUniformLocation
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
;
int
resolveBinding
(
EShLanguage
/*stage*/
,
TVarEntryInfo
&
ent
)
override
;
void
beginResolve
(
EShLanguage
/*stage*/
)
override
;
void
endResolve
(
EShLanguage
stage
)
override
;
void
beginCollect
(
EShLanguage
)
override
;
void
endCollect
(
EShLanguage
)
override
;
void
reserverStorageSlot
(
TVarEntryInfo
&
ent
,
TInfoSink
&
infoSink
)
override
;
void
reserverResourceSlot
(
TVarEntryInfo
&
ent
,
TInfoSink
&
infoSink
)
override
;
// in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol.
// We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage.
// if a resource is a program resource and we don't need know it usage stage, we can use same stage to build storage key.
// Note: both stage and type must less then 0xffff.
int
buildStorageKey
(
EShLanguage
stage
,
TStorageQualifier
type
)
{
assert
(
static_cast
<
uint32_t
>
(
stage
)
<=
0x0000ffff
&&
static_cast
<
uint32_t
>
(
type
)
<=
0x0000ffff
);
return
(
stage
<<
16
)
|
type
;
};
protected
:
// Use for mark pre stage, to get more interface symbol information.
EShLanguage
preStage
;
// Use for mark current shader stage for resolver
EShLanguage
currentStage
;
// Slot map for storage resource(location of uniform and interface symbol) It's a program share slot
TSlotMap
resourceSlotMap
;
// Slot map for other resource(image, ubo, ssbo), It's a program share slot.
TSlotMap
storageSlotMap
;
};
typedef
std
::
map
<
TString
,
TVarEntryInfo
>
TVarLiveMap
;
// override function "operator=", if a vector<const _Kty, _Ty> being sort,
// when use vc++, the sort function will call :
// pair& operator=(const pair<_Other1, _Other2>& _Right)
// {
// first = _Right.first;
// second = _Right.second;
// return (*this);
// }
// that will make a const type handing on left.
// override this function can avoid a compiler error.
// In the future, if the vc++ compiler can handle such a situation,
// this part of the code will be removed.
struct
TVarLivePair
:
std
::
pair
<
const
TString
,
TVarEntryInfo
>
{
TVarLivePair
(
std
::
pair
<
const
TString
,
TVarEntryInfo
>&
_Right
)
:
pair
(
_Right
.
first
,
_Right
.
second
)
{}
TVarLivePair
&
operator
=
(
const
TVarLivePair
&
_Right
)
{
const_cast
<
TString
&>
(
first
)
=
_Right
.
first
;
second
=
_Right
.
second
;
return
(
*
this
);
};
};
typedef
std
::
vector
<
TVarLivePair
>
TVarLiveVector
;
// I/O mapper
// I/O mapper
class
TIoMapper
{
class
TIoMapper
{
public
:
public
:
TIoMapper
()
{}
TIoMapper
()
{}
virtual
~
TIoMapper
()
{}
virtual
~
TIoMapper
()
{}
// grow the reflection stage by stage
bool
virtual
addStage
(
EShLanguage
,
TIntermediate
&
,
TInfoSink
&
,
TIoMapResolver
*
);
bool
virtual
doMap
(
TIoMapResolver
*
,
TInfoSink
&
)
{
return
true
;
};
};
// I/O mapper for OpenGL
class
TGlslIoMapper
:
public
TIoMapper
{
public
:
TGlslIoMapper
()
{
memset
(
inVarMaps
,
0
,
sizeof
(
TVarLiveMap
*
)
*
(
EShLangCount
+
1
));
memset
(
outVarMaps
,
0
,
sizeof
(
TVarLiveMap
*
)
*
(
EShLangCount
+
1
));
memset
(
uniformVarMap
,
0
,
sizeof
(
TVarLiveMap
*
)
*
(
EShLangCount
+
1
));
memset
(
intermediates
,
0
,
sizeof
(
TIntermediate
*
)
*
(
EShLangCount
+
1
));
}
virtual
~
TGlslIoMapper
()
{
for
(
size_t
stage
=
0
;
stage
<
EShLangCount
;
stage
++
)
{
if
(
inVarMaps
[
stage
]
!=
nullptr
)
{
delete
inVarMaps
[
stage
];
inVarMaps
[
stage
]
=
nullptr
;
}
if
(
outVarMaps
[
stage
]
!=
nullptr
)
{
delete
outVarMaps
[
stage
];
outVarMaps
[
stage
]
=
nullptr
;
}
if
(
uniformVarMap
[
stage
]
!=
nullptr
)
{
delete
uniformVarMap
[
stage
];
uniformVarMap
[
stage
]
=
nullptr
;
}
if
(
intermediates
[
stage
]
!=
nullptr
)
intermediates
[
stage
]
=
nullptr
;
}
}
// grow the reflection stage by stage
// grow the reflection stage by stage
bool
addStage
(
EShLanguage
,
TIntermediate
&
,
TInfoSink
&
,
TIoMapResolver
*
);
bool
addStage
(
EShLanguage
,
TIntermediate
&
,
TInfoSink
&
,
TIoMapResolver
*
)
override
;
bool
doMap
(
TIoMapResolver
*
,
TInfoSink
&
)
override
;
TVarLiveMap
*
inVarMaps
[
EShLangCount
],
*
outVarMaps
[
EShLangCount
],
*
uniformVarMap
[
EShLangCount
];
TIntermediate
*
intermediates
[
EShLangCount
];
bool
hadError
=
false
;
};
};
}
// end namespace glslang
}
// end namespace glslang
...
...
glslang/Public/ShaderLang.h
View file @
f04f1f93
...
@@ -648,6 +648,7 @@ protected:
...
@@ -648,6 +648,7 @@ protected:
class
TReflection
;
class
TReflection
;
class
TIoMapper
;
class
TIoMapper
;
struct
TVarEntryInfo
;
// Allows to customize the binding layout after linking.
// Allows to customize the binding layout after linking.
// All used uniform variables will invoke at least validateBinding.
// All used uniform variables will invoke at least validateBinding.
...
@@ -679,40 +680,50 @@ public:
...
@@ -679,40 +680,50 @@ public:
// Should return true if the resulting/current binding would be okay.
// Should return true if the resulting/current binding would be okay.
// Basic idea is to do aliasing binding checks with this.
// 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
;
virtual
bool
validateBinding
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return a value >= 0 if the current binding should be overridden.
// Should return a value >= 0 if the current binding should be overridden.
// Return -1 if the current binding (including no binding) should be kept.
// 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
;
virtual
int
resolveBinding
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return a value >= 0 if the current set should be overridden.
// Should return a value >= 0 if the current set should be overridden.
// Return -1 if the current set (including no set) should be kept.
// 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
;
virtual
int
resolveSet
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return a value >= 0 if the current location should be overridden.
// Should return a value >= 0 if the current location should be overridden.
// Return -1 if the current location (including no location) should be kept.
// Return -1 if the current location (including no location) should be kept.
virtual
int
resolveUniformLocation
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
int
resolveUniformLocation
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return true if the resulting/current setup would be okay.
// Should return true if the resulting/current setup would be okay.
// Basic idea is to do aliasing checks and reject invalid semantic names.
// Basic idea is to do aliasing checks and reject invalid semantic names.
virtual
bool
validateInOut
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
bool
validateInOut
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return a value >= 0 if the current location should be overridden.
// Should return a value >= 0 if the current location should be overridden.
// Return -1 if the current location (including no location) should be kept.
// Return -1 if the current location (including no location) should be kept.
virtual
int
resolveInOutLocation
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
int
resolveInOutLocation
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return a value >= 0 if the current component index should be overridden.
// Should return a value >= 0 if the current component index should be overridden.
// Return -1 if the current component index (including no index) should be kept.
// Return -1 if the current component index (including no index) should be kept.
virtual
int
resolveInOutComponent
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
int
resolveInOutComponent
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Should return a value >= 0 if the current color index should be overridden.
// Should return a value >= 0 if the current color index should be overridden.
// Return -1 if the current color index (including no index) should be kept.
// Return -1 if the current color index (including no index) should be kept.
virtual
int
resolveInOutIndex
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
int
resolveInOutIndex
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Notification of a uniform variable
// Notification of a uniform variable
virtual
void
notifyBinding
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
void
notifyBinding
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Notification of a in or out variable
// Notification of a in or out variable
virtual
void
notifyInOut
(
EShLanguage
stage
,
const
char
*
name
,
const
TType
&
type
,
bool
is_live
)
=
0
;
virtual
void
notifyInOut
(
EShLanguage
stage
,
TVarEntryInfo
&
ent
)
=
0
;
// Called by mapIO when it has finished the notify pass
virtual
void
endNotifications
(
EShLanguage
stage
)
=
0
;
// Called by mapIO when it starts its notify pass for the given stage
// Called by mapIO when it starts its notify pass for the given stage
virtual
void
beginNotifications
(
EShLanguage
stage
)
=
0
;
virtual
void
beginNotifications
(
EShLanguage
stage
)
=
0
;
// Called by mapIO when it has finished the notify pass
virtual
void
endNotifications
(
EShLanguage
stage
)
=
0
;
// Called by mipIO when it starts its resolve pass for the given stage
// Called by mipIO when it starts its resolve pass for the given stage
virtual
void
beginResolve
(
EShLanguage
stage
)
=
0
;
virtual
void
beginResolve
(
EShLanguage
stage
)
=
0
;
// Called by mapIO when it has finished the resolve pass
// Called by mapIO when it has finished the resolve pass
virtual
void
endResolve
(
EShLanguage
stage
)
=
0
;
virtual
void
endResolve
(
EShLanguage
stage
)
=
0
;
// Called by mapIO when it starts its symbol collect for teh given stage
virtual
void
beginCollect
(
EShLanguage
stage
)
=
0
;
// Called by mapIO when it has finished the symbol collect
virtual
void
endCollect
(
EShLanguage
stage
)
=
0
;
// Called by TSlotCollector to resolve storage locations or bindings
virtual
void
reserverStorageSlot
(
TVarEntryInfo
&
ent
,
TInfoSink
&
infoSink
)
=
0
;
// Called by TSlotCollector to resolve resource locations or bindings
virtual
void
reserverResourceSlot
(
TVarEntryInfo
&
ent
,
TInfoSink
&
infoSink
)
=
0
;
// Called by mapIO.addStage to set shader stage mask to mark a stage be added to this pipeline
virtual
void
addStage
(
EShLanguage
stage
)
=
0
;
};
};
// 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
...
@@ -824,7 +835,7 @@ public:
...
@@ -824,7 +835,7 @@ public:
// I/O mapping: apply base offsets and map live unbound variables
// I/O mapping: apply base offsets and map live unbound variables
// If resolver is not provided it uses the previous approach
// If resolver is not provided it uses the previous approach
// and respects auto assignment and offsets.
// and respects auto assignment and offsets.
bool
mapIO
(
TIoMapResolver
*
resolver
=
NULL
);
bool
mapIO
(
TIoMapResolver
*
pResolver
=
nullptr
,
TIoMapper
*
pIoMapper
=
nullptr
);
protected
:
protected
:
bool
linkStage
(
EShLanguage
,
EShMessages
);
bool
linkStage
(
EShLanguage
,
EShMessages
);
...
@@ -835,7 +846,6 @@ protected:
...
@@ -835,7 +846,6 @@ protected:
bool
newedIntermediate
[
EShLangCount
];
// track which intermediate were "new" versus reusing a singleton unit in a stage
bool
newedIntermediate
[
EShLangCount
];
// track which intermediate were "new" versus reusing a singleton unit in a stage
TInfoSink
*
infoSink
;
TInfoSink
*
infoSink
;
TReflection
*
reflection
;
TReflection
*
reflection
;
TIoMapper
*
ioMapper
;
bool
linked
;
bool
linked
;
private
:
private
:
...
...
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