Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
angle
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
angle
Commits
139b9091
Commit
139b9091
authored
Aug 30, 2013
by
Jamie Madill
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Simplify the gl::Varying struct to be more like sh::Varying.
The subsequent patches will remove gl::Varying entirely. TRAC #23746 Signed-off-by: Nicolas Capens Signed-off-by: Shannon Woods
parent
ce79dda1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
99 additions
and
67 deletions
+99
-67
OutputHLSL.cpp
src/compiler/OutputHLSL.cpp
+26
-2
ShaderVariable.cpp
src/compiler/ShaderVariable.cpp
+3
-2
ShaderVariable.h
src/compiler/ShaderVariable.h
+9
-1
ProgramBinary.cpp
src/libGLESv2/ProgramBinary.cpp
+38
-38
Shader.cpp
src/libGLESv2/Shader.cpp
+3
-5
Shader.h
src/libGLESv2/Shader.h
+20
-19
No files found.
src/compiler/OutputHLSL.cpp
View file @
139b9091
...
@@ -3643,18 +3643,42 @@ void OutputHLSL::declareUniformToList(const TType &type, const TString &name, in
...
@@ -3643,18 +3643,42 @@ void OutputHLSL::declareUniformToList(const TType &type, const TString &name, in
}
}
}
}
InterpolationType
getInterpolationType
(
TQualifier
qualifier
)
{
switch
(
qualifier
)
{
case
EvqFlatIn
:
case
EvqFlatOut
:
return
INTERPOLATION_FLAT
;
case
EvqSmoothIn
:
case
EvqSmoothOut
:
case
EvqVertexOut
:
case
EvqFragmentIn
:
return
INTERPOLATION_SMOOTH
;
case
EvqCentroidIn
:
case
EvqCentroidOut
:
return
INTERPOLATION_CENTROID
;
default
:
UNREACHABLE
();
return
INTERPOLATION_SMOOTH
;
}
}
void
OutputHLSL
::
declareVaryingToList
(
const
TType
&
type
,
const
TString
&
name
,
std
::
vector
<
Varying
>&
fieldsOut
)
void
OutputHLSL
::
declareVaryingToList
(
const
TType
&
type
,
const
TString
&
name
,
std
::
vector
<
Varying
>&
fieldsOut
)
{
{
const
TStructure
*
structure
=
type
.
getStruct
();
const
TStructure
*
structure
=
type
.
getStruct
();
InterpolationType
interpolation
=
getInterpolationType
(
type
.
getQualifier
());
if
(
!
structure
)
if
(
!
structure
)
{
{
Varying
varying
(
glVariableType
(
type
),
glVariablePrecision
(
type
),
name
.
c_str
(),
(
unsigned
int
)
type
.
getArraySize
());
Varying
varying
(
glVariableType
(
type
),
glVariablePrecision
(
type
),
name
.
c_str
(),
(
unsigned
int
)
type
.
getArraySize
()
,
interpolation
);
fieldsOut
.
push_back
(
varying
);
fieldsOut
.
push_back
(
varying
);
}
}
else
else
{
{
Varying
structVarying
(
GL_NONE
,
GL_NONE
,
name
.
c_str
(),
(
unsigned
int
)
type
.
getArraySize
());
Varying
structVarying
(
GL_NONE
,
GL_NONE
,
name
.
c_str
(),
(
unsigned
int
)
type
.
getArraySize
()
,
interpolation
);
const
TFieldList
&
fields
=
structure
->
fields
();
const
TFieldList
&
fields
=
structure
->
fields
();
for
(
size_t
fieldIndex
=
0
;
fieldIndex
<
fields
.
size
();
fieldIndex
++
)
for
(
size_t
fieldIndex
=
0
;
fieldIndex
<
fields
.
size
();
fieldIndex
++
)
...
...
src/compiler/ShaderVariable.cpp
View file @
139b9091
...
@@ -41,8 +41,9 @@ InterfaceBlockField::InterfaceBlockField(GLenum typeIn, GLenum precisionIn, cons
...
@@ -41,8 +41,9 @@ InterfaceBlockField::InterfaceBlockField(GLenum typeIn, GLenum precisionIn, cons
{
{
}
}
Varying
::
Varying
(
GLenum
typeIn
,
GLenum
precisionIn
,
const
char
*
nameIn
,
unsigned
int
arraySizeIn
)
Varying
::
Varying
(
GLenum
typeIn
,
GLenum
precisionIn
,
const
char
*
nameIn
,
unsigned
int
arraySizeIn
,
InterpolationType
interpolationIn
)
:
ShaderVariable
(
typeIn
,
precisionIn
,
nameIn
,
arraySizeIn
)
:
ShaderVariable
(
typeIn
,
precisionIn
,
nameIn
,
arraySizeIn
),
interpolation
(
interpolationIn
)
{
{
}
}
...
...
src/compiler/ShaderVariable.h
View file @
139b9091
...
@@ -17,6 +17,13 @@
...
@@ -17,6 +17,13 @@
namespace
sh
namespace
sh
{
{
enum
InterpolationType
{
INTERPOLATION_SMOOTH
,
INTERPOLATION_CENTROID
,
INTERPOLATION_FLAT
};
struct
ShaderVariable
struct
ShaderVariable
{
{
GLenum
type
;
GLenum
type
;
...
@@ -57,9 +64,10 @@ struct InterfaceBlockField : public ShaderVariable
...
@@ -57,9 +64,10 @@ struct InterfaceBlockField : public ShaderVariable
struct
Varying
:
public
ShaderVariable
struct
Varying
:
public
ShaderVariable
{
{
InterpolationType
interpolation
;
std
::
vector
<
Varying
>
fields
;
std
::
vector
<
Varying
>
fields
;
Varying
(
GLenum
typeIn
,
GLenum
precisionIn
,
const
char
*
nameIn
,
unsigned
int
arraySizeIn
);
Varying
(
GLenum
typeIn
,
GLenum
precisionIn
,
const
char
*
nameIn
,
unsigned
int
arraySizeIn
,
InterpolationType
interpolationIn
);
bool
isStruct
()
const
{
return
!
fields
.
empty
();
}
bool
isStruct
()
const
{
return
!
fields
.
empty
();
}
};
};
...
...
src/libGLESv2/ProgramBinary.cpp
View file @
139b9091
...
@@ -936,7 +936,7 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
...
@@ -936,7 +936,7 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
{
{
Varying
*
varying
=
&
fragmentShader
->
mVaryings
[
varyingIndex
];
Varying
*
varying
=
&
fragmentShader
->
mVaryings
[
varyingIndex
];
GLenum
transposedType
=
TransposeMatrixType
(
varying
->
type
);
GLenum
transposedType
=
TransposeMatrixType
(
varying
->
type
);
int
n
=
VariableRowCount
(
transposedType
)
*
varying
->
size
;
int
n
=
VariableRowCount
(
transposedType
)
*
varying
->
elementCount
()
;
int
m
=
VariableColumnCount
(
transposedType
);
int
m
=
VariableColumnCount
(
transposedType
);
bool
success
=
false
;
bool
success
=
false
;
...
@@ -959,8 +959,8 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
...
@@ -959,8 +959,8 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
if
(
available
)
if
(
available
)
{
{
varying
->
reg
=
r
;
varying
->
reg
isterIndex
=
r
;
varying
->
col
=
0
;
varying
->
elementIndex
=
0
;
for
(
int
y
=
0
;
y
<
n
;
y
++
)
for
(
int
y
=
0
;
y
<
n
;
y
++
)
{
{
...
@@ -993,8 +993,8 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
...
@@ -993,8 +993,8 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
if
(
available
)
if
(
available
)
{
{
varying
->
reg
=
r
;
varying
->
reg
isterIndex
=
r
;
varying
->
col
=
2
;
varying
->
elementIndex
=
2
;
for
(
int
y
=
0
;
y
<
n
;
y
++
)
for
(
int
y
=
0
;
y
<
n
;
y
++
)
{
{
...
@@ -1037,7 +1037,7 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
...
@@ -1037,7 +1037,7 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
{
{
if
(
!
packing
[
r
][
column
])
if
(
!
packing
[
r
][
column
])
{
{
varying
->
reg
=
r
;
varying
->
reg
isterIndex
=
r
;
for
(
int
y
=
r
;
y
<
r
+
n
;
y
++
)
for
(
int
y
=
r
;
y
<
r
+
n
;
y
++
)
{
{
...
@@ -1048,7 +1048,7 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
...
@@ -1048,7 +1048,7 @@ int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], F
}
}
}
}
varying
->
col
=
column
;
varying
->
elementIndex
=
column
;
success
=
true
;
success
=
true
;
}
}
...
@@ -1152,15 +1152,15 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
...
@@ -1152,15 +1152,15 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
Varying
*
output
=
&
vertexShader
->
mVaryings
[
vertVaryingIndex
];
Varying
*
output
=
&
vertexShader
->
mVaryings
[
vertVaryingIndex
];
if
(
output
->
name
==
input
->
name
)
if
(
output
->
name
==
input
->
name
)
{
{
if
(
output
->
type
!=
input
->
type
||
output
->
size
!=
input
->
s
ize
||
output
->
interpolation
!=
input
->
interpolation
)
if
(
output
->
type
!=
input
->
type
||
output
->
arraySize
!=
input
->
arrayS
ize
||
output
->
interpolation
!=
input
->
interpolation
)
{
{
infoLog
.
append
(
"Type of vertex varying %s does not match that of the fragment varying"
,
output
->
name
.
c_str
());
infoLog
.
append
(
"Type of vertex varying %s does not match that of the fragment varying"
,
output
->
name
.
c_str
());
return
false
;
return
false
;
}
}
output
->
reg
=
input
->
reg
;
output
->
reg
isterIndex
=
input
->
registerIndex
;
output
->
col
=
input
->
col
;
output
->
elementIndex
=
input
->
elementIndex
;
matched
=
true
;
matched
=
true
;
break
;
break
;
...
@@ -1302,15 +1302,15 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
...
@@ -1302,15 +1302,15 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
for
(
unsigned
int
vertVaryingIndex
=
0
;
vertVaryingIndex
<
vertexShader
->
mVaryings
.
size
();
vertVaryingIndex
++
)
for
(
unsigned
int
vertVaryingIndex
=
0
;
vertVaryingIndex
<
vertexShader
->
mVaryings
.
size
();
vertVaryingIndex
++
)
{
{
Varying
*
varying
=
&
vertexShader
->
mVaryings
[
vertVaryingIndex
];
Varying
*
varying
=
&
vertexShader
->
mVaryings
[
vertVaryingIndex
];
if
(
varying
->
reg
>=
0
)
if
(
varying
->
reg
isterAssigned
()
)
{
{
for
(
int
i
=
0
;
i
<
varying
->
size
;
i
++
)
for
(
unsigned
int
elementIndex
=
0
;
elementIndex
<
varying
->
elementCount
();
elementIndex
++
)
{
{
int
r
ows
=
VariableRowCount
(
TransposeMatrixType
(
varying
->
type
));
int
variableR
ows
=
VariableRowCount
(
TransposeMatrixType
(
varying
->
type
));
for
(
int
j
=
0
;
j
<
rows
;
j
++
)
for
(
int
row
=
0
;
row
<
variableRows
;
row
++
)
{
{
int
r
=
varying
->
reg
+
i
*
rows
+
j
;
int
r
=
varying
->
reg
isterIndex
+
elementIndex
*
variableRows
+
row
;
vertexHLSL
+=
" output.v"
+
str
(
r
);
vertexHLSL
+=
" output.v"
+
str
(
r
);
bool
sharedRegister
=
false
;
// Register used by multiple varyings
bool
sharedRegister
=
false
;
// Register used by multiple varyings
...
@@ -1343,16 +1343,16 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
...
@@ -1343,16 +1343,16 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
}
}
}
}
vertexHLSL
+=
" = "
+
varying
->
name
;
vertexHLSL
+=
" =
_
"
+
varying
->
name
;
if
(
varying
->
array
)
if
(
varying
->
isArray
()
)
{
{
vertexHLSL
+=
arrayString
(
i
);
vertexHLSL
+=
arrayString
(
elementIndex
);
}
}
if
(
r
ows
>
1
)
if
(
variableR
ows
>
1
)
{
{
vertexHLSL
+=
arrayString
(
j
);
vertexHLSL
+=
arrayString
(
row
);
}
}
vertexHLSL
+=
";
\n
"
;
vertexHLSL
+=
";
\n
"
;
...
@@ -1501,25 +1501,25 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
...
@@ -1501,25 +1501,25 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
fragmentShader
->
mVaryings
.
size
();
varyingIndex
++
)
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
fragmentShader
->
mVaryings
.
size
();
varyingIndex
++
)
{
{
Varying
*
varying
=
&
fragmentShader
->
mVaryings
[
varyingIndex
];
Varying
*
varying
=
&
fragmentShader
->
mVaryings
[
varyingIndex
];
if
(
varying
->
reg
>=
0
)
if
(
varying
->
reg
isterAssigned
()
)
{
{
for
(
int
i
=
0
;
i
<
varying
->
size
;
i
++
)
for
(
unsigned
int
elementIndex
=
0
;
elementIndex
<
varying
->
elementCount
();
elementIndex
++
)
{
{
GLenum
transposedType
=
TransposeMatrixType
(
varying
->
type
);
GLenum
transposedType
=
TransposeMatrixType
(
varying
->
type
);
int
r
ows
=
VariableRowCount
(
transposedType
);
int
variableR
ows
=
VariableRowCount
(
transposedType
);
for
(
int
j
=
0
;
j
<
rows
;
j
++
)
for
(
int
row
=
0
;
row
<
variableRows
;
row
++
)
{
{
std
::
string
n
=
str
(
varying
->
reg
+
i
*
rows
+
j
);
std
::
string
n
=
str
(
varying
->
reg
isterIndex
+
elementIndex
*
variableRows
+
row
);
pixelHLSL
+=
" "
+
varying
->
name
;
pixelHLSL
+=
"
_
"
+
varying
->
name
;
if
(
varying
->
array
)
if
(
varying
->
isArray
()
)
{
{
pixelHLSL
+=
arrayString
(
i
);
pixelHLSL
+=
arrayString
(
elementIndex
);
}
}
if
(
r
ows
>
1
)
if
(
variableR
ows
>
1
)
{
{
pixelHLSL
+=
arrayString
(
j
);
pixelHLSL
+=
arrayString
(
row
);
}
}
switch
(
VariableColumnCount
(
transposedType
))
switch
(
VariableColumnCount
(
transposedType
))
...
@@ -1582,23 +1582,23 @@ std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, c
...
@@ -1582,23 +1582,23 @@ std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, c
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
fragmentShader
->
mVaryings
.
size
();
varyingIndex
++
)
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
fragmentShader
->
mVaryings
.
size
();
varyingIndex
++
)
{
{
Varying
*
varying
=
&
fragmentShader
->
mVaryings
[
varyingIndex
];
Varying
*
varying
=
&
fragmentShader
->
mVaryings
[
varyingIndex
];
if
(
varying
->
reg
>=
0
)
if
(
varying
->
reg
isterAssigned
()
)
{
{
for
(
int
i
=
0
;
i
<
varying
->
size
;
i
++
)
for
(
unsigned
int
elementIndex
=
0
;
elementIndex
<
varying
->
elementCount
();
elementIndex
++
)
{
{
GLenum
transposedType
=
TransposeMatrixType
(
varying
->
type
);
GLenum
transposedType
=
TransposeMatrixType
(
varying
->
type
);
int
r
ows
=
VariableRowCount
(
transposedType
);
int
variableR
ows
=
VariableRowCount
(
transposedType
);
for
(
int
j
=
0
;
j
<
rows
;
j
++
)
for
(
int
row
=
0
;
row
<
variableRows
;
row
++
)
{
{
switch
(
varying
->
interpolation
)
switch
(
varying
->
interpolation
)
{
{
case
Smooth
:
varyingHLSL
+=
" "
;
break
;
case
sh
:
:
INTERPOLATION_SMOOTH
:
varyingHLSL
+=
" "
;
break
;
case
Flat
:
varyingHLSL
+=
" nointerpolation "
;
break
;
case
sh
:
:
INTERPOLATION_FLAT
:
varyingHLSL
+=
" nointerpolation "
;
break
;
case
Centroid
:
varyingHLSL
+=
" centroid "
;
break
;
case
sh
:
:
INTERPOLATION_CENTROID
:
varyingHLSL
+=
" centroid "
;
break
;
default
:
UNREACHABLE
();
default
:
UNREACHABLE
();
}
}
std
::
string
n
=
str
(
varying
->
reg
+
i
*
rows
+
j
);
std
::
string
n
=
str
(
varying
->
reg
isterIndex
+
elementIndex
*
variableRows
+
row
);
std
::
string
typeString
=
gl_d3d
::
TypeString
(
UniformComponentType
(
transposedType
))
+
str
(
VariableColumnCount
(
transposedType
));
std
::
string
typeString
=
gl_d3d
::
TypeString
(
UniformComponentType
(
transposedType
))
+
str
(
VariableColumnCount
(
transposedType
));
varyingHLSL
+=
typeString
+
" v"
+
n
+
" : "
+
varyingSemantic
+
n
+
";
\n
"
;
varyingHLSL
+=
typeString
+
" v"
+
n
+
" : "
+
varyingSemantic
+
n
+
";
\n
"
;
...
...
src/libGLESv2/Shader.cpp
View file @
139b9091
...
@@ -219,7 +219,7 @@ void Shader::parseVaryings(void *compiler)
...
@@ -219,7 +219,7 @@ void Shader::parseVaryings(void *compiler)
{
{
if
(
!
mHlsl
.
empty
())
if
(
!
mHlsl
.
empty
())
{
{
std
::
vector
<
sh
::
ShaderVariable
>
*
activeVaryings
;
std
::
vector
<
sh
::
Varying
>
*
activeVaryings
;
ShGetInfoPointer
(
compiler
,
SH_ACTIVE_VARYINGS_ARRAY
,
reinterpret_cast
<
void
**>
(
&
activeVaryings
));
ShGetInfoPointer
(
compiler
,
SH_ACTIVE_VARYINGS_ARRAY
,
reinterpret_cast
<
void
**>
(
&
activeVaryings
));
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
activeVaryings
->
size
();
varyingIndex
++
)
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
activeVaryings
->
size
();
varyingIndex
++
)
...
@@ -243,9 +243,7 @@ void Shader::resetVaryingsRegisterAssignment()
...
@@ -243,9 +243,7 @@ void Shader::resetVaryingsRegisterAssignment()
{
{
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
mVaryings
.
size
();
varyingIndex
++
)
for
(
unsigned
int
varyingIndex
=
0
;
varyingIndex
<
mVaryings
.
size
();
varyingIndex
++
)
{
{
Varying
*
varying
=
&
mVaryings
[
varyingIndex
];
mVaryings
[
varyingIndex
].
resetRegisterAssignment
();
varying
->
reg
=
-
1
;
varying
->
col
=
-
1
;
}
}
}
}
...
@@ -420,7 +418,7 @@ bool Shader::compareVarying(const Varying &x, const Varying &y)
...
@@ -420,7 +418,7 @@ bool Shader::compareVarying(const Varying &x, const Varying &y)
{
{
if
(
x
.
type
==
y
.
type
)
if
(
x
.
type
==
y
.
type
)
{
{
return
x
.
size
>
y
.
s
ize
;
return
x
.
arraySize
>
y
.
arrayS
ize
;
}
}
unsigned
int
xPriority
=
GL_INVALID_INDEX
;
unsigned
int
xPriority
=
GL_INVALID_INDEX
;
...
...
src/libGLESv2/Shader.h
View file @
139b9091
...
@@ -31,33 +31,34 @@ namespace gl
...
@@ -31,33 +31,34 @@ namespace gl
{
{
class
ResourceManager
;
class
ResourceManager
;
enum
Interpolation
{
Smooth
,
Centroid
,
Flat
};
struct
Varying
struct
Varying
{
{
Varying
(
const
sh
::
ShaderVariable
&
shaderVar
)
Varying
(
const
sh
::
Varying
&
shaderVar
)
:
interpolation
(
Smooth
),
:
interpolation
(
shaderVar
.
interpolation
),
type
(
shaderVar
.
type
),
type
(
shaderVar
.
type
),
name
(
"_"
+
shaderVar
.
name
),
name
(
shaderVar
.
name
),
size
(
std
::
max
((
int
)
shaderVar
.
arraySize
,
1
)),
arraySize
(
shaderVar
.
arraySize
),
array
(
shaderVar
.
arraySize
>
0
),
registerIndex
(
GL_INVALID_INDEX
),
reg
(
-
1
),
elementIndex
(
GL_INVALID_INDEX
)
col
(
-
1
)
{}
{}
Interpolation
interpolation
;
sh
::
InterpolationType
interpolation
;
GLenum
type
;
GLenum
type
;
std
::
string
name
;
std
::
string
name
;
int
size
;
// Number of 'type' elements
unsigned
int
arraySize
;
bool
array
;
bool
isArray
()
const
{
return
arraySize
>
0
;
}
unsigned
int
elementCount
()
const
{
return
std
::
max
(
1u
,
arraySize
);
}
bool
registerAssigned
()
const
{
return
registerIndex
!=
GL_INVALID_INDEX
;
}
void
resetRegisterAssignment
()
{
registerIndex
=
GL_INVALID_INDEX
;
elementIndex
=
GL_INVALID_INDEX
;
}
int
reg
;
// First varying register, assigned during link
unsigned
int
registerIndex
;
// First varying register, assigned during link
int
col
;
// First register element, assigned during link
unsigned
int
elementIndex
;
// First register element, assigned during link
};
};
class
Shader
class
Shader
...
...
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