opengles emulator: Support current value for attribute 0

In GLES, a vertex shader attribute can be at location 0 and have
a current value. In OpenGL, the spec is not clear, resulting in
absurdities like the ATI driver binding an attribute to location
0, does not give an erro when you set it, but gives an error when
you try to get it back. And it doesn't actually set the value in
the shader.

So, in this patch we:

  1. Track attribute 0 value internally, setting and getting it
     as necessary.

  2. Upon glDrawArrays and glDrawElements, if attribute 0 is not
     "array enabled" (that is, it should use a current value) we
     create a dummy array, fill it with the intended current value,
     and attach and enable it. After the draw, we disable it.

Change-Id: I35f3e8a924e6fba236f4f4d85423b04ae448dad4
This commit is contained in:
Yochai Shefi Simchon
2011-08-08 13:37:03 +03:00
committed by David 'Digit' Turner
parent c9d192691e
commit 97fa8de7a2
5 changed files with 122 additions and 17 deletions

View File

@@ -26,11 +26,61 @@ void GLESv2Context::init() {
for(int i=0; i < s_glSupport.maxVertexAttribs;i++){ for(int i=0; i < s_glSupport.maxVertexAttribs;i++){
m_map[i] = new GLESpointer(); m_map[i] = new GLESpointer();
} }
setAttribute0value(0.0, 0.0, 0.0, 1.0);
} }
m_initialized = true; m_initialized = true;
} }
GLESv2Context::GLESv2Context():GLEScontext(){}; GLESv2Context::GLESv2Context():GLEScontext(), m_att0Array(NULL), m_att0ArrayLength(0), m_att0NeedsDisable(false){};
GLESv2Context::~GLESv2Context()
{
delete[] m_att0Array;
}
void GLESv2Context::setAttribute0value(float x, float y, float z, float w)
{
m_attribute0value[0] = x;
m_attribute0value[1] = y;
m_attribute0value[2] = z;
m_attribute0value[3] = w;
}
void GLESv2Context::validateAtt0PreDraw(unsigned int count)
{
m_att0NeedsDisable = false;
if(count == 0)
return;
int enabled = 0;
s_glDispatch.glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
if(enabled)
return;
if(count > m_att0ArrayLength)
{
delete [] m_att0Array;
m_att0Array = new GLfloat[4*count];
m_att0ArrayLength = count;
}
for(unsigned int i=0; i<count; i++)
memcpy(m_att0Array+i*4, m_attribute0value, 4*sizeof(GLfloat));
s_glDispatch.glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, m_att0Array);
s_glDispatch.glEnableVertexAttribArray(0);
m_att0NeedsDisable = true;
}
void GLESv2Context::validateAtt0PostDraw(void)
{
if(m_att0NeedsDisable)
s_glDispatch.glDisableVertexAttribArray(0);
m_att0NeedsDisable = false;
}
void GLESv2Context::setupArraysPointers(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct) { void GLESv2Context::setupArraysPointers(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct) {
ArraysMap::iterator it; ArraysMap::iterator it;

View File

@@ -28,13 +28,29 @@ class GLESv2Context : public GLEScontext{
public: public:
void init(); void init();
GLESv2Context(); GLESv2Context();
virtual ~GLESv2Context();
void setupArraysPointers(GLESConversionArrays& fArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct); void setupArraysPointers(GLESConversionArrays& fArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct);
int getMaxTexUnits(); int getMaxTexUnits();
// This whole att0 thing is about a incompatibility between GLES and OpenGL.
// GLES allows a vertex shader attribute to be in location 0 and have a
// current value, while OpenGL is not very clear about this, which results
// in each implementation doing something different.
void setAttribute0value(float x, float y, float z, float w);
void validateAtt0PreDraw(unsigned int count);
void validateAtt0PostDraw(void);
const float* getAtt0(void) {return m_attribute0value;}
protected: protected:
bool needConvert(GLESConversionArrays& fArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct,GLESpointer* p,GLenum array_id); bool needConvert(GLESConversionArrays& fArrs,GLint first,GLsizei count,GLenum type,const GLvoid* indices,bool direct,GLESpointer* p,GLenum array_id);
private: private:
void setupArr(const GLvoid* arr,GLenum arrayType,GLenum dataType,GLint size,GLsizei stride,GLboolean normalized, int pointsIndex = -1); void setupArr(const GLvoid* arr,GLenum arrayType,GLenum dataType,GLint size,GLsizei stride,GLboolean normalized, int pointsIndex = -1);
void initExtensionString(); void initExtensionString();
float m_attribute0value[4];
GLfloat* m_att0Array;
unsigned int m_att0ArrayLength;
bool m_att0NeedsDisable;
}; };
#endif #endif

View File

@@ -546,7 +546,7 @@ GL_APICALL void GL_APIENTRY glDisableVertexAttribArray(GLuint index){
} }
GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count){ GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count){
GET_CTX(); GET_CTX_V2();
SET_ERROR_IF(count < 0,GL_INVALID_VALUE) SET_ERROR_IF(count < 0,GL_INVALID_VALUE)
SET_ERROR_IF(!GLESv2Validate::drawMode(mode),GL_INVALID_ENUM); SET_ERROR_IF(!GLESv2Validate::drawMode(mode),GL_INVALID_ENUM);
@@ -555,6 +555,8 @@ GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei coun
GLESConversionArrays tmpArrs; GLESConversionArrays tmpArrs;
ctx->setupArraysPointers(tmpArrs,first,count,0,NULL,true); ctx->setupArraysPointers(tmpArrs,first,count,0,NULL,true);
ctx->validateAtt0PreDraw(count);
//Enable texture generation for GL_POINTS and gl_PointSize shader variable //Enable texture generation for GL_POINTS and gl_PointSize shader variable
//GLES2 assumes this is enabled by default, we need to set this state for GL //GLES2 assumes this is enabled by default, we need to set this state for GL
if (mode==GL_POINTS) { if (mode==GL_POINTS) {
@@ -568,10 +570,12 @@ GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei coun
ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
ctx->dispatcher().glDisable(GL_POINT_SPRITE); ctx->dispatcher().glDisable(GL_POINT_SPRITE);
} }
ctx->validateAtt0PostDraw();
} }
GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* elementsIndices){ GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* elementsIndices){
GET_CTX(); GET_CTX_V2();
SET_ERROR_IF(count < 0,GL_INVALID_VALUE) SET_ERROR_IF(count < 0,GL_INVALID_VALUE)
SET_ERROR_IF(!(GLESv2Validate::drawMode(mode) && GLESv2Validate::drawType(type)),GL_INVALID_ENUM); SET_ERROR_IF(!(GLESv2Validate::drawMode(mode) && GLESv2Validate::drawType(type)),GL_INVALID_ENUM);
@@ -586,6 +590,9 @@ GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum t
GLESConversionArrays tmpArrs; GLESConversionArrays tmpArrs;
ctx->setupArraysPointers(tmpArrs,0,count,type,indices,false); ctx->setupArraysPointers(tmpArrs,0,count,type,indices,false);
int maxIndex = ctx->findMaxIndex(count, type, indices);
ctx->validateAtt0PreDraw(maxIndex);
//See glDrawArrays //See glDrawArrays
if (mode==GL_POINTS) { if (mode==GL_POINTS) {
ctx->dispatcher().glEnable(GL_POINT_SPRITE); ctx->dispatcher().glEnable(GL_POINT_SPRITE);
@@ -598,6 +605,8 @@ GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum t
ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
ctx->dispatcher().glDisable(GL_POINT_SPRITE); ctx->dispatcher().glDisable(GL_POINT_SPRITE);
} }
ctx->validateAtt0PostDraw();
} }
GL_APICALL void GL_APIENTRY glEnable(GLenum cap){ GL_APICALL void GL_APIENTRY glEnable(GLenum cap){
@@ -1300,7 +1309,7 @@ GL_APICALL int GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* na
GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params){ GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params){
GET_CTX(); GET_CTX_V2();
const GLESpointer* p = ctx->getPointer(index); const GLESpointer* p = ctx->getPointer(index);
if(p) { if(p) {
switch(pname){ switch(pname){
@@ -1323,6 +1332,13 @@ GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLf
*params = p->isNormalize(); *params = p->isNormalize();
break; break;
case GL_CURRENT_VERTEX_ATTRIB: case GL_CURRENT_VERTEX_ATTRIB:
if(index == 0)
{
const float* att0 = ctx->getAtt0();
for(int i=0; i<4; i++)
params[i] = att0[i];
}
else
ctx->dispatcher().glGetVertexAttribfv(index,pname,params); ctx->dispatcher().glGetVertexAttribfv(index,pname,params);
break; break;
default: default:
@@ -1334,7 +1350,7 @@ GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLf
} }
GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params){ GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params){
GET_CTX(); GET_CTX_V2();
const GLESpointer* p = ctx->getPointer(index); const GLESpointer* p = ctx->getPointer(index);
if(p) { if(p) {
switch(pname){ switch(pname){
@@ -1357,6 +1373,13 @@ GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLi
*params = p->isNormalize(); *params = p->isNormalize();
break; break;
case GL_CURRENT_VERTEX_ATTRIB: case GL_CURRENT_VERTEX_ATTRIB:
if(index == 0)
{
const float* att0 = ctx->getAtt0();
for(int i=0; i<4; i++)
params[i] = (GLint)att0[i];
}
else
ctx->dispatcher().glGetVertexAttribiv(index,pname,params); ctx->dispatcher().glGetVertexAttribiv(index,pname,params);
break; break;
default: default:
@@ -1816,43 +1839,59 @@ GL_APICALL void GL_APIENTRY glValidateProgram(GLuint program){
} }
GL_APICALL void GL_APIENTRY glVertexAttrib1f(GLuint indx, GLfloat x){ GL_APICALL void GL_APIENTRY glVertexAttrib1f(GLuint indx, GLfloat x){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib1f(indx,x); ctx->dispatcher().glVertexAttrib1f(indx,x);
if(indx == 0)
ctx->setAttribute0value(x, 0.0, 0.0, 1.0);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat* values){ GL_APICALL void GL_APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat* values){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib1fv(indx,values); ctx->dispatcher().glVertexAttrib1fv(indx,values);
if(indx == 0)
ctx->setAttribute0value(values[0], 0.0, 0.0, 1.0);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y){ GL_APICALL void GL_APIENTRY glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib2f(indx,x,y); ctx->dispatcher().glVertexAttrib2f(indx,x,y);
if(indx == 0)
ctx->setAttribute0value(x, y, 0.0, 1.0);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat* values){ GL_APICALL void GL_APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat* values){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib2fv(indx,values); ctx->dispatcher().glVertexAttrib2fv(indx,values);
if(indx == 0)
ctx->setAttribute0value(values[0], values[1], 0.0, 1.0);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z){ GL_APICALL void GL_APIENTRY glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib3f(indx,x,y,z); ctx->dispatcher().glVertexAttrib3f(indx,x,y,z);
if(indx == 0)
ctx->setAttribute0value(x, y, z, 1.0);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat* values){ GL_APICALL void GL_APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat* values){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib3fv(indx,values); ctx->dispatcher().glVertexAttrib3fv(indx,values);
if(indx == 0)
ctx->setAttribute0value(values[0], values[1], values[2], 1.0);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w){ GL_APICALL void GL_APIENTRY glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib4f(indx,x,y,z,w); ctx->dispatcher().glVertexAttrib4f(indx,x,y,z,w);
if(indx == 0)
ctx->setAttribute0value(x, y, z, w);
} }
GL_APICALL void GL_APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat* values){ GL_APICALL void GL_APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat* values){
GET_CTX(); GET_CTX_V2();
ctx->dispatcher().glVertexAttrib4fv(indx,values); ctx->dispatcher().glVertexAttrib4fv(indx,values);
if(indx == 0)
ctx->setAttribute0value(values[0], values[1], values[2], values[3]);
} }
GL_APICALL void GL_APIENTRY glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr){ GL_APICALL void GL_APIENTRY glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr){

View File

@@ -9,7 +9,6 @@
#include <strings.h> #include <strings.h>
//decleration //decleration
static int findMaxIndex(GLsizei count,GLenum type,const GLvoid* indices);
static void convertFixedDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize); static void convertFixedDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize);
static void convertFixedIndirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,GLsizei count,GLenum indices_type,const GLvoid* indices,unsigned int strideOut,int attribSize); static void convertFixedIndirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,GLsizei count,GLenum indices_type,const GLvoid* indices,unsigned int strideOut,int attribSize);
static void convertByteDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize); static void convertByteDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize);
@@ -331,7 +330,7 @@ void GLEScontext::convertDirectVBO(GLESConversionArrays& cArrs,GLint first,GLsiz
cArrs.setArr(data,p->getStride(),GL_FLOAT); cArrs.setArr(data,p->getStride(),GL_FLOAT);
} }
static int findMaxIndex(GLsizei count,GLenum type,const GLvoid* indices) { int GLEScontext::findMaxIndex(GLsizei count,GLenum type,const GLvoid* indices) {
//finding max index //finding max index
int max = 0; int max = 0;
if(type == GL_UNSIGNED_BYTE) { if(type == GL_UNSIGNED_BYTE) {

View File

@@ -151,6 +151,7 @@ public:
static Version glslVersion(){return s_glSupport.glslVersion;} static Version glslVersion(){return s_glSupport.glslVersion;}
static bool isAutoMipmapSupported(){return s_glSupport.GL_SGIS_GENERATE_MIPMAP;} static bool isAutoMipmapSupported(){return s_glSupport.GL_SGIS_GENERATE_MIPMAP;}
static TextureTarget GLTextureTargetToLocal(GLenum target); static TextureTarget GLTextureTargetToLocal(GLenum target);
static int findMaxIndex(GLsizei count,GLenum type,const GLvoid* indices);
virtual bool glGetIntegerv(GLenum pname, GLint *params); virtual bool glGetIntegerv(GLenum pname, GLint *params);
virtual bool glGetBooleanv(GLenum pname, GLboolean *params); virtual bool glGetBooleanv(GLenum pname, GLboolean *params);