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