/* * Copyright (C) 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 "GLSharedGroup.h" #include "KeyedVectorUtils.h" #include "glUtils.h" /**** BufferData ****/ BufferData::BufferData() : m_size(0), m_usage(0), m_mapped(false) {}; BufferData::BufferData(GLsizeiptr size, const void* data) : m_size(size), m_usage(0), m_mapped(false) { if (size > 0) { m_fixedBuffer.resize(size); } if (data) { memcpy(m_fixedBuffer.data(), data, size); } } /**** ProgramData ****/ ProgramData::ProgramData() : m_numIndexes(0), m_numAttributes(0), m_initialized(false) { m_Indexes = NULL; m_attribIndexes = NULL; m_refcount = 1; m_linkStatus = 0; m_activeUniformBlockCount = 0; m_transformFeedbackVaryingsCount = 0; } void ProgramData::initProgramData(GLuint numIndexes, GLuint numAttributes) { m_initialized = true; m_numIndexes = numIndexes; m_numAttributes = numAttributes; delete [] m_Indexes; delete [] m_attribIndexes; m_Indexes = new IndexInfo[numIndexes]; m_attribIndexes = new AttribInfo[m_numAttributes]; } bool ProgramData::isInitialized() { return m_initialized; } ProgramData::~ProgramData() { delete [] m_Indexes; delete [] m_attribIndexes; m_Indexes = NULL; } void ProgramData::setIndexInfo( GLuint index, GLint base, GLint size, GLenum type) { if (index >= m_numIndexes) return; m_Indexes[index].base = base; m_Indexes[index].size = size; m_Indexes[index].type = type; m_Indexes[index].hostLocsPerElement = 1; m_Indexes[index].flags = 0; m_Indexes[index].samplerValue = 0; } void ProgramData::setAttribInfo( GLuint index, GLint attribLoc, GLint size, GLenum type) { if (index >= m_numAttributes) return; m_attribIndexes[index].attribLoc = attribLoc; m_attribIndexes[index].size = size; m_attribIndexes[index].type = type; } void ProgramData::setIndexFlags(GLuint index, GLuint flags) { if (index >= m_numIndexes) return; m_Indexes[index].flags |= flags; } GLuint ProgramData::getIndexForLocation(GLint location) { GLuint index = m_numIndexes; GLint minDist = -1; for (GLuint i = 0; i < m_numIndexes; ++i) { GLint dist = location - m_Indexes[i].base; if (dist >= 0 && (minDist < 0 || dist < minDist)) { index = i; minDist = dist; } } return index; } GLenum ProgramData::getTypeForLocation(GLint location) { GLuint index = getIndexForLocation(location); if (index < m_numIndexes) { return m_Indexes[index].type; } return 0; } bool ProgramData::isValidUniformLocation(GLint location) { for (GLuint i = 0; i < m_numIndexes; ++i) { if (location >= m_Indexes[i].base && location < m_Indexes[i].base + m_Indexes[i].size) return true; } return false; } GLint ProgramData::getNextSamplerUniform( GLint index, GLint* val, GLenum* target) { for (GLint i = index + 1; i >= 0 && i < (GLint)m_numIndexes; i++) { if (m_Indexes[i].type == GL_SAMPLER_2D) { if (val) *val = m_Indexes[i].samplerValue; if (target) { if (m_Indexes[i].flags & INDEX_FLAG_SAMPLER_EXTERNAL) { *target = GL_TEXTURE_EXTERNAL_OES; } else { *target = GL_TEXTURE_2D; } } return i; } } return -1; } bool ProgramData::setSamplerUniform(GLint appLoc, GLint val, GLenum* target) { for (GLuint i = 0; i < m_numIndexes; i++) { GLint elemIndex = appLoc - m_Indexes[i].base; if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) { if (m_Indexes[i].type == GL_SAMPLER_2D) { m_Indexes[i].samplerValue = val; if (target) { if (m_Indexes[i].flags & INDEX_FLAG_SAMPLER_EXTERNAL) { *target = GL_TEXTURE_EXTERNAL_OES; } else { *target = GL_TEXTURE_2D; } } return true; } } } return false; } bool ProgramData::attachShader(GLuint shader, GLenum shaderType) { size_t n = m_shaders.size(); for (size_t i = 0; i < n; i++) { if (m_shaders[i] == shader) { return false; } else if (m_shaderTypes[i] == shaderType) { return false; } } m_shaders.push_back(shader); m_shaderTypes.push_back(shaderType); return true; } bool ProgramData::detachShader(GLuint shader) { size_t n = m_shaders.size(); for (size_t i = 0; i < n; i++) { if (m_shaders[i] == shader) { m_shaders.erase(m_shaders.begin() + i); m_shaderTypes.erase(m_shaderTypes.begin() + i); return true; } } return false; } UniformValidationInfo ProgramData::compileValidationInfo(bool* error) const { UniformValidationInfo res; if (!m_Indexes) { *error = true; return res; } for (GLuint i = 0; i < m_numIndexes; ++i) { if (m_Indexes[i].base < 0) continue; UniformLocationInfo info = { .valid = true, .columns = getColumnsOfType(m_Indexes[i].type), .rows = getRowsOfType(m_Indexes[i].type), .isSampler = isSamplerType(m_Indexes[i].type), .isInt = isIntegerType(m_Indexes[i].type), .isArray = m_Indexes[i].size > 1, .isUnsigned = isUnsignedIntType(m_Indexes[i].type), .isBool = isBoolType(m_Indexes[i].type), }; for (GLuint j = 0; j < m_Indexes[i].size; ++j) { res.add(m_Indexes[i].base + j, info); } } return res; } AttribValidationInfo ProgramData::compileAttribValidationInfo(bool* error) const { AttribValidationInfo res; if (!m_attribIndexes) { *error = true; return res; } for (GLuint i = 0; i < m_numAttributes; ++i) { if (m_attribIndexes[i].attribLoc < 0) continue; AttribIndexInfo info = { .validInProgram = true, }; for (GLuint j = 0; j < getAttributeCountOfType(m_attribIndexes[i].type) * m_attribIndexes[i].size ; ++j) { res.add(m_attribIndexes[i].attribLoc + j, info); } } return res; } /***** GLSharedGroup ****/ GLSharedGroup::GLSharedGroup() { } GLSharedGroup::~GLSharedGroup() { m_buffers.clear(); m_programs.clear(); clearObjectMap(m_buffers); clearObjectMap(m_programs); clearObjectMap(m_shaders); clearObjectMap(m_shaderPrograms); } bool GLSharedGroup::isShaderOrProgramObject(GLuint obj) { AutoLock _lock(m_lock); return (findObjectOrDefault(m_shaders, obj) || findObjectOrDefault(m_programs, obj) || findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[obj])); } BufferData* GLSharedGroup::getBufferData(GLuint bufferId) { AutoLock _lock(m_lock); return findObjectOrDefault(m_buffers, bufferId); } SharedTextureDataMap* GLSharedGroup::getTextureData() { return &m_textureRecs; } RenderbufferInfo* GLSharedGroup::getRenderbufferInfo() { return &m_renderbufferInfo; } SamplerInfo* GLSharedGroup::getSamplerInfo() { return &m_samplerInfo; } void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, const void* data) { AutoLock _lock(m_lock); m_buffers[bufferId] = new BufferData(size, data); } void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, const void* data) { AutoLock _lock(m_lock); BufferData* currentBuffer = findObjectOrDefault(m_buffers, bufferId); if (currentBuffer) delete currentBuffer; m_buffers[bufferId] = new BufferData(size, data); } void GLSharedGroup::setBufferUsage(GLuint bufferId, GLenum usage) { AutoLock _lock(m_lock); BufferData* data = findObjectOrDefault(m_buffers, bufferId); if (data) data->m_usage = usage; } void GLSharedGroup::setBufferMapped(GLuint bufferId, bool mapped) { BufferData* buf = findObjectOrDefault(m_buffers, bufferId); if (!buf) return; buf->m_mapped = mapped; } GLenum GLSharedGroup::getBufferUsage(GLuint bufferId) { BufferData* buf = findObjectOrDefault(m_buffers, bufferId); if (!buf) return 0; return buf->m_usage; } bool GLSharedGroup::isBufferMapped(GLuint bufferId) { BufferData* buf = findObjectOrDefault(m_buffers, bufferId); if (!buf) return false; return buf->m_mapped; } GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, const void* data) { AutoLock _lock(m_lock); BufferData* buf = findObjectOrDefault(m_buffers, bufferId); if ((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)) { return GL_INVALID_VALUE; } memcpy(&buf->m_fixedBuffer[offset], data, size); buf->m_indexRangeCache.invalidateRange((size_t)offset, (size_t)size); return GL_NO_ERROR; } void GLSharedGroup::deleteBufferData(GLuint bufferId) { AutoLock _lock(m_lock); BufferData* buf = findObjectOrDefault(m_buffers, bufferId); if (buf) { delete buf; m_buffers.erase(bufferId); } } void GLSharedGroup::addProgramData(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) { delete pData; } m_programs[program] = new ProgramData(); } void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes, GLuint numAttributes) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) { pData->initProgramData(numIndexes, numAttributes); } } void GLSharedGroup::refProgramData(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (!pData) return; pData->incRef(); } void GLSharedGroup::onUseProgram(GLuint previous, GLuint next) { if (previous == next) return; AutoLock _lock(m_lock); if (previous) { deleteProgramDataLocked(previous); } ProgramData* pData = findObjectOrDefault(m_programs, next); if (!pData) return; pData->incRef(); } bool GLSharedGroup::isProgramInitialized(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) { return pData->isInitialized(); } if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) { return false; } ShaderProgramData* shaderProgramData = findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[program]); if (shaderProgramData) { return shaderProgramData->programData.isInitialized(); } return false; } void GLSharedGroup::deleteProgramData(GLuint program) { AutoLock _lock(m_lock); deleteProgramDataLocked(program); } void GLSharedGroup::deleteProgramDataLocked(GLuint program) { ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData && pData->decRef()) { size_t numShaders = pData->getNumShaders(); for (size_t i = 0; i < numShaders; ++i) { // changes the first one detachShaderLocked(program, pData->getShader(0)); } delete pData; m_programs.erase(program); } if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return; ShaderProgramData* spData = findObjectOrDefault( m_shaderPrograms, m_shaderProgramIdMap[program]); if (spData) delete spData; m_shaderPrograms.erase(m_shaderProgramIdMap[program]); m_shaderProgramIdMap.erase(program); } // No such thing for separable shader programs. bool GLSharedGroup::attachShader(GLuint program, GLuint shader) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); ShaderData* sData = findObjectOrDefault(m_shaders, shader); bool res = false; if (pData && sData) { res = pData->attachShader(shader, sData->shaderType); if (res) { refShaderDataLocked(shader); } } return res; } bool GLSharedGroup::detachShader(GLuint program, GLuint shader) { AutoLock _lock(m_lock); return detachShaderLocked(program, shader); } bool GLSharedGroup::detachShaderLocked(GLuint program, GLuint shader) { ProgramData* pData = findObjectOrDefault(m_programs, program); ShaderData* sData = findObjectOrDefault(m_shaders, shader); bool res = false; if (pData && sData) { res = pData->detachShader(shader); if (res) { unrefShaderDataLocked(shader); } } return res; } // Not needed/used for separate shader programs. void GLSharedGroup::setProgramIndexInfo( GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) { pData->setIndexInfo(index,base,size,type); if (type == GL_SAMPLER_2D) { size_t n = pData->getNumShaders(); for (size_t i = 0; i < n; i++) { GLuint shaderId = pData->getShader(i); ShaderData* shader = findObjectOrDefault(m_shaders, shaderId); if (!shader) continue; ShaderData::StringList::iterator nameIter = shader->samplerExternalNames.begin(); ShaderData::StringList::iterator nameEnd = shader->samplerExternalNames.end(); while (nameIter != nameEnd) { if (*nameIter == name || *nameIter + "[0]" == name) { pData->setIndexFlags( index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL); break; } ++nameIter; } } } } } void GLSharedGroup::setProgramAttribInfo( GLuint program, GLuint index, GLint attribLoc, GLint size, GLenum type, __attribute__((unused)) const char* name) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (pData) { pData->setAttribInfo(index,attribLoc,size,type); } } GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); GLenum type = 0; if (pData) { type = pData->getTypeForLocation(location); } if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return type; ShaderProgramData* spData = findObjectOrDefault( m_shaderPrograms, m_shaderProgramIdMap[program]); if (spData) { type = spData->programData.getTypeForLocation(location); } return type; } bool GLSharedGroup::isProgram(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) return true; if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return false; ShaderProgramData* spData = findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[program]); if (spData) return true; return false; } GLint GLSharedGroup::getNextSamplerUniform( GLuint program, GLint index, GLint* val, GLenum* target) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) return pData->getNextSamplerUniform(index, val, target); if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return -1; ShaderProgramData* spData = findObjectOrDefault( m_shaderPrograms, findObjectOrDefault(m_shaderProgramIdMap, program)); if (spData) return spData->programData.getNextSamplerUniform(index, val, target); return -1; } bool GLSharedGroup::setSamplerUniform( GLuint program, GLint appLoc, GLint val, GLenum* target) { AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) return pData->setSamplerUniform(appLoc, val, target); if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return false; ShaderProgramData* spData = findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[program]); if (spData) return spData->programData.setSamplerUniform(appLoc, val, target); return false; } bool GLSharedGroup::isProgramUniformLocationValid(GLuint program, GLint location) { if (location < 0) return false; AutoLock _lock(m_lock); ProgramData* pData = findObjectOrDefault(m_programs, program); if (!pData) return false; return pData->isValidUniformLocation(location); } bool GLSharedGroup::isShader(GLuint shader) { AutoLock _lock(m_lock); ShaderData* pData = findObjectOrDefault(m_shaders, shader); return pData != NULL; } bool GLSharedGroup::addShaderData(GLuint shader, GLenum shaderType) { AutoLock _lock(m_lock); ShaderData* data = new ShaderData; if (data) { m_shaders[shader] = data; data->refcount = 1; data->shaderType = shaderType; } return data != NULL; } ShaderData* GLSharedGroup::getShaderData(GLuint shader) { AutoLock _lock(m_lock); return findObjectOrDefault(m_shaders, shader); } void GLSharedGroup::unrefShaderData(GLuint shader) { AutoLock _lock(m_lock); unrefShaderDataLocked(shader); } void GLSharedGroup::refShaderDataLocked(GLuint shaderId) { ShaderData* data = findObjectOrDefault(m_shaders, shaderId); data->refcount++; } void GLSharedGroup::unrefShaderDataLocked(GLuint shaderId) { ShaderData* data = findObjectOrDefault(m_shaders, shaderId); if (data && --data->refcount == 0) { delete data; m_shaders.erase(shaderId); } } ProgramData* GLSharedGroup::getProgramDataLocked(GLuint program) { // Check the space of normal programs, then separable ones ProgramData* pData = findObjectOrDefault(m_programs, program); if (pData) return pData; std::map::const_iterator it = m_shaderProgramIdMap.find(program); if (it == m_shaderProgramIdMap.end()) return NULL; ShaderProgramData* spData = findObjectOrDefault(m_shaderPrograms, it->second); if (!spData) return NULL; return &spData->programData; } uint32_t GLSharedGroup::addNewShaderProgramData() { AutoLock _lock(m_lock); ShaderProgramData* data = new ShaderProgramData; uint32_t currId = m_shaderProgramId; m_shaderPrograms[currId] = data; m_shaderProgramId++; return currId; } void GLSharedGroup::associateGLShaderProgram( GLuint shaderProgramName, uint32_t shaderProgramId) { AutoLock _lock(m_lock); m_shaderProgramIdMap[shaderProgramName] = shaderProgramId; } ShaderProgramData* GLSharedGroup::getShaderProgramDataById(uint32_t id) { AutoLock _lock(m_lock); ShaderProgramData* res = findObjectOrDefault(m_shaderPrograms, id); return res; } ShaderProgramData* GLSharedGroup::getShaderProgramData( GLuint shaderProgramName) { AutoLock _lock(m_lock); return findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[shaderProgramName]); } void GLSharedGroup::deleteShaderProgramDataById(uint32_t id) { AutoLock _lock(m_lock); ShaderProgramData* data = findObjectOrDefault(m_shaderPrograms, id); delete data; m_shaderPrograms.erase(id); } void GLSharedGroup::deleteShaderProgramData(GLuint shaderProgramName) { AutoLock _lock(m_lock); uint32_t id = m_shaderProgramIdMap[shaderProgramName]; ShaderProgramData* data = findObjectOrDefault(m_shaderPrograms, id); delete data; m_shaderPrograms.erase(id); m_shaderProgramIdMap.erase(shaderProgramName); } void GLSharedGroup::initShaderProgramData(GLuint shaderProgram, GLuint numIndices, GLuint numAttributes) { ShaderProgramData* spData = getShaderProgramData(shaderProgram); spData->programData.initProgramData(numIndices, numAttributes); } void GLSharedGroup::setShaderProgramIndexInfo( GLuint shaderProgram, GLuint index, GLint base, GLint size, GLenum type, const char* name) { ShaderProgramData* spData = getShaderProgramData(shaderProgram); ProgramData& pData = spData->programData; ShaderData& sData = spData->shaderData; pData.setIndexInfo(index, base, size, type); if (type == GL_SAMPLER_2D) { ShaderData::StringList::iterator nameIter = sData.samplerExternalNames.begin(); ShaderData::StringList::iterator nameEnd = sData.samplerExternalNames.end(); while (nameIter != nameEnd) { if (*nameIter == name) { pData.setIndexFlags( index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL); break; } ++nameIter; } } } UniformValidationInfo GLSharedGroup::getUniformValidationInfo(GLuint program) { UniformValidationInfo res; AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return res; bool error; (void)error; return pData->compileValidationInfo(&error); } AttribValidationInfo GLSharedGroup::getAttribValidationInfo(GLuint program) { AttribValidationInfo res; AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return res; bool error; (void)error; return pData->compileAttribValidationInfo(&error); } void GLSharedGroup::setProgramLinkStatus(GLuint program, GLint linkStatus) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return; pData->setLinkStatus(linkStatus); } GLint GLSharedGroup::getProgramLinkStatus(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return 0; return pData->getLinkStatus(); } void GLSharedGroup::setActiveUniformBlockCountForProgram(GLuint program, GLint count) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return; pData->setActiveUniformBlockCount(count); } GLint GLSharedGroup::getActiveUniformBlockCount(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return 0; return pData->getActiveUniformBlockCount(); } void GLSharedGroup::setTransformFeedbackVaryingsCountForProgram(GLuint program, GLint count) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return; pData->setTransformFeedbackVaryingsCount(count); } GLint GLSharedGroup::getTransformFeedbackVaryingsCountForProgram(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return 0; return pData->getTransformFeedbackVaryingsCount(); } int GLSharedGroup::getActiveUniformsCountForProgram(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return 0; return pData->getActiveUniformsCount(); } int GLSharedGroup::getActiveAttributesCountForProgram(GLuint program) { AutoLock _lock(m_lock); ProgramData* pData = getProgramDataLocked(program); if (!pData) return 0; return pData->getActiveAttributesCount(); }