1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "GLSharedGroup.h" 18 19 /**** BufferData ****/ 20 21 BufferData::BufferData() : m_size(0) {}; 22 BufferData::BufferData(GLsizeiptr size, void * data) : m_size(size) 23 { 24 void * buffer = NULL; 25 if (size>0) buffer = m_fixedBuffer.alloc(size); 26 if (data) memcpy(buffer, data, size); 27 } 28 29 /**** ProgramData ****/ 30 ProgramData::ProgramData() : m_numIndexes(0), 31 m_initialized(false), 32 m_locShiftWAR(false) 33 { 34 m_Indexes = NULL; 35 } 36 37 void ProgramData::initProgramData(GLuint numIndexes) 38 { 39 m_initialized = true; 40 m_numIndexes = numIndexes; 41 delete[] m_Indexes; 42 m_Indexes = new IndexInfo[numIndexes]; 43 m_locShiftWAR = false; 44 } 45 46 bool ProgramData::isInitialized() 47 { 48 return m_initialized; 49 } 50 51 ProgramData::~ProgramData() 52 { 53 delete[] m_Indexes; 54 m_Indexes = NULL; 55 } 56 57 void ProgramData::setIndexInfo(GLuint index, GLint base, GLint size, GLenum type) 58 { 59 if (index>=m_numIndexes) 60 return; 61 m_Indexes[index].base = base; 62 m_Indexes[index].size = size; 63 m_Indexes[index].type = type; 64 if (index > 0) { 65 m_Indexes[index].appBase = m_Indexes[index-1].appBase + 66 m_Indexes[index-1].size; 67 } 68 else { 69 m_Indexes[index].appBase = 0; 70 } 71 m_Indexes[index].hostLocsPerElement = 1; 72 m_Indexes[index].flags = 0; 73 m_Indexes[index].samplerValue = 0; 74 } 75 76 void ProgramData::setIndexFlags(GLuint index, GLuint flags) 77 { 78 if (index >= m_numIndexes) 79 return; 80 m_Indexes[index].flags |= flags; 81 } 82 83 GLuint ProgramData::getIndexForLocation(GLint location) 84 { 85 GLuint index = m_numIndexes; 86 GLint minDist = -1; 87 for (GLuint i=0;i<m_numIndexes;++i) 88 { 89 GLint dist = location - m_Indexes[i].base; 90 if (dist >= 0 && 91 (minDist < 0 || dist < minDist)) { 92 index = i; 93 minDist = dist; 94 } 95 } 96 return index; 97 } 98 99 GLenum ProgramData::getTypeForLocation(GLint location) 100 { 101 GLuint index = getIndexForLocation(location); 102 if (index<m_numIndexes) { 103 return m_Indexes[index].type; 104 } 105 return 0; 106 } 107 108 void ProgramData::setupLocationShiftWAR() 109 { 110 m_locShiftWAR = false; 111 for (GLuint i=0; i<m_numIndexes; i++) { 112 if (0 != (m_Indexes[i].base & 0xffff)) { 113 return; 114 } 115 } 116 // if we have one uniform at location 0, we do not need the WAR. 117 if (m_numIndexes > 1) { 118 m_locShiftWAR = true; 119 } 120 } 121 122 GLint ProgramData::locationWARHostToApp(GLint hostLoc, GLint arrIndex) 123 { 124 if (!m_locShiftWAR) return hostLoc; 125 126 GLuint index = getIndexForLocation(hostLoc); 127 if (index<m_numIndexes) { 128 if (arrIndex > 0) { 129 m_Indexes[index].hostLocsPerElement = 130 (hostLoc - m_Indexes[index].base) / arrIndex; 131 } 132 return m_Indexes[index].appBase + arrIndex; 133 } 134 return -1; 135 } 136 137 GLint ProgramData::locationWARAppToHost(GLint appLoc) 138 { 139 if (!m_locShiftWAR) return appLoc; 140 141 for(GLuint i=0; i<m_numIndexes; i++) { 142 GLint elemIndex = appLoc - m_Indexes[i].appBase; 143 if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) { 144 return m_Indexes[i].base + 145 elemIndex * m_Indexes[i].hostLocsPerElement; 146 } 147 } 148 return -1; 149 } 150 151 GLint ProgramData::getNextSamplerUniform(GLint index, GLint* val, GLenum* target) 152 { 153 for (GLint i = index + 1; i >= 0 && i < (GLint)m_numIndexes; i++) { 154 if (m_Indexes[i].type == GL_SAMPLER_2D) { 155 if (val) *val = m_Indexes[i].samplerValue; 156 if (target) { 157 if (m_Indexes[i].flags & INDEX_FLAG_SAMPLER_EXTERNAL) { 158 *target = GL_TEXTURE_EXTERNAL_OES; 159 } else { 160 *target = GL_TEXTURE_2D; 161 } 162 } 163 return i; 164 } 165 } 166 return -1; 167 } 168 169 bool ProgramData::setSamplerUniform(GLint appLoc, GLint val, GLenum* target) 170 { 171 for (GLuint i = 0; i < m_numIndexes; i++) { 172 GLint elemIndex = appLoc - m_Indexes[i].appBase; 173 if (elemIndex >= 0 && elemIndex < m_Indexes[i].size) { 174 if (m_Indexes[i].type == GL_TEXTURE_2D) { 175 m_Indexes[i].samplerValue = val; 176 if (target) { 177 if (m_Indexes[i].flags & INDEX_FLAG_SAMPLER_EXTERNAL) { 178 *target = GL_TEXTURE_EXTERNAL_OES; 179 } else { 180 *target = GL_TEXTURE_2D; 181 } 182 } 183 return true; 184 } 185 } 186 } 187 return false; 188 } 189 190 bool ProgramData::attachShader(GLuint shader) 191 { 192 size_t n = m_shaders.size(); 193 for (size_t i = 0; i < n; i++) { 194 if (m_shaders[i] == shader) { 195 return false; 196 } 197 } 198 // AKA m_shaders.push_back(), but that has an ambiguous call to insertAt() 199 // due to the default parameters. This is the desired insertAt() overload. 200 m_shaders.insertAt(shader, m_shaders.size(), 1); 201 return true; 202 } 203 204 bool ProgramData::detachShader(GLuint shader) 205 { 206 size_t n = m_shaders.size(); 207 for (size_t i = 0; i < n; i++) { 208 if (m_shaders[i] == shader) { 209 m_shaders.removeAt(i); 210 return true; 211 } 212 } 213 return false; 214 } 215 216 /***** GLSharedGroup ****/ 217 218 GLSharedGroup::GLSharedGroup() : 219 m_buffers(android::DefaultKeyedVector<GLuint, BufferData*>(NULL)), 220 m_programs(android::DefaultKeyedVector<GLuint, ProgramData*>(NULL)), 221 m_shaders(android::DefaultKeyedVector<GLuint, ShaderData*>(NULL)) 222 { 223 } 224 225 GLSharedGroup::~GLSharedGroup() 226 { 227 m_buffers.clear(); 228 m_programs.clear(); 229 } 230 231 BufferData * GLSharedGroup::getBufferData(GLuint bufferId) 232 { 233 android::AutoMutex _lock(m_lock); 234 return m_buffers.valueFor(bufferId); 235 } 236 237 void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, void * data) 238 { 239 android::AutoMutex _lock(m_lock); 240 m_buffers.add(bufferId, new BufferData(size, data)); 241 } 242 243 void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, void * data) 244 { 245 android::AutoMutex _lock(m_lock); 246 m_buffers.replaceValueFor(bufferId, new BufferData(size, data)); 247 } 248 249 GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, void * data) 250 { 251 android::AutoMutex _lock(m_lock); 252 BufferData * buf = m_buffers.valueFor(bufferId); 253 if ((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)) return GL_INVALID_VALUE; 254 255 //it's safe to update now 256 memcpy((char*)buf->m_fixedBuffer.ptr() + offset, data, size); 257 return GL_NO_ERROR; 258 } 259 260 void GLSharedGroup::deleteBufferData(GLuint bufferId) 261 { 262 android::AutoMutex _lock(m_lock); 263 m_buffers.removeItem(bufferId); 264 } 265 266 void GLSharedGroup::addProgramData(GLuint program) 267 { 268 android::AutoMutex _lock(m_lock); 269 ProgramData *pData = m_programs.valueFor(program); 270 if (pData) 271 { 272 m_programs.removeItem(program); 273 delete pData; 274 } 275 276 m_programs.add(program,new ProgramData()); 277 } 278 279 void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes) 280 { 281 android::AutoMutex _lock(m_lock); 282 ProgramData *pData = m_programs.valueFor(program); 283 if (pData) 284 { 285 pData->initProgramData(numIndexes); 286 } 287 } 288 289 bool GLSharedGroup::isProgramInitialized(GLuint program) 290 { 291 android::AutoMutex _lock(m_lock); 292 ProgramData* pData = m_programs.valueFor(program); 293 if (pData) 294 { 295 return pData->isInitialized(); 296 } 297 return false; 298 } 299 300 void GLSharedGroup::deleteProgramData(GLuint program) 301 { 302 android::AutoMutex _lock(m_lock); 303 ProgramData *pData = m_programs.valueFor(program); 304 if (pData) 305 delete pData; 306 m_programs.removeItem(program); 307 } 308 309 void GLSharedGroup::attachShader(GLuint program, GLuint shader) 310 { 311 android::AutoMutex _lock(m_lock); 312 ProgramData* programData = m_programs.valueFor(program); 313 ssize_t idx = m_shaders.indexOfKey(shader); 314 if (programData && idx >= 0) { 315 if (programData->attachShader(shader)) { 316 refShaderDataLocked(idx); 317 } 318 } 319 } 320 321 void GLSharedGroup::detachShader(GLuint program, GLuint shader) 322 { 323 android::AutoMutex _lock(m_lock); 324 ProgramData* programData = m_programs.valueFor(program); 325 ssize_t idx = m_shaders.indexOfKey(shader); 326 if (programData && idx >= 0) { 327 if (programData->detachShader(shader)) { 328 unrefShaderDataLocked(idx); 329 } 330 } 331 } 332 333 void GLSharedGroup::setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name) 334 { 335 android::AutoMutex _lock(m_lock); 336 ProgramData* pData = m_programs.valueFor(program); 337 if (pData) 338 { 339 pData->setIndexInfo(index,base,size,type); 340 341 if (type == GL_SAMPLER_2D) { 342 size_t n = pData->getNumShaders(); 343 for (size_t i = 0; i < n; i++) { 344 GLuint shaderId = pData->getShader(i); 345 ShaderData* shader = m_shaders.valueFor(shaderId); 346 if (!shader) continue; 347 ShaderData::StringList::iterator nameIter = shader->samplerExternalNames.begin(); 348 ShaderData::StringList::iterator nameEnd = shader->samplerExternalNames.end(); 349 while (nameIter != nameEnd) { 350 if (*nameIter == name) { 351 pData->setIndexFlags(index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL); 352 break; 353 } 354 ++nameIter; 355 } 356 } 357 } 358 } 359 } 360 361 GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) 362 { 363 android::AutoMutex _lock(m_lock); 364 ProgramData* pData = m_programs.valueFor(program); 365 GLenum type=0; 366 if (pData) 367 { 368 type = pData->getTypeForLocation(location); 369 } 370 return type; 371 } 372 373 bool GLSharedGroup::isProgram(GLuint program) 374 { 375 android::AutoMutex _lock(m_lock); 376 ProgramData* pData = m_programs.valueFor(program); 377 return (pData!=NULL); 378 } 379 380 void GLSharedGroup::setupLocationShiftWAR(GLuint program) 381 { 382 android::AutoMutex _lock(m_lock); 383 ProgramData* pData = m_programs.valueFor(program); 384 if (pData) pData->setupLocationShiftWAR(); 385 } 386 387 GLint GLSharedGroup::locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex) 388 { 389 android::AutoMutex _lock(m_lock); 390 ProgramData* pData = m_programs.valueFor(program); 391 if (pData) return pData->locationWARHostToApp(hostLoc, arrIndex); 392 else return hostLoc; 393 } 394 395 GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc) 396 { 397 android::AutoMutex _lock(m_lock); 398 ProgramData* pData = m_programs.valueFor(program); 399 if (pData) return pData->locationWARAppToHost(appLoc); 400 else return appLoc; 401 } 402 403 bool GLSharedGroup::needUniformLocationWAR(GLuint program) 404 { 405 android::AutoMutex _lock(m_lock); 406 ProgramData* pData = m_programs.valueFor(program); 407 if (pData) return pData->needUniformLocationWAR(); 408 return false; 409 } 410 411 GLint GLSharedGroup::getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const 412 { 413 android::AutoMutex _lock(m_lock); 414 ProgramData* pData = m_programs.valueFor(program); 415 return pData ? pData->getNextSamplerUniform(index, val, target) : -1; 416 } 417 418 bool GLSharedGroup::setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target) 419 { 420 android::AutoMutex _lock(m_lock); 421 ProgramData* pData = m_programs.valueFor(program); 422 return pData ? pData->setSamplerUniform(appLoc, val, target) : false; 423 } 424 425 bool GLSharedGroup::addShaderData(GLuint shader) 426 { 427 android::AutoMutex _lock(m_lock); 428 ShaderData* data = new ShaderData; 429 if (data) { 430 if (m_shaders.add(shader, data) < 0) { 431 delete data; 432 data = NULL; 433 } 434 data->refcount = 1; 435 } 436 return data != NULL; 437 } 438 439 ShaderData* GLSharedGroup::getShaderData(GLuint shader) 440 { 441 android::AutoMutex _lock(m_lock); 442 return m_shaders.valueFor(shader); 443 } 444 445 void GLSharedGroup::unrefShaderData(GLuint shader) 446 { 447 android::AutoMutex _lock(m_lock); 448 ssize_t idx = m_shaders.indexOfKey(shader); 449 if (idx >= 0) { 450 unrefShaderDataLocked(idx); 451 } 452 } 453 454 void GLSharedGroup::refShaderDataLocked(ssize_t shaderIdx) 455 { 456 assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size()); 457 ShaderData* data = m_shaders.valueAt(shaderIdx); 458 data->refcount++; 459 } 460 461 void GLSharedGroup::unrefShaderDataLocked(ssize_t shaderIdx) 462 { 463 assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size()); 464 ShaderData* data = m_shaders.valueAt(shaderIdx); 465 if (--data->refcount == 0) { 466 delete data; 467 m_shaders.removeItemsAt(shaderIdx); 468 } 469 } 470