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