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