Commit c9d9b30a by Nicolas Capens

Set symbol extension at insertion.

BUG=angle:926 Change-Id: I4c96ae89c79d720d99bde803541c3158ba4629ab Reviewed-on: https://chromium-review.googlesource.com/251662Tested-by: 's avatarNicolas Capens <capn@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 05ae50dc
...@@ -255,10 +255,10 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR ...@@ -255,10 +255,10 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
/* The *Grad* variants are new to both vertex and fragment shaders; the fragment /* The *Grad* variants are new to both vertex and fragment shaders; the fragment
* shader specific pieces are added separately below. * shader specific pieces are added separately below.
*/ */
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DGradEXT", sampler2D, float2, float2, float2); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DGradEXT", sampler2D, float2, float2, float2);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeGradEXT", samplerCube, float3, float3, float3);
} }
if (type == GL_FRAGMENT_SHADER) if (type == GL_FRAGMENT_SHADER)
...@@ -270,17 +270,17 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR ...@@ -270,17 +270,17 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
if (resources.OES_standard_derivatives) if (resources.OES_standard_derivatives)
{ {
symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdx, genType, "dFdx", genType); symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdx, "GL_OES_standard_derivatives", genType, "dFdx", genType);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdy, genType, "dFdy", genType); symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdy, "GL_OES_standard_derivatives", genType, "dFdy", genType);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpFwidth, genType, "fwidth", genType); symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpFwidth, "GL_OES_standard_derivatives", genType, "fwidth", genType);
} }
if (resources.EXT_shader_texture_lod) if (resources.EXT_shader_texture_lod)
{ {
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLodEXT", sampler2D, float2, float1); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DLodEXT", sampler2D, float2, float1);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float3, float1); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float3, float1);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float4, float1); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float4, float1);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLodEXT", samplerCube, float3, float1); symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeLodEXT", samplerCube, float3, float1);
} }
} }
...@@ -352,9 +352,9 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR ...@@ -352,9 +352,9 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
if (type == GL_FRAGMENT_SHADER) if (type == GL_FRAGMENT_SHADER)
{ {
symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdx, genType, "dFdx", genType); symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdx, "GL_OES_standard_derivatives", genType, "dFdx", genType);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdy, genType, "dFdy", genType); symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdy, "GL_OES_standard_derivatives", genType, "dFdy", genType);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFwidth, genType, "fwidth", genType); symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFwidth, "GL_OES_standard_derivatives", genType, "fwidth", genType);
} }
symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2);
...@@ -493,21 +493,20 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, ...@@ -493,21 +493,20 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
if (resources.EXT_frag_depth) { if (resources.EXT_frag_depth) {
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_frag_depth", new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1)));
symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_FragDepthEXT", "GL_EXT_frag_depth");
} }
if (resources.EXT_shader_framebuffer_fetch) if (resources.EXT_shader_framebuffer_fetch)
{ {
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_LastFragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqLastFragData, 4))); symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqLastFragData, 4)));
} }
else if (resources.NV_shader_framebuffer_fetch) else if (resources.NV_shader_framebuffer_fetch)
{ {
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_LastFragColor"), TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragColor"), TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_LastFragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqLastFragData, 4))); symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqLastFragData, 4)));
} }
else if (resources.ARM_shader_framebuffer_fetch) else if (resources.ARM_shader_framebuffer_fetch)
{ {
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_LastFragColorARM"), TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragColorARM"), TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
} }
} else { } else {
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4))); symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4)));
...@@ -525,42 +524,6 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, ...@@ -525,42 +524,6 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
default: assert(false && "Language not supported"); default: assert(false && "Language not supported");
} }
// Map language-specific operators.
switch(type) {
case GL_VERTEX_SHADER:
break;
case GL_FRAGMENT_SHADER:
if (resources.OES_standard_derivatives)
{
symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdx", "GL_OES_standard_derivatives");
symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdy", "GL_OES_standard_derivatives");
symbolTable.relateToExtension(ESSL1_BUILTINS, "fwidth", "GL_OES_standard_derivatives");
}
if (resources.EXT_shader_texture_lod)
{
symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DLodEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjLodEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeLodEXT", "GL_EXT_shader_texture_lod");
}
if (resources.NV_shader_framebuffer_fetch)
{
symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_LastFragColor", "GL_NV_shader_framebuffer_fetch");
}
else if (resources.ARM_shader_framebuffer_fetch)
{
symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_LastFragColorARM", "GL_ARM_shader_framebuffer_fetch");
}
break;
default: break;
}
if (resources.EXT_shader_texture_lod)
{
symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DGradEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjGradEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeGradEXT", "GL_EXT_shader_texture_lod");
}
// Finally add resource-specific variables. // Finally add resource-specific variables.
switch(type) { switch(type) {
case GL_FRAGMENT_SHADER: case GL_FRAGMENT_SHADER:
...@@ -574,15 +537,14 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, ...@@ -574,15 +537,14 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
// Set up gl_LastFragData. The array size. // Set up gl_LastFragData. The array size.
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
lastFragData.setArraySize(resources.MaxDrawBuffers); lastFragData.setArraySize(resources.MaxDrawBuffers);
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
if (resources.EXT_shader_framebuffer_fetch) if (resources.EXT_shader_framebuffer_fetch)
{ {
symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_LastFragData", "GL_EXT_shader_framebuffer_fetch"); symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
} }
else if (resources.NV_shader_framebuffer_fetch) else if (resources.NV_shader_framebuffer_fetch)
{ {
symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_LastFragData", "GL_NV_shader_framebuffer_fetch"); symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
} }
} }
} }
......
...@@ -57,22 +57,6 @@ TSymbol *TSymbolTableLevel::find(const TString &name) const ...@@ -57,22 +57,6 @@ TSymbol *TSymbolTableLevel::find(const TString &name) const
return (*it).second; return (*it).second;
} }
//
// Change all function entries in the table with the non-mangled name
// to be related to the provided built-in extension. This is a low
// performance operation, and only intended for symbol tables that
// live across a large number of compiles.
//
void TSymbolTableLevel::relateToExtension(const char *name, const TString &ext)
{
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
{
TSymbol *symbol = it->second;
if (symbol->getName() == name)
symbol->relateToExtension(ext);
}
}
TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, TSymbol *TSymbolTable::find(const TString &name, int shaderVersion,
bool *builtIn, bool *sameScope) const bool *builtIn, bool *sameScope) const
{ {
...@@ -187,7 +171,8 @@ TType *VectorType(TType *type, int size) ...@@ -187,7 +171,8 @@ TType *VectorType(TType *type, int size)
} }
} }
void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name,
TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5)
{ {
if (ptype1->getBasicType() == EbtGSampler2D) if (ptype1->getBasicType() == EbtGSampler2D)
{ {
...@@ -220,21 +205,21 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue ...@@ -220,21 +205,21 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue
else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3)) else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
{ {
ASSERT(!ptype4 && !ptype5); ASSERT(!ptype4 && !ptype5);
insertBuiltIn(level, op, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1)); insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1));
insertBuiltIn(level, op, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2)); insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2));
insertBuiltIn(level, op, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3)); insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3));
insertBuiltIn(level, op, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), SpecificType(ptype2, 4), SpecificType(ptype3, 4)); insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), SpecificType(ptype2, 4), SpecificType(ptype3, 4));
} }
else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3)) else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
{ {
ASSERT(!ptype4 && !ptype5); ASSERT(!ptype4 && !ptype5);
insertBuiltIn(level, op, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2)); insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2));
insertBuiltIn(level, op, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3)); insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3));
insertBuiltIn(level, op, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4)); insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4));
} }
else else
{ {
TFunction *function = new TFunction(NewPoolTString(name), *rvalue, op); TFunction *function = new TFunction(NewPoolTString(name), *rvalue, op, ext);
TParameter param1 = {0, ptype1}; TParameter param1 = {0, ptype1};
function->addParameter(param1); function->addParameter(param1);
......
...@@ -186,13 +186,14 @@ class TFunction : public TSymbol ...@@ -186,13 +186,14 @@ class TFunction : public TSymbol
defined(false) defined(false)
{ {
} }
TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull) TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull, const char *ext = "")
: TSymbol(name), : TSymbol(name),
returnType(retType), returnType(retType),
mangledName(TFunction::mangleName(*name)), mangledName(TFunction::mangleName(*name)),
op(tOp), op(tOp),
defined(false) defined(false)
{ {
relateToExtension(ext);
} }
virtual ~TFunction(); virtual ~TFunction();
virtual bool isFunction() const virtual bool isFunction() const
...@@ -289,8 +290,6 @@ class TSymbolTableLevel ...@@ -289,8 +290,6 @@ class TSymbolTableLevel
TSymbol *find(const TString &name) const; TSymbol *find(const TString &name) const;
void relateToExtension(const char *name, const TString &ext);
protected: protected:
tLevel level; tLevel level;
}; };
...@@ -358,6 +357,12 @@ class TSymbolTable ...@@ -358,6 +357,12 @@ class TSymbolTable
return table[level]->insert(symbol); return table[level]->insert(symbol);
} }
bool insert(ESymbolLevel level, const char *ext, TSymbol *symbol)
{
symbol->relateToExtension(ext);
return table[level]->insert(symbol);
}
bool insertConstInt(ESymbolLevel level, const char *name, int value) bool insertConstInt(ESymbolLevel level, const char *name, int value)
{ {
TVariable *constant = new TVariable( TVariable *constant = new TVariable(
...@@ -366,13 +371,25 @@ class TSymbolTable ...@@ -366,13 +371,25 @@ class TSymbolTable
return insert(level, constant); return insert(level, constant);
} }
void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name,
TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0);
TType *ptype4 = 0, TType *ptype5 = 0);
void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name,
TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
{ {
insertBuiltIn(level, EOpNull, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
void insertBuiltIn(ESymbolLevel level, const char *ext, TType *rvalue, const char *name,
TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
{
insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name,
TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
{
insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
} }
TSymbol *find(const TString &name, int shaderVersion, TSymbol *find(const TString &name, int shaderVersion,
...@@ -385,10 +402,6 @@ class TSymbolTable ...@@ -385,10 +402,6 @@ class TSymbolTable
return table[currentLevel() - 1]; return table[currentLevel() - 1];
} }
void relateToExtension(ESymbolLevel level, const char *name, const TString &ext)
{
table[level]->relateToExtension(name, ext);
}
void dump(TInfoSink &infoSink) const; void dump(TInfoSink &infoSink) const;
bool setDefaultPrecision(const TPublicType &type, TPrecision prec) bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment