1 /* libs/opengles/texture.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include "context.h"
21 #include "fp.h"
22 #include "state.h"
23 #include "texture.h"
24 #include "TextureObjectManager.h"
25
26 #include <ETC1/etc1.h>
27
28 #include <ui/GraphicBufferMapper.h>
29 #include <ui/Rect.h>
30
31 namespace android {
32
33 // ----------------------------------------------------------------------------
34
35 static void bindTextureTmu(
36 ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
37
38 static __attribute__((noinline))
39 void generateMipmap(ogles_context_t* c, GLint level);
40
41 // ----------------------------------------------------------------------------
42
43 #if 0
44 #pragma mark -
45 #pragma mark Init
46 #endif
47
ogles_init_texture(ogles_context_t * c)48 void ogles_init_texture(ogles_context_t* c)
49 {
50 c->textures.packAlignment = 4;
51 c->textures.unpackAlignment = 4;
52
53 // each context has a default named (0) texture (not shared)
54 c->textures.defaultTexture = new EGLTextureObject();
55 c->textures.defaultTexture->incStrong(c);
56
57 // bind the default texture to each texture unit
58 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
59 bindTextureTmu(c, i, 0, c->textures.defaultTexture);
60 memset(c->current.texture[i].v, 0, sizeof(vec4_t));
61 c->current.texture[i].Q = 0x10000;
62 }
63 }
64
ogles_uninit_texture(ogles_context_t * c)65 void ogles_uninit_texture(ogles_context_t* c)
66 {
67 if (c->textures.ggl)
68 gglUninit(c->textures.ggl);
69 c->textures.defaultTexture->decStrong(c);
70 for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
71 if (c->textures.tmu[i].texture)
72 c->textures.tmu[i].texture->decStrong(c);
73 }
74 }
75
76 static __attribute__((noinline))
validate_tmu(ogles_context_t * c,int i)77 void validate_tmu(ogles_context_t* c, int i)
78 {
79 texture_unit_t& u(c->textures.tmu[i]);
80 if (u.dirty) {
81 u.dirty = 0;
82 c->rasterizer.procs.activeTexture(c, i);
83 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
84 c->rasterizer.procs.texGeni(c, GGL_S,
85 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
86 c->rasterizer.procs.texGeni(c, GGL_T,
87 GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
88 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
89 GGL_TEXTURE_WRAP_S, u.texture->wraps);
90 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
91 GGL_TEXTURE_WRAP_T, u.texture->wrapt);
92 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
93 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
94 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
95 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
96
97 // disable this texture unit if it's not complete
98 if (!u.texture->isComplete()) {
99 c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
100 }
101 }
102 }
103
ogles_validate_texture(ogles_context_t * c)104 void ogles_validate_texture(ogles_context_t* c)
105 {
106 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
107 if (c->rasterizer.state.texture[i].enable)
108 validate_tmu(c, i);
109 }
110 c->rasterizer.procs.activeTexture(c, c->textures.active);
111 }
112
113 static
invalidate_texture(ogles_context_t * c,int tmu,uint8_t flags=0xFF)114 void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
115 c->textures.tmu[tmu].dirty = flags;
116 }
117
118 /*
119 * If the active textures are EGLImage, they need to be locked before
120 * they can be used.
121 *
122 * FIXME: code below is far from being optimal
123 *
124 */
125
ogles_lock_textures(ogles_context_t * c)126 void ogles_lock_textures(ogles_context_t* c)
127 {
128 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
129 if (c->rasterizer.state.texture[i].enable) {
130 texture_unit_t& u(c->textures.tmu[i]);
131 ANativeWindowBuffer* native_buffer = u.texture->buffer;
132 if (native_buffer) {
133 c->rasterizer.procs.activeTexture(c, i);
134
135 auto& mapper = GraphicBufferMapper::get();
136 void* vaddr;
137 mapper.lock(native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN,
138 Rect(native_buffer->width, native_buffer->height),
139 &vaddr);
140
141 u.texture->setImageBits(vaddr);
142 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
143 }
144 }
145 }
146 }
147
ogles_unlock_textures(ogles_context_t * c)148 void ogles_unlock_textures(ogles_context_t* c)
149 {
150 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
151 if (c->rasterizer.state.texture[i].enable) {
152 texture_unit_t& u(c->textures.tmu[i]);
153 ANativeWindowBuffer* native_buffer = u.texture->buffer;
154 if (native_buffer) {
155 c->rasterizer.procs.activeTexture(c, i);
156
157 auto& mapper = GraphicBufferMapper::get();
158 mapper.unlock(native_buffer->handle);
159
160 u.texture->setImageBits(NULL);
161 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
162 }
163 }
164 }
165 c->rasterizer.procs.activeTexture(c, c->textures.active);
166 }
167
168 // ----------------------------------------------------------------------------
169 #if 0
170 #pragma mark -
171 #pragma mark Format conversion
172 #endif
173
174 static uint32_t gl2format_table[6][4] = {
175 // BYTE, 565, 4444, 5551
176 { GGL_PIXEL_FORMAT_A_8,
177 0, 0, 0 }, // GL_ALPHA
178 { GGL_PIXEL_FORMAT_RGB_888,
179 GGL_PIXEL_FORMAT_RGB_565,
180 0, 0 }, // GL_RGB
181 { GGL_PIXEL_FORMAT_RGBA_8888,
182 0,
183 GGL_PIXEL_FORMAT_RGBA_4444,
184 GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA
185 { GGL_PIXEL_FORMAT_L_8,
186 0, 0, 0 }, // GL_LUMINANCE
187 { GGL_PIXEL_FORMAT_LA_88,
188 0, 0, 0 }, // GL_LUMINANCE_ALPHA
189 };
190
convertGLPixelFormat(GLint format,GLenum type)191 static int32_t convertGLPixelFormat(GLint format, GLenum type)
192 {
193 int32_t fi = -1;
194 int32_t ti = -1;
195 switch (format) {
196 case GL_ALPHA: fi = 0; break;
197 case GL_RGB: fi = 1; break;
198 case GL_RGBA: fi = 2; break;
199 case GL_LUMINANCE: fi = 3; break;
200 case GL_LUMINANCE_ALPHA: fi = 4; break;
201 }
202 switch (type) {
203 case GL_UNSIGNED_BYTE: ti = 0; break;
204 case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break;
205 case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
206 case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
207 }
208 if (fi==-1 || ti==-1)
209 return 0;
210 return gl2format_table[fi][ti];
211 }
212
213 // ----------------------------------------------------------------------------
214
validFormatType(ogles_context_t * c,GLenum format,GLenum type)215 static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
216 {
217 GLenum error = 0;
218 if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
219 error = GL_INVALID_ENUM;
220 }
221 if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
222 type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
223 error = GL_INVALID_ENUM;
224 }
225 if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
226 error = GL_INVALID_OPERATION;
227 }
228 if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
229 type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) {
230 error = GL_INVALID_OPERATION;
231 }
232 if (error) {
233 ogles_error(c, error);
234 }
235 return error;
236 }
237
238 // ----------------------------------------------------------------------------
239
getRasterizer(ogles_context_t * c)240 GGLContext* getRasterizer(ogles_context_t* c)
241 {
242 GGLContext* ggl = c->textures.ggl;
243 if (ggl_unlikely(!ggl)) {
244 // this is quite heavy the first time...
245 gglInit(&ggl);
246 if (!ggl) {
247 return 0;
248 }
249 GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
250 c->textures.ggl = ggl;
251 ggl->activeTexture(ggl, 0);
252 ggl->enable(ggl, GGL_TEXTURE_2D);
253 ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
254 ggl->disable(ggl, GGL_DITHER);
255 ggl->shadeModel(ggl, GGL_FLAT);
256 ggl->color4xv(ggl, colors);
257 }
258 return ggl;
259 }
260
261 static __attribute__((noinline))
copyPixels(ogles_context_t * c,const GGLSurface & dst,GLint xoffset,GLint yoffset,const GGLSurface & src,GLint x,GLint y,GLsizei w,GLsizei h)262 int copyPixels(
263 ogles_context_t* c,
264 const GGLSurface& dst,
265 GLint xoffset, GLint yoffset,
266 const GGLSurface& src,
267 GLint x, GLint y, GLsizei w, GLsizei h)
268 {
269 if ((dst.format == src.format) &&
270 (dst.stride == src.stride) &&
271 (dst.width == src.width) &&
272 (dst.height == src.height) &&
273 (dst.stride > 0) &&
274 ((x|y) == 0) &&
275 ((xoffset|yoffset) == 0))
276 {
277 // this is a common case...
278 const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
279 const size_t size = src.height * src.stride * pixelFormat.size;
280 memcpy(dst.data, src.data, size);
281 return 0;
282 }
283
284 // use pixel-flinger to handle all the conversions
285 GGLContext* ggl = getRasterizer(c);
286 if (!ggl) {
287 // the only reason this would fail is because we ran out of memory
288 return GL_OUT_OF_MEMORY;
289 }
290
291 ggl->colorBuffer(ggl, &dst);
292 ggl->bindTexture(ggl, &src);
293 ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
294 ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
295 return 0;
296 }
297
298 // ----------------------------------------------------------------------------
299
300 static __attribute__((noinline))
getAndBindActiveTextureObject(ogles_context_t * c)301 sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
302 {
303 sp<EGLTextureObject> tex;
304 const int active = c->textures.active;
305 const GLuint name = c->textures.tmu[active].name;
306
307 // free the reference to the previously bound object
308 texture_unit_t& u(c->textures.tmu[active]);
309 if (u.texture)
310 u.texture->decStrong(c);
311
312 if (name == 0) {
313 // 0 is our local texture object, not shared with anyone.
314 // But it affects all bound TMUs immediately.
315 // (we need to invalidate all units bound to this texture object)
316 tex = c->textures.defaultTexture;
317 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
318 if (c->textures.tmu[i].texture == tex.get())
319 invalidate_texture(c, i);
320 }
321 } else {
322 // get a new texture object for that name
323 tex = c->surfaceManager->replaceTexture(name);
324 }
325
326 // bind this texture to the current active texture unit
327 // and add a reference to this texture object
328 u.texture = tex.get();
329 u.texture->incStrong(c);
330 u.name = name;
331 invalidate_texture(c, active);
332 return tex;
333 }
334
bindTextureTmu(ogles_context_t * c,int tmu,GLuint texture,const sp<EGLTextureObject> & tex)335 void bindTextureTmu(
336 ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
337 {
338 if (tex.get() == c->textures.tmu[tmu].texture)
339 return;
340
341 // free the reference to the previously bound object
342 texture_unit_t& u(c->textures.tmu[tmu]);
343 if (u.texture)
344 u.texture->decStrong(c);
345
346 // bind this texture to the current active texture unit
347 // and add a reference to this texture object
348 u.texture = tex.get();
349 u.texture->incStrong(c);
350 u.name = texture;
351 invalidate_texture(c, tmu);
352 }
353
createTextureSurface(ogles_context_t * c,GGLSurface ** outSurface,int32_t * outSize,GLint level,GLenum format,GLenum type,GLsizei width,GLsizei height,GLenum compressedFormat=0)354 int createTextureSurface(ogles_context_t* c,
355 GGLSurface** outSurface, int32_t* outSize, GLint level,
356 GLenum format, GLenum type, GLsizei width, GLsizei height,
357 GLenum compressedFormat = 0)
358 {
359 // find out which texture is bound to the current unit
360 const int active = c->textures.active;
361 const GLuint name = c->textures.tmu[active].name;
362
363 // convert the pixelformat to one we can handle
364 const int32_t formatIdx = convertGLPixelFormat(format, type);
365 if (formatIdx == 0) { // we don't know what to do with this
366 return GL_INVALID_OPERATION;
367 }
368
369 // figure out the size we need as well as the stride
370 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
371 const int32_t align = c->textures.unpackAlignment-1;
372 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
373 const size_t size = bpr * height;
374 const int32_t stride = bpr / pixelFormat.size;
375
376 if (level > 0) {
377 const int active = c->textures.active;
378 EGLTextureObject* tex = c->textures.tmu[active].texture;
379 status_t err = tex->reallocate(level,
380 width, height, stride, formatIdx, compressedFormat, bpr);
381 if (err != NO_ERROR)
382 return GL_OUT_OF_MEMORY;
383 GGLSurface& surface = tex->editMip(level);
384 *outSurface = &surface;
385 *outSize = size;
386 return 0;
387 }
388
389 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
390 status_t err = tex->reallocate(level,
391 width, height, stride, formatIdx, compressedFormat, bpr);
392 if (err != NO_ERROR)
393 return GL_OUT_OF_MEMORY;
394
395 tex->internalformat = format;
396 *outSurface = &tex->surface;
397 *outSize = size;
398 return 0;
399 }
400
dataSizePalette4(int numLevels,int width,int height,int format)401 static GLsizei dataSizePalette4(int numLevels, int width, int height, int format)
402 {
403 int indexBits = 8;
404 int entrySize = 0;
405 switch (format) {
406 case GL_PALETTE4_RGB8_OES:
407 indexBits = 4;
408 /* FALLTHROUGH */
409 case GL_PALETTE8_RGB8_OES:
410 entrySize = 3;
411 break;
412
413 case GL_PALETTE4_RGBA8_OES:
414 indexBits = 4;
415 /* FALLTHROUGH */
416 case GL_PALETTE8_RGBA8_OES:
417 entrySize = 4;
418 break;
419
420 case GL_PALETTE4_R5_G6_B5_OES:
421 case GL_PALETTE4_RGBA4_OES:
422 case GL_PALETTE4_RGB5_A1_OES:
423 indexBits = 4;
424 /* FALLTHROUGH */
425 case GL_PALETTE8_R5_G6_B5_OES:
426 case GL_PALETTE8_RGBA4_OES:
427 case GL_PALETTE8_RGB5_A1_OES:
428 entrySize = 2;
429 break;
430 }
431
432 size_t size = (1 << indexBits) * entrySize; // palette size
433
434 for (int i=0 ; i< numLevels ; i++) {
435 int w = (width >> i) ? : 1;
436 int h = (height >> i) ? : 1;
437 int levelSize = h * ((w * indexBits) / 8) ? : 1;
438 size += levelSize;
439 }
440
441 return size;
442 }
443
decodePalette4(const GLvoid * data,int level,int width,int height,void * surface,int stride,int format)444 static void decodePalette4(const GLvoid *data, int level, int width, int height,
445 void *surface, int stride, int format)
446
447 {
448 int indexBits = 8;
449 int entrySize = 0;
450 switch (format) {
451 case GL_PALETTE4_RGB8_OES:
452 indexBits = 4;
453 /* FALLTHROUGH */
454 case GL_PALETTE8_RGB8_OES:
455 entrySize = 3;
456 break;
457
458 case GL_PALETTE4_RGBA8_OES:
459 indexBits = 4;
460 /* FALLTHROUGH */
461 case GL_PALETTE8_RGBA8_OES:
462 entrySize = 4;
463 break;
464
465 case GL_PALETTE4_R5_G6_B5_OES:
466 case GL_PALETTE4_RGBA4_OES:
467 case GL_PALETTE4_RGB5_A1_OES:
468 indexBits = 4;
469 /* FALLTHROUGH */
470 case GL_PALETTE8_R5_G6_B5_OES:
471 case GL_PALETTE8_RGBA4_OES:
472 case GL_PALETTE8_RGB5_A1_OES:
473 entrySize = 2;
474 break;
475 }
476
477 const int paletteSize = (1 << indexBits) * entrySize;
478
479 uint8_t const* pixels = (uint8_t *)data + paletteSize;
480 for (int i=0 ; i<level ; i++) {
481 int w = (width >> i) ? : 1;
482 int h = (height >> i) ? : 1;
483 pixels += h * ((w * indexBits) / 8);
484 }
485 width = (width >> level) ? : 1;
486 height = (height >> level) ? : 1;
487
488 if (entrySize == 2) {
489 uint8_t const* const palette = (uint8_t*)data;
490 for (int y=0 ; y<height ; y++) {
491 uint8_t* p = (uint8_t*)surface + y*stride*2;
492 if (indexBits == 8) {
493 for (int x=0 ; x<width ; x++) {
494 int index = 2 * (*pixels++);
495 *p++ = palette[index + 0];
496 *p++ = palette[index + 1];
497 }
498 } else {
499 for (int x=0 ; x<width ; x+=2) {
500 int v = *pixels++;
501 int index = 2 * (v >> 4);
502 *p++ = palette[index + 0];
503 *p++ = palette[index + 1];
504 if (x+1 < width) {
505 index = 2 * (v & 0xF);
506 *p++ = palette[index + 0];
507 *p++ = palette[index + 1];
508 }
509 }
510 }
511 }
512 } else if (entrySize == 3) {
513 uint8_t const* const palette = (uint8_t*)data;
514 for (int y=0 ; y<height ; y++) {
515 uint8_t* p = (uint8_t*)surface + y*stride*3;
516 if (indexBits == 8) {
517 for (int x=0 ; x<width ; x++) {
518 int index = 3 * (*pixels++);
519 *p++ = palette[index + 0];
520 *p++ = palette[index + 1];
521 *p++ = palette[index + 2];
522 }
523 } else {
524 for (int x=0 ; x<width ; x+=2) {
525 int v = *pixels++;
526 int index = 3 * (v >> 4);
527 *p++ = palette[index + 0];
528 *p++ = palette[index + 1];
529 *p++ = palette[index + 2];
530 if (x+1 < width) {
531 index = 3 * (v & 0xF);
532 *p++ = palette[index + 0];
533 *p++ = palette[index + 1];
534 *p++ = palette[index + 2];
535 }
536 }
537 }
538 }
539 } else if (entrySize == 4) {
540 uint8_t const* const palette = (uint8_t*)data;
541 for (int y=0 ; y<height ; y++) {
542 uint8_t* p = (uint8_t*)surface + y*stride*4;
543 if (indexBits == 8) {
544 for (int x=0 ; x<width ; x++) {
545 int index = 4 * (*pixels++);
546 *p++ = palette[index + 0];
547 *p++ = palette[index + 1];
548 *p++ = palette[index + 2];
549 *p++ = palette[index + 3];
550 }
551 } else {
552 for (int x=0 ; x<width ; x+=2) {
553 int v = *pixels++;
554 int index = 4 * (v >> 4);
555 *p++ = palette[index + 0];
556 *p++ = palette[index + 1];
557 *p++ = palette[index + 2];
558 *p++ = palette[index + 3];
559 if (x+1 < width) {
560 index = 4 * (v & 0xF);
561 *p++ = palette[index + 0];
562 *p++ = palette[index + 1];
563 *p++ = palette[index + 2];
564 *p++ = palette[index + 3];
565 }
566 }
567 }
568 }
569 }
570 }
571
572
573
574 static __attribute__((noinline))
set_depth_and_fog(ogles_context_t * c,GGLfixed z)575 void set_depth_and_fog(ogles_context_t* c, GGLfixed z)
576 {
577 const uint32_t enables = c->rasterizer.state.enables;
578 // we need to compute Zw
579 int32_t iterators[3];
580 iterators[1] = iterators[2] = 0;
581 GGLfixed Zw;
582 GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
583 GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
584 if (z<=0) Zw = n;
585 else if (z>=0x10000) Zw = f;
586 else Zw = gglMulAddx(z, (f-n), n);
587 if (enables & GGL_ENABLE_FOG) {
588 // set up fog if needed...
589 iterators[0] = c->fog.fog(c, Zw);
590 c->rasterizer.procs.fogGrad3xv(c, iterators);
591 }
592 if (enables & GGL_ENABLE_DEPTH_TEST) {
593 // set up z-test if needed...
594 int32_t z = (Zw & ~(Zw>>31));
595 if (z >= 0x10000)
596 z = 0xFFFF;
597 iterators[0] = (z << 16) | z;
598 c->rasterizer.procs.zGrad3xv(c, iterators);
599 }
600 }
601
602 // ----------------------------------------------------------------------------
603 #if 0
604 #pragma mark -
605 #pragma mark Generate mimaps
606 #endif
607
608 extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
609
generateMipmap(ogles_context_t * c,GLint level)610 void generateMipmap(ogles_context_t* c, GLint level)
611 {
612 if (level == 0) {
613 const int active = c->textures.active;
614 EGLTextureObject* tex = c->textures.tmu[active].texture;
615 if (tex->generate_mipmap) {
616 if (buildAPyramid(c, tex) != NO_ERROR) {
617 ogles_error(c, GL_OUT_OF_MEMORY);
618 return;
619 }
620 }
621 }
622 }
623
624
texParameterx(GLenum target,GLenum pname,GLfixed param,ogles_context_t * c)625 static void texParameterx(
626 GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
627 {
628 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
629 ogles_error(c, GL_INVALID_ENUM);
630 return;
631 }
632
633 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
634 switch (pname) {
635 case GL_TEXTURE_WRAP_S:
636 if ((param == GL_REPEAT) ||
637 (param == GL_CLAMP_TO_EDGE)) {
638 textureObject->wraps = param;
639 } else {
640 goto invalid_enum;
641 }
642 break;
643 case GL_TEXTURE_WRAP_T:
644 if ((param == GL_REPEAT) ||
645 (param == GL_CLAMP_TO_EDGE)) {
646 textureObject->wrapt = param;
647 } else {
648 goto invalid_enum;
649 }
650 break;
651 case GL_TEXTURE_MIN_FILTER:
652 if ((param == GL_NEAREST) ||
653 (param == GL_LINEAR) ||
654 (param == GL_NEAREST_MIPMAP_NEAREST) ||
655 (param == GL_LINEAR_MIPMAP_NEAREST) ||
656 (param == GL_NEAREST_MIPMAP_LINEAR) ||
657 (param == GL_LINEAR_MIPMAP_LINEAR)) {
658 textureObject->min_filter = param;
659 } else {
660 goto invalid_enum;
661 }
662 break;
663 case GL_TEXTURE_MAG_FILTER:
664 if ((param == GL_NEAREST) ||
665 (param == GL_LINEAR)) {
666 textureObject->mag_filter = param;
667 } else {
668 goto invalid_enum;
669 }
670 break;
671 case GL_GENERATE_MIPMAP:
672 textureObject->generate_mipmap = param;
673 break;
674 default:
675 invalid_enum:
676 ogles_error(c, GL_INVALID_ENUM);
677 return;
678 }
679 invalidate_texture(c, c->textures.active);
680 }
681
682
683
drawTexxOESImp(GLfixed x,GLfixed y,GLfixed z,GLfixed w,GLfixed h,ogles_context_t * c)684 static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
685 ogles_context_t* c)
686 {
687 ogles_lock_textures(c);
688
689 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
690 y = gglIntToFixed(cbSurface.height) - (y + h);
691 w >>= FIXED_BITS;
692 h >>= FIXED_BITS;
693
694 // set up all texture units
695 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
696 if (!c->rasterizer.state.texture[i].enable)
697 continue;
698
699 int32_t texcoords[8];
700 texture_unit_t& u(c->textures.tmu[i]);
701
702 // validate this tmu (bind, wrap, filter)
703 validate_tmu(c, i);
704 // we CLAMP here, which works with premultiplied (s,t)
705 c->rasterizer.procs.texParameteri(c,
706 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
707 c->rasterizer.procs.texParameteri(c,
708 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
709 u.dirty = 0xFF; // XXX: should be more subtle
710
711 EGLTextureObject* textureObject = u.texture;
712 const GLint Ucr = textureObject->crop_rect[0] << 16;
713 const GLint Vcr = textureObject->crop_rect[1] << 16;
714 const GLint Wcr = textureObject->crop_rect[2] << 16;
715 const GLint Hcr = textureObject->crop_rect[3] << 16;
716
717 // computes texture coordinates (pre-multiplied)
718 int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
719 int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
720 int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
721 int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
722 texcoords[0] = s0;
723 texcoords[1] = dsdx;
724 texcoords[2] = 0;
725 texcoords[3] = t0;
726 texcoords[4] = 0;
727 texcoords[5] = dtdy;
728 texcoords[6] = 0;
729 texcoords[7] = 0;
730 c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
731 }
732
733 const uint32_t enables = c->rasterizer.state.enables;
734 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
735 set_depth_and_fog(c, z);
736
737 c->rasterizer.procs.activeTexture(c, c->textures.active);
738 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
739 c->rasterizer.procs.disable(c, GGL_W_LERP);
740 c->rasterizer.procs.disable(c, GGL_AA);
741 c->rasterizer.procs.shadeModel(c, GL_FLAT);
742 c->rasterizer.procs.recti(c,
743 gglFixedToIntRound(x),
744 gglFixedToIntRound(y),
745 gglFixedToIntRound(x)+w,
746 gglFixedToIntRound(y)+h);
747
748 ogles_unlock_textures(c);
749 }
750
drawTexxOES(GLfixed x,GLfixed y,GLfixed z,GLfixed w,GLfixed h,ogles_context_t * c)751 static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
752 ogles_context_t* c)
753 {
754 // quickly reject empty rects
755 if ((w|h) <= 0)
756 return;
757
758 drawTexxOESImp(x, y, z, w, h, c);
759 }
760
drawTexiOES(GLint x,GLint y,GLint z,GLint w,GLint h,ogles_context_t * c)761 static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
762 {
763 // All coordinates are integer, so if we have only one
764 // texture unit active and no scaling is required
765 // THEN, we can use our special 1:1 mapping
766 // which is a lot faster.
767
768 if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
769 const int tmu = 0;
770 texture_unit_t& u(c->textures.tmu[tmu]);
771 EGLTextureObject* textureObject = u.texture;
772 const GLint Wcr = textureObject->crop_rect[2];
773 const GLint Hcr = textureObject->crop_rect[3];
774
775 if ((w == Wcr) && (h == -Hcr)) {
776 if ((w|h) <= 0) return; // quickly reject empty rects
777
778 if (u.dirty) {
779 c->rasterizer.procs.activeTexture(c, tmu);
780 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
781 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
782 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
783 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
784 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
785 }
786 c->rasterizer.procs.texGeni(c, GGL_S,
787 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
788 c->rasterizer.procs.texGeni(c, GGL_T,
789 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
790 u.dirty = 0xFF; // XXX: should be more subtle
791 c->rasterizer.procs.activeTexture(c, c->textures.active);
792
793 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
794 y = cbSurface.height - (y + h);
795 const GLint Ucr = textureObject->crop_rect[0];
796 const GLint Vcr = textureObject->crop_rect[1];
797 const GLint s0 = Ucr - x;
798 const GLint t0 = (Vcr + Hcr) - y;
799
800 const GLuint tw = textureObject->surface.width;
801 const GLuint th = textureObject->surface.height;
802 if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
803 // The GL spec is unclear about what should happen
804 // in this case, so we just use the slow case, which
805 // at least won't crash
806 goto slow_case;
807 }
808
809 ogles_lock_textures(c);
810
811 c->rasterizer.procs.texCoord2i(c, s0, t0);
812 const uint32_t enables = c->rasterizer.state.enables;
813 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
814 set_depth_and_fog(c, gglIntToFixed(z));
815
816 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
817 c->rasterizer.procs.disable(c, GGL_W_LERP);
818 c->rasterizer.procs.disable(c, GGL_AA);
819 c->rasterizer.procs.shadeModel(c, GL_FLAT);
820 c->rasterizer.procs.recti(c, x, y, x+w, y+h);
821
822 ogles_unlock_textures(c);
823
824 return;
825 }
826 }
827
828 slow_case:
829 drawTexxOESImp(
830 gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
831 gglIntToFixed(w), gglIntToFixed(h),
832 c);
833 }
834
835
836 }; // namespace android
837 // ----------------------------------------------------------------------------
838
839 using namespace android;
840
841
842 #if 0
843 #pragma mark -
844 #pragma mark Texture API
845 #endif
846
glActiveTexture(GLenum texture)847 void glActiveTexture(GLenum texture)
848 {
849 ogles_context_t* c = ogles_context_t::get();
850 if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
851 ogles_error(c, GL_INVALID_ENUM);
852 return;
853 }
854 c->textures.active = texture - GL_TEXTURE0;
855 c->rasterizer.procs.activeTexture(c, c->textures.active);
856 }
857
glBindTexture(GLenum target,GLuint texture)858 void glBindTexture(GLenum target, GLuint texture)
859 {
860 ogles_context_t* c = ogles_context_t::get();
861 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
862 ogles_error(c, GL_INVALID_ENUM);
863 return;
864 }
865
866 // Bind or create a texture
867 sp<EGLTextureObject> tex;
868 if (texture == 0) {
869 // 0 is our local texture object
870 tex = c->textures.defaultTexture;
871 } else {
872 tex = c->surfaceManager->texture(texture);
873 if (ggl_unlikely(tex == 0)) {
874 tex = c->surfaceManager->createTexture(texture);
875 if (tex == 0) {
876 ogles_error(c, GL_OUT_OF_MEMORY);
877 return;
878 }
879 }
880 }
881 bindTextureTmu(c, c->textures.active, texture, tex);
882 }
883
glGenTextures(GLsizei n,GLuint * textures)884 void glGenTextures(GLsizei n, GLuint *textures)
885 {
886 ogles_context_t* c = ogles_context_t::get();
887 if (n<0) {
888 ogles_error(c, GL_INVALID_VALUE);
889 return;
890 }
891 // generate unique (shared) texture names
892 c->surfaceManager->getToken(n, textures);
893 }
894
glDeleteTextures(GLsizei n,const GLuint * textures)895 void glDeleteTextures(GLsizei n, const GLuint *textures)
896 {
897 ogles_context_t* c = ogles_context_t::get();
898 if (n<0) {
899 ogles_error(c, GL_INVALID_VALUE);
900 return;
901 }
902
903 // If deleting a bound texture, bind this unit to 0
904 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
905 if (c->textures.tmu[t].name == 0)
906 continue;
907 for (int i=0 ; i<n ; i++) {
908 if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
909 // bind this tmu to texture 0
910 sp<EGLTextureObject> tex(c->textures.defaultTexture);
911 bindTextureTmu(c, t, 0, tex);
912 }
913 }
914 }
915 c->surfaceManager->deleteTextures(n, textures);
916 c->surfaceManager->recycleTokens(n, textures);
917 }
918
glMultiTexCoord4f(GLenum target,GLfloat s,GLfloat t,GLfloat r,GLfloat q)919 void glMultiTexCoord4f(
920 GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
921 {
922 ogles_context_t* c = ogles_context_t::get();
923 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
924 ogles_error(c, GL_INVALID_ENUM);
925 return;
926 }
927 const int tmu = target-GL_TEXTURE0;
928 c->current.texture[tmu].S = gglFloatToFixed(s);
929 c->current.texture[tmu].T = gglFloatToFixed(t);
930 c->current.texture[tmu].R = gglFloatToFixed(r);
931 c->current.texture[tmu].Q = gglFloatToFixed(q);
932 }
933
glMultiTexCoord4x(GLenum target,GLfixed s,GLfixed t,GLfixed r,GLfixed q)934 void glMultiTexCoord4x(
935 GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
936 {
937 ogles_context_t* c = ogles_context_t::get();
938 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
939 ogles_error(c, GL_INVALID_ENUM);
940 return;
941 }
942 const int tmu = target-GL_TEXTURE0;
943 c->current.texture[tmu].S = s;
944 c->current.texture[tmu].T = t;
945 c->current.texture[tmu].R = r;
946 c->current.texture[tmu].Q = q;
947 }
948
glPixelStorei(GLenum pname,GLint param)949 void glPixelStorei(GLenum pname, GLint param)
950 {
951 ogles_context_t* c = ogles_context_t::get();
952 if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
953 ogles_error(c, GL_INVALID_ENUM);
954 return;
955 }
956 if ((param<=0 || param>8) || (param & (param-1))) {
957 ogles_error(c, GL_INVALID_VALUE);
958 return;
959 }
960 if (pname == GL_PACK_ALIGNMENT)
961 c->textures.packAlignment = param;
962 if (pname == GL_UNPACK_ALIGNMENT)
963 c->textures.unpackAlignment = param;
964 }
965
glTexEnvf(GLenum target,GLenum pname,GLfloat param)966 void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
967 {
968 ogles_context_t* c = ogles_context_t::get();
969 c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
970 }
971
glTexEnvfv(GLenum target,GLenum pname,const GLfloat * params)972 void glTexEnvfv(
973 GLenum target, GLenum pname, const GLfloat *params)
974 {
975 ogles_context_t* c = ogles_context_t::get();
976 if (pname == GL_TEXTURE_ENV_MODE) {
977 c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
978 return;
979 }
980 if (pname == GL_TEXTURE_ENV_COLOR) {
981 GGLfixed fixed[4];
982 for (int i=0 ; i<4 ; i++)
983 fixed[i] = gglFloatToFixed(params[i]);
984 c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
985 return;
986 }
987 ogles_error(c, GL_INVALID_ENUM);
988 }
989
glTexEnvx(GLenum target,GLenum pname,GLfixed param)990 void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
991 {
992 ogles_context_t* c = ogles_context_t::get();
993 c->rasterizer.procs.texEnvi(c, target, pname, param);
994 }
995
glTexEnvxv(GLenum target,GLenum pname,const GLfixed * params)996 void glTexEnvxv(
997 GLenum target, GLenum pname, const GLfixed *params)
998 {
999 ogles_context_t* c = ogles_context_t::get();
1000 c->rasterizer.procs.texEnvxv(c, target, pname, params);
1001 }
1002
glTexParameteriv(GLenum target,GLenum pname,const GLint * params)1003 void glTexParameteriv(
1004 GLenum target, GLenum pname, const GLint* params)
1005 {
1006 ogles_context_t* c = ogles_context_t::get();
1007 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
1008 ogles_error(c, GL_INVALID_ENUM);
1009 return;
1010 }
1011
1012 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
1013 switch (pname) {
1014 case GL_TEXTURE_CROP_RECT_OES:
1015 memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
1016 break;
1017 default:
1018 texParameterx(target, pname, GLfixed(params[0]), c);
1019 return;
1020 }
1021 }
1022
glTexParameterf(GLenum target,GLenum pname,GLfloat param)1023 void glTexParameterf(
1024 GLenum target, GLenum pname, GLfloat param)
1025 {
1026 ogles_context_t* c = ogles_context_t::get();
1027 texParameterx(target, pname, GLfixed(param), c);
1028 }
1029
glTexParameterx(GLenum target,GLenum pname,GLfixed param)1030 void glTexParameterx(
1031 GLenum target, GLenum pname, GLfixed param)
1032 {
1033 ogles_context_t* c = ogles_context_t::get();
1034 texParameterx(target, pname, param, c);
1035 }
1036
glTexParameteri(GLenum target,GLenum pname,GLint param)1037 void glTexParameteri(
1038 GLenum target, GLenum pname, GLint param)
1039 {
1040 ogles_context_t* c = ogles_context_t::get();
1041 texParameterx(target, pname, GLfixed(param), c);
1042 }
1043
1044 // ----------------------------------------------------------------------------
1045 #if 0
1046 #pragma mark -
1047 #endif
1048
glCompressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLsizei imageSize,const GLvoid * data)1049 void glCompressedTexImage2D(
1050 GLenum target, GLint level, GLenum internalformat,
1051 GLsizei width, GLsizei height, GLint border,
1052 GLsizei imageSize, const GLvoid *data)
1053 {
1054 ogles_context_t* c = ogles_context_t::get();
1055 if (target != GL_TEXTURE_2D) {
1056 ogles_error(c, GL_INVALID_ENUM);
1057 return;
1058 }
1059 if (width<0 || height<0 || border!=0) {
1060 ogles_error(c, GL_INVALID_VALUE);
1061 return;
1062 }
1063
1064 // "uncompress" the texture since pixelflinger doesn't support
1065 // any compressed texture format natively.
1066 GLenum format;
1067 GLenum type;
1068 switch (internalformat) {
1069 case GL_PALETTE8_RGB8_OES:
1070 case GL_PALETTE4_RGB8_OES:
1071 format = GL_RGB;
1072 type = GL_UNSIGNED_BYTE;
1073 break;
1074 case GL_PALETTE8_RGBA8_OES:
1075 case GL_PALETTE4_RGBA8_OES:
1076 format = GL_RGBA;
1077 type = GL_UNSIGNED_BYTE;
1078 break;
1079 case GL_PALETTE8_R5_G6_B5_OES:
1080 case GL_PALETTE4_R5_G6_B5_OES:
1081 format = GL_RGB;
1082 type = GL_UNSIGNED_SHORT_5_6_5;
1083 break;
1084 case GL_PALETTE8_RGBA4_OES:
1085 case GL_PALETTE4_RGBA4_OES:
1086 format = GL_RGBA;
1087 type = GL_UNSIGNED_SHORT_4_4_4_4;
1088 break;
1089 case GL_PALETTE8_RGB5_A1_OES:
1090 case GL_PALETTE4_RGB5_A1_OES:
1091 format = GL_RGBA;
1092 type = GL_UNSIGNED_SHORT_5_5_5_1;
1093 break;
1094 #ifdef GL_OES_compressed_ETC1_RGB8_texture
1095 case GL_ETC1_RGB8_OES:
1096 format = GL_RGB;
1097 type = GL_UNSIGNED_BYTE;
1098 break;
1099 #endif
1100 default:
1101 ogles_error(c, GL_INVALID_ENUM);
1102 return;
1103 }
1104
1105 if (!data || !width || !height) {
1106 // unclear if this is an error or not...
1107 return;
1108 }
1109
1110 int32_t size;
1111 GGLSurface* surface;
1112
1113 #ifdef GL_OES_compressed_ETC1_RGB8_texture
1114 if (internalformat == GL_ETC1_RGB8_OES) {
1115 GLsizei compressedSize = etc1_get_encoded_data_size(width, height);
1116 if (compressedSize > imageSize) {
1117 ogles_error(c, GL_INVALID_VALUE);
1118 return;
1119 }
1120 int error = createTextureSurface(c, &surface, &size,
1121 level, format, type, width, height);
1122 if (error) {
1123 ogles_error(c, error);
1124 return;
1125 }
1126 if (etc1_decode_image(
1127 (const etc1_byte*)data,
1128 (etc1_byte*)surface->data,
1129 width, height, 3, surface->stride*3) != 0) {
1130 ogles_error(c, GL_INVALID_OPERATION);
1131 }
1132 return;
1133 }
1134 #endif
1135
1136 // all mipmap levels are specified at once.
1137 const int numLevels = level<0 ? -level : 1;
1138
1139 if (dataSizePalette4(numLevels, width, height, format) > imageSize) {
1140 ogles_error(c, GL_INVALID_VALUE);
1141 return;
1142 }
1143
1144 for (int i=0 ; i<numLevels ; i++) {
1145 int lod_w = (width >> i) ? : 1;
1146 int lod_h = (height >> i) ? : 1;
1147 int error = createTextureSurface(c, &surface, &size,
1148 i, format, type, lod_w, lod_h);
1149 if (error) {
1150 ogles_error(c, error);
1151 return;
1152 }
1153 decodePalette4(data, i, width, height,
1154 surface->data, surface->stride, internalformat);
1155 }
1156 }
1157
1158
glTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid * pixels)1159 void glTexImage2D(
1160 GLenum target, GLint level, GLint internalformat,
1161 GLsizei width, GLsizei height, GLint border,
1162 GLenum format, GLenum type, const GLvoid *pixels)
1163 {
1164 ogles_context_t* c = ogles_context_t::get();
1165 if (target != GL_TEXTURE_2D) {
1166 ogles_error(c, GL_INVALID_ENUM);
1167 return;
1168 }
1169 if (width<0 || height<0 || border!=0 || level < 0) {
1170 ogles_error(c, GL_INVALID_VALUE);
1171 return;
1172 }
1173 if (format != (GLenum)internalformat) {
1174 ogles_error(c, GL_INVALID_OPERATION);
1175 return;
1176 }
1177 if (validFormatType(c, format, type)) {
1178 return;
1179 }
1180
1181 int32_t size = 0;
1182 GGLSurface* surface = 0;
1183 int error = createTextureSurface(c, &surface, &size,
1184 level, format, type, width, height);
1185 if (error) {
1186 ogles_error(c, error);
1187 return;
1188 }
1189
1190 if (pixels) {
1191 const int32_t formatIdx = convertGLPixelFormat(format, type);
1192 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1193 const int32_t align = c->textures.unpackAlignment-1;
1194 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1195 const size_t size = bpr * height;
1196 const int32_t stride = bpr / pixelFormat.size;
1197
1198 GGLSurface userSurface;
1199 userSurface.version = sizeof(userSurface);
1200 userSurface.width = width;
1201 userSurface.height = height;
1202 userSurface.stride = stride;
1203 userSurface.format = formatIdx;
1204 userSurface.compressedFormat = 0;
1205 userSurface.data = (GLubyte*)pixels;
1206
1207 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
1208 if (err) {
1209 ogles_error(c, err);
1210 return;
1211 }
1212 generateMipmap(c, level);
1213 }
1214 }
1215
1216 // ----------------------------------------------------------------------------
1217
glCompressedTexSubImage2D(GLenum,GLint,GLint,GLint,GLsizei,GLsizei,GLenum,GLsizei,const GLvoid *)1218 void glCompressedTexSubImage2D(
1219 GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/,
1220 GLint /*yoffset*/, GLsizei /*width*/, GLsizei /*height*/,
1221 GLenum /*format*/, GLsizei /*imageSize*/,
1222 const GLvoid* /*data*/)
1223 {
1224 ogles_context_t* c = ogles_context_t::get();
1225 ogles_error(c, GL_INVALID_ENUM);
1226 }
1227
glTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid * pixels)1228 void glTexSubImage2D(
1229 GLenum target, GLint level, GLint xoffset,
1230 GLint yoffset, GLsizei width, GLsizei height,
1231 GLenum format, GLenum type, const GLvoid *pixels)
1232 {
1233 ogles_context_t* c = ogles_context_t::get();
1234 if (target != GL_TEXTURE_2D) {
1235 ogles_error(c, GL_INVALID_ENUM);
1236 return;
1237 }
1238 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1239 ogles_error(c, GL_INVALID_VALUE);
1240 return;
1241 }
1242 if (validFormatType(c, format, type)) {
1243 return;
1244 }
1245
1246 // find out which texture is bound to the current unit
1247 const int active = c->textures.active;
1248 EGLTextureObject* tex = c->textures.tmu[active].texture;
1249 const GGLSurface& surface(tex->mip(level));
1250
1251 if (!tex->internalformat || tex->direct) {
1252 ogles_error(c, GL_INVALID_OPERATION);
1253 return;
1254 }
1255
1256 if (format != tex->internalformat) {
1257 ogles_error(c, GL_INVALID_OPERATION);
1258 return;
1259 }
1260 if ((xoffset + width > GLsizei(surface.width)) ||
1261 (yoffset + height > GLsizei(surface.height))) {
1262 ogles_error(c, GL_INVALID_VALUE);
1263 return;
1264 }
1265 if (!width || !height) {
1266 return; // okay, but no-op.
1267 }
1268
1269 // figure out the size we need as well as the stride
1270 const int32_t formatIdx = convertGLPixelFormat(format, type);
1271 if (formatIdx == 0) { // we don't know what to do with this
1272 ogles_error(c, GL_INVALID_OPERATION);
1273 return;
1274 }
1275
1276 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1277 const int32_t align = c->textures.unpackAlignment-1;
1278 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1279 const size_t size = bpr * height;
1280 const int32_t stride = bpr / pixelFormat.size;
1281 GGLSurface userSurface;
1282 userSurface.version = sizeof(userSurface);
1283 userSurface.width = width;
1284 userSurface.height = height;
1285 userSurface.stride = stride;
1286 userSurface.format = formatIdx;
1287 userSurface.compressedFormat = 0;
1288 userSurface.data = (GLubyte*)pixels;
1289
1290 int err = copyPixels(c,
1291 surface, xoffset, yoffset,
1292 userSurface, 0, 0, width, height);
1293 if (err) {
1294 ogles_error(c, err);
1295 return;
1296 }
1297
1298 generateMipmap(c, level);
1299
1300 // since we only changed the content of the texture, we don't need
1301 // to call bindTexture on the main rasterizer.
1302 }
1303
1304 // ----------------------------------------------------------------------------
1305
glCopyTexImage2D(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,GLint border)1306 void glCopyTexImage2D(
1307 GLenum target, GLint level, GLenum internalformat,
1308 GLint x, GLint y, GLsizei width, GLsizei height,
1309 GLint border)
1310 {
1311 ogles_context_t* c = ogles_context_t::get();
1312 if (target != GL_TEXTURE_2D) {
1313 ogles_error(c, GL_INVALID_ENUM);
1314 return;
1315 }
1316 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
1317 ogles_error(c, GL_INVALID_ENUM);
1318 return;
1319 }
1320 if (width<0 || height<0 || border!=0 || level<0) {
1321 ogles_error(c, GL_INVALID_VALUE);
1322 return;
1323 }
1324
1325 GLenum format = 0;
1326 GLenum type = GL_UNSIGNED_BYTE;
1327 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1328 const int cbFormatIdx = cbSurface.format;
1329 switch (cbFormatIdx) {
1330 case GGL_PIXEL_FORMAT_RGB_565:
1331 type = GL_UNSIGNED_SHORT_5_6_5;
1332 break;
1333 case GGL_PIXEL_FORMAT_RGBA_5551:
1334 type = GL_UNSIGNED_SHORT_5_5_5_1;
1335 break;
1336 case GGL_PIXEL_FORMAT_RGBA_4444:
1337 type = GL_UNSIGNED_SHORT_4_4_4_4;
1338 break;
1339 }
1340 switch (internalformat) {
1341 case GL_ALPHA:
1342 case GL_LUMINANCE_ALPHA:
1343 case GL_LUMINANCE:
1344 type = GL_UNSIGNED_BYTE;
1345 break;
1346 }
1347
1348 // figure out the format to use for the new texture
1349 switch (cbFormatIdx) {
1350 case GGL_PIXEL_FORMAT_RGBA_8888:
1351 case GGL_PIXEL_FORMAT_A_8:
1352 case GGL_PIXEL_FORMAT_RGBA_5551:
1353 case GGL_PIXEL_FORMAT_RGBA_4444:
1354 format = internalformat;
1355 break;
1356 case GGL_PIXEL_FORMAT_RGBX_8888:
1357 case GGL_PIXEL_FORMAT_RGB_888:
1358 case GGL_PIXEL_FORMAT_RGB_565:
1359 case GGL_PIXEL_FORMAT_L_8:
1360 switch (internalformat) {
1361 case GL_LUMINANCE:
1362 case GL_RGB:
1363 format = internalformat;
1364 break;
1365 }
1366 break;
1367 }
1368
1369 if (format == 0) {
1370 // invalid combination
1371 ogles_error(c, GL_INVALID_ENUM);
1372 return;
1373 }
1374
1375 // create the new texture...
1376 int32_t size;
1377 GGLSurface* surface;
1378 int error = createTextureSurface(c, &surface, &size,
1379 level, format, type, width, height);
1380 if (error) {
1381 ogles_error(c, error);
1382 return;
1383 }
1384
1385 // The bottom row is stored first in textures
1386 GGLSurface txSurface(*surface);
1387 txSurface.stride = -txSurface.stride;
1388
1389 // (x,y) is the lower-left corner of colorBuffer
1390 y = cbSurface.height - (y + height);
1391
1392 /* The GLES spec says:
1393 * If any of the pixels within the specified rectangle are outside
1394 * the framebuffer associated with the current rendering context,
1395 * then the values obtained for those pixels are undefined.
1396 */
1397 if (x+width > GLint(cbSurface.width))
1398 width = cbSurface.width - x;
1399
1400 if (y+height > GLint(cbSurface.height))
1401 height = cbSurface.height - y;
1402
1403 int err = copyPixels(c,
1404 txSurface, 0, 0,
1405 cbSurface, x, y, width, height);
1406 if (err) {
1407 ogles_error(c, err);
1408 }
1409
1410 generateMipmap(c, level);
1411 }
1412
glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height)1413 void glCopyTexSubImage2D(
1414 GLenum target, GLint level, GLint xoffset, GLint yoffset,
1415 GLint x, GLint y, GLsizei width, GLsizei height)
1416 {
1417 ogles_context_t* c = ogles_context_t::get();
1418 if (target != GL_TEXTURE_2D) {
1419 ogles_error(c, GL_INVALID_ENUM);
1420 return;
1421 }
1422 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1423 ogles_error(c, GL_INVALID_VALUE);
1424 return;
1425 }
1426 if (!width || !height) {
1427 return; // okay, but no-op.
1428 }
1429
1430 // find out which texture is bound to the current unit
1431 const int active = c->textures.active;
1432 EGLTextureObject* tex = c->textures.tmu[active].texture;
1433 const GGLSurface& surface(tex->mip(level));
1434
1435 if (!tex->internalformat) {
1436 ogles_error(c, GL_INVALID_OPERATION);
1437 return;
1438 }
1439 if ((xoffset + width > GLsizei(surface.width)) ||
1440 (yoffset + height > GLsizei(surface.height))) {
1441 ogles_error(c, GL_INVALID_VALUE);
1442 return;
1443 }
1444
1445 // The bottom row is stored first in textures
1446 GGLSurface txSurface(surface);
1447 txSurface.stride = -txSurface.stride;
1448
1449 // (x,y) is the lower-left corner of colorBuffer
1450 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1451 y = cbSurface.height - (y + height);
1452
1453 /* The GLES spec says:
1454 * If any of the pixels within the specified rectangle are outside
1455 * the framebuffer associated with the current rendering context,
1456 * then the values obtained for those pixels are undefined.
1457 */
1458 if (x+width > GLint(cbSurface.width))
1459 width = cbSurface.width - x;
1460
1461 if (y+height > GLint(cbSurface.height))
1462 height = cbSurface.height - y;
1463
1464 int err = copyPixels(c,
1465 txSurface, xoffset, yoffset,
1466 cbSurface, x, y, width, height);
1467 if (err) {
1468 ogles_error(c, err);
1469 return;
1470 }
1471
1472 generateMipmap(c, level);
1473 }
1474
glReadPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLvoid * pixels)1475 void glReadPixels(
1476 GLint x, GLint y, GLsizei width, GLsizei height,
1477 GLenum format, GLenum type, GLvoid *pixels)
1478 {
1479 ogles_context_t* c = ogles_context_t::get();
1480 if ((format != GL_RGBA) && (format != GL_RGB)) {
1481 ogles_error(c, GL_INVALID_ENUM);
1482 return;
1483 }
1484 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
1485 ogles_error(c, GL_INVALID_ENUM);
1486 return;
1487 }
1488 if (width<0 || height<0) {
1489 ogles_error(c, GL_INVALID_VALUE);
1490 return;
1491 }
1492 if (x<0 || y<0) {
1493 ogles_error(c, GL_INVALID_VALUE);
1494 return;
1495 }
1496
1497 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
1498 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
1499 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
1500 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
1501 formatIdx = GGL_PIXEL_FORMAT_RGB_565;
1502 } else {
1503 ogles_error(c, GL_INVALID_OPERATION);
1504 return;
1505 }
1506
1507 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
1508 if ((x+width > GLint(readSurface.width)) ||
1509 (y+height > GLint(readSurface.height))) {
1510 ogles_error(c, GL_INVALID_VALUE);
1511 return;
1512 }
1513
1514 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1515 const int32_t align = c->textures.packAlignment-1;
1516 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1517 const int32_t stride = bpr / pixelFormat.size;
1518
1519 GGLSurface userSurface;
1520 userSurface.version = sizeof(userSurface);
1521 userSurface.width = width;
1522 userSurface.height = height;
1523 userSurface.stride = -stride; // bottom row is transfered first
1524 userSurface.format = formatIdx;
1525 userSurface.compressedFormat = 0;
1526 userSurface.data = (GLubyte*)pixels;
1527
1528 // use pixel-flinger to handle all the conversions
1529 GGLContext* ggl = getRasterizer(c);
1530 if (!ggl) {
1531 // the only reason this would fail is because we ran out of memory
1532 ogles_error(c, GL_OUT_OF_MEMORY);
1533 return;
1534 }
1535
1536 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
1537 ggl->bindTexture(ggl, &readSurface); // source is read-buffer
1538 ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
1539 ggl->recti(ggl, 0, 0, width, height);
1540 }
1541
1542 // ----------------------------------------------------------------------------
1543 #if 0
1544 #pragma mark -
1545 #pragma mark DrawTexture Extension
1546 #endif
1547
glDrawTexsvOES(const GLshort * coords)1548 void glDrawTexsvOES(const GLshort* coords) {
1549 ogles_context_t* c = ogles_context_t::get();
1550 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1551 }
glDrawTexivOES(const GLint * coords)1552 void glDrawTexivOES(const GLint* coords) {
1553 ogles_context_t* c = ogles_context_t::get();
1554 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1555 }
glDrawTexsOES(GLshort x,GLshort y,GLshort z,GLshort w,GLshort h)1556 void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
1557 ogles_context_t* c = ogles_context_t::get();
1558 drawTexiOES(x, y, z, w, h, c);
1559 }
glDrawTexiOES(GLint x,GLint y,GLint z,GLint w,GLint h)1560 void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
1561 ogles_context_t* c = ogles_context_t::get();
1562 drawTexiOES(x, y, z, w, h, c);
1563 }
1564
glDrawTexfvOES(const GLfloat * coords)1565 void glDrawTexfvOES(const GLfloat* coords) {
1566 ogles_context_t* c = ogles_context_t::get();
1567 drawTexxOES(
1568 gglFloatToFixed(coords[0]),
1569 gglFloatToFixed(coords[1]),
1570 gglFloatToFixed(coords[2]),
1571 gglFloatToFixed(coords[3]),
1572 gglFloatToFixed(coords[4]),
1573 c);
1574 }
glDrawTexxvOES(const GLfixed * coords)1575 void glDrawTexxvOES(const GLfixed* coords) {
1576 ogles_context_t* c = ogles_context_t::get();
1577 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1578 }
glDrawTexfOES(GLfloat x,GLfloat y,GLfloat z,GLfloat w,GLfloat h)1579 void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
1580 ogles_context_t* c = ogles_context_t::get();
1581 drawTexxOES(
1582 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
1583 gglFloatToFixed(w), gglFloatToFixed(h),
1584 c);
1585 }
glDrawTexxOES(GLfixed x,GLfixed y,GLfixed z,GLfixed w,GLfixed h)1586 void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
1587 ogles_context_t* c = ogles_context_t::get();
1588 drawTexxOES(x, y, z, w, h, c);
1589 }
1590
1591 // ----------------------------------------------------------------------------
1592 #if 0
1593 #pragma mark -
1594 #pragma mark EGL Image Extension
1595 #endif
1596
glEGLImageTargetTexture2DOES(GLenum target,GLeglImageOES image)1597 void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
1598 {
1599 ogles_context_t* c = ogles_context_t::get();
1600 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
1601 ogles_error(c, GL_INVALID_ENUM);
1602 return;
1603 }
1604
1605 if (image == EGL_NO_IMAGE_KHR) {
1606 ogles_error(c, GL_INVALID_VALUE);
1607 return;
1608 }
1609
1610 ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
1611 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
1612 ogles_error(c, GL_INVALID_VALUE);
1613 return;
1614 }
1615 if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
1616 ogles_error(c, GL_INVALID_VALUE);
1617 return;
1618 }
1619
1620 // bind it to the texture unit
1621 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
1622 tex->setImage(native_buffer);
1623 }
1624
glEGLImageTargetRenderbufferStorageOES(GLenum target,GLeglImageOES image)1625 void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1626 {
1627 ogles_context_t* c = ogles_context_t::get();
1628 if (target != GL_RENDERBUFFER_OES) {
1629 ogles_error(c, GL_INVALID_ENUM);
1630 return;
1631 }
1632
1633 if (image == EGL_NO_IMAGE_KHR) {
1634 ogles_error(c, GL_INVALID_VALUE);
1635 return;
1636 }
1637
1638 ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
1639 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
1640 ogles_error(c, GL_INVALID_VALUE);
1641 return;
1642 }
1643 if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
1644 ogles_error(c, GL_INVALID_VALUE);
1645 return;
1646 }
1647
1648 // well, we're not supporting this extension anyways
1649 }
1650