OSDN Git Service

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