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
BufferData()21 BufferData::BufferData() : m_size(0) {};
BufferData(GLsizeiptr size,void * data)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 ****/
ProgramData()30 ProgramData::ProgramData() : m_numIndexes(0),
31 m_initialized(false),
32 m_locShiftWAR(false)
33 {
34 m_Indexes = NULL;
35 }
36
initProgramData(GLuint numIndexes)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
isInitialized()46 bool ProgramData::isInitialized()
47 {
48 return m_initialized;
49 }
50
~ProgramData()51 ProgramData::~ProgramData()
52 {
53 delete[] m_Indexes;
54 m_Indexes = NULL;
55 }
56
setIndexInfo(GLuint index,GLint base,GLint size,GLenum type)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
setIndexFlags(GLuint index,GLuint flags)76 void ProgramData::setIndexFlags(GLuint index, GLuint flags)
77 {
78 if (index >= m_numIndexes)
79 return;
80 m_Indexes[index].flags |= flags;
81 }
82
getIndexForLocation(GLint location)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
getTypeForLocation(GLint location)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
setupLocationShiftWAR()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
locationWARHostToApp(GLint hostLoc,GLint arrIndex)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
locationWARAppToHost(GLint appLoc)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
getNextSamplerUniform(GLint index,GLint * val,GLenum * target)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
setSamplerUniform(GLint appLoc,GLint val,GLenum * target)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
attachShader(GLuint shader)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
detachShader(GLuint shader)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
GLSharedGroup()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
~GLSharedGroup()225 GLSharedGroup::~GLSharedGroup()
226 {
227 m_buffers.clear();
228 m_programs.clear();
229 }
230
getBufferData(GLuint bufferId)231 BufferData * GLSharedGroup::getBufferData(GLuint bufferId)
232 {
233 android::AutoMutex _lock(m_lock);
234 return m_buffers.valueFor(bufferId);
235 }
236
addBufferData(GLuint bufferId,GLsizeiptr size,void * data)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
updateBufferData(GLuint bufferId,GLsizeiptr size,void * data)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
subUpdateBufferData(GLuint bufferId,GLintptr offset,GLsizeiptr size,void * data)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
deleteBufferData(GLuint bufferId)260 void GLSharedGroup::deleteBufferData(GLuint bufferId)
261 {
262 android::AutoMutex _lock(m_lock);
263 m_buffers.removeItem(bufferId);
264 }
265
addProgramData(GLuint program)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
initProgramData(GLuint program,GLuint numIndexes)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
isProgramInitialized(GLuint program)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
deleteProgramData(GLuint program)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
attachShader(GLuint program,GLuint shader)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
detachShader(GLuint program,GLuint shader)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
setProgramIndexInfo(GLuint program,GLuint index,GLint base,GLint size,GLenum type,const char * name)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
getProgramUniformType(GLuint program,GLint location)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
isProgram(GLuint program)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
setupLocationShiftWAR(GLuint program)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
locationWARHostToApp(GLuint program,GLint hostLoc,GLint arrIndex)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
locationWARAppToHost(GLuint program,GLint appLoc)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
needUniformLocationWAR(GLuint program)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
getNextSamplerUniform(GLuint program,GLint index,GLint * val,GLenum * target) const411 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
setSamplerUniform(GLuint program,GLint appLoc,GLint val,GLenum * target)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
addShaderData(GLuint shader)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
getShaderData(GLuint shader)439 ShaderData* GLSharedGroup::getShaderData(GLuint shader)
440 {
441 android::AutoMutex _lock(m_lock);
442 return m_shaders.valueFor(shader);
443 }
444
unrefShaderData(GLuint shader)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
refShaderDataLocked(ssize_t shaderIdx)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
unrefShaderDataLocked(ssize_t shaderIdx)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