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
4329d555
Commit
4329d555
authored
Jun 21, 2017
by
John Kessenich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
HLSL: Broaden solution for #940, editing integer input for 'flat'.
parent
f0bc598d
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
250 additions
and
46 deletions
+250
-46
hlsl.intrinsics.double.frag.out
Test/baseResults/hlsl.intrinsics.double.frag.out
+30
-24
hlsl.struct.frag.out
Test/baseResults/hlsl.struct.frag.out
+5
-4
hlsl.synthesizeInput.frag.out
Test/baseResults/hlsl.synthesizeInput.frag.out
+151
-0
hlsl.synthesizeInput.frag
Test/hlsl.synthesizeInput.frag
+10
-0
Hlsl.FromFile.cpp
gtests/Hlsl.FromFile.cpp
+1
-0
hlslParseHelper.cpp
hlsl/hlslParseHelper.cpp
+53
-18
No files found.
Test/baseResults/hlsl.intrinsics.double.frag.out
View file @
4329d555
...
...
@@ -35,22 +35,22 @@ gl_FragCoord origin is upper left
0:? Sequence
0:5 move second child to first child ( temp double)
0:? 'inDV1a' ( temp double)
0:? 'inDV1a' (layout( location=0) in double)
0:? 'inDV1a' (layout( location=0)
flat
in double)
0:5 move second child to first child ( temp double)
0:? 'inDV1b' ( temp double)
0:? 'inDV1b' (layout( location=1) in double)
0:? 'inDV1b' (layout( location=1)
flat
in double)
0:5 move second child to first child ( temp double)
0:? 'inDV1c' ( temp double)
0:? 'inDV1c' (layout( location=2) in double)
0:? 'inDV1c' (layout( location=2)
flat
in double)
0:5 move second child to first child ( temp 2-component vector of double)
0:? 'inDV2' ( temp 2-component vector of double)
0:? 'inDV2' (layout( location=3) in 2-component vector of double)
0:? 'inDV2' (layout( location=3)
flat
in 2-component vector of double)
0:5 move second child to first child ( temp 3-component vector of double)
0:? 'inDV3' ( temp 3-component vector of double)
0:? 'inDV3' (layout( location=4) in 3-component vector of double)
0:? 'inDV3' (layout( location=4)
flat
in 3-component vector of double)
0:5 move second child to first child ( temp 4-component vector of double)
0:? 'inDV4' ( temp 4-component vector of double)
0:? 'inDV4' (layout( location=6) in 4-component vector of double)
0:? 'inDV4' (layout( location=6)
flat
in 4-component vector of double)
0:5 move second child to first child ( temp uint)
0:? 'inU1a' ( temp uint)
0:? 'inU1a' (layout( location=8) flat in uint)
...
...
@@ -70,12 +70,12 @@ gl_FragCoord origin is upper left
0:? 'inU1b' ( temp uint)
0:? Linker Objects
0:? '@entryPointOutput' (layout( location=0) out float)
0:? 'inDV1a' (layout( location=0) in double)
0:? 'inDV1b' (layout( location=1) in double)
0:? 'inDV1c' (layout( location=2) in double)
0:? 'inDV2' (layout( location=3) in 2-component vector of double)
0:? 'inDV3' (layout( location=4) in 3-component vector of double)
0:? 'inDV4' (layout( location=6) in 4-component vector of double)
0:? 'inDV1a' (layout( location=0)
flat
in double)
0:? 'inDV1b' (layout( location=1)
flat
in double)
0:? 'inDV1c' (layout( location=2)
flat
in double)
0:? 'inDV2' (layout( location=3)
flat
in 2-component vector of double)
0:? 'inDV3' (layout( location=4)
flat
in 3-component vector of double)
0:? 'inDV4' (layout( location=6)
flat
in 4-component vector of double)
0:? 'inU1a' (layout( location=8) flat in uint)
0:? 'inU1b' (layout( location=9) flat in uint)
...
...
@@ -119,22 +119,22 @@ gl_FragCoord origin is upper left
0:? Sequence
0:5 move second child to first child ( temp double)
0:? 'inDV1a' ( temp double)
0:? 'inDV1a' (layout( location=0) in double)
0:? 'inDV1a' (layout( location=0)
flat
in double)
0:5 move second child to first child ( temp double)
0:? 'inDV1b' ( temp double)
0:? 'inDV1b' (layout( location=1) in double)
0:? 'inDV1b' (layout( location=1)
flat
in double)
0:5 move second child to first child ( temp double)
0:? 'inDV1c' ( temp double)
0:? 'inDV1c' (layout( location=2) in double)
0:? 'inDV1c' (layout( location=2)
flat
in double)
0:5 move second child to first child ( temp 2-component vector of double)
0:? 'inDV2' ( temp 2-component vector of double)
0:? 'inDV2' (layout( location=3) in 2-component vector of double)
0:? 'inDV2' (layout( location=3)
flat
in 2-component vector of double)
0:5 move second child to first child ( temp 3-component vector of double)
0:? 'inDV3' ( temp 3-component vector of double)
0:? 'inDV3' (layout( location=4) in 3-component vector of double)
0:? 'inDV3' (layout( location=4)
flat
in 3-component vector of double)
0:5 move second child to first child ( temp 4-component vector of double)
0:? 'inDV4' ( temp 4-component vector of double)
0:? 'inDV4' (layout( location=6) in 4-component vector of double)
0:? 'inDV4' (layout( location=6)
flat
in 4-component vector of double)
0:5 move second child to first child ( temp uint)
0:? 'inU1a' ( temp uint)
0:? 'inU1a' (layout( location=8) flat in uint)
...
...
@@ -154,12 +154,12 @@ gl_FragCoord origin is upper left
0:? 'inU1b' ( temp uint)
0:? Linker Objects
0:? '@entryPointOutput' (layout( location=0) out float)
0:? 'inDV1a' (layout( location=0) in double)
0:? 'inDV1b' (layout( location=1) in double)
0:? 'inDV1c' (layout( location=2) in double)
0:? 'inDV2' (layout( location=3) in 2-component vector of double)
0:? 'inDV3' (layout( location=4) in 3-component vector of double)
0:? 'inDV4' (layout( location=6) in 4-component vector of double)
0:? 'inDV1a' (layout( location=0)
flat
in double)
0:? 'inDV1b' (layout( location=1)
flat
in double)
0:? 'inDV1c' (layout( location=2)
flat
in double)
0:? 'inDV2' (layout( location=3)
flat
in 2-component vector of double)
0:? 'inDV3' (layout( location=4)
flat
in 3-component vector of double)
0:? 'inDV4' (layout( location=6)
flat
in 4-component vector of double)
0:? 'inU1a' (layout( location=8) flat in uint)
0:? 'inU1b' (layout( location=9) flat in uint)
...
...
@@ -211,11 +211,17 @@ gl_FragCoord origin is upper left
Name 83 "param"
Name 85 "param"
Name 87 "param"
Decorate 44(inDV1a) Flat
Decorate 44(inDV1a) Location 0
Decorate 47(inDV1b) Flat
Decorate 47(inDV1b) Location 1
Decorate 50(inDV1c) Flat
Decorate 50(inDV1c) Location 2
Decorate 54(inDV2) Flat
Decorate 54(inDV2) Location 3
Decorate 58(inDV3) Flat
Decorate 58(inDV3) Location 4
Decorate 62(inDV4) Flat
Decorate 62(inDV4) Location 6
Decorate 66(inU1a) Flat
Decorate 66(inU1a) Location 8
...
...
Test/baseResults/hlsl.struct.frag.out
View file @
4329d555
...
...
@@ -79,7 +79,7 @@ gl_FragCoord origin is upper left
0:? 's' ( temp structure{ temp 4-component vector of float a, temp bool b, temp 1-component vector of float c, temp 2-component vector of float d, temp bool ff1, temp bool ff2, temp bool ff3, temp 4-component vector of float ff4})
0:40 Constant:
0:40 4 (const int)
0:? 's_ff1' ( in bool Face)
0:? 's_ff1' (
flat
in bool Face)
0:40 move second child to first child ( temp bool)
0:40 ff2: direct index for structure ( temp bool)
0:? 's' ( temp structure{ temp 4-component vector of float a, temp bool b, temp 1-component vector of float c, temp 2-component vector of float d, temp bool ff1, temp bool ff2, temp bool ff3, temp 4-component vector of float ff4})
...
...
@@ -118,7 +118,7 @@ gl_FragCoord origin is upper left
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'input' (layout( location=0) in 4-component vector of float)
0:? 's' (layout( location=1) in structure{ smooth temp 4-component vector of float a, flat temp bool b, centroid noperspective temp 1-component vector of float c, centroid sample temp 2-component vector of float d, flat temp bool ff2, flat temp bool ff3, temp 4-component vector of float ff4})
0:? 's_ff1' ( in bool Face)
0:? 's_ff1' (
flat
in bool Face)
Linked fragment stage:
...
...
@@ -200,7 +200,7 @@ gl_FragCoord origin is upper left
0:? 's' ( temp structure{ temp 4-component vector of float a, temp bool b, temp 1-component vector of float c, temp 2-component vector of float d, temp bool ff1, temp bool ff2, temp bool ff3, temp 4-component vector of float ff4})
0:40 Constant:
0:40 4 (const int)
0:? 's_ff1' ( in bool Face)
0:? 's_ff1' (
flat
in bool Face)
0:40 move second child to first child ( temp bool)
0:40 ff2: direct index for structure ( temp bool)
0:? 's' ( temp structure{ temp 4-component vector of float a, temp bool b, temp 1-component vector of float c, temp 2-component vector of float d, temp bool ff1, temp bool ff2, temp bool ff3, temp 4-component vector of float ff4})
...
...
@@ -239,7 +239,7 @@ gl_FragCoord origin is upper left
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'input' (layout( location=0) in 4-component vector of float)
0:? 's' (layout( location=1) in structure{ smooth temp 4-component vector of float a, flat temp bool b, centroid noperspective temp 1-component vector of float c, centroid sample temp 2-component vector of float d, flat temp bool ff2, flat temp bool ff3, temp 4-component vector of float ff4})
0:? 's_ff1' ( in bool Face)
0:? 's_ff1' (
flat
in bool Face)
// Module Version 10000
// Generated by (magic number): 80001
...
...
@@ -309,6 +309,7 @@ gl_FragCoord origin is upper left
MemberDecorate 54(IN_S) 4 Flat
MemberDecorate 54(IN_S) 5 Flat
Decorate 56(s) Location 1
Decorate 79(s_ff1) Flat
Decorate 79(s_ff1) BuiltIn FrontFacing
Decorate 94(@entryPointOutput) Location 0
MemberDecorate 101(myS) 0 Offset 0
...
...
Test/baseResults/hlsl.synthesizeInput.frag.out
0 → 100755
View file @
4329d555
hlsl.synthesizeInput.frag
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:7 Function Definition: @main(struct-PSInput-f1-u11; ( temp 4-component vector of float)
0:7 Function Parameters:
0:7 'input' ( in structure{ temp float interp, temp uint no_interp})
0:? Sequence
0:8 Branch: Return with expression
0:? Construct vec4 ( temp 4-component vector of float)
0:8 Convert uint to float ( temp float)
0:8 no_interp: direct index for structure ( temp uint)
0:8 'input' ( in structure{ temp float interp, temp uint no_interp})
0:8 Constant:
0:8 1 (const int)
0:8 interp: direct index for structure ( temp float)
0:8 'input' ( in structure{ temp float interp, temp uint no_interp})
0:8 Constant:
0:8 0 (const int)
0:8 Constant:
0:8 0.000000
0:8 Constant:
0:8 1.000000
0:7 Function Definition: main( ( temp void)
0:7 Function Parameters:
0:? Sequence
0:7 move second child to first child ( temp structure{ temp float interp, temp uint no_interp})
0:? 'input' ( temp structure{ temp float interp, temp uint no_interp})
0:? 'input' (layout( location=0) in structure{ temp float interp, flat temp uint no_interp})
0:7 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:7 Function Call: @main(struct-PSInput-f1-u11; ( temp 4-component vector of float)
0:? 'input' ( temp structure{ temp float interp, temp uint no_interp})
0:? Linker Objects
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'input' (layout( location=0) in structure{ temp float interp, flat temp uint no_interp})
Linked fragment stage:
Shader version: 500
gl_FragCoord origin is upper left
0:? Sequence
0:7 Function Definition: @main(struct-PSInput-f1-u11; ( temp 4-component vector of float)
0:7 Function Parameters:
0:7 'input' ( in structure{ temp float interp, temp uint no_interp})
0:? Sequence
0:8 Branch: Return with expression
0:? Construct vec4 ( temp 4-component vector of float)
0:8 Convert uint to float ( temp float)
0:8 no_interp: direct index for structure ( temp uint)
0:8 'input' ( in structure{ temp float interp, temp uint no_interp})
0:8 Constant:
0:8 1 (const int)
0:8 interp: direct index for structure ( temp float)
0:8 'input' ( in structure{ temp float interp, temp uint no_interp})
0:8 Constant:
0:8 0 (const int)
0:8 Constant:
0:8 0.000000
0:8 Constant:
0:8 1.000000
0:7 Function Definition: main( ( temp void)
0:7 Function Parameters:
0:? Sequence
0:7 move second child to first child ( temp structure{ temp float interp, temp uint no_interp})
0:? 'input' ( temp structure{ temp float interp, temp uint no_interp})
0:? 'input' (layout( location=0) in structure{ temp float interp, flat temp uint no_interp})
0:7 move second child to first child ( temp 4-component vector of float)
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:7 Function Call: @main(struct-PSInput-f1-u11; ( temp 4-component vector of float)
0:? 'input' ( temp structure{ temp float interp, temp uint no_interp})
0:? Linker Objects
0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float)
0:? 'input' (layout( location=0) in structure{ temp float interp, flat temp uint no_interp})
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 44
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 33 40
ExecutionMode 4 OriginUpperLeft
Source HLSL 500
Name 4 "main"
Name 8 "PSInput"
MemberName 8(PSInput) 0 "interp"
MemberName 8(PSInput) 1 "no_interp"
Name 13 "@main(struct-PSInput-f1-u11;"
Name 12 "input"
Name 30 "input"
Name 31 "PSInput"
MemberName 31(PSInput) 0 "interp"
MemberName 31(PSInput) 1 "no_interp"
Name 33 "input"
Name 40 "@entryPointOutput"
Name 41 "param"
MemberDecorate 31(PSInput) 1 Flat
Decorate 33(input) Location 0
Decorate 40(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeInt 32 0
8(PSInput): TypeStruct 6(float) 7(int)
9: TypePointer Function 8(PSInput)
10: TypeVector 6(float) 4
11: TypeFunction 10(fvec4) 9(ptr)
15: TypeInt 32 1
16: 15(int) Constant 1
17: TypePointer Function 7(int)
21: 15(int) Constant 0
22: TypePointer Function 6(float)
25: 6(float) Constant 0
26: 6(float) Constant 1065353216
31(PSInput): TypeStruct 6(float) 7(int)
32: TypePointer Input 31(PSInput)
33(input): 32(ptr) Variable Input
39: TypePointer Output 10(fvec4)
40(@entryPointOutput): 39(ptr) Variable Output
4(main): 2 Function None 3
5: Label
30(input): 9(ptr) Variable Function
41(param): 9(ptr) Variable Function
34: 31(PSInput) Load 33(input)
35: 6(float) CompositeExtract 34 0
36: 22(ptr) AccessChain 30(input) 21
Store 36 35
37: 7(int) CompositeExtract 34 1
38: 17(ptr) AccessChain 30(input) 16
Store 38 37
42: 8(PSInput) Load 30(input)
Store 41(param) 42
43: 10(fvec4) FunctionCall 13(@main(struct-PSInput-f1-u11;) 41(param)
Store 40(@entryPointOutput) 43
Return
FunctionEnd
13(@main(struct-PSInput-f1-u11;): 10(fvec4) Function None 11
12(input): 9(ptr) FunctionParameter
14: Label
18: 17(ptr) AccessChain 12(input) 16
19: 7(int) Load 18
20: 6(float) ConvertUToF 19
23: 22(ptr) AccessChain 12(input) 21
24: 6(float) Load 23
27: 10(fvec4) CompositeConstruct 20 24 25 26
ReturnValue 27
FunctionEnd
Test/hlsl.synthesizeInput.frag
0 → 100644
View file @
4329d555
struct
PSInput
{
float
interp
;
uint
no_interp
;
};
float4
main
(
PSInput
input
:
INPUT
)
:
SV_TARGET
{
return
float4
(
float
(
input
.
no_interp
),
input
.
interp
,
0
,
1
);
}
\ No newline at end of file
gtests/Hlsl.FromFile.cpp
View file @
4329d555
...
...
@@ -275,6 +275,7 @@ INSTANTIATE_TEST_CASE_P(
{
"hlsl.structin.vert"
,
"main"
},
{
"hlsl.structIoFourWay.frag"
,
"main"
},
{
"hlsl.structStructName.frag"
,
"main"
},
{
"hlsl.synthesizeInput.frag"
,
"main"
},
{
"hlsl.texture.subvec4.frag"
,
"main"
},
{
"hlsl.this.frag"
,
"main"
},
{
"hlsl.intrinsics.vert"
,
"VertexShaderFunction"
},
...
...
hlsl/hlslParseHelper.cpp
View file @
4329d555
...
...
@@ -1527,8 +1527,6 @@ void HlslParseContext::fixBuiltInIoType(TType& type)
// Variables that correspond to the user-interface in and out of a stage
// (not the built-in interface) are
// - assigned locations
// - corrected for interpolation
// * non-floating point values must be nointerpolation
// - registered as a linkage node (part of the stage's external interface).
// Assumes it is called in the order in which locations should be assigned.
void
HlslParseContext
::
assignToInterface
(
TVariable
&
variable
)
...
...
@@ -1554,21 +1552,6 @@ void HlslParseContext::assignToInterface(TVariable& variable)
nextOutLocation
+=
size
;
}
}
if
(
qualifier
.
storage
==
EvqVaryingIn
&&
language
==
EShLangFragment
)
{
// Going into the fragment stage, integer-based stuff must be flat/nointerpolation
const
auto
fixQualifier
=
[](
TType
&
type
)
{
if
(
type
.
getQualifier
().
builtIn
==
EbvNone
&&
(
type
.
isIntegerDomain
()
||
type
.
getBasicType
()
==
EbtBool
))
{
type
.
getQualifier
().
clearInterpolation
();
type
.
getQualifier
().
flat
=
true
;
}
};
if
(
type
.
isStruct
())
for
(
auto
mem
=
(
*
type
.
getStruct
()).
begin
();
mem
!=
(
*
type
.
getStruct
()).
end
();
++
mem
)
fixQualifier
(
*
mem
->
type
);
else
fixQualifier
(
type
);
}
trackLinkage
(
variable
);
}
};
...
...
@@ -2134,12 +2117,63 @@ void HlslParseContext::handleFunctionBody(const TSourceLoc& loc, TFunction& func
void
HlslParseContext
::
remapEntryPointIO
(
TFunction
&
function
,
TVariable
*&
returnValue
,
TVector
<
TVariable
*>&
inputs
,
TVector
<
TVariable
*>&
outputs
)
{
// We might have in input structure type with no decorations that caused it
// to look like an input type, yet it has (e.g.) interpolation types that
// must be modified that turn it into an input type.
// Hence, a missing ioTypeMap for 'input' might need to be synthesized.
const
auto
synthesizeEditedInput
=
[
this
](
TType
&
type
)
{
// True if a type needs to be 'flat'
const
auto
needsFlat
=
[](
const
TType
&
type
)
{
return
type
.
containsBasicType
(
EbtInt
)
||
type
.
containsBasicType
(
EbtUint
)
||
type
.
containsBasicType
(
EbtInt64
)
||
type
.
containsBasicType
(
EbtUint64
)
||
type
.
containsBasicType
(
EbtBool
)
||
type
.
containsBasicType
(
EbtDouble
);
};
if
(
language
==
EShLangFragment
&&
needsFlat
(
type
))
{
if
(
type
.
isStruct
())
{
TTypeList
*
finalList
=
nullptr
;
auto
it
=
ioTypeMap
.
find
(
type
.
getStruct
());
if
(
it
==
ioTypeMap
.
end
()
||
it
->
second
.
input
==
nullptr
)
{
// Getting here means we have no input struct, but we need one.
auto
list
=
new
TTypeList
;
for
(
auto
member
=
type
.
getStruct
()
->
begin
();
member
!=
type
.
getStruct
()
->
end
();
++
member
)
{
TType
*
newType
=
new
TType
;
newType
->
shallowCopy
(
*
member
->
type
);
TTypeLoc
typeLoc
=
{
newType
,
member
->
loc
};
list
->
push_back
(
typeLoc
);
}
// install the new input type
if
(
it
==
ioTypeMap
.
end
())
{
tIoKinds
newLists
=
{
list
,
nullptr
,
nullptr
};
ioTypeMap
[
type
.
getStruct
()]
=
newLists
;
}
else
it
->
second
.
input
=
list
;
finalList
=
list
;
}
else
finalList
=
it
->
second
.
input
;
// edit for 'flat'
for
(
auto
member
=
finalList
->
begin
();
member
!=
finalList
->
end
();
++
member
)
{
if
(
needsFlat
(
*
member
->
type
))
{
member
->
type
->
getQualifier
().
clearInterpolation
();
member
->
type
->
getQualifier
().
flat
=
true
;
}
}
}
else
{
type
.
getQualifier
().
clearInterpolation
();
type
.
getQualifier
().
flat
=
true
;
}
}
};
// Do the actual work to make a type be a shader input or output variable,
// and clear the original to be non-IO (for use as a normal function parameter/return).
const
auto
makeIoVariable
=
[
this
](
const
char
*
name
,
TType
&
type
,
TStorageQualifier
storage
)
->
TVariable
*
{
TVariable
*
ioVariable
=
makeInternalVariable
(
name
,
type
);
clearUniformInputOutput
(
type
.
getQualifier
());
if
(
type
.
getStruct
()
!=
nullptr
)
{
if
(
type
.
isStruct
()
)
{
auto
newLists
=
ioTypeMap
.
find
(
ioVariable
->
getType
().
getStruct
());
if
(
newLists
!=
ioTypeMap
.
end
())
{
if
(
storage
==
EvqVaryingIn
&&
newLists
->
second
.
input
)
...
...
@@ -2192,6 +2226,7 @@ void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& return
for
(
int
i
=
0
;
i
<
function
.
getParamCount
();
i
++
)
{
TType
&
paramType
=
*
function
[
i
].
type
;
if
(
paramType
.
getQualifier
().
isParamInput
())
{
synthesizeEditedInput
(
paramType
);
TVariable
*
argAsGlobal
=
makeIoVariable
(
function
[
i
].
name
->
c_str
(),
paramType
,
EvqVaryingIn
);
inputs
.
push_back
(
argAsGlobal
);
...
...
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