am af4f66be: EmuGL: implement OES_EGL_image_external for GLESv1

* commit 'af4f66be50b17c8b8fce1dda53389bb0a10968ba':
  EmuGL: implement OES_EGL_image_external for GLESv1
This commit is contained in:
Jesse Hall
2011-11-22 15:43:26 -08:00
committed by Android Git Automerger
6 changed files with 697 additions and 36 deletions

View File

@@ -21,6 +21,10 @@
#include "glUtils.h"
#include <cutils/log.h>
#ifndef MAX
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif
GLClientState::GLClientState(int nLocations)
{
if (nLocations < LAST_LOCATION) {
@@ -54,6 +58,12 @@ GLClientState::GLClientState(int nLocations)
m_pixelStore.unpack_alignment = 4;
m_pixelStore.pack_alignment = 4;
memset(m_tex.unit, 0, sizeof(m_tex.unit));
m_tex.activeUnit = &m_tex.unit[0];
m_tex.textures = NULL;
m_tex.numTextures = 0;
m_tex.allocTextures = 0;
}
GLClientState::~GLClientState()
@@ -230,3 +240,173 @@ size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format
return aligned_linesize * height;
}
GLenum GLClientState::setActiveTextureUnit(GLenum texture)
{
GLuint unit = texture - GL_TEXTURE0;
if (unit >= MAX_TEXTURE_UNITS) {
return GL_INVALID_OPERATION;
}
m_tex.activeUnit = &m_tex.unit[unit];
return GL_NO_ERROR;
}
void GLClientState::enableTextureTarget(GLenum target)
{
switch (target) {
case GL_TEXTURE_2D:
m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
break;
case GL_TEXTURE_EXTERNAL_OES:
m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
break;
}
}
void GLClientState::disableTextureTarget(GLenum target)
{
switch (target) {
case GL_TEXTURE_2D:
m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
break;
case GL_TEXTURE_EXTERNAL_OES:
m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
break;
}
}
GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
{
unsigned int enables = m_tex.activeUnit->enables;
if (enables & (1u << TEXTURE_EXTERNAL)) {
return GL_TEXTURE_EXTERNAL_OES;
} else if (enables & (1u << TEXTURE_2D)) {
return GL_TEXTURE_2D;
} else {
return allDisabled;
}
}
int GLClientState::compareTexId(const void* pid, const void* prec)
{
const GLuint* id = (const GLuint*)pid;
const TextureRec* rec = (const TextureRec*)prec;
return (GLint)(*id) - (GLint)rec->id;
}
GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
GLboolean* firstUse)
{
GLboolean first = GL_FALSE;
TextureRec* texrec = NULL;
if (texture != 0) {
if (m_tex.textures) {
texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
m_tex.numTextures, sizeof(TextureRec), compareTexId);
}
if (!texrec) {
if (!(texrec = addTextureRec(texture, target))) {
return GL_OUT_OF_MEMORY;
}
first = GL_TRUE;
}
if (target != texrec->target) {
return GL_INVALID_OPERATION;
}
}
switch (target) {
case GL_TEXTURE_2D:
m_tex.activeUnit->texture[TEXTURE_2D] = texture;
break;
case GL_TEXTURE_EXTERNAL_OES:
m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
break;
}
if (firstUse) {
*firstUse = first;
}
return GL_NO_ERROR;
}
GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
GLenum target)
{
if (m_tex.numTextures == m_tex.allocTextures) {
const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
GLuint newAlloc;
if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
newAlloc = MAX(4, 2 * m_tex.allocTextures);
} else {
if (m_tex.allocTextures == MAX_TEXTURES) {
return NULL;
}
newAlloc = MAX_TEXTURES;
}
TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
newAlloc * sizeof(TextureRec));
if (!newTextures) {
return NULL;
}
m_tex.textures = newTextures;
m_tex.allocTextures = newAlloc;
}
TextureRec* tex = m_tex.textures + m_tex.numTextures;
TextureRec* prev = tex - 1;
while (tex != m_tex.textures && id < prev->id) {
*tex-- = *prev--;
}
tex->id = id;
tex->target = target;
m_tex.numTextures++;
return tex;
}
GLuint GLClientState::getBoundTexture(GLenum target) const
{
switch (target) {
case GL_TEXTURE_2D:
return m_tex.activeUnit->texture[TEXTURE_2D];
case GL_TEXTURE_EXTERNAL_OES:
return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
default:
return 0;
}
}
void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
{
// Updating the textures array could be made more efficient when deleting
// several textures:
// - compacting the array could be done in a single pass once the deleted
// textures are marked, or
// - could swap deleted textures to the end and re-sort.
TextureRec* texrec;
for (const GLuint* texture = textures; texture != textures + n; texture++) {
texrec = (TextureRec*)bsearch(texture, m_tex.textures,
m_tex.numTextures, sizeof(TextureRec), compareTexId);
if (texrec) {
const TextureRec* end = m_tex.textures + m_tex.numTextures;
memmove(texrec, texrec + 1,
(end - texrec + 1) * sizeof(TextureRec));
m_tex.numTextures--;
for (TextureUnit* unit = m_tex.unit;
unit != m_tex.unit + MAX_TEXTURE_UNITS;
unit++)
{
if (unit->texture[TEXTURE_2D] == *texture) {
unit->texture[TEXTURE_2D] = 0;
} else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
unit->texture[TEXTURE_EXTERNAL] = 0;
}
}
}
}
}

View File

@@ -70,6 +70,10 @@ public:
int pack_alignment;
} PixelStoreState;
enum {
MAX_TEXTURE_UNITS = 32,
};
public:
GLClientState(int nLocations = CODEC_MAX_VERTEX_ATTRIBUTES);
~GLClientState();
@@ -123,6 +127,53 @@ public:
void setCurrentProgram(GLint program) { m_currentProgram = program; }
GLint currentProgram() const { return m_currentProgram; }
/* OES_EGL_image_external
*
* These functions manipulate GL state which interacts with the
* OES_EGL_image_external extension, to support client-side emulation on
* top of host implementations that don't have it.
*
* Most of these calls should only be used with TEXTURE_2D or
* TEXTURE_EXTERNAL_OES texture targets; TEXTURE_CUBE_MAP or other extension
* targets should bypass this. An exception is bindTexture(), which should
* see all glBindTexture() calls for any target.
*/
// glActiveTexture(GL_TEXTURE0 + i)
// Sets the active texture unit. Up to MAX_TEXTURE_UNITS are supported.
GLenum setActiveTextureUnit(GLenum texture);
// glEnable(GL_TEXTURE_(2D|EXTERNAL_OES))
void enableTextureTarget(GLenum target);
// glDisable(GL_TEXTURE_(2D|EXTERNAL_OES))
void disableTextureTarget(GLenum target);
// Implements the target priority logic:
// * Return GL_TEXTURE_EXTERNAL_OES if enabled, else
// * Return GL_TEXTURE_2D if enabled, else
// * Return the allDisabled value.
// For some cases passing GL_TEXTURE_2D for allDisabled makes callee code
// simpler; for other cases passing a recognizable enum like GL_ZERO or
// GL_INVALID_ENUM is appropriate.
GLenum getPriorityEnabledTarget(GLenum allDisabled) const;
// glBindTexture(GL_TEXTURE_*, ...)
// Set the target binding of the active texture unit to texture. Returns
// GL_NO_ERROR on success or GL_INVALID_OPERATION if the texture has
// previously been bound to a different target. If firstUse is not NULL,
// it is set to indicate whether this is the first use of the texture.
// For accurate error detection, bindTexture should be called for *all*
// targets, not just 2D and EXTERNAL_OES.
GLenum bindTexture(GLenum target, GLuint texture, GLboolean* firstUse);
// Return the texture currently bound to GL_TEXTURE_(2D|EXTERNAL_OES).
GLuint getBoundTexture(GLenum target) const;
// glDeleteTextures(...)
// Remove references to the to-be-deleted textures.
void deleteTextures(GLsizei n, const GLuint* textures);
private:
PixelStoreState m_pixelStore;
VertexAttribState *m_states;
@@ -133,6 +184,32 @@ private:
GLint m_currentProgram;
bool validLocation(int location) { return (location >= 0 && location < m_nLocations); }
enum TextureTarget {
TEXTURE_2D = 0,
TEXTURE_EXTERNAL = 1,
TEXTURE_TARGET_COUNT
};
struct TextureUnit {
unsigned int enables;
GLuint texture[TEXTURE_TARGET_COUNT];
};
struct TextureRec {
GLuint id;
GLenum target;
};
struct TextureState {
TextureUnit unit[MAX_TEXTURE_UNITS];
TextureUnit* activeUnit;
TextureRec* textures;
GLuint numTextures;
GLuint allocTextures;
};
TextureState m_tex;
static int compareTexId(const void* pid, const void* prec);
TextureRec* addTextureRec(GLuint id, GLenum target);
public:
void getClientStatePointer(GLenum pname, GLvoid** params);