opengl translator: GLSL ES translation
There are some differences between GLSL/ES and Desktop GLSL. This change translate the GLSL/ES shader source to be compatible with the desktop GLSL language. Change-Id: Ia6fdd6a90944926adcf440299b9ea3a4500d1eb1
This commit is contained in:
committed by
Guy Zadikario
parent
d61fb75ef8
commit
dd26774dac
@@ -7,10 +7,11 @@ translator_path := $(LOCAL_PATH)/..
|
|||||||
#exclude darwin builds
|
#exclude darwin builds
|
||||||
ifeq (, $(findstring $(HOST_OS), darwin))
|
ifeq (, $(findstring $(HOST_OS), darwin))
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
GLESv2Context.cpp \
|
GLESv2Imp.cpp \
|
||||||
GLESv2Validate.cpp \
|
GLESv2Context.cpp \
|
||||||
GLESv2Imp.cpp
|
GLESv2Validate.cpp \
|
||||||
|
ShaderParser.cpp \
|
||||||
|
|
||||||
LOCAL_C_INCLUDES += \
|
LOCAL_C_INCLUDES += \
|
||||||
$(translator_path)/include \
|
$(translator_path)/include \
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "GLESv2Context.h"
|
#include "GLESv2Context.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void GLESv2Context::init() {
|
void GLESv2Context::init() {
|
||||||
android::Mutex::Autolock mutex(s_lock);
|
android::Mutex::Autolock mutex(s_lock);
|
||||||
if(!m_initialized) {
|
if(!m_initialized) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <utils/threads.h>
|
#include <utils/threads.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GLESv2Context : public GLEScontext{
|
class GLESv2Context : public GLEScontext{
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
@@ -31,7 +32,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void sendArr(GLvoid* arr,GLenum arrayType,GLint size,GLsizei stride,int pointsIndex = -1);
|
void sendArr(GLvoid* arr,GLenum arrayType,GLint size,GLsizei stride,int pointsIndex = -1);
|
||||||
void initExtensionString();
|
void initExtensionString();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <GLcommon/ThreadInfo.h>
|
#include <GLcommon/ThreadInfo.h>
|
||||||
#include "GLESv2Context.h"
|
#include "GLESv2Context.h"
|
||||||
#include "GLESv2Validate.h"
|
#include "GLESv2Validate.h"
|
||||||
|
#include "ShaderParser.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
@@ -313,11 +314,13 @@ GL_APICALL GLuint GL_APIENTRY glCreateProgram(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
GL_APICALL GLuint GL_APIENTRY glCreateShader(GLenum type){
|
GL_APICALL GLuint GL_APIENTRY glCreateShader(GLenum type){
|
||||||
GET_CTX_RET(0);
|
GET_CTX_V2_RET(0);
|
||||||
const GLuint globalShaderName = ctx->dispatcher().glCreateShader(type);
|
const GLuint globalShaderName = ctx->dispatcher().glCreateShader(type);
|
||||||
if(thrd->shareGroup.Ptr() && globalShaderName) {
|
if(thrd->shareGroup.Ptr() && globalShaderName) {
|
||||||
const GLuint localShaderName = thrd->shareGroup->genName(SHADER);
|
const GLuint localShaderName = thrd->shareGroup->genName(SHADER);
|
||||||
|
ShaderParser* sp = new ShaderParser(type);
|
||||||
thrd->shareGroup->replaceGlobalName(SHADER,localShaderName,globalShaderName);
|
thrd->shareGroup->replaceGlobalName(SHADER,localShaderName,globalShaderName);
|
||||||
|
thrd->shareGroup->setObjectData(SHADER,localShaderName,ObjectDataPtr(sp));
|
||||||
return localShaderName;
|
return localShaderName;
|
||||||
}
|
}
|
||||||
if(globalShaderName){
|
if(globalShaderName){
|
||||||
@@ -381,7 +384,8 @@ GL_APICALL void GL_APIENTRY glDeleteProgram(GLuint program){
|
|||||||
GET_CTX();
|
GET_CTX();
|
||||||
if(thrd->shareGroup.Ptr()) {
|
if(thrd->shareGroup.Ptr()) {
|
||||||
const GLuint globalProgramName = thrd->shareGroup->getGlobalName(SHADER,program);
|
const GLuint globalProgramName = thrd->shareGroup->getGlobalName(SHADER,program);
|
||||||
ctx->dispatcher().glDeleteProgram(globalProgramName);
|
thrd->shareGroup->deleteName(SHADER,program);
|
||||||
|
ctx->dispatcher().glDeleteProgram(program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +393,8 @@ GL_APICALL void GL_APIENTRY glDeleteShader(GLuint shader){
|
|||||||
GET_CTX();
|
GET_CTX();
|
||||||
if(thrd->shareGroup.Ptr()) {
|
if(thrd->shareGroup.Ptr()) {
|
||||||
const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
|
const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
|
||||||
ctx->dispatcher().glDeleteShader(globalShaderName);
|
thrd->shareGroup->deleteName(SHADER,shader);
|
||||||
|
ctx->dispatcher().glDeleteShader(shader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,17 +690,28 @@ GL_APICALL void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision){
|
GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision){
|
||||||
GET_CTX();
|
GET_CTX_V2();
|
||||||
ctx->dispatcher().glGetShaderPrecisionFormat(shadertype,precisiontype,range,precision);
|
SET_ERROR_IF(!(GLESv2Validate::shaderType(shadertype) && GLESv2Validate::precisionType(precisiontype)),GL_INVALID_ENUM);
|
||||||
|
if(ctx->glslVersion() < Version(1,30,10)){ //version 1.30.10 is the first version of GLSL Language containing precision qualifiers
|
||||||
|
range[0] = range[1] = 0;
|
||||||
|
precision = 0;
|
||||||
|
} else {
|
||||||
|
ctx->dispatcher().glGetShaderPrecisionFormat(shadertype,precisiontype,range,precision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: may need to convert the source to fit to gles 2.0 shadders
|
|
||||||
GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source){
|
GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source){
|
||||||
GET_CTX();
|
GET_CTX();
|
||||||
if(thrd->shareGroup.Ptr()) {
|
if(thrd->shareGroup.Ptr()) {
|
||||||
const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
|
const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
|
||||||
ctx->dispatcher().glGetShaderSource(globalShaderName,bufsize,length,source);
|
SET_ERROR_IF(globalShaderName == 0,GL_INVALID_VALUE);
|
||||||
//now need to convert it to match gles syntax
|
ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,shader);
|
||||||
|
SET_ERROR_IF(!objData.Ptr(),GL_INVALID_OPERATION);
|
||||||
|
const char* src = ((ShaderParser*)objData.Ptr())->getOriginalSrc();
|
||||||
|
int srcLength = strlen(src);
|
||||||
|
SET_ERROR_IF(bufsize < 0 || srcLength > bufsize,GL_INVALID_VALUE);
|
||||||
|
*length = srcLength;
|
||||||
|
strncpy(source,src,srcLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -969,12 +985,17 @@ GL_APICALL void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: may need to change the source to match to GL shaders format
|
|
||||||
GL_APICALL void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length){
|
GL_APICALL void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length){
|
||||||
GET_CTX();
|
GET_CTX_V2();
|
||||||
|
SET_ERROR_IF(count < 0,GL_INVALID_VALUE);
|
||||||
if(thrd->shareGroup.Ptr()){
|
if(thrd->shareGroup.Ptr()){
|
||||||
const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
|
const GLuint globalShaderName = thrd->shareGroup->getGlobalName(SHADER,shader);
|
||||||
ctx->dispatcher().glShaderSource(globalShaderName,count,string,length);
|
SET_ERROR_IF(globalShaderName == 0,GL_INVALID_VALUE);
|
||||||
|
ObjectDataPtr objData = thrd->shareGroup->getObjectData(SHADER,shader);
|
||||||
|
SET_ERROR_IF(!objData.Ptr(),GL_INVALID_OPERATION);
|
||||||
|
ShaderParser* sp = (ShaderParser*)objData.Ptr();
|
||||||
|
sp->setSrc(ctx->glslVersion(),count,string,length);
|
||||||
|
ctx->dispatcher().glShaderSource(globalShaderName,1,sp->parsedLines(),NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,3 +119,20 @@ bool GLESv2Validate::readPixelFrmt(GLenum format){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GLESv2Validate::shaderType(GLenum type){
|
||||||
|
return type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLESv2Validate::precisionType(GLenum type){
|
||||||
|
switch(type){
|
||||||
|
case GL_LOW_FLOAT:
|
||||||
|
case GL_MEDIUM_FLOAT:
|
||||||
|
case GL_HIGH_FLOAT:
|
||||||
|
case GL_LOW_INT:
|
||||||
|
case GL_MEDIUM_INT:
|
||||||
|
case GL_HIGH_INT:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ static bool hintTargetMode(GLenum target,GLenum mode);
|
|||||||
static bool capability(GLenum cap);
|
static bool capability(GLenum cap);
|
||||||
static bool pixelStoreParam(GLenum param);
|
static bool pixelStoreParam(GLenum param);
|
||||||
static bool readPixelFrmt(GLenum format);
|
static bool readPixelFrmt(GLenum format);
|
||||||
|
static bool shaderType(GLenum type);
|
||||||
|
static bool precisionType(GLenum type);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#include "ShaderParser.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
ShaderParser::ShaderParser():m_type(0),
|
||||||
|
m_src(NULL),
|
||||||
|
m_parsedLines(NULL){};
|
||||||
|
|
||||||
|
ShaderParser::ShaderParser(GLenum type):m_type(type),
|
||||||
|
m_parsedLines(NULL){};
|
||||||
|
|
||||||
|
void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){
|
||||||
|
for(int i = 0;i<count;i++){
|
||||||
|
m_src.append(strings[i]);
|
||||||
|
}
|
||||||
|
clearParsedSrc();
|
||||||
|
/*
|
||||||
|
version 1.30.10 is the first version of GLSL Language containing precision qualifiers
|
||||||
|
if the glsl version is less than 1.30.10 than we will use a shader parser which omits
|
||||||
|
all precision qualifiers from the shader source , otherwise we will use a shader parser
|
||||||
|
which set the default precisions to be the same as the default precisions of GLSL ES
|
||||||
|
*/
|
||||||
|
if(ver < Version(1,30,10)){
|
||||||
|
parseOmitPrecision();
|
||||||
|
} else {
|
||||||
|
parseExtendDefaultPrecision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ShaderParser::getOriginalSrc(){
|
||||||
|
return m_src.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderParser::parseOmitPrecision(){
|
||||||
|
|
||||||
|
//defines we need to add in order to Omit precisions qualifiers
|
||||||
|
static const GLchar defines[] = {
|
||||||
|
"#define GLES 1\n"
|
||||||
|
"#define lowp \n"
|
||||||
|
"#define mediump \n"
|
||||||
|
"#define highp \n"
|
||||||
|
"#define precision \n"
|
||||||
|
};
|
||||||
|
|
||||||
|
//the lengths of defines we need to add in order to Omit precisions qualifiers
|
||||||
|
static GLuint definesLength = strlen(defines);
|
||||||
|
|
||||||
|
const GLchar* origSrc = m_src.c_str();
|
||||||
|
unsigned int origLength = strlen(origSrc);
|
||||||
|
|
||||||
|
m_parsedLines = new GLchar[origLength + definesLength + 1];
|
||||||
|
strncpy(m_parsedLines,defines,definesLength);
|
||||||
|
strcpy(m_parsedLines+definesLength,origSrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderParser::parseExtendDefaultPrecision(){
|
||||||
|
|
||||||
|
//the precision lines which we need to add to the shader
|
||||||
|
static const GLchar extend[] = {
|
||||||
|
"#define GLES 1\n"
|
||||||
|
"precision lowp sampler2D;\n"
|
||||||
|
"precision lowp samplerCube;\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
//the length of the precision lines which we need to add to the shader
|
||||||
|
static GLint extendLength = strlen(extend);
|
||||||
|
|
||||||
|
const GLchar* origSrc = m_src.c_str();
|
||||||
|
unsigned int origLength = strlen(origSrc);
|
||||||
|
|
||||||
|
m_parsedLines = new GLchar[origLength + extendLength + 1];
|
||||||
|
strncpy(m_parsedLines,extend,extendLength);
|
||||||
|
strcpy(m_parsedLines+extendLength,origSrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderParser::clearParsedSrc(){
|
||||||
|
if(m_parsedLines){
|
||||||
|
delete[] m_parsedLines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderParser::~ShaderParser(){
|
||||||
|
clearParsedSrc();
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef SHADER_PARSER_H
|
||||||
|
#define SHADER_PARSER_H
|
||||||
|
|
||||||
|
#include "GLESv2Context.h"
|
||||||
|
#include <string>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#include <GLcommon/objectNameManager.h>
|
||||||
|
|
||||||
|
class ShaderParser:public ObjectData{
|
||||||
|
public:
|
||||||
|
ShaderParser();
|
||||||
|
ShaderParser(GLenum type);
|
||||||
|
void setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length);
|
||||||
|
const char* getOriginalSrc();
|
||||||
|
const GLchar** parsedLines(){return const_cast<const GLchar**>(&m_parsedLines);};
|
||||||
|
~ShaderParser();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parseOmitPrecision();
|
||||||
|
void parseExtendDefaultPrecision();
|
||||||
|
void clearParsedSrc();
|
||||||
|
|
||||||
|
GLenum m_type;
|
||||||
|
std::string m_src;
|
||||||
|
GLchar* m_parsedLines;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -22,6 +22,45 @@ android::Mutex GLEScontext::s_lock;
|
|||||||
std::string* GLEScontext::s_glExtensions= NULL;
|
std::string* GLEScontext::s_glExtensions= NULL;
|
||||||
GLSupport GLEScontext::s_glSupport;
|
GLSupport GLEScontext::s_glSupport;
|
||||||
|
|
||||||
|
Version::Version():m_major(0),
|
||||||
|
m_minor(0),
|
||||||
|
m_release(0){};
|
||||||
|
|
||||||
|
Version::Version(int major,int minor,int release):m_major(major),
|
||||||
|
m_minor(minor),
|
||||||
|
m_release(release){};
|
||||||
|
|
||||||
|
Version::Version(const Version& ver):m_major(ver.m_major),
|
||||||
|
m_minor(ver.m_minor),
|
||||||
|
m_release(ver.m_release){}
|
||||||
|
|
||||||
|
Version::Version(const char* versionString){
|
||||||
|
m_release = 0;
|
||||||
|
if((!versionString) ||
|
||||||
|
((!(sscanf(versionString,"%d.%d" ,&m_major,&m_minor) == 2)) &&
|
||||||
|
(!(sscanf(versionString,"%d.%d.%d",&m_major,&m_minor,&m_release) == 3)))){
|
||||||
|
m_major = m_minor = 0; // the version is not in the right format
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Version& Version::operator=(const Version& ver){
|
||||||
|
m_major = ver.m_major;
|
||||||
|
m_minor = ver.m_minor;
|
||||||
|
m_release = ver.m_release;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Version::operator<(const Version& ver) const{
|
||||||
|
if(m_major < ver.m_major) return true;
|
||||||
|
if(m_major == ver.m_major){
|
||||||
|
if(m_minor < ver.m_minor) return true;
|
||||||
|
if(m_minor == ver.m_minor){
|
||||||
|
return m_release < ver.m_release;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GLEScontext::GLEScontext():
|
GLEScontext::GLEScontext():
|
||||||
m_initialized(false) ,
|
m_initialized(false) ,
|
||||||
m_activeTexture(0) ,
|
m_activeTexture(0) ,
|
||||||
@@ -378,6 +417,8 @@ void GLEScontext::initCapsLocked(const GLubyte * extensionString)
|
|||||||
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_SIZE,&s_glSupport.maxTexSize);
|
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_SIZE,&s_glSupport.maxTexSize);
|
||||||
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_UNITS,&maxTexUnits);
|
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_UNITS,&maxTexUnits);
|
||||||
s_glSupport.maxTexUnits = maxTexUnits < MAX_TEX_UNITS ? maxTexUnits:MAX_TEX_UNITS;
|
s_glSupport.maxTexUnits = maxTexUnits < MAX_TEX_UNITS ? maxTexUnits:MAX_TEX_UNITS;
|
||||||
|
const GLubyte* glslVersion = s_glDispatch.glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||||
|
s_glSupport.glslVersion = Version((const char*)(glslVersion));
|
||||||
|
|
||||||
if (strstr(cstring,"GL_EXT_bgra ")!=NULL)
|
if (strstr(cstring,"GL_EXT_bgra ")!=NULL)
|
||||||
s_glSupport.GL_EXT_TEXTURE_FORMAT_BGRA8888 = true;
|
s_glSupport.GL_EXT_TEXTURE_FORMAT_BGRA8888 = true;
|
||||||
|
|||||||
@@ -22,6 +22,20 @@ typedef struct _textureUnitState {
|
|||||||
GLboolean enabled[NUM_TEXTURE_TARGETS];
|
GLboolean enabled[NUM_TEXTURE_TARGETS];
|
||||||
} textureUnitState;
|
} textureUnitState;
|
||||||
|
|
||||||
|
class Version{
|
||||||
|
public:
|
||||||
|
Version();
|
||||||
|
Version(int major,int minor,int release);
|
||||||
|
Version(const char* versionString);
|
||||||
|
Version(const Version& ver);
|
||||||
|
bool operator<(const Version& ver) const;
|
||||||
|
Version& operator=(const Version& ver);
|
||||||
|
private:
|
||||||
|
int m_major;
|
||||||
|
int m_minor;
|
||||||
|
int m_release;
|
||||||
|
};
|
||||||
|
|
||||||
struct GLSupport {
|
struct GLSupport {
|
||||||
GLSupport():maxLights(0),maxVertexAttribs(0),maxClipPlane(0),maxTexUnits(0),maxTexSize(0) , \
|
GLSupport():maxLights(0),maxVertexAttribs(0),maxClipPlane(0),maxTexUnits(0),maxTexSize(0) , \
|
||||||
GL_EXT_TEXTURE_FORMAT_BGRA8888(false), GL_EXT_FRAMEBUFFER_OBJECT(false), \
|
GL_EXT_TEXTURE_FORMAT_BGRA8888(false), GL_EXT_FRAMEBUFFER_OBJECT(false), \
|
||||||
@@ -34,6 +48,7 @@ struct GLSupport {
|
|||||||
int maxClipPlane;
|
int maxClipPlane;
|
||||||
int maxTexUnits;
|
int maxTexUnits;
|
||||||
int maxTexSize;
|
int maxTexSize;
|
||||||
|
Version glslVersion;
|
||||||
bool GL_EXT_TEXTURE_FORMAT_BGRA8888;
|
bool GL_EXT_TEXTURE_FORMAT_BGRA8888;
|
||||||
bool GL_EXT_FRAMEBUFFER_OBJECT;
|
bool GL_EXT_FRAMEBUFFER_OBJECT;
|
||||||
bool GL_ARB_VERTEX_BLEND;
|
bool GL_ARB_VERTEX_BLEND;
|
||||||
@@ -93,6 +108,7 @@ public:
|
|||||||
static int getMaxClipPlanes(){return s_glSupport.maxClipPlane;}
|
static int getMaxClipPlanes(){return s_glSupport.maxClipPlane;}
|
||||||
static int getMaxTexUnits(){return s_glSupport.maxTexUnits;}
|
static int getMaxTexUnits(){return s_glSupport.maxTexUnits;}
|
||||||
static int getMaxTexSize(){return s_glSupport.maxTexSize;}
|
static int getMaxTexSize(){return s_glSupport.maxTexSize;}
|
||||||
|
static Version glslVersion(){return s_glSupport.glslVersion;}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user