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 
BufferData()23 BufferData::BufferData() : m_size(0) {};
24 
BufferData(GLsizeiptr size,void * data)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 ****/
ProgramData()38 ProgramData::ProgramData() : m_numIndexes(0),
39                              m_initialized(false),
40                              m_locShiftWAR(false)
41 {
42     m_Indexes = NULL;
43 }
44 
initProgramData(GLuint numIndexes)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 
isInitialized()54 bool ProgramData::isInitialized()
55 {
56     return m_initialized;
57 }
58 
~ProgramData()59 ProgramData::~ProgramData()
60 {
61     delete[] m_Indexes;
62     m_Indexes = NULL;
63 }
64 
setIndexInfo(GLuint index,GLint base,GLint size,GLenum type)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 
setIndexFlags(GLuint index,GLuint flags)84 void ProgramData::setIndexFlags(GLuint index, GLuint flags)
85 {
86     if (index >= m_numIndexes)
87         return;
88     m_Indexes[index].flags |= flags;
89 }
90 
getIndexForLocation(GLint location)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 
getTypeForLocation(GLint location)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 
setupLocationShiftWAR()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 
locationWARHostToApp(GLint hostLoc,GLint arrIndex)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 
locationWARAppToHost(GLint appLoc)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 
getNextSamplerUniform(GLint index,GLint * val,GLenum * target)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 
setSamplerUniform(GLint appLoc,GLint val,GLenum * target)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 
attachShader(GLuint shader)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 
detachShader(GLuint shader)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 
GLSharedGroup()224 GLSharedGroup::GLSharedGroup() :
225     m_buffers(), m_programs(), m_shaders() {}
226 
~GLSharedGroup()227 GLSharedGroup::~GLSharedGroup() {}
228 
getBufferData(GLuint bufferId)229 BufferData * GLSharedGroup::getBufferData(GLuint bufferId)
230 {
231     emugl::Mutex::AutoLock _lock(m_lock);
232     return m_buffers.get(bufferId);
233 }
234 
addBufferData(GLuint bufferId,GLsizeiptr size,void * data)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 
updateBufferData(GLuint bufferId,GLsizeiptr size,void * data)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 
subUpdateBufferData(GLuint bufferId,GLintptr offset,GLsizeiptr size,void * data)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 
deleteBufferData(GLuint bufferId)258 void GLSharedGroup::deleteBufferData(GLuint bufferId)
259 {
260     emugl::Mutex::AutoLock _lock(m_lock);
261     (void) m_buffers.remove(bufferId);
262 }
263 
addProgramData(GLuint program)264 void GLSharedGroup::addProgramData(GLuint program)
265 {
266     emugl::Mutex::AutoLock _lock(m_lock);
267     m_programs.set(program, new ProgramData());
268 }
269 
initProgramData(GLuint program,GLuint numIndexes)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 
isProgramInitialized(GLuint program)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 
deleteProgramData(GLuint program)286 void GLSharedGroup::deleteProgramData(GLuint program)
287 {
288     emugl::Mutex::AutoLock _lock(m_lock);
289     m_programs.remove(program);
290 }
291 
attachShader(GLuint program,GLuint shader)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 
detachShader(GLuint program,GLuint shader)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 
setProgramIndexInfo(GLuint program,GLuint index,GLint base,GLint size,GLenum type,const char * name)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 
getProgramUniformType(GLuint program,GLint location)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 
isProgram(GLuint program)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 
setupLocationShiftWAR(GLuint program)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 
locationWARHostToApp(GLuint program,GLint hostLoc,GLint arrIndex)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 
locationWARAppToHost(GLuint program,GLint appLoc)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 
needUniformLocationWAR(GLuint program)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 
getNextSamplerUniform(GLuint program,GLint index,GLint * val,GLenum * target) const394 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 
setSamplerUniform(GLuint program,GLint appLoc,GLint val,GLenum * target)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 
addShaderData(GLuint shader)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 
getShaderData(GLuint shader)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 
unrefShaderData(GLuint shader)433 void GLSharedGroup::unrefShaderData(GLuint shader)
434 {
435     emugl::Mutex::AutoLock _lock(m_lock);
436     unrefShaderDataLocked(shader);
437 }
438 
refShaderDataLocked(GLuint shader)439 void GLSharedGroup::refShaderDataLocked(GLuint shader)
440 {
441     ShaderData* data = m_shaders.get(shader);
442     if (data) {
443         data->refcount++;
444     }
445 }
446 
unrefShaderDataLocked(GLuint shader)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