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