| /* |
| * 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" |
| |
| /**** 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_initialized(false) { |
| m_Indexes = NULL; |
| } |
| |
| void ProgramData::initProgramData(GLuint numIndexes) { |
| m_initialized = true; |
| m_numIndexes = numIndexes; |
| |
| delete [] m_Indexes; |
| |
| m_Indexes = new IndexInfo[numIndexes]; |
| } |
| |
| bool ProgramData::isInitialized() { |
| return m_initialized; |
| } |
| |
| ProgramData::~ProgramData() { |
| |
| delete [] m_Indexes; |
| |
| 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::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; |
| } |
| |
| 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) { |
| size_t n = m_shaders.size(); |
| |
| for (size_t i = 0; i < n; i++) { |
| if (m_shaders[i] == shader) { |
| return false; |
| } |
| } |
| m_shaders.push_back(shader); |
| 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); |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /***** 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) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| return (findObjectOrDefault(m_shaders, obj) || |
| findObjectOrDefault(m_programs, obj) || |
| findObjectOrDefault(m_shaderPrograms, m_shaderProgramIdMap[obj])); |
| } |
| |
| BufferData* GLSharedGroup::getBufferData(GLuint bufferId) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| return findObjectOrDefault(m_buffers, bufferId); |
| } |
| |
| SharedTextureDataMap* GLSharedGroup::getTextureData() { |
| return &m_textureRecs; |
| } |
| |
| void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, const void* data) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| m_buffers[bufferId] = new BufferData(size, data); |
| } |
| |
| void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, const void* data) { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| BufferData* buf = findObjectOrDefault(m_buffers, bufferId); |
| if (buf) { |
| delete buf; |
| m_buffers.erase(bufferId); |
| } |
| } |
| |
| void GLSharedGroup::addProgramData(GLuint program) { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ProgramData* pData = findObjectOrDefault(m_programs, program); |
| if (pData) { |
| pData->initProgramData(numIndexes); |
| } |
| } |
| |
| bool GLSharedGroup::isProgramInitialized(GLuint program) { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ProgramData* pData = findObjectOrDefault(m_programs, program); |
| |
| if (pData) 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. |
| void GLSharedGroup::attachShader(GLuint program, GLuint shader) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ProgramData* pData = findObjectOrDefault(m_programs, program); |
| ShaderData* sData = findObjectOrDefault(m_shaders, shader); |
| |
| if (pData && sData) { |
| if (pData->attachShader(shader)) { |
| refShaderDataLocked(shader); |
| } |
| } |
| } |
| |
| void GLSharedGroup::detachShader(GLuint program, GLuint shader) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ProgramData* pData = findObjectOrDefault(m_programs, program); |
| ShaderData* sData = findObjectOrDefault(m_shaders, shader); |
| if (pData && sData) { |
| if (pData->detachShader(shader)) { |
| unrefShaderDataLocked(shader); |
| } |
| } |
| } |
| |
| // Not needed/used for separate shader programs. |
| void GLSharedGroup::setProgramIndexInfo( |
| GLuint program, GLuint index, GLint base, |
| GLint size, GLenum type, const char* name) { |
| |
| android::AutoMutex _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) { |
| pData->setIndexFlags( |
| index, |
| ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL); |
| break; |
| } |
| ++nameIter; |
| } |
| } |
| } |
| } |
| } |
| |
| GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _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) const { |
| |
| android::AutoMutex _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) { |
| |
| android::AutoMutex _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::isShader(GLuint shader) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ShaderData* pData = findObjectOrDefault(m_shaders, shader); |
| |
| return pData != NULL; |
| } |
| |
| bool GLSharedGroup::addShaderData(GLuint shader) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ShaderData* data = new ShaderData; |
| |
| if (data) { |
| m_shaders[shader] = data; |
| data->refcount = 1; |
| } |
| |
| return data != NULL; |
| } |
| |
| ShaderData* GLSharedGroup::getShaderData(GLuint shader) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| return findObjectOrDefault(m_shaders, shader); |
| } |
| |
| void GLSharedGroup::unrefShaderData(GLuint shader) { |
| |
| android::AutoMutex _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); |
| } |
| } |
| |
| uint32_t GLSharedGroup::addNewShaderProgramData() { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ShaderProgramData* data = new ShaderProgramData; |
| uint32_t currId = m_shaderProgramId; |
| |
| ALOGD("%s: new data %p id %u", __FUNCTION__, data, currId); |
| |
| m_shaderPrograms[currId] = data; |
| m_shaderProgramId++; |
| return currId; |
| } |
| |
| void GLSharedGroup::associateGLShaderProgram( |
| GLuint shaderProgramName, uint32_t shaderProgramId) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| m_shaderProgramIdMap[shaderProgramName] = shaderProgramId; |
| } |
| |
| ShaderProgramData* GLSharedGroup::getShaderProgramDataById(uint32_t id) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ShaderProgramData* res = findObjectOrDefault(m_shaderPrograms, id); |
| |
| ALOGD("%s: id=%u res=%p", __FUNCTION__, id, res); |
| |
| return res; |
| } |
| |
| ShaderProgramData* GLSharedGroup::getShaderProgramData( |
| GLuint shaderProgramName) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| return findObjectOrDefault(m_shaderPrograms, |
| m_shaderProgramIdMap[shaderProgramName]); |
| } |
| |
| void GLSharedGroup::deleteShaderProgramDataById(uint32_t id) { |
| |
| android::AutoMutex _lock(m_lock); |
| |
| ShaderProgramData* data = |
| findObjectOrDefault(m_shaderPrograms, id); |
| |
| delete data; |
| |
| m_shaderPrograms.erase(id); |
| } |
| |
| |
| void GLSharedGroup::deleteShaderProgramData(GLuint shaderProgramName) { |
| |
| android::AutoMutex _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) { |
| ShaderProgramData* spData = getShaderProgramData(shaderProgram); |
| spData->programData.initProgramData(numIndices); |
| } |
| |
| 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; |
| } |
| } |
| } |