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
21template <typename T>
22static 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
30BufferData::BufferData() : m_size(0), m_usage(0), m_mapped(false) {};
31BufferData::BufferData(GLsizeiptr size, void * data) : m_size(size), m_usage(0), m_mapped(false)
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 ****/
39ProgramData::ProgramData() : m_numIndexes(0),
40                             m_initialized(false),
41                             m_locShiftWAR(false)
42{
43    m_Indexes = NULL;
44}
45
46void 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
55bool ProgramData::isInitialized()
56{
57    return m_initialized;
58}
59
60ProgramData::~ProgramData()
61{
62    delete[] m_Indexes;
63    m_Indexes = NULL;
64}
65
66void 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
85void ProgramData::setIndexFlags(GLuint index, GLuint flags)
86{
87    if (index >= m_numIndexes)
88        return;
89    m_Indexes[index].flags |= flags;
90}
91
92GLuint 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
108GLenum 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
117void 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
131GLint 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
146GLint 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
160GLint 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
178bool 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
199bool 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
213bool 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
227GLSharedGroup::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    m_shaderPrograms(android::DefaultKeyedVector<GLuint, ShaderProgramData*>(NULL))
232{
233}
234
235GLSharedGroup::~GLSharedGroup()
236{
237    m_buffers.clear();
238    m_programs.clear();
239    clearObjectMap(m_buffers);
240    clearObjectMap(m_programs);
241    clearObjectMap(m_shaders);
242    clearObjectMap(m_shaderPrograms);
243}
244
245bool GLSharedGroup::isShaderOrProgramObject(GLuint obj)
246{
247    android::AutoMutex _lock(m_lock);
248    return ((m_shaders.valueFor(obj)!=NULL) ||
249            (m_programs.valueFor(obj)!=NULL) ||
250            (m_shaderPrograms.valueFor(m_shaderProgramIdMap[obj]) !=NULL));
251}
252
253BufferData * GLSharedGroup::getBufferData(GLuint bufferId)
254{
255    android::AutoMutex _lock(m_lock);
256    return m_buffers.valueFor(bufferId);
257}
258
259SharedTextureDataMap* GLSharedGroup::getTextureData() {
260    return &m_textureRecs;
261}
262
263void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, void * data)
264{
265    android::AutoMutex _lock(m_lock);
266    m_buffers.add(bufferId, new BufferData(size, data));
267}
268
269void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, void * data)
270{
271    android::AutoMutex _lock(m_lock);
272    ssize_t idx = m_buffers.indexOfKey(bufferId);
273    if (idx >= 0) {
274        delete m_buffers.valueAt(idx);
275        m_buffers.editValueAt(idx) = new BufferData(size, data);
276    } else {
277        m_buffers.add(bufferId, new BufferData(size, data));
278    }
279}
280
281void GLSharedGroup::setBufferUsage(GLuint bufferId, GLenum usage) {
282    android::AutoMutex _lock(m_lock);
283    ssize_t idx = m_buffers.indexOfKey(bufferId);
284    if (idx >= 0) {
285        m_buffers.editValueAt(idx)->m_usage = usage;
286    }
287}
288
289void GLSharedGroup::setBufferMapped(GLuint bufferId, bool mapped) {
290    BufferData * buf = m_buffers.valueFor(bufferId);
291    if (!buf) return;
292    buf->m_mapped = mapped;
293}
294
295GLenum GLSharedGroup::getBufferUsage(GLuint bufferId) {
296    BufferData * buf = m_buffers.valueFor(bufferId);
297    if (!buf) return 0;
298    return buf->m_usage;
299}
300
301bool GLSharedGroup::isBufferMapped(GLuint bufferId) {
302    BufferData * buf = m_buffers.valueFor(bufferId);
303    if (!buf) return false;
304    return buf->m_mapped;
305}
306
307GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, void * data)
308{
309    android::AutoMutex _lock(m_lock);
310    BufferData * buf = m_buffers.valueFor(bufferId);
311    if ((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)) return GL_INVALID_VALUE;
312
313    //it's safe to update now
314    memcpy((char*)buf->m_fixedBuffer.ptr() + offset, data, size);
315
316    buf->m_indexRangeCache.invalidateRange((size_t)offset, (size_t)size);
317    return GL_NO_ERROR;
318}
319
320void GLSharedGroup::deleteBufferData(GLuint bufferId)
321{
322    android::AutoMutex _lock(m_lock);
323    ssize_t idx = m_buffers.indexOfKey(bufferId);
324    if (idx >= 0) {
325        delete m_buffers.valueAt(idx);
326        m_buffers.removeItemsAt(idx);
327    }
328}
329
330void GLSharedGroup::addProgramData(GLuint program)
331{
332    android::AutoMutex _lock(m_lock);
333    ProgramData *pData = m_programs.valueFor(program);
334    if (pData)
335    {
336        m_programs.removeItem(program);
337        delete pData;
338    }
339
340    m_programs.add(program,new ProgramData());
341}
342
343void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes)
344{
345    android::AutoMutex _lock(m_lock);
346    ProgramData *pData = m_programs.valueFor(program);
347    if (pData)
348    {
349        pData->initProgramData(numIndexes);
350    }
351}
352
353bool GLSharedGroup::isProgramInitialized(GLuint program)
354{
355    android::AutoMutex _lock(m_lock);
356    ProgramData* pData = m_programs.valueFor(program);
357    if (pData)
358    {
359        return pData->isInitialized();
360    }
361    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return false;
362    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
363    if (spData) {
364        return spData->programData->isInitialized();
365    }
366    return false;
367}
368
369void GLSharedGroup::deleteProgramData(GLuint program)
370{
371    android::AutoMutex _lock(m_lock);
372    ProgramData *pData = m_programs.valueFor(program);
373    if (pData) {
374        delete pData;
375    }
376    m_programs.removeItem(program);
377
378    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return;
379    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
380    if (spData) {
381        delete spData;
382    }
383    m_shaderPrograms.removeItem(m_shaderProgramIdMap[program]);
384    m_shaderProgramIdMap.erase(program);
385}
386
387// No such thing for separable shader programs.
388void GLSharedGroup::attachShader(GLuint program, GLuint shader)
389{
390    android::AutoMutex _lock(m_lock);
391    ProgramData* programData = m_programs.valueFor(program);
392    ssize_t idx = m_shaders.indexOfKey(shader);
393    if (programData && idx >= 0) {
394        if (programData->attachShader(shader)) {
395            refShaderDataLocked(idx);
396        }
397    }
398}
399
400void GLSharedGroup::detachShader(GLuint program, GLuint shader)
401{
402    android::AutoMutex _lock(m_lock);
403    ProgramData* programData = m_programs.valueFor(program);
404    ssize_t idx = m_shaders.indexOfKey(shader);
405    if (programData && idx >= 0) {
406        if (programData->detachShader(shader)) {
407            unrefShaderDataLocked(idx);
408        }
409    }
410}
411
412// Not needed/used for separate shader programs.
413void GLSharedGroup::setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name)
414{
415    android::AutoMutex _lock(m_lock);
416    ProgramData* pData = m_programs.valueFor(program);
417    if (pData)
418    {
419        pData->setIndexInfo(index,base,size,type);
420
421        if (type == GL_SAMPLER_2D) {
422            size_t n = pData->getNumShaders();
423            for (size_t i = 0; i < n; i++) {
424                GLuint shaderId = pData->getShader(i);
425                ShaderData* shader = m_shaders.valueFor(shaderId);
426                if (!shader) continue;
427                ShaderData::StringList::iterator nameIter = shader->samplerExternalNames.begin();
428                ShaderData::StringList::iterator nameEnd  = shader->samplerExternalNames.end();
429                while (nameIter != nameEnd) {
430                    if (*nameIter == name) {
431                        pData->setIndexFlags(index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL);
432                        break;
433                    }
434                    ++nameIter;
435                }
436            }
437        }
438    }
439}
440
441GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location)
442{
443    android::AutoMutex _lock(m_lock);
444    ProgramData* pData = m_programs.valueFor(program);
445    GLenum type=0;
446    if (pData) {
447        type = pData->getTypeForLocation(location);
448    }
449    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return type;
450    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
451    if (spData) {
452        type = spData->programData->getTypeForLocation(location);
453    }
454    return type;
455}
456
457bool  GLSharedGroup::isProgram(GLuint program)
458{
459    android::AutoMutex _lock(m_lock);
460    ProgramData* pData = m_programs.valueFor(program);
461    if (pData) return true;
462    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return false;
463    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
464    if (spData) return true;
465    return false;
466}
467
468void GLSharedGroup::setupLocationShiftWAR(GLuint program)
469{
470    android::AutoMutex _lock(m_lock);
471    ProgramData* pData = m_programs.valueFor(program);
472    if (pData) pData->setupLocationShiftWAR();
473}
474
475GLint GLSharedGroup::locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex)
476{
477    android::AutoMutex _lock(m_lock);
478    ProgramData* pData = m_programs.valueFor(program);
479    if (pData) return pData->locationWARHostToApp(hostLoc, arrIndex);
480    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return hostLoc;
481    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
482    if (spData) return spData->programData->locationWARHostToApp(hostLoc, arrIndex);
483    return hostLoc;
484}
485
486GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc)
487{
488    android::AutoMutex _lock(m_lock);
489    ProgramData* pData = m_programs.valueFor(program);
490    if (pData) return pData->locationWARAppToHost(appLoc);
491    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return appLoc;
492    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
493    if (spData) return spData->programData->locationWARAppToHost(appLoc);
494    return appLoc;
495}
496
497bool GLSharedGroup::needUniformLocationWAR(GLuint program)
498{
499    android::AutoMutex _lock(m_lock);
500    ProgramData* pData = m_programs.valueFor(program);
501    if (pData) return pData->needUniformLocationWAR();
502    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return false;
503    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
504    if (spData) return spData->programData->needUniformLocationWAR();
505    return false;
506}
507
508GLint GLSharedGroup::getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const
509{
510    android::AutoMutex _lock(m_lock);
511    ProgramData* pData = m_programs.valueFor(program);
512    if (pData) return pData->getNextSamplerUniform(index, val, target);
513    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return -1;
514    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap.find(program)->second);
515    if (spData) return spData->programData->getNextSamplerUniform(index, val, target);
516    return -1;
517}
518
519bool GLSharedGroup::setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target)
520{
521    android::AutoMutex _lock(m_lock);
522    ProgramData* pData = m_programs.valueFor(program);
523    if (pData) return pData->setSamplerUniform(appLoc, val, target);
524    if (m_shaderProgramIdMap.find(program) == m_shaderProgramIdMap.end()) return false;
525    ShaderProgramData* spData = m_shaderPrograms.valueFor(m_shaderProgramIdMap[program]);
526    if (spData) return spData->programData->setSamplerUniform(appLoc, val, target);
527    return false;
528}
529
530bool  GLSharedGroup::isShader(GLuint shader)
531{
532    android::AutoMutex _lock(m_lock);
533    ShaderData* pData = m_shaders.valueFor(shader);
534    return (pData!=NULL);
535}
536
537bool GLSharedGroup::addShaderData(GLuint shader)
538{
539    android::AutoMutex _lock(m_lock);
540    ShaderData* data = new ShaderData;
541    if (data) {
542        if (m_shaders.add(shader, data) < 0) {
543            delete data;
544            data = NULL;
545        }
546        data->refcount = 1;
547    }
548    return data != NULL;
549}
550
551ShaderData* GLSharedGroup::getShaderData(GLuint shader)
552{
553    android::AutoMutex _lock(m_lock);
554    return m_shaders.valueFor(shader);
555}
556
557void GLSharedGroup::unrefShaderData(GLuint shader)
558{
559    android::AutoMutex _lock(m_lock);
560    ssize_t idx = m_shaders.indexOfKey(shader);
561    if (idx >= 0) {
562        unrefShaderDataLocked(idx);
563    }
564}
565
566void GLSharedGroup::refShaderDataLocked(ssize_t shaderIdx)
567{
568    assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size());
569    ShaderData* data = m_shaders.valueAt(shaderIdx);
570    data->refcount++;
571}
572
573void GLSharedGroup::unrefShaderDataLocked(ssize_t shaderIdx)
574{
575    assert(shaderIdx >= 0 && shaderIdx <= m_shaders.size());
576    ShaderData* data = m_shaders.valueAt(shaderIdx);
577    if (--data->refcount == 0) {
578        delete data;
579        m_shaders.removeItemsAt(shaderIdx);
580    }
581}
582
583uint32_t GLSharedGroup::addNewShaderProgramData() {
584    android::AutoMutex _lock(m_lock);
585    ShaderProgramData* data = new ShaderProgramData;
586    uint32_t currId = m_shaderProgramId;
587    ALOGD("%s: new data %p id %u", __FUNCTION__, data, currId);
588    m_shaderPrograms.add(currId, data);
589    m_shaderProgramId++;
590    return currId;
591}
592
593void GLSharedGroup::associateGLShaderProgram(GLuint shaderProgramName, uint32_t shaderProgramId) {
594    android::AutoMutex _lock(m_lock);
595    m_shaderProgramIdMap[shaderProgramName] = shaderProgramId;
596}
597
598ShaderProgramData* GLSharedGroup::getShaderProgramDataById(uint32_t id) {
599    android::AutoMutex _lock(m_lock);
600    ShaderProgramData* res = m_shaderPrograms.valueFor(id);
601    ALOGD("%s: id=%u res=%p", __FUNCTION__, id, res);
602    return res;
603}
604
605ShaderProgramData* GLSharedGroup::getShaderProgramData(GLuint shaderProgramName) {
606    android::AutoMutex _lock(m_lock);
607    return m_shaderPrograms.valueFor(m_shaderProgramIdMap[shaderProgramName]);
608}
609
610void GLSharedGroup::deleteShaderProgramDataById(uint32_t id) {
611    android::AutoMutex _lock(m_lock);
612    ShaderProgramData* data = m_shaderPrograms.valueFor(id);
613    delete data;
614    m_shaderPrograms.removeItemsAt(id);
615}
616
617
618void GLSharedGroup::deleteShaderProgramData(GLuint shaderProgramName) {
619    android::AutoMutex _lock(m_lock);
620    uint32_t id = m_shaderProgramIdMap[shaderProgramName];
621    ShaderProgramData* data = m_shaderPrograms.valueFor(id);
622    delete data;
623    m_shaderPrograms.removeItemsAt(id);
624    m_shaderProgramIdMap.erase(shaderProgramName);
625}
626
627void GLSharedGroup::initShaderProgramData(GLuint shaderProgram, GLuint numIndices) {
628    ShaderProgramData* spData = getShaderProgramData(shaderProgram);
629    spData->programData->initProgramData(numIndices);
630}
631
632void GLSharedGroup::setShaderProgramIndexInfo(GLuint shaderProgram, GLuint index, GLint base, GLint size, GLenum type, const char* name) {
633    ShaderProgramData* spData = getShaderProgramData(shaderProgram);
634    ProgramData* pData = spData->programData;
635    ShaderData* sData = spData->shaderData;
636
637    if (pData)
638    {
639        pData->setIndexInfo(index, base, size, type);
640
641        if (type == GL_SAMPLER_2D) {
642            ShaderData::StringList::iterator nameIter = sData->samplerExternalNames.begin();
643            ShaderData::StringList::iterator nameEnd  = sData->samplerExternalNames.end();
644            while (nameIter != nameEnd) {
645                if (*nameIter == name) {
646                    pData->setIndexFlags(index, ProgramData::INDEX_FLAG_SAMPLER_EXTERNAL);
647                    break;
648                }
649                ++nameIter;
650            }
651        }
652    }
653}
654
655void GLSharedGroup::setupShaderProgramLocationShiftWAR(GLuint shaderProgram) {
656    ShaderProgramData* spData = getShaderProgramData(shaderProgram);
657    spData->programData->setupLocationShiftWAR();
658}
659