blob: 4de1f1664e817af9cfbec05ffe1ea70270b2f932 [file] [log] [blame]
David Liaf94ceb2011-03-01 16:54:04 -08001#include "gles2context.h"
2
3//#undef LOGD
4//#define LOGD(...)
5
6#define API_ENTRY
7#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
8#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
9
10static inline GGLTexture * AllocTexture()
11{
12 GGLTexture * tex = (GGLTexture *)calloc(1, sizeof(GGLTexture));
13 tex->minFilter = GGLTexture::GGL_LINEAR; // should be NEAREST_ MIPMAP_LINEAR
14 tex->magFilter = GGLTexture::GGL_LINEAR;
15 return tex;
16}
17
18void GLES2Context::InitializeTextures()
19{
20 tex.textures = std::map<GLuint, GGLTexture *>(); // the entire struct has been zeroed in constructor
21 tex.tex2D = AllocTexture();
22 tex.textures[GL_TEXTURE_2D] = tex.tex2D;
23 tex.texCube = AllocTexture();
24 tex.textures[GL_TEXTURE_CUBE_MAP] = tex.texCube;
25 for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) {
26 tex.tmus[i] = NULL;
27 tex.sampler2tmu[i] = NULL;
28 }
29
30 tex.active = 0;
31
32 tex.free = max(GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP) + 1;
33
34 tex.tex2D->format = GGL_PIXEL_FORMAT_RGBA_8888;
35 tex.tex2D->type = GL_TEXTURE_2D;
36 tex.tex2D->levelCount = 1;
37 tex.tex2D->wrapS = tex.tex2D->wrapT = GGLTexture::GGL_REPEAT;
38 tex.tex2D->minFilter = tex.tex2D->magFilter = GGLTexture::GGL_NEAREST;
39 tex.tex2D->width = tex.tex2D->height = 1;
40 tex.tex2D->levels = malloc(4);
41 *(unsigned *)tex.tex2D->levels = 0xff000000;
42
43
44 tex.texCube->format = GGL_PIXEL_FORMAT_RGBA_8888;
45 tex.texCube->type = GL_TEXTURE_CUBE_MAP;
46 tex.texCube->levelCount = 1;
47 tex.texCube->wrapS = tex.texCube->wrapT = GGLTexture::GGL_REPEAT;
48 tex.texCube->minFilter = tex.texCube->magFilter = GGLTexture::GGL_NEAREST;
49 tex.texCube->width = tex.texCube->height = 1;
50 tex.texCube->levels = malloc(4 * 6);
51 static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
52 0xff00ffff, 0xffffff00, 0xffff00ff
53 };
54 memcpy(tex.texCube->levels, texels, sizeof texels);
55
56 //texture.levelCount = GenerateMipmaps(texture.levels, texture.width, texture.height);
57
58 // static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
59 // 0xff00ffff, 0xffffff00, 0xffff00ff};
60 // memcpy(texture.levels[0], texels, sizeof texels);
61 // texture.format = GGL_PIXEL_FORMAT_RGBA_8888;
62 // texture.width = texture.height = 1;
63 //texture.height /= 6;
64 //texture.type = GL_TEXTURE_CUBE_MAP;
65
66 tex.unpack = 4;
67}
68
69void GLES2Context::TextureState::UpdateSampler(GGLInterface * iface, unsigned tmu)
70{
71 for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
72 if (tmu == sampler2tmu[i])
73 iface->SetSampler(iface, i, tmus[tmu]);
74}
75
76void GLES2Context::UninitializeTextures()
77{
78 for (std::map<GLuint, GGLTexture *>::iterator it = tex.textures.begin(); it != tex.textures.end(); it++) {
79 if (!it->second)
80 continue;
81 free(it->second->levels);
82 free(it->second);
83 }
84}
85
86static inline void GetFormatAndBytesPerPixel(const GLenum format, unsigned * bytesPerPixel,
87 GGLPixelFormat * texFormat)
88{
89 switch (format) {
90 case GL_ALPHA:
91 *texFormat = GGL_PIXEL_FORMAT_A_8;
92 *bytesPerPixel = 1;
93 break;
94 case GL_LUMINANCE:
95 *texFormat = GGL_PIXEL_FORMAT_L_8;
96 *bytesPerPixel = 1;
97 break;
98 case GL_LUMINANCE_ALPHA:
99 *texFormat = GGL_PIXEL_FORMAT_LA_88;
100 *bytesPerPixel = 2;
101 break;
102 case GL_RGB:
103 *texFormat = GGL_PIXEL_FORMAT_RGB_888;
104 *bytesPerPixel = 3;
105 break;
106 case GL_RGBA:
107 *texFormat = GGL_PIXEL_FORMAT_RGBA_8888;
108 *bytesPerPixel = 4;
109 break;
110
111 // internal formats to avoid conversion
112 case GL_UNSIGNED_SHORT_5_6_5:
113 *texFormat = GGL_PIXEL_FORMAT_RGB_565;
114 *bytesPerPixel = 2;
115 break;
116
117 default:
118 assert(0);
119 return;
120 }
121}
122
123static inline void CopyTexture(char * dst, const char * src, const unsigned bytesPerPixel,
124 const unsigned sx, const unsigned sy, const unsigned sw,
125 const unsigned dx, const unsigned dy, const unsigned dw,
126 const unsigned w, const unsigned h)
127{
128 const unsigned bpp = bytesPerPixel;
129 if (dw == sw && dw == w && sx == 0 && dx == 0)
130 memcpy(dst + dy * dw * bpp, src + sy * sw * bpp, w * h * bpp);
131 else
132 for (unsigned y = 0; y < h; y++)
133 memcpy(dst + ((dy + y) * dw + dx) * bpp, src + ((sy + y) * sw + sx) * bpp, w * bpp);
134}
135
136void glActiveTexture(GLenum texture)
137{
138 GLES2_GET_CONST_CONTEXT(ctx);
139 unsigned index = texture - GL_TEXTURE0;
140 assert(NELEM(ctx->tex.tmus) > index);
141// LOGD("agl2: glActiveTexture %u", index);
142 ctx->tex.active = index;
143}
144
145void glBindTexture(GLenum target, GLuint texture)
146{
147 GLES2_GET_CONST_CONTEXT(ctx);
148// LOGD("agl2: glBindTexture target=0x%.4X texture=%u active=%u", target, texture, ctx->tex.active);
149 std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(texture);
150 GGLTexture * tex = NULL;
151 if (it != ctx->tex.textures.end()) {
152 tex = it->second;
153 if (!tex) {
154 tex = AllocTexture();
155 tex->type = target;
156 it->second = tex;
157// LOGD("agl2: glBindTexture allocTexture");
158 }
159// else
160// LOGD("agl2: glBindTexture bind existing texture");
161 assert(target == tex->type);
162 } else if (0 == texture) {
163 if (GL_TEXTURE_2D == target)
164 {
165 tex = ctx->tex.tex2D;
166// LOGD("agl2: glBindTexture bind default tex2D");
167 }
168 else if (GL_TEXTURE_CUBE_MAP == target)
169 {
170 tex = ctx->tex.texCube;
171// LOGD("agl2: glBindTexture bind default texCube");
172 }
173 else
174 assert(0);
175 } else {
176 if (texture <= ctx->tex.free)
177 ctx->tex.free = texture + 1;
178 tex = AllocTexture();
179 tex->type = target;
180 ctx->tex.textures[texture] = tex;
181// LOGD("agl2: glBindTexture new texture=%u", texture);
182 }
183 ctx->tex.tmus[ctx->tex.active] = tex;
184// LOGD("agl2: glBindTexture format=0x%.2X w=%u h=%u levels=%p", tex->format,
185// tex->width, tex->height, tex->levels);
186 ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
187}
188
189void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
190{
191 CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
192}
193
194void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
195{
196 CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
197}
198
199void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
200 GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
201{
202 GLES2_GET_CONST_CONTEXT(ctx);
203// LOGD("agl2: glCopyTexImage2D target=0x%.4X internalformat=0x%.4X", target, internalformat);
204// LOGD("x=%d y=%d width=%d height=%d border=%d level=%d ", x, y, width, height, border, level);
205 assert(0 == border);
206 assert(0 == level);
207 unsigned bytesPerPixel = 0;
208 GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
209 GetFormatAndBytesPerPixel(internalformat, &bytesPerPixel, &texFormat);
210
211 assert(texFormat == ctx->rasterizer.frameSurface.format);
212// LOGD("texFormat=0x%.2X bytesPerPixel=%d \n", texFormat, bytesPerPixel);
213 unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
214
215 assert(ctx->tex.tmus[ctx->tex.active]);
216 assert(y + height <= ctx->rasterizer.frameSurface.height);
217 assert(x + width <= ctx->rasterizer.frameSurface.width);
218 GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
219 tex.width = width;
220 tex.height = height;
221 tex.levelCount = 1;
222 tex.format = texFormat;
223 switch (target) {
224 case GL_TEXTURE_2D:
225 tex.levels = realloc(tex.levels, totalSize);
226 CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
227 x, y, ctx->rasterizer.frameSurface.width, 0, 0, width, width, height);
228 break;
229 default:
230 assert(0);
231 return;
232 }
233 ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
234}
235
236void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
237{
238 // x, y are src offset
239 // xoffset and yoffset are dst offset
240 GLES2_GET_CONST_CONTEXT(ctx);
241// LOGD("agl2: glCopyTexSubImage2D target=0x%.4X level=%d", target, level);
242// LOGD("xoffset=%d yoffset=%d x=%d y=%d width=%d height=%d", xoffset, yoffset, x, y, width, height);
243 assert(0 == level);
244
245 unsigned bytesPerPixel = 4;
246 unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
247
248 assert(ctx->tex.tmus[ctx->tex.active]);
249 GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
250
251 assert(tex.format == ctx->rasterizer.frameSurface.format);
252 assert(GGL_PIXEL_FORMAT_RGBA_8888 == tex.format);
253
254 const unsigned srcWidth = ctx->rasterizer.frameSurface.width;
255 const unsigned srcHeight = ctx->rasterizer.frameSurface.height;
256
257 assert(x >= 0 && y >= 0);
258 assert(xoffset >= 0 && yoffset >= 0);
259 assert(x + width <= srcWidth);
260 assert(y + height <= srcHeight);
261 assert(xoffset + width <= tex.width);
262 assert(yoffset + height <= tex.height);
263
264 switch (target) {
265 case GL_TEXTURE_2D:
266 CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
267 x, y, srcWidth, xoffset, yoffset, tex.width, width, height);
268 break;
269 default:
270 assert(0);
271 return;
272 }
273 ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
274}
275
276void glDeleteTextures(GLsizei n, const GLuint* textures)
277{
278 GLES2_GET_CONST_CONTEXT(ctx);
279 for (unsigned i = 0; i < n; i++) {
280 std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(textures[i]);
281 if (it == ctx->tex.textures.end())
282 continue;
283 ctx->tex.free = min(ctx->tex.free, textures[i]);
284 for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
285 if (ctx->tex.tmus[i] == it->second) {
286 if (GL_TEXTURE_2D == it->second->type)
287 ctx->tex.tmus[i] = ctx->tex.tex2D;
288 else if (GL_TEXTURE_CUBE_MAP == it->second->type)
289 ctx->tex.tmus[i] = ctx->tex.texCube;
290 else
291 assert(0);
292 ctx->tex.UpdateSampler(ctx->iface, i);
293 }
294 if (it->second) {
295 free(it->second->levels);
296 free(it->second);
297 }
298 ctx->tex.textures.erase(it);
299 }
300}
301
302void glGenTextures(GLsizei n, GLuint* textures)
303{
304 GLES2_GET_CONST_CONTEXT(ctx);
305 for (unsigned i = 0; i < n; i++) {
306 textures[i] = 0;
307 for (ctx->tex.free; ctx->tex.free < 0xffffffffu; ctx->tex.free++)
308 if (ctx->tex.textures.find(ctx->tex.free) == ctx->tex.textures.end()) {
309 ctx->tex.textures[ctx->tex.free] = NULL;
310 textures[i] = ctx->tex.free;
311 ctx->tex.free++;
312 break;
313 }
314 assert(textures[i]);
315 }
316}
317
318void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params)
319{
320 CALL_GL_API(glGetTexParameterfv, target, pname, params);
321}
322void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params)
323{
324 CALL_GL_API(glGetTexParameteriv, target, pname, params);
325}
326
327GLboolean glIsTexture(GLuint texture)
328{
329 GLES2_GET_CONST_CONTEXT(ctx);
330 if (ctx->tex.textures.find(texture) == ctx->tex.textures.end())
331 return GL_FALSE;
332 else
333 return GL_TRUE;
334}
335
336void glPixelStorei(GLenum pname, GLint param)
337{
338 GLES2_GET_CONST_CONTEXT(ctx);
339 assert(GL_UNPACK_ALIGNMENT == pname);
340 assert(1 == param || 2 == param || 4 == param || 8 == param);
341// LOGD("\n*\n* agl2: glPixelStorei not implemented pname=0x%.4X param=%d \n*", pname, param);
342 ctx->tex.unpack = param;
343// CALL_GL_API(glPixelStorei, pname, param);
344}
345void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
346 GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
347{
348 GLES2_GET_CONST_CONTEXT(ctx);
349// LOGD("agl2: glTexImage2D internalformat=0x%.4X format=0x%.4X type=0x%.4X \n", internalformat, format, type);
350// LOGD("width=%d height=%d border=%d level=%d pixels=%p \n", width, height, border, level, pixels);
351 switch (type) {
352 case GL_UNSIGNED_BYTE:
353 break;
354 case GL_UNSIGNED_SHORT_5_6_5:
355 internalformat = format = GL_UNSIGNED_SHORT_5_6_5;
356 assert(4 == ctx->tex.unpack);
357 break;
358 default:
359 assert(0);
360 }
361 assert(internalformat == format);
362 assert(0 == border);
363 if (0 != level) {
364 LOGD("agl2: glTexImage2D level=%d", level);
365 return;
366 }
367 unsigned bytesPerPixel = 0;
368 GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
369 GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
370
371 assert(texFormat && bytesPerPixel);
372// LOGD("texFormat=0x%.2X bytesPerPixel=%d active=%u", texFormat, bytesPerPixel, ctx->tex.active);
373 unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
374
375 assert(ctx->tex.tmus[ctx->tex.active]);
376
377 GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
378 tex.width = width;
379 tex.height = height;
380 tex.levelCount = 1;
381 tex.format = texFormat;
382
383 switch (target) {
384 case GL_TEXTURE_2D:
385 assert(GL_TEXTURE_2D == ctx->tex.tmus[ctx->tex.active]->type);
386 offset = 0;
387 break;
388 break;
389 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
390 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
391 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
392 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
393 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
394 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
395 assert(GL_TEXTURE_CUBE_MAP == ctx->tex.tmus[ctx->tex.active]->type);
396 assert(width == height);
397 offset = (target - GL_TEXTURE_CUBE_MAP_POSITIVE_X) * size;
398 totalSize = 6 * size;
399 break;
400 default:
401 assert(0);
402 return;
403 }
404
405 tex.levels = realloc(tex.levels, totalSize);
406 if (pixels)
407 CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, 0, 0, width, width, height);
408 ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
409}
410
411void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
412{
413// LOGD("agl2: glTexParameterf target=0x%.4X pname=0x%.4X param=%f", target, pname, param);
414 glTexParameteri(target, pname, param);
415}
416void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params)
417{
418 CALL_GL_API(glTexParameterfv, target, pname, params);
419}
420void glTexParameteri(GLenum target, GLenum pname, GLint param)
421{
422 GLES2_GET_CONST_CONTEXT(ctx);
423// LOGD("alg2: glTexParameteri target=0x%.0X pname=0x%.4X param=0x%.4X",
424// target, pname, param);
425 assert(ctx->tex.tmus[ctx->tex.active]);
426 assert(target == ctx->tex.tmus[ctx->tex.active]->type);
427 GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
428 switch (pname) {
429 case GL_TEXTURE_WRAP_S:
430 case GL_TEXTURE_WRAP_T:
431 GGLTexture::GGLTextureWrap wrap;
432 switch (param) {
433 case GL_REPEAT:
434 wrap = GGLTexture::GGL_REPEAT;
435 break;
436 case GL_CLAMP_TO_EDGE:
437 wrap = GGLTexture::GGL_CLAMP_TO_EDGE;
438 break;
439 case GL_MIRRORED_REPEAT:
440 wrap = GGLTexture::GGL_MIRRORED_REPEAT;
441 break;
442 default:
443 assert(0);
444 return;
445 }
446 if (GL_TEXTURE_WRAP_S == pname)
447 tex.wrapS = wrap;
448 else
449 tex.wrapT = wrap;
450 break;
451 case GL_TEXTURE_MIN_FILTER:
452 switch (param) {
453 case GL_NEAREST:
454 tex.minFilter = GGLTexture::GGL_NEAREST;
455 break;
456 case GL_LINEAR:
457 tex.minFilter = GGLTexture::GGL_LINEAR;
458 break;
459 case GL_NEAREST_MIPMAP_NEAREST:
460// tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_NEAREST;
461 break;
462 case GL_NEAREST_MIPMAP_LINEAR:
463// tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_LINEAR;
464 break;
465 case GL_LINEAR_MIPMAP_NEAREST:
466// tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_NEAREST;
467 break;
468 case GL_LINEAR_MIPMAP_LINEAR:
469// tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_LINEAR;
470 break;
471 default:
472 assert(0);
473 return;
474 }
475 break;
476 case GL_TEXTURE_MAG_FILTER:
477 switch (param) {
478 case GL_NEAREST:
479 tex.minFilter = GGLTexture::GGL_NEAREST;
480 break;
481 case GL_LINEAR:
482 tex.minFilter = GGLTexture::GGL_LINEAR;
483 break;
484 default:
485 assert(0);
486 return;
487 }
488 break;
489 default:
490 assert(0);
491 return;
492 }
493 // implementation restriction
494 if (tex.magFilter != tex.minFilter)
495 tex.magFilter = tex.minFilter = GGLTexture::GGL_LINEAR;
496 ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
497}
498void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params)
499{
500 CALL_GL_API(glTexParameteriv, target, pname, params);
501}
502void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
503{
504 GLES2_GET_CONST_CONTEXT(ctx);
505// LOGD("agl2: glTexSubImage2D target=0x%.4X level=%d xoffset=%d yoffset=%d width=%d height=%d format=0x%.4X type=0x%.4X pixels=%p",
506// target, level, xoffset, yoffset, width, height, format, type, pixels);
507 assert(0 == level);
508 assert(target == ctx->tex.tmus[ctx->tex.active]->type);
509 switch (type) {
510 case GL_UNSIGNED_BYTE:
511 break;
512 case GL_UNSIGNED_SHORT_5_6_5:
513 format = GL_UNSIGNED_SHORT_5_6_5;
514 assert(4 == ctx->tex.unpack);
515 break;
516 default:
517 assert(0);
518 }
519 GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
520 GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
521 unsigned bytesPerPixel = 0;
522 GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
523 assert(texFormat == tex.format);
524 assert(GL_UNSIGNED_BYTE == type);
525 switch (target) {
526 case GL_TEXTURE_2D:
527 CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, xoffset,
528 yoffset, tex.width, width, height);
529 break;
530 default:
531 assert(0);
532 }
533 ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
534}