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 BufferData * GLSharedGroup::getBufferData(GLuint bufferId) 244 { 245 android::AutoMutex _lock(m_lock); 246 return m_buffers.valueFor(bufferId); 247 } 248 249 void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, void * data) 250 { 251 android::AutoMutex _lock(m_lock); 252 m_buffers.add(bufferId, new BufferData(size, data)); 253 } 254 255 void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, void * data) 256 { 257 android::AutoMutex _lock(m_lock); 258 ssize_t idx = m_buffers.indexOfKey(bufferId); 259 if (idx >= 0) { 260 delete m_buffers.valueAt(idx); 261 m_buffers.editValueAt(idx) = new BufferData(size, data); 262 } else { 263 m_buffers.add(bufferId, new BufferData(size, data)); 264 } 265 } 266 267 GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, void * data) 268 { 269 android::AutoMutex _lock(m_lock); 270 BufferData * buf = m_buffers.valueFor(bufferId); 271 if ((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)) return GL_INVALID_VALUE; 272 273 //it's safe to update now 274 memcpy((char*)buf->m_fixedBuffer.ptr() + offset, data, size); 275 return GL_NO_ERROR; 276 } 277 278 void GLSharedGroup::deleteBufferData(GLuint bufferId) 279 { 280 android::AutoMutex _lock(m_lock); 281 ssize_t idx = m_buffers.indexOfKey(bufferId); 282 if (idx >= 0) { 283 delete m_buffers.valueAt(idx); 284 m_buffers.removeItemsAt(idx); 285 } 286 } 287 288 void GLSharedGroup::addProgramData(GLuint program) 289 { 290 android::AutoMutex _lock(m_lock); 291 ProgramData *pData = m_programs.valueFor(program); 292 if (pData) 293 { 294 m_programs.removeItem(program); 295 delete pData; 296 } 297 298 m_programs.add(program,new ProgramData()); 299 } 300 301 void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes) 302 { 303 android::AutoMutex _lock(m_lock); 304 ProgramData *pData = m_programs.valueFor(program); 305 if (pData) 306 { 307 pData->initProgramData(numIndexes); 308 } 309 } 310 311 bool GLSharedGroup::isProgramInitialized(GLuint program) 312 { 313 android::AutoMutex _lock(m_lock); 314 ProgramData* pData = m_programs.valueFor(program); 315 if (pData) 316 { 317 return pData->isInitialized(); 318 } 319 return false; 320 } 321 322 void GLSharedGroup::deleteProgramData(GLuint program) 323 { 324 android::AutoMutex _lock(m_lock); 325 ProgramData *pData = m_programs.valueFor(program); 326 if (pData) 327 delete pData; 328 m_programs.removeItem(program); 329 } 330 331 void GLSharedGroup::attachShader(GLuint program, GLuint shader) 332 { 333 android::AutoMutex _lock(m_lock); 334 ProgramData* programData = m_programs.valueFor(program); 335 ssize_t idx = m_shaders.indexOfKey(shader); 336 if (programData && idx >= 0) { 337 if (programData->attachShader(shader)) { 338 refShaderDataLocked(idx); 339 } 340 } 341 } 342 343 void GLSharedGroup::detachShader(GLuint program, GLuint shader) 344 { 345 android::AutoMutex _lock(m_lock); 346 ProgramData* programData = m_programs.valueFor(program); 347 ssize_t idx = m_shaders.indexOfKey(shader); 348 if (programData && idx >= 0) { 349 if (programData->detachShader(shader)) { 350 unrefShaderDataLocked(idx); 351 } 352 } 353 } 354 355 void GLSharedGroup::setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name) 356 { 357 android::AutoMutex _lock(m_lock); 358 ProgramData* pData = m_programs.valueFor(program); 359 if (pData) 360 { 361 pData->setIndexInfo(index,base,size,type); 362 363 if (type == GL_SAMPLER_2D) { 364 size_t n = pData->getNumShaders(); 365 for (size_t i = 0; i < n; i++) { 366 GLuint shaderId = pData->getShader(i); 367 ShaderData* shader = m_shaders.valueFor(shaderId); 368 if (!shader) continue; 369 ShaderData::StringList::iterator nameIter = shader->samplerExternalNames.begin(); 370 ShaderData::StringList::iterator nameEnd = shader->samplerExternalNames.end(); 371 while (nameIter != nameEnd) { 372 if (*nameIter == name) { 373 pData->setIndexFlags(index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL); 374 break; 375 } 376 ++nameIter; 377 } 378 } 379 } 380 } 381 } 382 383 GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) 384 { 385 android::AutoMutex _lock(m_lock); 386 ProgramData* pData = m_programs.valueFor(program); 387 GLenum type=0; 388 if (pData) 389 { 390 type = pData->getTypeForLocation(location); 391 } 392 return type; 393 } 394 395 bool GLSharedGroup::isProgram(GLuint program) 396 { 397 android::AutoMutex _lock(m_lock); 398 ProgramData* pData = m_programs.valueFor(program); 399 return (pData!=NULL); 400 } 401 402 void GLSharedGroup::setupLocationShiftWAR(GLuint program) 403 { 404 android::AutoMutex _lock(m_lock); 405 ProgramData* pData = m_programs.valueFor(program); 406 if (pData) pData->setupLocationShiftWAR(); 407 } 408 409 GLint GLSharedGroup::locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex) 410 { 411 android::AutoMutex _lock(m_lock); 412 ProgramData* pData = m_programs.valueFor(program); 413 if (pData) return pData->locationWARHostToApp(hostLoc, arrIndex); 414 else return hostLoc; 415 } 416 417 GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc) 418 { 419 android::AutoMutex _lock(m_lock); 420 ProgramData* pData = m_programs.valueFor(program); 421 if (pData) return pData->locationWARAppToHost(appLoc); 422 else return appLoc; 423 } 424 425 bool GLSharedGroup::needUniformLocationWAR(GLuint program) 426 { 427 android::AutoMutex _lock(m_lock); 428 ProgramData* pData = m_programs.valueFor(program); 429 if (pData) return pData->needUniformLocationWAR(); 430 return false; 431 } 432 433 GLint GLSharedGroup::getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const 434 { 435 android::AutoMutex _lock(m_lock); 436 ProgramData* pData = m_programs.valueFor(program); 437 return pData ? pData->getNextSamplerUniform(index, val, target) : -1; 438 } 439 440 bool GLSharedGroup::setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target) 441 { 442 android::AutoMutex _lock(m_lock); 443 ProgramData* pData = m_programs.valueFor(program); 444 return pData ? pData->setSamplerUniform(appLoc, val, target) : false; 445 } 446 447 bool GLSharedGroup::addShaderData(GLuint shader) 448 { 449 android::AutoMutex _lock(m_lock); 450 ShaderData* data = new ShaderData; 451 if (data) { 452 if (m_shaders.add(shader, data) < 0) { 453 delete data; 454 data = NULL; 455 } 456 data->refcount = 1; 457 } 458 return data != NULL; 459 } 460 461 ShaderData* GLSharedGroup::getShaderData(GLuint shader) 462 { 463 android::AutoMutex _lock(m_lock); 464 return m_shaders.valueFor(shader); 465 } 466 467 void GLSharedGroup::unrefShaderData(GLuint shader) 468 { 469 android::AutoMutex _lock(m_lock); 470 ssize_t idx = m_shaders.indexOfKey(shader); 471 if (idx >= 0) { 472 unrefShaderDataLocked(idx); 473 } 474 } 475 476 void GLSharedGroup::refShaderDataLocked(ssize_t shaderIdx) 477 { 478 assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size()); 479 ShaderData* data = m_shaders.valueAt(shaderIdx); 480 data->refcount++; 481 } 482 483 void GLSharedGroup::unrefShaderDataLocked(ssize_t shaderIdx) 484 { 485 assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size()); 486 ShaderData* data = m_shaders.valueAt(shaderIdx); 487 if (--data->refcount == 0) { 488 delete data; 489 m_shaders.removeItemsAt(shaderIdx); 490 } 491 } 492