blob: 6b2640a720d358c1d01af0f05853b12bd8ebe099 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/* 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 != GGL_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_CLAMP) ||
538 (param == GL_REPEAT) ||
539 (param == GL_CLAMP_TO_EDGE)) {
540 textureObject->wraps = param;
541 } else {
542 goto invalid_enum;
543 }
544 break;
545 case GL_TEXTURE_WRAP_T:
546 if ((param == GGL_CLAMP) ||
547 (param == GGL_REPEAT) ||
548 (param == GGL_CLAMP_TO_EDGE)) {
549 textureObject->wrapt = param;
550 } else {
551 goto invalid_enum;
552 }
553 break;
554 case GL_TEXTURE_MIN_FILTER:
555 if ((param == GL_NEAREST) ||
556 (param == GL_LINEAR) ||
557 (param == GL_NEAREST_MIPMAP_NEAREST) ||
558 (param == GL_LINEAR_MIPMAP_NEAREST) ||
559 (param == GL_NEAREST_MIPMAP_LINEAR) ||
560 (param == GL_LINEAR_MIPMAP_LINEAR)) {
561 textureObject->min_filter = param;
562 } else {
563 goto invalid_enum;
564 }
565 break;
566 case GL_TEXTURE_MAG_FILTER:
567 if ((param == GL_NEAREST) ||
568 (param == GL_LINEAR)) {
569 textureObject->mag_filter = param;
570 } else {
571 goto invalid_enum;
572 }
573 break;
574 case GL_GENERATE_MIPMAP:
575 textureObject->generate_mipmap = param;
576 break;
577 default:
578invalid_enum:
579 ogles_error(c, GL_INVALID_ENUM);
580 return;
581 }
582 invalidate_texture(c, c->textures.active);
583}
584
585
586static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
587 ogles_context_t* c)
588{
589 // quickly reject empty rects
590 if ((w|h) <= 0)
591 return;
592
593 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
594 y = gglIntToFixed(cbSurface.height) - (y + h);
595 w >>= FIXED_BITS;
596 h >>= FIXED_BITS;
597
598 // set up all texture units
599 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
600 if (!c->rasterizer.state.texture[i].enable)
601 continue;
602
603 int32_t texcoords[8];
604 texture_unit_t& u(c->textures.tmu[i]);
605
606 // validate this tmu (bind, wrap, filter)
607 validate_tmu(c, i);
608 // we CLAMP here, which works with premultiplied (s,t)
609 c->rasterizer.procs.texParameteri(c,
610 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
611 c->rasterizer.procs.texParameteri(c,
612 GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
613 u.dirty = 0xFF; // XXX: should be more subtle
614
615 EGLTextureObject* textureObject = u.texture;
616 const GLint Ucr = textureObject->crop_rect[0] << 16;
617 const GLint Vcr = textureObject->crop_rect[1] << 16;
618 const GLint Wcr = textureObject->crop_rect[2] << 16;
619 const GLint Hcr = textureObject->crop_rect[3] << 16;
620
621 // computes texture coordinates (pre-multiplied)
622 int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
623 int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
624 int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
625 int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
626 texcoords[0] = s0;
627 texcoords[1] = dsdx;
628 texcoords[2] = 0;
629 texcoords[3] = t0;
630 texcoords[4] = 0;
631 texcoords[5] = dtdy;
632 texcoords[6] = 0;
633 texcoords[7] = 0;
634 c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
635 }
636
637 const uint32_t enables = c->rasterizer.state.enables;
638 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
639 set_depth_and_fog(c, z);
640
641 c->rasterizer.procs.activeTexture(c, c->textures.active);
642 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
643 c->rasterizer.procs.disable(c, GGL_W_LERP);
644 c->rasterizer.procs.disable(c, GGL_AA);
645 c->rasterizer.procs.shadeModel(c, GL_FLAT);
646 c->rasterizer.procs.recti(c,
647 gglFixedToIntRound(x),
648 gglFixedToIntRound(y),
649 gglFixedToIntRound(x)+w,
650 gglFixedToIntRound(y)+h);
651}
652
653static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
654{
655 // All coordinates are integer, so if we have only one
656 // texture unit active and no scaling is required
657 // THEN, we can use our special 1:1 mapping
658 // which is a lot faster.
659
660 if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
661 const int tmu = 0;
662 texture_unit_t& u(c->textures.tmu[tmu]);
663 EGLTextureObject* textureObject = u.texture;
664 const GLint Wcr = textureObject->crop_rect[2];
665 const GLint Hcr = textureObject->crop_rect[3];
666
667 if ((w == Wcr) && (h == -Hcr)) {
668 if ((w|h) <= 0) return; // quickly reject empty rects
669
670 if (u.dirty) {
671 c->rasterizer.procs.activeTexture(c, tmu);
672 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
673 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
674 GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
675 c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
676 GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
677 }
678 c->rasterizer.procs.texGeni(c, GGL_S,
679 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
680 c->rasterizer.procs.texGeni(c, GGL_T,
681 GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
682 u.dirty = 0xFF; // XXX: should be more subtle
683 c->rasterizer.procs.activeTexture(c, c->textures.active);
684
685 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
686 y = cbSurface.height - (y + h);
687 const GLint Ucr = textureObject->crop_rect[0];
688 const GLint Vcr = textureObject->crop_rect[1];
689 const GLint s0 = Ucr - x;
690 const GLint t0 = (Vcr + Hcr) - y;
691
692 const GLuint tw = textureObject->surface.width;
693 const GLuint th = textureObject->surface.height;
694 if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
695 // The GL spec is unclear about what should happen
696 // in this case, so we just use the slow case, which
697 // at least won't crash
698 goto slow_case;
699 }
700
701 c->rasterizer.procs.texCoord2i(c, s0, t0);
702 const uint32_t enables = c->rasterizer.state.enables;
703 if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
704 set_depth_and_fog(c, z);
705
706 c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
707 c->rasterizer.procs.disable(c, GGL_W_LERP);
708 c->rasterizer.procs.disable(c, GGL_AA);
709 c->rasterizer.procs.shadeModel(c, GL_FLAT);
710 c->rasterizer.procs.recti(c, x, y, x+w, y+h);
711 return;
712 }
713 }
714
715slow_case:
716 drawTexxOES(
717 gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
718 gglIntToFixed(w), gglIntToFixed(h),
719 c);
720}
721
722
723}; // namespace android
724// ----------------------------------------------------------------------------
725
726using namespace android;
727
728
729#if 0
730#pragma mark -
731#pragma mark Texture API
732#endif
733
734void glActiveTexture(GLenum texture)
735{
736 ogles_context_t* c = ogles_context_t::get();
737 if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
738 ogles_error(c, GL_INVALID_ENUM);
739 return;
740 }
741 c->textures.active = texture - GL_TEXTURE0;
742 c->rasterizer.procs.activeTexture(c, c->textures.active);
743}
744
745void glBindTexture(GLenum target, GLuint texture)
746{
747 ogles_context_t* c = ogles_context_t::get();
748 if (target != GL_TEXTURE_2D) {
749 ogles_error(c, GL_INVALID_ENUM);
750 return;
751 }
752
753 // Bind or create a texture
754 sp<EGLTextureObject> tex;
755 if (texture == 0) {
756 // 0 is our local texture object
757 tex = c->textures.defaultTexture;
758 } else {
759 tex = c->surfaceManager->texture(texture);
760 if (ggl_unlikely(tex == 0)) {
761 tex = c->surfaceManager->createTexture(texture);
762 if (tex == 0) {
763 ogles_error(c, GL_OUT_OF_MEMORY);
764 return;
765 }
766 }
767 }
768 bindTextureTmu(c, c->textures.active, texture, tex);
769}
770
771void glGenTextures(GLsizei n, GLuint *textures)
772{
773 ogles_context_t* c = ogles_context_t::get();
774 if (n<0) {
775 ogles_error(c, GL_INVALID_VALUE);
776 return;
777 }
778 // generate unique (shared) texture names
779 c->surfaceManager->getToken(n, textures);
780}
781
782void glDeleteTextures(GLsizei n, const GLuint *textures)
783{
784 ogles_context_t* c = ogles_context_t::get();
785 if (n<0) {
786 ogles_error(c, GL_INVALID_VALUE);
787 return;
788 }
789
790 // If deleting a bound texture, bind this unit to 0
791 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
792 if (c->textures.tmu[t].name == 0)
793 continue;
794 for (int i=0 ; i<n ; i++) {
795 if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
796 // bind this tmu to texture 0
797 sp<EGLTextureObject> tex(c->textures.defaultTexture);
798 bindTextureTmu(c, t, 0, tex);
799 }
800 }
801 }
802 c->surfaceManager->deleteTextures(n, textures);
803 c->surfaceManager->recycleTokens(n, textures);
804}
805
806void glMultiTexCoord4f(
807 GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
808{
809 ogles_context_t* c = ogles_context_t::get();
810 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
811 ogles_error(c, GL_INVALID_ENUM);
812 return;
813 }
814 const int tmu = target-GL_TEXTURE0;
815 c->current.texture[tmu].S = gglFloatToFixed(s);
816 c->current.texture[tmu].T = gglFloatToFixed(t);
817 c->current.texture[tmu].R = gglFloatToFixed(r);
818 c->current.texture[tmu].Q = gglFloatToFixed(q);
819}
820
821void glMultiTexCoord4x(
822 GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
823{
824 ogles_context_t* c = ogles_context_t::get();
825 if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
826 ogles_error(c, GL_INVALID_ENUM);
827 return;
828 }
829 const int tmu = target-GL_TEXTURE0;
830 c->current.texture[tmu].S = s;
831 c->current.texture[tmu].T = t;
832 c->current.texture[tmu].R = r;
833 c->current.texture[tmu].Q = q;
834}
835
836void glPixelStorei(GLenum pname, GLint param)
837{
838 ogles_context_t* c = ogles_context_t::get();
839 if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
840 ogles_error(c, GL_INVALID_ENUM);
841 return;
842 }
843 if ((param<=0 || param>8) || (param & (param-1))) {
844 ogles_error(c, GL_INVALID_VALUE);
845 return;
846 }
847 if (pname == GL_PACK_ALIGNMENT)
848 c->textures.packAlignment = param;
849 if (pname == GL_UNPACK_ALIGNMENT)
850 c->textures.unpackAlignment = param;
851}
852
853void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
854{
855 ogles_context_t* c = ogles_context_t::get();
856 c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
857}
858
859void glTexEnvfv(
860 GLenum target, GLenum pname, const GLfloat *params)
861{
862 ogles_context_t* c = ogles_context_t::get();
863 if (pname == GL_TEXTURE_ENV_MODE) {
864 c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
865 return;
866 }
867 if (pname == GL_TEXTURE_ENV_COLOR) {
868 GGLfixed fixed[4];
869 for (int i=0 ; i<4 ; i++)
870 fixed[i] = gglFloatToFixed(params[i]);
871 c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
872 return;
873 }
874 ogles_error(c, GL_INVALID_ENUM);
875}
876
877void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
878{
879 ogles_context_t* c = ogles_context_t::get();
880 c->rasterizer.procs.texEnvi(c, target, pname, param);
881}
882
883void glTexEnvxv(
884 GLenum target, GLenum pname, const GLfixed *params)
885{
886 ogles_context_t* c = ogles_context_t::get();
887 c->rasterizer.procs.texEnvxv(c, target, pname, params);
888}
889
890void glTexParameteriv(
891 GLenum target, GLenum pname, const GLint* params)
892{
893 ogles_context_t* c = ogles_context_t::get();
894 if (target != GGL_TEXTURE_2D) {
895 ogles_error(c, GL_INVALID_ENUM);
896 return;
897 }
898
899 EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
900 switch (pname) {
901 case GL_TEXTURE_CROP_RECT_OES:
902 memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
903 break;
904 default:
905 ogles_error(c, GL_INVALID_ENUM);
906 return;
907 }
908}
909
910void glTexParameterf(
911 GLenum target, GLenum pname, GLfloat param)
912{
913 ogles_context_t* c = ogles_context_t::get();
914 texParameterx(target, pname, GLfixed(param), c);
915}
916
917void glTexParameterx(
918 GLenum target, GLenum pname, GLfixed param)
919{
920 ogles_context_t* c = ogles_context_t::get();
921 texParameterx(target, pname, param, c);
922}
923
924// ----------------------------------------------------------------------------
925#if 0
926#pragma mark -
927#endif
928
929void glCompressedTexImage2D(
930 GLenum target, GLint level, GLenum internalformat,
931 GLsizei width, GLsizei height, GLint border,
932 GLsizei imageSize, const GLvoid *data)
933{
934 ogles_context_t* c = ogles_context_t::get();
935 if (target != GL_TEXTURE_2D) {
936 ogles_error(c, GL_INVALID_ENUM);
937 return;
938 }
939 if ((internalformat < GL_PALETTE4_RGB8_OES ||
940 internalformat > GL_PALETTE8_RGB5_A1_OES)) {
941 ogles_error(c, GL_INVALID_ENUM);
942 return;
943 }
944 if (width<0 || height<0 || border!=0) {
945 ogles_error(c, GL_INVALID_VALUE);
946 return;
947 }
948
949 // "uncompress" the texture since pixelflinger doesn't support
950 // any compressed texture format natively.
951 GLenum format;
952 GLenum type;
953 switch (internalformat) {
954 case GL_PALETTE8_RGB8_OES:
955 case GL_PALETTE4_RGB8_OES:
956 format = GL_RGB;
957 type = GL_UNSIGNED_BYTE;
958 break;
959 case GL_PALETTE8_RGBA8_OES:
960 case GL_PALETTE4_RGBA8_OES:
961 format = GL_RGBA;
962 type = GL_UNSIGNED_BYTE;
963 break;
964 case GL_PALETTE8_R5_G6_B5_OES:
965 case GL_PALETTE4_R5_G6_B5_OES:
966 format = GL_RGB;
967 type = GL_UNSIGNED_SHORT_5_6_5;
968 break;
969 case GL_PALETTE8_RGBA4_OES:
970 case GL_PALETTE4_RGBA4_OES:
971 format = GL_RGBA;
972 type = GL_UNSIGNED_SHORT_4_4_4_4;
973 break;
974 case GL_PALETTE8_RGB5_A1_OES:
975 case GL_PALETTE4_RGB5_A1_OES:
976 format = GL_RGBA;
977 type = GL_UNSIGNED_SHORT_5_5_5_1;
978 break;
979 default:
980 ogles_error(c, GL_INVALID_ENUM);
981 return;
982 }
983
984 if (!data || !width || !height) {
985 // unclear if this is an error or not...
986 return;
987 }
988
989 int32_t size;
990 GGLSurface* surface;
991 // all mipmap levels are specified at once.
992 const int numLevels = level<0 ? -level : 1;
993 for (int i=0 ; i<numLevels ; i++) {
994 int lod_w = (width >> i) ? : 1;
995 int lod_h = (height >> i) ? : 1;
996 int error = createTextureSurface(c, &surface, &size,
997 i, format, type, lod_w, lod_h);
998 if (error) {
999 ogles_error(c, error);
1000 return;
1001 }
1002 decodePalette4(data, i, width, height,
1003 surface->data, surface->stride, internalformat);
1004 }
1005}
1006
1007
1008void glTexImage2D(
1009 GLenum target, GLint level, GLenum internalformat,
1010 GLsizei width, GLsizei height, GLint border,
1011 GLenum format, GLenum type, const GLvoid *pixels)
1012{
1013 ogles_context_t* c = ogles_context_t::get();
1014 if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
1015 ogles_error(c, GL_INVALID_ENUM);
1016 return;
1017 }
1018 if (width<0 || height<0 || border!=0 || level < 0) {
1019 ogles_error(c, GL_INVALID_VALUE);
1020 return;
1021 }
1022 if (format != internalformat) {
1023 ogles_error(c, GL_INVALID_OPERATION);
1024 return;
1025 }
1026 if (validFormatType(c, format, type)) {
1027 return;
1028 }
1029
1030 int32_t size = 0;
1031 GGLSurface* surface = 0;
1032 if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
1033 int error = createTextureSurface(c, &surface, &size,
1034 level, format, type, width, height);
1035 if (error) {
1036 ogles_error(c, error);
1037 return;
1038 }
1039 } else if (pixels == 0 || level != 0) {
1040 // pixel can't be null for direct texture
1041 ogles_error(c, GL_INVALID_OPERATION);
1042 return;
1043 }
1044
1045 if (pixels) {
1046 const int32_t formatIdx = convertGLPixelFormat(format, type);
1047 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1048 const int32_t align = c->textures.unpackAlignment-1;
1049 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1050 const size_t size = bpr * height;
1051 const int32_t stride = bpr / pixelFormat.size;
1052
1053 GGLSurface userSurface;
1054 userSurface.version = sizeof(userSurface);
1055 userSurface.width = width;
1056 userSurface.height = height;
1057 userSurface.stride = stride;
1058 userSurface.format = formatIdx;
1059 userSurface.compressedFormat = 0;
1060 userSurface.data = (GLubyte*)pixels;
1061
1062 if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
1063 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
1064 if (err) {
1065 ogles_error(c, err);
1066 return;
1067 }
1068 generateMipmap(c, level);
1069 } else {
1070 // bind it to the texture unit
1071 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
1072 tex->setSurface(&userSurface);
1073 }
1074 }
1075}
1076
1077// ----------------------------------------------------------------------------
1078
1079void glCompressedTexSubImage2D(
1080 GLenum target, GLint level, GLint xoffset,
1081 GLint yoffset, GLsizei width, GLsizei height,
1082 GLenum format, GLsizei imageSize,
1083 const GLvoid *data)
1084{
1085 ogles_context_t* c = ogles_context_t::get();
1086 ogles_error(c, GL_INVALID_ENUM);
1087}
1088
1089void glTexSubImage2D(
1090 GLenum target, GLint level, GLint xoffset,
1091 GLint yoffset, GLsizei width, GLsizei height,
1092 GLenum format, GLenum type, const GLvoid *pixels)
1093{
1094 ogles_context_t* c = ogles_context_t::get();
1095 if (target != GL_TEXTURE_2D) {
1096 ogles_error(c, GL_INVALID_ENUM);
1097 return;
1098 }
1099 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1100 ogles_error(c, GL_INVALID_VALUE);
1101 return;
1102 }
1103 if (validFormatType(c, format, type)) {
1104 return;
1105 }
1106
1107 // find out which texture is bound to the current unit
1108 const int active = c->textures.active;
1109 EGLTextureObject* tex = c->textures.tmu[active].texture;
1110 const GGLSurface& surface(tex->mip(level));
1111
1112 if (!tex->internalformat || tex->direct) {
1113 ogles_error(c, GL_INVALID_OPERATION);
1114 return;
1115 }
1116 if ((xoffset + width > GLsizei(surface.width)) ||
1117 (yoffset + height > GLsizei(surface.height))) {
1118 ogles_error(c, GL_INVALID_VALUE);
1119 return;
1120 }
1121 if (!width || !height) {
1122 return; // okay, but no-op.
1123 }
1124
1125 // figure out the size we need as well as the stride
1126 const int32_t formatIdx = convertGLPixelFormat(format, type);
1127 if (formatIdx == 0) { // we don't know what to do with this
1128 ogles_error(c, GL_INVALID_OPERATION);
1129 return;
1130 }
1131
1132 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1133 const int32_t align = c->textures.unpackAlignment-1;
1134 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1135 const size_t size = bpr * height;
1136 const int32_t stride = bpr / pixelFormat.size;
1137 GGLSurface userSurface;
1138 userSurface.version = sizeof(userSurface);
1139 userSurface.width = width;
1140 userSurface.height = height;
1141 userSurface.stride = stride;
1142 userSurface.format = formatIdx;
1143 userSurface.compressedFormat = 0;
1144 userSurface.data = (GLubyte*)pixels;
1145
1146 int err = copyPixels(c,
1147 surface, xoffset, yoffset,
1148 userSurface, 0, 0, width, height);
1149 if (err) {
1150 ogles_error(c, err);
1151 return;
1152 }
1153
1154 generateMipmap(c, level);
1155
1156 // since we only changed the content of the texture, we don't need
1157 // to call bindTexture on the main rasterizer.
1158}
1159
1160// ----------------------------------------------------------------------------
1161
1162void glCopyTexImage2D(
1163 GLenum target, GLint level, GLenum internalformat,
1164 GLint x, GLint y, GLsizei width, GLsizei height,
1165 GLint border)
1166{
1167 ogles_context_t* c = ogles_context_t::get();
1168 if (target != GL_TEXTURE_2D) {
1169 ogles_error(c, GL_INVALID_ENUM);
1170 return;
1171 }
1172 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
1173 ogles_error(c, GL_INVALID_ENUM);
1174 return;
1175 }
1176 if (width<0 || height<0 || border!=0 || level<0) {
1177 ogles_error(c, GL_INVALID_VALUE);
1178 return;
1179 }
1180
1181 GLenum format = 0;
1182 GLenum type = GL_UNSIGNED_BYTE;
1183 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1184 const int cbFormatIdx = cbSurface.format;
1185 switch (cbFormatIdx) {
1186 case GGL_PIXEL_FORMAT_RGB_565:
1187 type = GL_UNSIGNED_SHORT_5_6_5;
1188 break;
1189 case GGL_PIXEL_FORMAT_RGBA_5551:
1190 type = GL_UNSIGNED_SHORT_5_5_5_1;
1191 break;
1192 case GGL_PIXEL_FORMAT_RGBA_4444:
1193 type = GL_UNSIGNED_SHORT_4_4_4_4;
1194 break;
1195 }
1196 switch (internalformat) {
1197 case GL_ALPHA:
1198 case GL_LUMINANCE_ALPHA:
1199 case GL_LUMINANCE:
1200 type = GL_UNSIGNED_BYTE;
1201 break;
1202 }
1203
1204 // figure out the format to use for the new texture
1205 switch (cbFormatIdx) {
1206 case GGL_PIXEL_FORMAT_RGBA_8888:
1207 case GGL_PIXEL_FORMAT_A_8:
1208 case GGL_PIXEL_FORMAT_RGBA_5551:
1209 case GGL_PIXEL_FORMAT_RGBA_4444:
1210 format = internalformat;
1211 break;
1212 case GGL_PIXEL_FORMAT_RGBX_8888:
1213 case GGL_PIXEL_FORMAT_RGB_888:
1214 case GGL_PIXEL_FORMAT_RGB_565:
1215 case GGL_PIXEL_FORMAT_L_8:
1216 switch (internalformat) {
1217 case GL_LUMINANCE:
1218 case GL_RGB:
1219 format = internalformat;
1220 break;
1221 }
1222 break;
1223 }
1224
1225 if (format == 0) {
1226 // invalid combination
1227 ogles_error(c, GL_INVALID_ENUM);
1228 return;
1229 }
1230
1231 // create the new texture...
1232 int32_t size;
1233 GGLSurface* surface;
1234 int error = createTextureSurface(c, &surface, &size,
1235 level, format, type, width, height);
1236 if (error) {
1237 ogles_error(c, error);
1238 return;
1239 }
1240
1241 // The bottom row is stored first in textures
1242 GGLSurface txSurface(*surface);
1243 txSurface.stride = -txSurface.stride;
1244
1245 // (x,y) is the lower-left corner of colorBuffer
1246 y = cbSurface.height - (y + height);
1247
1248 int err = copyPixels(c,
1249 txSurface, 0, 0,
1250 cbSurface, x, y, cbSurface.width, cbSurface.height);
1251 if (err) {
1252 ogles_error(c, err);
1253 }
1254
1255 generateMipmap(c, level);
1256}
1257
1258void glCopyTexSubImage2D(
1259 GLenum target, GLint level, GLint xoffset, GLint yoffset,
1260 GLint x, GLint y, GLsizei width, GLsizei height)
1261{
1262 ogles_context_t* c = ogles_context_t::get();
1263 if (target != GL_TEXTURE_2D) {
1264 ogles_error(c, GL_INVALID_ENUM);
1265 return;
1266 }
1267 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1268 ogles_error(c, GL_INVALID_VALUE);
1269 return;
1270 }
1271 if (!width || !height) {
1272 return; // okay, but no-op.
1273 }
1274
1275 // find out which texture is bound to the current unit
1276 const int active = c->textures.active;
1277 EGLTextureObject* tex = c->textures.tmu[active].texture;
1278 const GGLSurface& surface(tex->mip(level));
1279
1280 if (!tex->internalformat) {
1281 ogles_error(c, GL_INVALID_OPERATION);
1282 return;
1283 }
1284 if ((xoffset + width > GLsizei(surface.width)) ||
1285 (yoffset + height > GLsizei(surface.height))) {
1286 ogles_error(c, GL_INVALID_VALUE);
1287 return;
1288 }
1289
1290 // The bottom row is stored first in textures
1291 GGLSurface txSurface(surface);
1292 txSurface.stride = -txSurface.stride;
1293
1294 // (x,y) is the lower-left corner of colorBuffer
1295 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1296 y = cbSurface.height - (y + height);
1297
1298 int err = copyPixels(c,
1299 surface, xoffset, yoffset,
1300 cbSurface, x, y, width, height);
1301 if (err) {
1302 ogles_error(c, err);
1303 return;
1304 }
1305
1306 generateMipmap(c, level);
1307}
1308
1309void glReadPixels(
1310 GLint x, GLint y, GLsizei width, GLsizei height,
1311 GLenum format, GLenum type, GLvoid *pixels)
1312{
1313 ogles_context_t* c = ogles_context_t::get();
1314 if ((format != GL_RGBA) && (format != GL_RGB)) {
1315 ogles_error(c, GL_INVALID_ENUM);
1316 return;
1317 }
1318 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
1319 ogles_error(c, GL_INVALID_ENUM);
1320 return;
1321 }
1322 if (width<0 || height<0) {
1323 ogles_error(c, GL_INVALID_VALUE);
1324 return;
1325 }
1326 if (x<0 || x<0) {
1327 ogles_error(c, GL_INVALID_VALUE);
1328 return;
1329 }
1330
1331 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
1332 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
1333 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
1334 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
1335 formatIdx = GGL_PIXEL_FORMAT_RGB_565;
1336 } else {
1337 ogles_error(c, GL_INVALID_OPERATION);
1338 return;
1339 }
1340
1341 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
1342 if ((x+width > GLint(readSurface.width)) ||
1343 (y+height > GLint(readSurface.height))) {
1344 ogles_error(c, GL_INVALID_VALUE);
1345 return;
1346 }
1347
1348 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1349 const int32_t align = c->textures.packAlignment-1;
1350 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1351 const int32_t stride = bpr / pixelFormat.size;
1352
1353 GGLSurface userSurface;
1354 userSurface.version = sizeof(userSurface);
1355 userSurface.width = width;
1356 userSurface.height = height;
1357 userSurface.stride = -stride; // bottom row is transfered first
1358 userSurface.format = formatIdx;
1359 userSurface.compressedFormat = 0;
1360 userSurface.data = (GLubyte*)pixels;
1361
1362 // use pixel-flinger to handle all the conversions
1363 GGLContext* ggl = getRasterizer(c);
1364 if (!ggl) {
1365 // the only reason this would fail is because we ran out of memory
1366 ogles_error(c, GL_OUT_OF_MEMORY);
1367 return;
1368 }
1369
1370 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
1371 ggl->bindTexture(ggl, &readSurface); // source is read-buffer
1372 ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
1373 ggl->recti(ggl, 0, 0, width, height);
1374}
1375
1376// ----------------------------------------------------------------------------
1377#if 0
1378#pragma mark -
1379#pragma mark DrawTexture Extension
1380#endif
1381
1382void glDrawTexsvOES(const GLshort* coords) {
1383 ogles_context_t* c = ogles_context_t::get();
1384 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1385}
1386void glDrawTexivOES(const GLint* coords) {
1387 ogles_context_t* c = ogles_context_t::get();
1388 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1389}
1390void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
1391 ogles_context_t* c = ogles_context_t::get();
1392 drawTexiOES(x, y, z, w, h, c);
1393}
1394void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
1395 ogles_context_t* c = ogles_context_t::get();
1396 drawTexiOES(x, y, z, w, h, c);
1397}
1398
1399void glDrawTexfvOES(const GLfloat* coords) {
1400 ogles_context_t* c = ogles_context_t::get();
1401 drawTexxOES(
1402 gglFloatToFixed(coords[0]),
1403 gglFloatToFixed(coords[1]),
1404 gglFloatToFixed(coords[2]),
1405 gglFloatToFixed(coords[3]),
1406 gglFloatToFixed(coords[4]),
1407 c);
1408}
1409void glDrawTexxvOES(const GLfixed* coords) {
1410 ogles_context_t* c = ogles_context_t::get();
1411 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1412}
1413void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
1414 ogles_context_t* c = ogles_context_t::get();
1415 drawTexxOES(
1416 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
1417 gglFloatToFixed(w), gglFloatToFixed(h),
1418 c);
1419}
1420void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
1421 ogles_context_t* c = ogles_context_t::get();
1422 drawTexxOES(x, y, z, w, h, c);
1423}