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