blob: 14a910c87336189dd84629165412781557c00ecd [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:
Mathias Agopianaaf4b6b2009-06-22 18:04:45 -0700903 texParameterx(target, pname, GLfixed(params[0]), c);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 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
Mathias Agopianaaf4b6b2009-06-22 18:04:45 -0700922void glTexParameteri(
923 GLenum target, GLenum pname, GLint param)
924{
925 ogles_context_t* c = ogles_context_t::get();
926 texParameterx(target, pname, GLfixed(param), c);
927}
928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929// ----------------------------------------------------------------------------
930#if 0
931#pragma mark -
932#endif
933
934void glCompressedTexImage2D(
935 GLenum target, GLint level, GLenum internalformat,
936 GLsizei width, GLsizei height, GLint border,
937 GLsizei imageSize, const GLvoid *data)
938{
939 ogles_context_t* c = ogles_context_t::get();
940 if (target != GL_TEXTURE_2D) {
941 ogles_error(c, GL_INVALID_ENUM);
942 return;
943 }
944 if ((internalformat < GL_PALETTE4_RGB8_OES ||
945 internalformat > GL_PALETTE8_RGB5_A1_OES)) {
946 ogles_error(c, GL_INVALID_ENUM);
947 return;
948 }
949 if (width<0 || height<0 || border!=0) {
950 ogles_error(c, GL_INVALID_VALUE);
951 return;
952 }
953
954 // "uncompress" the texture since pixelflinger doesn't support
955 // any compressed texture format natively.
956 GLenum format;
957 GLenum type;
958 switch (internalformat) {
959 case GL_PALETTE8_RGB8_OES:
960 case GL_PALETTE4_RGB8_OES:
961 format = GL_RGB;
962 type = GL_UNSIGNED_BYTE;
963 break;
964 case GL_PALETTE8_RGBA8_OES:
965 case GL_PALETTE4_RGBA8_OES:
966 format = GL_RGBA;
967 type = GL_UNSIGNED_BYTE;
968 break;
969 case GL_PALETTE8_R5_G6_B5_OES:
970 case GL_PALETTE4_R5_G6_B5_OES:
971 format = GL_RGB;
972 type = GL_UNSIGNED_SHORT_5_6_5;
973 break;
974 case GL_PALETTE8_RGBA4_OES:
975 case GL_PALETTE4_RGBA4_OES:
976 format = GL_RGBA;
977 type = GL_UNSIGNED_SHORT_4_4_4_4;
978 break;
979 case GL_PALETTE8_RGB5_A1_OES:
980 case GL_PALETTE4_RGB5_A1_OES:
981 format = GL_RGBA;
982 type = GL_UNSIGNED_SHORT_5_5_5_1;
983 break;
984 default:
985 ogles_error(c, GL_INVALID_ENUM);
986 return;
987 }
988
989 if (!data || !width || !height) {
990 // unclear if this is an error or not...
991 return;
992 }
993
994 int32_t size;
995 GGLSurface* surface;
996 // all mipmap levels are specified at once.
997 const int numLevels = level<0 ? -level : 1;
998 for (int i=0 ; i<numLevels ; i++) {
999 int lod_w = (width >> i) ? : 1;
1000 int lod_h = (height >> i) ? : 1;
1001 int error = createTextureSurface(c, &surface, &size,
1002 i, format, type, lod_w, lod_h);
1003 if (error) {
1004 ogles_error(c, error);
1005 return;
1006 }
1007 decodePalette4(data, i, width, height,
1008 surface->data, surface->stride, internalformat);
1009 }
1010}
1011
1012
1013void glTexImage2D(
1014 GLenum target, GLint level, GLint internalformat,
1015 GLsizei width, GLsizei height, GLint border,
1016 GLenum format, GLenum type, const GLvoid *pixels)
1017{
1018 ogles_context_t* c = ogles_context_t::get();
1019 if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
1020 ogles_error(c, GL_INVALID_ENUM);
1021 return;
1022 }
1023 if (width<0 || height<0 || border!=0 || level < 0) {
1024 ogles_error(c, GL_INVALID_VALUE);
1025 return;
1026 }
1027 if (format != internalformat) {
1028 ogles_error(c, GL_INVALID_OPERATION);
1029 return;
1030 }
1031 if (validFormatType(c, format, type)) {
1032 return;
1033 }
1034
1035 int32_t size = 0;
1036 GGLSurface* surface = 0;
1037 if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
1038 int error = createTextureSurface(c, &surface, &size,
1039 level, format, type, width, height);
1040 if (error) {
1041 ogles_error(c, error);
1042 return;
1043 }
1044 } else if (pixels == 0 || level != 0) {
1045 // pixel can't be null for direct texture
1046 ogles_error(c, GL_INVALID_OPERATION);
1047 return;
1048 }
1049
1050 if (pixels) {
1051 const int32_t formatIdx = convertGLPixelFormat(format, type);
1052 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1053 const int32_t align = c->textures.unpackAlignment-1;
1054 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1055 const size_t size = bpr * height;
1056 const int32_t stride = bpr / pixelFormat.size;
1057
1058 GGLSurface userSurface;
1059 userSurface.version = sizeof(userSurface);
1060 userSurface.width = width;
1061 userSurface.height = height;
1062 userSurface.stride = stride;
1063 userSurface.format = formatIdx;
1064 userSurface.compressedFormat = 0;
1065 userSurface.data = (GLubyte*)pixels;
1066
1067 if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
1068 int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
1069 if (err) {
1070 ogles_error(c, err);
1071 return;
1072 }
1073 generateMipmap(c, level);
1074 } else {
1075 // bind it to the texture unit
1076 sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
1077 tex->setSurface(&userSurface);
1078 }
1079 }
1080}
1081
1082// ----------------------------------------------------------------------------
1083
1084void glCompressedTexSubImage2D(
1085 GLenum target, GLint level, GLint xoffset,
1086 GLint yoffset, GLsizei width, GLsizei height,
1087 GLenum format, GLsizei imageSize,
1088 const GLvoid *data)
1089{
1090 ogles_context_t* c = ogles_context_t::get();
1091 ogles_error(c, GL_INVALID_ENUM);
1092}
1093
1094void glTexSubImage2D(
1095 GLenum target, GLint level, GLint xoffset,
1096 GLint yoffset, GLsizei width, GLsizei height,
1097 GLenum format, GLenum type, const GLvoid *pixels)
1098{
1099 ogles_context_t* c = ogles_context_t::get();
1100 if (target != GL_TEXTURE_2D) {
1101 ogles_error(c, GL_INVALID_ENUM);
1102 return;
1103 }
1104 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1105 ogles_error(c, GL_INVALID_VALUE);
1106 return;
1107 }
1108 if (validFormatType(c, format, type)) {
1109 return;
1110 }
1111
1112 // find out which texture is bound to the current unit
1113 const int active = c->textures.active;
1114 EGLTextureObject* tex = c->textures.tmu[active].texture;
1115 const GGLSurface& surface(tex->mip(level));
1116
1117 if (!tex->internalformat || tex->direct) {
1118 ogles_error(c, GL_INVALID_OPERATION);
1119 return;
1120 }
1121 if ((xoffset + width > GLsizei(surface.width)) ||
1122 (yoffset + height > GLsizei(surface.height))) {
1123 ogles_error(c, GL_INVALID_VALUE);
1124 return;
1125 }
1126 if (!width || !height) {
1127 return; // okay, but no-op.
1128 }
1129
1130 // figure out the size we need as well as the stride
1131 const int32_t formatIdx = convertGLPixelFormat(format, type);
1132 if (formatIdx == 0) { // we don't know what to do with this
1133 ogles_error(c, GL_INVALID_OPERATION);
1134 return;
1135 }
1136
1137 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1138 const int32_t align = c->textures.unpackAlignment-1;
1139 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1140 const size_t size = bpr * height;
1141 const int32_t stride = bpr / pixelFormat.size;
1142 GGLSurface userSurface;
1143 userSurface.version = sizeof(userSurface);
1144 userSurface.width = width;
1145 userSurface.height = height;
1146 userSurface.stride = stride;
1147 userSurface.format = formatIdx;
1148 userSurface.compressedFormat = 0;
1149 userSurface.data = (GLubyte*)pixels;
1150
1151 int err = copyPixels(c,
1152 surface, xoffset, yoffset,
1153 userSurface, 0, 0, width, height);
1154 if (err) {
1155 ogles_error(c, err);
1156 return;
1157 }
1158
1159 generateMipmap(c, level);
1160
1161 // since we only changed the content of the texture, we don't need
1162 // to call bindTexture on the main rasterizer.
1163}
1164
1165// ----------------------------------------------------------------------------
1166
1167void glCopyTexImage2D(
1168 GLenum target, GLint level, GLenum internalformat,
1169 GLint x, GLint y, GLsizei width, GLsizei height,
1170 GLint border)
1171{
1172 ogles_context_t* c = ogles_context_t::get();
1173 if (target != GL_TEXTURE_2D) {
1174 ogles_error(c, GL_INVALID_ENUM);
1175 return;
1176 }
1177 if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
1178 ogles_error(c, GL_INVALID_ENUM);
1179 return;
1180 }
1181 if (width<0 || height<0 || border!=0 || level<0) {
1182 ogles_error(c, GL_INVALID_VALUE);
1183 return;
1184 }
1185
1186 GLenum format = 0;
1187 GLenum type = GL_UNSIGNED_BYTE;
1188 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1189 const int cbFormatIdx = cbSurface.format;
1190 switch (cbFormatIdx) {
1191 case GGL_PIXEL_FORMAT_RGB_565:
1192 type = GL_UNSIGNED_SHORT_5_6_5;
1193 break;
1194 case GGL_PIXEL_FORMAT_RGBA_5551:
1195 type = GL_UNSIGNED_SHORT_5_5_5_1;
1196 break;
1197 case GGL_PIXEL_FORMAT_RGBA_4444:
1198 type = GL_UNSIGNED_SHORT_4_4_4_4;
1199 break;
1200 }
1201 switch (internalformat) {
1202 case GL_ALPHA:
1203 case GL_LUMINANCE_ALPHA:
1204 case GL_LUMINANCE:
1205 type = GL_UNSIGNED_BYTE;
1206 break;
1207 }
1208
1209 // figure out the format to use for the new texture
1210 switch (cbFormatIdx) {
1211 case GGL_PIXEL_FORMAT_RGBA_8888:
1212 case GGL_PIXEL_FORMAT_A_8:
1213 case GGL_PIXEL_FORMAT_RGBA_5551:
1214 case GGL_PIXEL_FORMAT_RGBA_4444:
1215 format = internalformat;
1216 break;
1217 case GGL_PIXEL_FORMAT_RGBX_8888:
1218 case GGL_PIXEL_FORMAT_RGB_888:
1219 case GGL_PIXEL_FORMAT_RGB_565:
1220 case GGL_PIXEL_FORMAT_L_8:
1221 switch (internalformat) {
1222 case GL_LUMINANCE:
1223 case GL_RGB:
1224 format = internalformat;
1225 break;
1226 }
1227 break;
1228 }
1229
1230 if (format == 0) {
1231 // invalid combination
1232 ogles_error(c, GL_INVALID_ENUM);
1233 return;
1234 }
1235
1236 // create the new texture...
1237 int32_t size;
1238 GGLSurface* surface;
1239 int error = createTextureSurface(c, &surface, &size,
1240 level, format, type, width, height);
1241 if (error) {
1242 ogles_error(c, error);
1243 return;
1244 }
1245
1246 // The bottom row is stored first in textures
1247 GGLSurface txSurface(*surface);
1248 txSurface.stride = -txSurface.stride;
1249
1250 // (x,y) is the lower-left corner of colorBuffer
1251 y = cbSurface.height - (y + height);
1252
1253 int err = copyPixels(c,
1254 txSurface, 0, 0,
1255 cbSurface, x, y, cbSurface.width, cbSurface.height);
1256 if (err) {
1257 ogles_error(c, err);
1258 }
1259
1260 generateMipmap(c, level);
1261}
1262
1263void glCopyTexSubImage2D(
1264 GLenum target, GLint level, GLint xoffset, GLint yoffset,
1265 GLint x, GLint y, GLsizei width, GLsizei height)
1266{
1267 ogles_context_t* c = ogles_context_t::get();
1268 if (target != GL_TEXTURE_2D) {
1269 ogles_error(c, GL_INVALID_ENUM);
1270 return;
1271 }
1272 if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
1273 ogles_error(c, GL_INVALID_VALUE);
1274 return;
1275 }
1276 if (!width || !height) {
1277 return; // okay, but no-op.
1278 }
1279
1280 // find out which texture is bound to the current unit
1281 const int active = c->textures.active;
1282 EGLTextureObject* tex = c->textures.tmu[active].texture;
1283 const GGLSurface& surface(tex->mip(level));
1284
1285 if (!tex->internalformat) {
1286 ogles_error(c, GL_INVALID_OPERATION);
1287 return;
1288 }
1289 if ((xoffset + width > GLsizei(surface.width)) ||
1290 (yoffset + height > GLsizei(surface.height))) {
1291 ogles_error(c, GL_INVALID_VALUE);
1292 return;
1293 }
1294
1295 // The bottom row is stored first in textures
1296 GGLSurface txSurface(surface);
1297 txSurface.stride = -txSurface.stride;
1298
1299 // (x,y) is the lower-left corner of colorBuffer
1300 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
1301 y = cbSurface.height - (y + height);
1302
1303 int err = copyPixels(c,
1304 surface, xoffset, yoffset,
1305 cbSurface, x, y, width, height);
1306 if (err) {
1307 ogles_error(c, err);
1308 return;
1309 }
1310
1311 generateMipmap(c, level);
1312}
1313
1314void glReadPixels(
1315 GLint x, GLint y, GLsizei width, GLsizei height,
1316 GLenum format, GLenum type, GLvoid *pixels)
1317{
1318 ogles_context_t* c = ogles_context_t::get();
1319 if ((format != GL_RGBA) && (format != GL_RGB)) {
1320 ogles_error(c, GL_INVALID_ENUM);
1321 return;
1322 }
1323 if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
1324 ogles_error(c, GL_INVALID_ENUM);
1325 return;
1326 }
1327 if (width<0 || height<0) {
1328 ogles_error(c, GL_INVALID_VALUE);
1329 return;
1330 }
1331 if (x<0 || x<0) {
1332 ogles_error(c, GL_INVALID_VALUE);
1333 return;
1334 }
1335
1336 int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
1337 if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
1338 formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
1339 } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
1340 formatIdx = GGL_PIXEL_FORMAT_RGB_565;
1341 } else {
1342 ogles_error(c, GL_INVALID_OPERATION);
1343 return;
1344 }
1345
1346 const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
1347 if ((x+width > GLint(readSurface.width)) ||
1348 (y+height > GLint(readSurface.height))) {
1349 ogles_error(c, GL_INVALID_VALUE);
1350 return;
1351 }
1352
1353 const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
1354 const int32_t align = c->textures.packAlignment-1;
1355 const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
1356 const int32_t stride = bpr / pixelFormat.size;
1357
1358 GGLSurface userSurface;
1359 userSurface.version = sizeof(userSurface);
1360 userSurface.width = width;
1361 userSurface.height = height;
1362 userSurface.stride = -stride; // bottom row is transfered first
1363 userSurface.format = formatIdx;
1364 userSurface.compressedFormat = 0;
1365 userSurface.data = (GLubyte*)pixels;
1366
1367 // use pixel-flinger to handle all the conversions
1368 GGLContext* ggl = getRasterizer(c);
1369 if (!ggl) {
1370 // the only reason this would fail is because we ran out of memory
1371 ogles_error(c, GL_OUT_OF_MEMORY);
1372 return;
1373 }
1374
1375 ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
1376 ggl->bindTexture(ggl, &readSurface); // source is read-buffer
1377 ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
1378 ggl->recti(ggl, 0, 0, width, height);
1379}
1380
1381// ----------------------------------------------------------------------------
1382#if 0
1383#pragma mark -
1384#pragma mark DrawTexture Extension
1385#endif
1386
1387void glDrawTexsvOES(const GLshort* coords) {
1388 ogles_context_t* c = ogles_context_t::get();
1389 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1390}
1391void glDrawTexivOES(const GLint* coords) {
1392 ogles_context_t* c = ogles_context_t::get();
1393 drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1394}
1395void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
1396 ogles_context_t* c = ogles_context_t::get();
1397 drawTexiOES(x, y, z, w, h, c);
1398}
1399void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
1400 ogles_context_t* c = ogles_context_t::get();
1401 drawTexiOES(x, y, z, w, h, c);
1402}
1403
1404void glDrawTexfvOES(const GLfloat* coords) {
1405 ogles_context_t* c = ogles_context_t::get();
1406 drawTexxOES(
1407 gglFloatToFixed(coords[0]),
1408 gglFloatToFixed(coords[1]),
1409 gglFloatToFixed(coords[2]),
1410 gglFloatToFixed(coords[3]),
1411 gglFloatToFixed(coords[4]),
1412 c);
1413}
1414void glDrawTexxvOES(const GLfixed* coords) {
1415 ogles_context_t* c = ogles_context_t::get();
1416 drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
1417}
1418void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
1419 ogles_context_t* c = ogles_context_t::get();
1420 drawTexxOES(
1421 gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
1422 gglFloatToFixed(w), gglFloatToFixed(h),
1423 c);
1424}
1425void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
1426 ogles_context_t* c = ogles_context_t::get();
1427 drawTexxOES(x, y, z, w, h, c);
1428}