blob: c807ad332833ace40647862b8b88539cc07df14c [file] [log] [blame]
/*
* Copyright 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <GLcommon/GLEScontext.h>
#include <GLcommon/GLconversion_macros.h>
#include <GLcommon/GLESmacros.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <OpenglCodecCommon/ErrorLog.h>
#include <GLcommon/GLESvalidate.h>
#include <GLcommon/TextureUtils.h>
#include <GLcommon/FramebufferData.h>
#include <strings.h>
#include <string.h>
//decleration
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 convertByteDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize);
static void convertByteIndirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,GLsizei count,GLenum indices_type,const GLvoid* indices,unsigned int strideOut,int attribSize);
GLESConversionArrays::~GLESConversionArrays() {
for(auto it = m_arrays.begin(); it != m_arrays.end(); ++it) {
if((*it).second.allocated){
if((*it).second.type == GL_FLOAT){
GLfloat* p = (GLfloat *)((*it).second.data);
if(p) delete[] p;
} else if((*it).second.type == GL_SHORT){
GLshort* p = (GLshort *)((*it).second.data);
if(p) delete[] p;
}
}
}
}
void GLESConversionArrays::allocArr(unsigned int size,GLenum type){
if(type == GL_FIXED){
m_arrays[m_current].data = new GLfloat[size];
m_arrays[m_current].type = GL_FLOAT;
} else if(type == GL_BYTE){
m_arrays[m_current].data = new GLshort[size];
m_arrays[m_current].type = GL_SHORT;
}
m_arrays[m_current].stride = 0;
m_arrays[m_current].allocated = true;
}
void GLESConversionArrays::setArr(void* data,unsigned int stride,GLenum type){
m_arrays[m_current].type = type;
m_arrays[m_current].data = data;
m_arrays[m_current].stride = stride;
m_arrays[m_current].allocated = false;
}
void* GLESConversionArrays::getCurrentData(){
return m_arrays[m_current].data;
}
ArrayData& GLESConversionArrays::getCurrentArray(){
return m_arrays[m_current];
}
unsigned int GLESConversionArrays::getCurrentIndex(){
return m_current;
}
ArrayData& GLESConversionArrays::operator[](int i){
return m_arrays[i];
}
void GLESConversionArrays::operator++(){
m_current++;
}
GLDispatch GLEScontext::s_glDispatch;
emugl::Mutex GLEScontext::s_lock;
std::string* GLEScontext::s_glExtensions= NULL;
std::string GLEScontext::s_glVendor;
std::string GLEScontext::s_glRenderer;
std::string GLEScontext::s_glVersion;
GLSupport GLEScontext::s_glSupport;
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;
}
static std::string getHostExtensionsString(GLDispatch* dispatch) {
// glGetString(GL_EXTENSIONS) is deprecated in GL 3.0, one has to use
// glGetStringi(GL_EXTENSIONS, index) instead to get individual extension
// names. Recent desktop drivers implement glGetStringi() but have a
// version of glGetString() that returns NULL, so deal with this by
// doing the following:
//
// - If glGetStringi() is available, and glGetIntegerv(GL_NUM_EXTENSIONS &num_exts)
// gives a nonzero value, use it to build the extensions
// string, using simple spaces to separate the names.
//
// - Otherwise, fallback to getGetString(). If it returns NULL, return
// an empty string.
//
std::string result;
int num_exts = 0;
if (dispatch->glGetStringi) {
dispatch->glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts);
GLenum err = dispatch->glGetError();
if (err == GL_NO_ERROR) {
for (int n = 0; n < num_exts; n++) {
const char* ext = reinterpret_cast<const char*>(
dispatch->glGetStringi(GL_EXTENSIONS, n));
if (ext != NULL) {
if (!result.empty()) {
result += " ";
}
result += ext;
}
}
}
}
// If glGetIntegerv does not affect the value,
// our system does not actually support
// GL 3.0 style extension getting.
if (!dispatch->glGetStringi || num_exts == 0) {
const char* extensions = reinterpret_cast<const char*>(
dispatch->glGetString(GL_EXTENSIONS));
if (extensions) {
result = extensions;
}
}
// For the sake of initCapsLocked() add a starting and trailing space.
if (!result.empty()) {
if (result[0] != ' ') {
result.insert(0, 1, ' ');
}
if (result[result.size() - 1U] != ' ') {
result += ' ';
}
}
return result;
}
static GLuint getIndex(GLenum indices_type, const GLvoid* indices, unsigned int i) {
switch (indices_type) {
case GL_UNSIGNED_BYTE:
return static_cast<const GLubyte*>(indices)[i];
case GL_UNSIGNED_SHORT:
return static_cast<const GLushort*>(indices)[i];
case GL_UNSIGNED_INT:
return static_cast<const GLuint*>(indices)[i];
default:
ERR("**** ERROR unknown type 0x%x (%s,%d)\n", indices_type, __FUNCTION__,__LINE__);
return 0;
}
}
void GLEScontext::init(GlLibrary* glLib) {
if (!s_glExtensions) {
initCapsLocked(reinterpret_cast<const GLubyte*>(
getHostExtensionsString(&s_glDispatch).c_str()));
// NOTE: the string below corresponds to the extensions reported
// by this context, which is initialized in each GLESv1 or GLESv2
// context implementation, based on the parsing of the host
// extensions string performed by initCapsLocked(). I.e. it will
// be populated after calling this ::init() method.
s_glExtensions = new std::string();
}
if (!m_initialized) {
initExtensionString();
int maxTexUnits = getMaxCombinedTexUnits();
m_texState = new textureUnitState[maxTexUnits];
for (int i=0;i<maxTexUnits;++i) {
for (int j=0;j<NUM_TEXTURE_TARGETS;++j)
{
m_texState[i][j].texture = 0;
m_texState[i][j].enabled = GL_FALSE;
}
}
}
}
GLenum GLEScontext::getGLerror() {
return m_glError;
}
void GLEScontext::setGLerror(GLenum err) {
m_glError = err;
}
void GLEScontext::setActiveTexture(GLenum tex) {
m_activeTexture = tex - GL_TEXTURE0;
}
GLEScontext::~GLEScontext() {
for(ArraysMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
GLESpointer* p = (*it).second;
if(p) {
delete p;
}
}
delete[] m_texState;
m_texState = NULL;
}
const GLvoid* GLEScontext::setPointer(GLenum arrType,GLint size,GLenum type,GLsizei stride,const GLvoid* data,bool normalize) {
GLuint bufferName = m_arrayBuffer;
if(bufferName) {
unsigned int offset = SafeUIntFromPointer(data);
GLESbuffer* vbo = static_cast<GLESbuffer*>(
m_shareGroup
->getObjectData(NamedObjectType::VERTEXBUFFER,
bufferName));
m_map[arrType]->setBuffer(size,type,stride,vbo,bufferName,offset,normalize);
return static_cast<const unsigned char*>(vbo->getData()) + offset;
}
m_map[arrType]->setArray(size,type,stride,data,normalize);
return data;
}
void GLEScontext::enableArr(GLenum arr,bool enable) {
m_map[arr]->enable(enable);
}
bool GLEScontext::isArrEnabled(GLenum arr) {
return m_map[arr]->isEnable();
}
const GLESpointer* GLEScontext::getPointer(GLenum arrType) {
const auto it = m_map.find(arrType);
return it != m_map.end() ? it->second : nullptr;
}
static void convertFixedDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize) {
for(unsigned int i = 0; i < nBytes;i+=strideOut) {
const GLfixed* fixed_data = (const GLfixed *)dataIn;
//filling attrib
for(int j=0;j<attribSize;j++) {
reinterpret_cast<GLfloat*>(&static_cast<unsigned char*>(dataOut)[i])[j] = X2F(fixed_data[j]);
}
dataIn += strideIn;
}
}
static void convertFixedIndirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,GLsizei count,GLenum indices_type,const GLvoid* indices,unsigned int strideOut,int attribSize) {
for(int i = 0 ;i < count ;i++) {
GLuint index = getIndex(indices_type, indices, i);
const GLfixed* fixed_data = (GLfixed *)(dataIn + index*strideIn);
GLfloat* float_data = reinterpret_cast<GLfloat*>(static_cast<unsigned char*>(dataOut) + index*strideOut);
for(int j=0;j<attribSize;j++) {
float_data[j] = X2F(fixed_data[j]);
}
}
}
static void convertByteDirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,unsigned int nBytes,unsigned int strideOut,int attribSize) {
for(unsigned int i = 0; i < nBytes;i+=strideOut) {
const GLbyte* byte_data = (const GLbyte *)dataIn;
//filling attrib
for(int j=0;j<attribSize;j++) {
reinterpret_cast<GLshort*>(&static_cast<unsigned char*>(dataOut)[i])[j] = B2S(byte_data[j]);
}
dataIn += strideIn;
}
}
static void convertByteIndirectLoop(const char* dataIn,unsigned int strideIn,void* dataOut,GLsizei count,GLenum indices_type,const GLvoid* indices,unsigned int strideOut,int attribSize) {
for(int i = 0 ;i < count ;i++) {
GLuint index = getIndex(indices_type, indices, i);
const GLbyte* bytes_data = (GLbyte *)(dataIn + index*strideIn);
GLshort* short_data = reinterpret_cast<GLshort*>(static_cast<unsigned char*>(dataOut) + index*strideOut);
for(int j=0;j<attribSize;j++) {
short_data[j] = B2S(bytes_data[j]);
}
}
}
static void directToBytesRanges(GLint first,GLsizei count,GLESpointer* p,RangeList& list) {
int attribSize = p->getSize()*4; //4 is the sizeof GLfixed or GLfloat in bytes
int stride = p->getStride()?p->getStride():attribSize;
int start = p->getBufferOffset()+first*attribSize;
if(!p->getStride()) {
list.addRange(Range(start,count*attribSize));
} else {
for(int i = 0 ;i < count; i++,start+=stride) {
list.addRange(Range(start,attribSize));
}
}
}
static void indirectToBytesRanges(const GLvoid* indices,GLenum indices_type,GLsizei count,GLESpointer* p,RangeList& list) {
int attribSize = p->getSize() * 4; //4 is the sizeof GLfixed or GLfloat in bytes
int stride = p->getStride()?p->getStride():attribSize;
int start = p->getBufferOffset();
for(int i=0 ; i < count; i++) {
GLuint index = getIndex(indices_type, indices, i);
list.addRange(Range(start+index*stride,attribSize));
}
}
int bytesRangesToIndices(RangeList& ranges,GLESpointer* p,GLuint* indices) {
int attribSize = p->getSize() * 4; //4 is the sizeof GLfixed or GLfloat in bytes
int stride = p->getStride()?p->getStride():attribSize;
int offset = p->getBufferOffset();
int n = 0;
for(int i=0;i<ranges.size();i++) {
int startIndex = (ranges[i].getStart() - offset) / stride;
int nElements = ranges[i].getSize()/attribSize;
for(int j=0;j<nElements;j++) {
indices[n++] = startIndex+j;
}
}
return n;
}
void GLEScontext::convertDirect(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum array_id,GLESpointer* p) {
GLenum type = p->getType();
int attribSize = p->getSize();
unsigned int size = attribSize*count + first;
unsigned int bytes = type == GL_FIXED ? sizeof(GLfixed):sizeof(GLbyte);
cArrs.allocArr(size,type);
int stride = p->getStride()?p->getStride():bytes*attribSize;
const char* data = (const char*)p->getArrayData() + (first*stride);
if(type == GL_FIXED) {
convertFixedDirectLoop(data,stride,cArrs.getCurrentData(),size*sizeof(GLfloat),attribSize*sizeof(GLfloat),attribSize);
} else if(type == GL_BYTE) {
convertByteDirectLoop(data,stride,cArrs.getCurrentData(),size*sizeof(GLshort),attribSize*sizeof(GLshort),attribSize);
}
}
void GLEScontext::convertDirectVBO(GLESConversionArrays& cArrs,GLint first,GLsizei count,GLenum array_id,GLESpointer* p) {
RangeList ranges;
RangeList conversions;
GLuint* indices = NULL;
int attribSize = p->getSize();
int stride = p->getStride()?p->getStride():sizeof(GLfixed)*attribSize;
char* data = (char*)p->getBufferData() + (first*stride);
if(p->bufferNeedConversion()) {
directToBytesRanges(first,count,p,ranges); //converting indices range to buffer bytes ranges by offset
p->getBufferConversions(ranges,conversions); // getting from the buffer the relevant ranges that still needs to be converted
if(conversions.size()) { // there are some elements to convert
indices = new GLuint[count];
int nIndices = bytesRangesToIndices(conversions,p,indices); //converting bytes ranges by offset to indices in this array
convertFixedIndirectLoop(data,stride,data,nIndices,GL_UNSIGNED_INT,indices,stride,attribSize);
}
}
if(indices) delete[] indices;
cArrs.setArr(data,p->getStride(),GL_FLOAT);
}
unsigned int GLEScontext::findMaxIndex(GLsizei count,GLenum type,const GLvoid* indices) {
//finding max index
unsigned int max = 0;
if(type == GL_UNSIGNED_BYTE) {
GLubyte* b_indices =(GLubyte *)indices;
for(int i=0;i<count;i++) {
if(b_indices[i] > max) max = b_indices[i];
}
} else if (type == GL_UNSIGNED_SHORT) {
GLushort* us_indices =(GLushort *)indices;
for(int i=0;i<count;i++) {
if(us_indices[i] > max) max = us_indices[i];
}
} else { // type == GL_UNSIGNED_INT
GLuint* ui_indices =(GLuint *)indices;
for(int i=0;i<count;i++) {
if(ui_indices[i] > max) max = ui_indices[i];
}
}
return max;
}
void GLEScontext::convertIndirect(GLESConversionArrays& cArrs,GLsizei count,GLenum indices_type,const GLvoid* indices,GLenum array_id,GLESpointer* p) {
GLenum type = p->getType();
int maxElements = findMaxIndex(count,indices_type,indices) + 1;
int attribSize = p->getSize();
int size = attribSize * maxElements;
unsigned int bytes = type == GL_FIXED ? sizeof(GLfixed):sizeof(GLbyte);
cArrs.allocArr(size,type);
int stride = p->getStride()?p->getStride():bytes*attribSize;
const char* data = (const char*)p->getArrayData();
if(type == GL_FIXED) {
convertFixedIndirectLoop(data,stride,cArrs.getCurrentData(),count,indices_type,indices,attribSize*sizeof(GLfloat),attribSize);
} else if(type == GL_BYTE){
convertByteIndirectLoop(data,stride,cArrs.getCurrentData(),count,indices_type,indices,attribSize*sizeof(GLshort),attribSize);
}
}
void GLEScontext::convertIndirectVBO(GLESConversionArrays& cArrs,GLsizei count,GLenum indices_type,const GLvoid* indices,GLenum array_id,GLESpointer* p) {
RangeList ranges;
RangeList conversions;
GLuint* conversionIndices = NULL;
int attribSize = p->getSize();
int stride = p->getStride()?p->getStride():sizeof(GLfixed)*attribSize;
char* data = static_cast<char*>(p->getBufferData());
if(p->bufferNeedConversion()) {
indirectToBytesRanges(indices,indices_type,count,p,ranges); //converting indices range to buffer bytes ranges by offset
p->getBufferConversions(ranges,conversions); // getting from the buffer the relevant ranges that still needs to be converted
if(conversions.size()) { // there are some elements to convert
conversionIndices = new GLuint[count];
int nIndices = bytesRangesToIndices(conversions,p,conversionIndices); //converting bytes ranges by offset to indices in this array
convertFixedIndirectLoop(data,stride,data,nIndices,GL_UNSIGNED_INT,conversionIndices,stride,attribSize);
}
}
if(conversionIndices) delete[] conversionIndices;
cArrs.setArr(data,p->getStride(),GL_FLOAT);
}
void GLEScontext::bindBuffer(GLenum target,GLuint buffer) {
if(target == GL_ARRAY_BUFFER) {
m_arrayBuffer = buffer;
} else {
m_elementBuffer = buffer;
}
}
void GLEScontext::unbindBuffer(GLuint buffer) {
if(m_arrayBuffer == buffer)
{
m_arrayBuffer = 0;
}
if(m_elementBuffer == buffer)
{
m_elementBuffer = 0;
}
}
//checks if any buffer is binded to target
bool GLEScontext::isBindedBuffer(GLenum target) {
if(target == GL_ARRAY_BUFFER) {
return m_arrayBuffer != 0;
} else {
return m_elementBuffer != 0;
}
}
GLuint GLEScontext::getBuffer(GLenum target) {
return target == GL_ARRAY_BUFFER ? m_arrayBuffer:m_elementBuffer;
}
GLvoid* GLEScontext::getBindedBuffer(GLenum target) {
GLuint bufferName = getBuffer(target);
if(!bufferName) return NULL;
GLESbuffer* vbo = static_cast<GLESbuffer*>(
m_shareGroup
->getObjectData(NamedObjectType::VERTEXBUFFER, bufferName));
return vbo->getData();
}
void GLEScontext::getBufferSize(GLenum target,GLint* param) {
GLuint bufferName = getBuffer(target);
GLESbuffer* vbo = static_cast<GLESbuffer*>(
m_shareGroup
->getObjectData(NamedObjectType::VERTEXBUFFER, bufferName));
*param = vbo->getSize();
}
void GLEScontext::getBufferUsage(GLenum target,GLint* param) {
GLuint bufferName = getBuffer(target);
GLESbuffer* vbo = static_cast<GLESbuffer*>(
m_shareGroup
->getObjectData(NamedObjectType::VERTEXBUFFER, bufferName));
*param = vbo->getUsage();
}
bool GLEScontext::setBufferData(GLenum target,GLsizeiptr size,const GLvoid* data,GLenum usage) {
GLuint bufferName = getBuffer(target);
if(!bufferName) return false;
GLESbuffer* vbo = static_cast<GLESbuffer*>(
m_shareGroup
->getObjectData(NamedObjectType::VERTEXBUFFER, bufferName));
return vbo->setBuffer(size,usage,data);
}
bool GLEScontext::setBufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const GLvoid* data) {
GLuint bufferName = getBuffer(target);
if(!bufferName) return false;
GLESbuffer* vbo = static_cast<GLESbuffer*>(
m_shareGroup
->getObjectData(NamedObjectType::VERTEXBUFFER, bufferName));
return vbo->setSubBuffer(offset,size,data);
}
const char * GLEScontext::getExtensionString() {
const char * ret;
s_lock.lock();
if (s_glExtensions)
ret = s_glExtensions->c_str();
else
ret="";
s_lock.unlock();
return ret;
}
const char * GLEScontext::getVendorString() const {
return s_glVendor.c_str();
}
const char * GLEScontext::getRendererString() const {
return s_glRenderer.c_str();
}
const char * GLEScontext::getVersionString() const {
return s_glVersion.c_str();
}
void GLEScontext::getGlobalLock() {
s_lock.lock();
}
void GLEScontext::releaseGlobalLock() {
s_lock.unlock();
}
void GLEScontext::initCapsLocked(const GLubyte * extensionString)
{
const char* cstring = (const char*)extensionString;
s_glDispatch.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS,&s_glSupport.maxVertexAttribs);
s_glDispatch.glGetIntegerv(GL_MAX_CLIP_PLANES,&s_glSupport.maxClipPlane);
s_glDispatch.glGetIntegerv(GL_MAX_LIGHTS,&s_glSupport.maxLights);
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_SIZE,&s_glSupport.maxTexSize);
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_UNITS,&s_glSupport.maxTexUnits);
s_glDispatch.glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&s_glSupport.maxTexImageUnits);
s_glDispatch.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &s_glSupport.maxCombinedTexImageUnits);
const GLubyte* glslVersion = s_glDispatch.glGetString(GL_SHADING_LANGUAGE_VERSION);
s_glSupport.glslVersion = Version((const char*)(glslVersion));
const GLubyte* glVersion = s_glDispatch.glGetString(GL_VERSION);
if (strstr(cstring,"GL_EXT_bgra ")!=NULL)
s_glSupport.GL_EXT_TEXTURE_FORMAT_BGRA8888 = true;
if (strstr(cstring,"GL_EXT_framebuffer_object ")!=NULL)
s_glSupport.GL_EXT_FRAMEBUFFER_OBJECT = true;
if (strstr(cstring,"GL_ARB_vertex_blend ")!=NULL)
s_glSupport.GL_ARB_VERTEX_BLEND = true;
if (strstr(cstring,"GL_ARB_matrix_palette ")!=NULL)
s_glSupport.GL_ARB_MATRIX_PALETTE = true;
if (strstr(cstring,"GL_EXT_packed_depth_stencil ")!=NULL )
s_glSupport.GL_EXT_PACKED_DEPTH_STENCIL = true;
if (strstr(cstring,"GL_OES_read_format ")!=NULL)
s_glSupport.GL_OES_READ_FORMAT = true;
if (strstr(cstring,"GL_ARB_half_float_pixel ")!=NULL)
s_glSupport.GL_ARB_HALF_FLOAT_PIXEL = true;
if (strstr(cstring,"GL_NV_half_float ")!=NULL)
s_glSupport.GL_NV_HALF_FLOAT = true;
if (strstr(cstring,"GL_ARB_half_float_vertex ")!=NULL)
s_glSupport.GL_ARB_HALF_FLOAT_VERTEX = true;
if (strstr(cstring,"GL_SGIS_generate_mipmap ")!=NULL)
s_glSupport.GL_SGIS_GENERATE_MIPMAP = true;
if (strstr(cstring,"GL_ARB_ES2_compatibility ")!=NULL)
s_glSupport.GL_ARB_ES2_COMPATIBILITY = true;
if (strstr(cstring,"GL_OES_standard_derivatives ")!=NULL)
s_glSupport.GL_OES_STANDARD_DERIVATIVES = true;
if (strstr(cstring,"GL_ARB_texture_non_power_of_two")!=NULL)
s_glSupport.GL_OES_TEXTURE_NPOT = true;
if (!(Version((const char*)glVersion) < Version("3.0")) || strstr(cstring,"GL_OES_rgb8_rgba8")!=NULL)
s_glSupport.GL_OES_RGB8_RGBA8 = true;
}
void GLEScontext::buildStrings(const char* baseVendor,
const char* baseRenderer, const char* baseVersion, const char* version)
{
static const char VENDOR[] = {"Google ("};
static const char RENDERER[] = {"Android Emulator OpenGL ES Translator ("};
const size_t VENDOR_LEN = sizeof(VENDOR) - 1;
const size_t RENDERER_LEN = sizeof(RENDERER) - 1;
// Sanitize the strings as some OpenGL implementations return NULL
// when asked the basic questions (this happened at least once on a client
// machine)
if (!baseVendor) {
baseVendor = "N/A";
}
if (!baseRenderer) {
baseRenderer = "N/A";
}
if (!baseVersion) {
baseVersion = "N/A";
}
if (!version) {
version = "N/A";
}
size_t baseVendorLen = strlen(baseVendor);
s_glVendor.clear();
s_glVendor.reserve(baseVendorLen + VENDOR_LEN + 1);
s_glVendor.append(VENDOR, VENDOR_LEN);
s_glVendor.append(baseVendor, baseVendorLen);
s_glVendor.append(")", 1);
size_t baseRendererLen = strlen(baseRenderer);
s_glRenderer.clear();
s_glRenderer.reserve(baseRendererLen + RENDERER_LEN + 1);
s_glRenderer.append(RENDERER, RENDERER_LEN);
s_glRenderer.append(baseRenderer, baseRendererLen);
s_glRenderer.append(")", 1);
size_t baseVersionLen = strlen(baseVersion);
size_t versionLen = strlen(version);
s_glVersion.clear();
s_glVersion.reserve(baseVersionLen + versionLen + 3);
s_glVersion.append(version, versionLen);
s_glVersion.append(" (", 2);
s_glVersion.append(baseVersion, baseVersionLen);
s_glVersion.append(")", 1);
}
bool GLEScontext::isTextureUnitEnabled(GLenum unit) {
for (int i=0;i<NUM_TEXTURE_TARGETS;++i) {
if (m_texState[unit-GL_TEXTURE0][i].enabled)
return true;
}
return false;
}
bool GLEScontext::glGetBooleanv(GLenum pname, GLboolean *params)
{
GLint iParam;
if(glGetIntegerv(pname, &iParam))
{
*params = (iParam != 0);
return true;
}
return false;
}
bool GLEScontext::glGetFixedv(GLenum pname, GLfixed *params)
{
bool result = false;
GLint numParams = 1;
GLint* iParams = new GLint[numParams];
if (numParams>0 && glGetIntegerv(pname,iParams)) {
while(numParams >= 0)
{
params[numParams] = I2X(iParams[numParams]);
numParams--;
}
result = true;
}
delete [] iParams;
return result;
}
bool GLEScontext::glGetFloatv(GLenum pname, GLfloat *params)
{
bool result = false;
GLint numParams = 1;
GLint* iParams = new GLint[numParams];
if (numParams>0 && glGetIntegerv(pname,iParams)) {
while(numParams >= 0)
{
params[numParams] = (GLfloat)iParams[numParams];
numParams--;
}
result = true;
}
delete [] iParams;
return result;
}
bool GLEScontext::glGetIntegerv(GLenum pname, GLint *params)
{
switch(pname)
{
case GL_ARRAY_BUFFER_BINDING:
*params = m_arrayBuffer;
break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
*params = m_elementBuffer;
break;
case GL_TEXTURE_BINDING_CUBE_MAP:
*params = m_texState[m_activeTexture][TEXTURE_CUBE_MAP].texture;
break;
case GL_TEXTURE_BINDING_2D:
*params = m_texState[m_activeTexture][TEXTURE_2D].texture;
break;
case GL_ACTIVE_TEXTURE:
*params = m_activeTexture+GL_TEXTURE0;
break;
case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
*params = GL_UNSIGNED_BYTE;
break;
case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
*params = GL_RGBA;
break;
case GL_MAX_TEXTURE_SIZE:
*params = getMaxTexSize();
break;
default:
return false;
}
return true;
}
TextureTarget GLEScontext::GLTextureTargetToLocal(GLenum target) {
TextureTarget value=TEXTURE_2D;
switch (target) {
case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
value = TEXTURE_CUBE_MAP;
break;
case GL_TEXTURE_2D:
value = TEXTURE_2D;
break;
}
return value;
}
unsigned int GLEScontext::getBindedTexture(GLenum target) {
TextureTarget pos = GLTextureTargetToLocal(target);
return m_texState[m_activeTexture][pos].texture;
}
unsigned int GLEScontext::getBindedTexture(GLenum unit, GLenum target) {
TextureTarget pos = GLTextureTargetToLocal(target);
return m_texState[unit-GL_TEXTURE0][pos].texture;
}
void GLEScontext::setBindedTexture(GLenum target, unsigned int tex) {
TextureTarget pos = GLTextureTargetToLocal(target);
m_texState[m_activeTexture][pos].texture = tex;
}
void GLEScontext::setTextureEnabled(GLenum target, GLenum enable) {
TextureTarget pos = GLTextureTargetToLocal(target);
m_texState[m_activeTexture][pos].enabled = enable;
}
#define INTERNAL_NAME(x) (x +0x100000000ll);
ObjectLocalName GLEScontext::getDefaultTextureName(GLenum target) {
ObjectLocalName name = 0;
switch (GLTextureTargetToLocal(target)) {
case TEXTURE_2D:
name = INTERNAL_NAME(0);
break;
case TEXTURE_CUBE_MAP:
name = INTERNAL_NAME(1);
break;
default:
name = 0;
break;
}
return name;
}
void GLEScontext::drawValidate(void)
{
if(m_framebuffer == 0)
return;
auto fbObj = m_shareGroup->getObjectData(
NamedObjectType::FRAMEBUFFER, m_framebuffer);
if (!fbObj)
return;
FramebufferData *fbData = (FramebufferData *)fbObj;
fbData->validate(this);
}