array.cpp revision 0926f50664c739eaee60341f8e8c694dc9a4f3eb
1/* 2** Copyright 2006, The Android Open Source Project 3** 4** Licensed under the Apache License, Version 2.0 (the "License"); 5** you may not use this file except in compliance with the License. 6** You may obtain a copy of the License at 7** 8** http://www.apache.org/licenses/LICENSE-2.0 9** 10** Unless required by applicable law or agreed to in writing, software 11** distributed under the License is distributed on an "AS IS" BASIS, 12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13** See the License for the specific language governing permissions and 14** limitations under the License. 15*/ 16 17#include <stdlib.h> 18#include <stdio.h> 19 20#include "context.h" 21#include "fp.h" 22#include "state.h" 23#include "matrix.h" 24#include "vertex.h" 25#include "light.h" 26#include "primitives.h" 27#include "texture.h" 28#include "BufferObjectManager.h" 29#ifdef LIBAGL_USE_GRALLOC_COPYBITS 30#include "copybit.h" 31#endif // LIBAGL_USE_GRALLOC_COPYBITS 32 33// ---------------------------------------------------------------------------- 34 35#define VC_CACHE_STATISTICS 0 36#define VC_CACHE_TYPE_NONE 0 37#define VC_CACHE_TYPE_INDEXED 1 38#define VC_CACHE_TYPE_LRU 2 39#define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED 40 41#if VC_CACHE_STATISTICS 42#include <utils/Timers.h> 43#endif 44 45// ---------------------------------------------------------------------------- 46 47namespace android { 48 49static void validate_arrays(ogles_context_t* c, GLenum mode); 50 51static void compileElements__generic(ogles_context_t*, 52 vertex_t*, GLint, GLsizei); 53static void compileElement__generic(ogles_context_t*, 54 vertex_t*, GLint); 55 56static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei); 57static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei); 58static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei); 59static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei); 60static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei); 61static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei); 62static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei); 63 64static void drawIndexedPrimitivesPoints(ogles_context_t*, 65 GLsizei, const GLvoid*); 66static void drawIndexedPrimitivesLineStrip(ogles_context_t*, 67 GLsizei, const GLvoid*); 68static void drawIndexedPrimitivesLineLoop(ogles_context_t*, 69 GLsizei, const GLvoid*); 70static void drawIndexedPrimitivesLines(ogles_context_t*, 71 GLsizei, const GLvoid*); 72static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*, 73 GLsizei, const GLvoid*); 74static void drawIndexedPrimitivesTriangleFan(ogles_context_t*, 75 GLsizei, const GLvoid*); 76static void drawIndexedPrimitivesTriangles(ogles_context_t*, 77 GLsizei, const GLvoid*); 78 79// ---------------------------------------------------------------------------- 80 81typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei); 82static const arrays_prims_fct_t drawArraysPrims[] = { 83 drawPrimitivesPoints, 84 drawPrimitivesLines, 85 drawPrimitivesLineLoop, 86 drawPrimitivesLineStrip, 87 drawPrimitivesTriangles, 88 drawPrimitivesTriangleStrip, 89 drawPrimitivesTriangleFan 90}; 91 92typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*); 93static const elements_prims_fct_t drawElementsPrims[] = { 94 drawIndexedPrimitivesPoints, 95 drawIndexedPrimitivesLines, 96 drawIndexedPrimitivesLineLoop, 97 drawIndexedPrimitivesLineStrip, 98 drawIndexedPrimitivesTriangles, 99 drawIndexedPrimitivesTriangleStrip, 100 drawIndexedPrimitivesTriangleFan 101}; 102 103// ---------------------------------------------------------------------------- 104#if 0 105#pragma mark - 106#endif 107 108void ogles_init_array(ogles_context_t* c) 109{ 110 c->arrays.vertex.size = 4; 111 c->arrays.vertex.type = GL_FLOAT; 112 c->arrays.color.size = 4; 113 c->arrays.color.type = GL_FLOAT; 114 c->arrays.normal.size = 4; 115 c->arrays.normal.type = GL_FLOAT; 116 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { 117 c->arrays.texture[i].size = 4; 118 c->arrays.texture[i].type = GL_FLOAT; 119 } 120 c->vc.init(); 121 122 if (!c->vc.vBuffer) { 123 // this could have failed 124 ogles_error(c, GL_OUT_OF_MEMORY); 125 } 126} 127 128void ogles_uninit_array(ogles_context_t* c) 129{ 130 c->vc.uninit(); 131} 132 133// ---------------------------------------------------------------------------- 134#if 0 135#pragma mark - 136#pragma mark Array fetchers 137#endif 138 139static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) { 140 memcpy(v, c->current.color.v, sizeof(vec4_t)); 141} 142static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) { 143 memcpy(v, c->currentColorClamped.v, sizeof(vec4_t)); 144} 145static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) { 146 memcpy(v, c->currentNormal.v, sizeof(vec3_t)); 147} 148static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) { 149 memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t)); 150} 151 152 153static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) { 154} 155static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) { 156 v[0] = gglIntToFixed(p[0]); 157 v[1] = gglIntToFixed(p[1]); 158} 159static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) { 160 v[0] = gglIntToFixed(p[0]); 161 v[1] = gglIntToFixed(p[1]); 162} 163static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) { 164 memcpy(v, p, 2*sizeof(GLfixed)); 165} 166static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) { 167 v[0] = gglFloatToFixed(p[0]); 168 v[1] = gglFloatToFixed(p[1]); 169} 170static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) { 171 v[0] = gglIntToFixed(p[0]); 172 v[1] = gglIntToFixed(p[1]); 173 v[2] = gglIntToFixed(p[2]); 174} 175static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) { 176 v[0] = gglIntToFixed(p[0]); 177 v[1] = gglIntToFixed(p[1]); 178 v[2] = gglIntToFixed(p[2]); 179} 180static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) { 181 memcpy(v, p, 3*sizeof(GLfixed)); 182} 183static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) { 184 v[0] = gglFloatToFixed(p[0]); 185 v[1] = gglFloatToFixed(p[1]); 186 v[2] = gglFloatToFixed(p[2]); 187} 188static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) { 189 v[0] = gglIntToFixed(p[0]); 190 v[1] = gglIntToFixed(p[1]); 191 v[2] = gglIntToFixed(p[2]); 192 v[3] = gglIntToFixed(p[3]); 193} 194static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) { 195 v[0] = gglIntToFixed(p[0]); 196 v[1] = gglIntToFixed(p[1]); 197 v[2] = gglIntToFixed(p[2]); 198 v[3] = gglIntToFixed(p[3]); 199} 200static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) { 201 memcpy(v, p, 4*sizeof(GLfixed)); 202} 203static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) { 204 v[0] = gglFloatToFixed(p[0]); 205 v[1] = gglFloatToFixed(p[1]); 206 v[2] = gglFloatToFixed(p[2]); 207 v[3] = gglFloatToFixed(p[3]); 208} 209static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) { 210 v[0] = GGL_UB_TO_X(p[0]); 211 v[1] = GGL_UB_TO_X(p[1]); 212 v[2] = GGL_UB_TO_X(p[2]); 213 v[3] = GGL_UB_TO_X(p[3]); 214} 215static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) { 216 v[0] = gglClampx(p[0]); 217 v[1] = gglClampx(p[1]); 218 v[2] = gglClampx(p[2]); 219 v[3] = gglClampx(p[3]); 220} 221static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) { 222 v[0] = gglClampx(gglFloatToFixed(p[0])); 223 v[1] = gglClampx(gglFloatToFixed(p[1])); 224 v[2] = gglClampx(gglFloatToFixed(p[2])); 225 v[3] = gglClampx(gglFloatToFixed(p[3])); 226} 227static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) { 228 v[0] = GGL_UB_TO_X(p[0]); 229 v[1] = GGL_UB_TO_X(p[1]); 230 v[2] = GGL_UB_TO_X(p[2]); 231 v[3] = 0x10000; 232} 233static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) { 234 v[0] = gglClampx(p[0]); 235 v[1] = gglClampx(p[1]); 236 v[2] = gglClampx(p[2]); 237 v[3] = 0x10000; 238} 239static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) { 240 v[0] = gglClampx(gglFloatToFixed(p[0])); 241 v[1] = gglClampx(gglFloatToFixed(p[1])); 242 v[2] = gglClampx(gglFloatToFixed(p[2])); 243 v[3] = 0x10000; 244} 245static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) { 246 v[0] = GGL_B_TO_X(p[0]); 247 v[1] = GGL_B_TO_X(p[1]); 248 v[2] = GGL_B_TO_X(p[2]); 249} 250static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) { 251 v[0] = GGL_S_TO_X(p[0]); 252 v[1] = GGL_S_TO_X(p[1]); 253 v[2] = GGL_S_TO_X(p[2]); 254} 255 256typedef array_t::fetcher_t fn_t; 257 258static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x} 259 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0, 260 (fn_t)fetch3f, 0, 0, 0, 0, 0, 261 (fn_t)fetch3x }, 262 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0, 263 (fn_t)fetch4f, 0, 0, 0, 0, 0, 264 (fn_t)fetch4x }, 265}; 266static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x} 267 { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0, 268 (fn_t)fetchClamp3f, 0, 0, 0, 0, 0, 269 (fn_t)fetchClamp3x }, 270 { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0, 271 (fn_t)fetchClamp4f, 0, 0, 0, 0, 0, 272 (fn_t)fetchClamp4x }, 273}; 274static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x} 275 { (fn_t)fetchExpand3b, 0, 276 (fn_t)fetchExpand3s, 0, 0, 0, 277 (fn_t)fetch3f, 0, 0, 0, 0, 0, 278 (fn_t)fetch3x }, 279}; 280static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x} 281 { (fn_t)fetch2b, 0, 282 (fn_t)fetch2s, 0, 0, 0, 283 (fn_t)fetch2f, 0, 0, 0, 0, 0, 284 (fn_t)fetch3x }, 285 { (fn_t)fetch3b, 0, 286 (fn_t)fetch3s, 0, 0, 0, 287 (fn_t)fetch3f, 0, 0, 0, 0, 0, 288 (fn_t)fetch3x }, 289 { (fn_t)fetch4b, 0, 290 (fn_t)fetch4s, 0, 0, 0, 291 (fn_t)fetch4f, 0, 0, 0, 0, 0, 292 (fn_t)fetch4x } 293}; 294static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x} 295 { (fn_t)fetch2b, 0, 296 (fn_t)fetch2s, 0, 0, 0, 297 (fn_t)fetch2f, 0, 0, 0, 0, 0, 298 (fn_t)fetch2x }, 299 { (fn_t)fetch3b, 0, 300 (fn_t)fetch3s, 0, 0, 0, 301 (fn_t)fetch3f, 0, 0, 0, 0, 0, 302 (fn_t)fetch3x }, 303 { (fn_t)fetch4b, 0, 304 (fn_t)fetch4s, 0, 0, 0, 305 (fn_t)fetch4f, 0, 0, 0, 0, 0, 306 (fn_t)fetch4x } 307}; 308 309// ---------------------------------------------------------------------------- 310#if 0 311#pragma mark - 312#pragma mark array_t 313#endif 314 315void array_t::init( 316 GLint size, GLenum type, GLsizei stride, 317 const GLvoid *pointer, const buffer_t* bo, GLsizei count) 318{ 319 if (!stride) { 320 stride = size; 321 switch (type) { 322 case GL_SHORT: 323 case GL_UNSIGNED_SHORT: 324 stride *= 2; 325 break; 326 case GL_FLOAT: 327 case GL_FIXED: 328 stride *= 4; 329 break; 330 } 331 } 332 this->size = size; 333 this->type = type; 334 this->stride = stride; 335 this->pointer = pointer; 336 this->bo = bo; 337 this->bounds = count; 338} 339 340inline void array_t::resolve() 341{ 342 physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer; 343} 344 345// ---------------------------------------------------------------------------- 346#if 0 347#pragma mark - 348#pragma mark vertex_cache_t 349#endif 350 351void vertex_cache_t::init() 352{ 353 // make sure the size of vertex_t allows cache-line alignment 354 CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize; 355 356 const int align = 32; 357 const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; 358 const size_t size = s*sizeof(vertex_t) + align; 359 base = malloc(size); 360 if (base) { 361 memset(base, 0, size); 362 vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1)); 363 vCache = vBuffer + VERTEX_BUFFER_SIZE; 364 sequence = 0; 365 } 366} 367 368void vertex_cache_t::uninit() 369{ 370 free(base); 371 base = vBuffer = vCache = 0; 372} 373 374void vertex_cache_t::clear() 375{ 376#if VC_CACHE_STATISTICS 377 startTime = systemTime(SYSTEM_TIME_THREAD); 378 total = 0; 379 misses = 0; 380#endif 381 382#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU 383 vertex_t* v = vBuffer; 384 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; 385 do { 386 v->mru = 0; 387 v++; 388 } while (--count); 389#endif 390 391 sequence += INDEX_SEQ; 392 if (sequence >= 0x80000000LU) { 393 sequence = INDEX_SEQ; 394 vertex_t* v = vBuffer; 395 size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; 396 do { 397 v->index = 0; 398 v++; 399 } while (--count); 400 } 401} 402 403void vertex_cache_t::dump_stats(GLenum mode) 404{ 405#if VC_CACHE_STATISTICS 406 nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime; 407 uint32_t hits = total - misses; 408 uint32_t prim_count; 409 switch (mode) { 410 case GL_POINTS: prim_count = total; break; 411 case GL_LINE_STRIP: prim_count = total - 1; break; 412 case GL_LINE_LOOP: prim_count = total - 1; break; 413 case GL_LINES: prim_count = total / 2; break; 414 case GL_TRIANGLE_STRIP: prim_count = total - 2; break; 415 case GL_TRIANGLE_FAN: prim_count = total - 2; break; 416 case GL_TRIANGLES: prim_count = total / 3; break; 417 default: return; 418 } 419 printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%," 420 " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n", 421 total, hits, misses, (hits*100)/total, 422 prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time), 423 float(misses) / prim_count); 424#endif 425} 426 427// ---------------------------------------------------------------------------- 428#if 0 429#pragma mark - 430#endif 431 432static __attribute__((noinline)) 433void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable) 434{ 435 const int tmu = c->arrays.activeTexture; 436 array_t* a; 437 switch (array) { 438 case GL_COLOR_ARRAY: a = &c->arrays.color; break; 439 case GL_NORMAL_ARRAY: a = &c->arrays.normal; break; 440 case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break; 441 case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break; 442 default: 443 ogles_error(c, GL_INVALID_ENUM); 444 return; 445 } 446 a->enable = enable ? GL_TRUE : GL_FALSE; 447} 448 449// ---------------------------------------------------------------------------- 450#if 0 451#pragma mark - 452#pragma mark Vertex Cache 453#endif 454 455static __attribute__((noinline)) 456vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index) 457{ 458 #if VC_CACHE_STATISTICS 459 c->vc.misses++; 460 #endif 461 if (ggl_unlikely(v->locked)) { 462 // we're just looking for an entry in the cache that is not locked. 463 // and we know that there cannot be more than 2 locked entries 464 // because a triangle needs at most 3 vertices. 465 // We never use the first and second entries because they might be in 466 // use by the striper or faner. Any other entry will do as long as 467 // it's not locked. 468 // We compute directly the index of a "free" entry from the locked 469 // state of v[2] and v[3]. 470 v = c->vc.vBuffer + 2; 471 v += v[0].locked | (v[1].locked<<1); 472 } 473 // note: compileElement clears v->flags 474 c->arrays.compileElement(c, v, index); 475 v->locked = 1; 476 return v; 477} 478 479static __attribute__((noinline)) 480vertex_t* fetch_vertex(ogles_context_t* c, size_t index) 481{ 482 index |= c->vc.sequence; 483 484#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED 485 486 vertex_t* const v = c->vc.vCache + 487 (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1)); 488 489 if (ggl_likely(v->index == index)) { 490 v->locked = 1; 491 return v; 492 } 493 return cache_vertex(c, v, index); 494 495#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU 496 497 vertex_t* v = c->vc.vCache + 498 (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2; 499 500 // always record LRU in v[0] 501 if (ggl_likely(v[0].index == index)) { 502 v[0].locked = 1; 503 v[0].mru = 0; 504 return &v[0]; 505 } 506 507 if (ggl_likely(v[1].index == index)) { 508 v[1].locked = 1; 509 v[0].mru = 1; 510 return &v[1]; 511 } 512 513 const int lru = 1 - v[0].mru; 514 v[0].mru = lru; 515 return cache_vertex(c, &v[lru], index); 516 517#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE 518 519 // just for debugging... 520 vertex_t* v = c->vc.vBuffer + 2; 521 return cache_vertex(c, v, index); 522 523#endif 524} 525 526// ---------------------------------------------------------------------------- 527#if 0 528#pragma mark - 529#pragma mark Primitive Assembly 530#endif 531 532void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count) 533{ 534 if (ggl_unlikely(count < 1)) 535 return; 536 537 // vertex cache size must be multiple of 1 538 const GLsizei vcs = 539 (vertex_cache_t::VERTEX_BUFFER_SIZE + 540 vertex_cache_t::VERTEX_CACHE_SIZE); 541 do { 542 vertex_t* v = c->vc.vBuffer; 543 GLsizei num = count > vcs ? vcs : count; 544 c->arrays.cull = vertex_t::CLIP_ALL; 545 c->arrays.compileElements(c, v, first, num); 546 first += num; 547 count -= num; 548 if (!c->arrays.cull) { 549 // quick/trivial reject of the whole batch 550 do { 551 const uint32_t cc = v[0].flags; 552 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 553 c->prims.renderPoint(c, v); 554 v++; 555 num--; 556 } while (num); 557 } 558 } while (count); 559} 560 561// ---------------------------------------------------------------------------- 562 563void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count) 564{ 565 if (ggl_unlikely(count < 2)) 566 return; 567 568 vertex_t *v, *v0, *v1; 569 c->arrays.cull = vertex_t::CLIP_ALL; 570 c->arrays.compileElement(c, c->vc.vBuffer, first); 571 first += 1; 572 count -= 1; 573 574 // vertex cache size must be multiple of 1 575 const GLsizei vcs = 576 (vertex_cache_t::VERTEX_BUFFER_SIZE + 577 vertex_cache_t::VERTEX_CACHE_SIZE - 1); 578 do { 579 v0 = c->vc.vBuffer + 0; 580 v = c->vc.vBuffer + 1; 581 GLsizei num = count > vcs ? vcs : count; 582 c->arrays.compileElements(c, v, first, num); 583 first += num; 584 count -= num; 585 if (!c->arrays.cull) { 586 // quick/trivial reject of the whole batch 587 do { 588 v1 = v++; 589 const uint32_t cc = v0->flags & v1->flags; 590 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 591 c->prims.renderLine(c, v0, v1); 592 v0 = v1; 593 num--; 594 } while (num); 595 } 596 // copy back the last processed vertex 597 c->vc.vBuffer[0] = *v0; 598 c->arrays.cull = v0->flags & vertex_t::CLIP_ALL; 599 } while (count); 600} 601 602void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count) 603{ 604 if (ggl_unlikely(count < 2)) 605 return; 606 drawPrimitivesLineStrip(c, first, count); 607 if (ggl_likely(count >= 3)) { 608 vertex_t* v0 = c->vc.vBuffer; 609 vertex_t* v1 = c->vc.vBuffer + 1; 610 c->arrays.compileElement(c, v1, first); 611 const uint32_t cc = v0->flags & v1->flags; 612 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 613 c->prims.renderLine(c, v0, v1); 614 } 615} 616 617void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count) 618{ 619 if (ggl_unlikely(count < 2)) 620 return; 621 622 // vertex cache size must be multiple of 2 623 const GLsizei vcs = 624 ((vertex_cache_t::VERTEX_BUFFER_SIZE + 625 vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2; 626 do { 627 vertex_t* v = c->vc.vBuffer; 628 GLsizei num = count > vcs ? vcs : count; 629 c->arrays.cull = vertex_t::CLIP_ALL; 630 c->arrays.compileElements(c, v, first, num); 631 first += num; 632 count -= num; 633 if (!c->arrays.cull) { 634 // quick/trivial reject of the whole batch 635 num -= 2; 636 do { 637 const uint32_t cc = v[0].flags & v[1].flags; 638 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 639 c->prims.renderLine(c, v, v+1); 640 v += 2; 641 num -= 2; 642 } while (num >= 0); 643 } 644 } while (count >= 2); 645} 646 647// ---------------------------------------------------------------------------- 648 649static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c, 650 GLint first, GLsizei count, int winding) 651{ 652 // winding == 2 : fan 653 // winding == 1 : strip 654 655 if (ggl_unlikely(count < 3)) 656 return; 657 658 vertex_t *v, *v0, *v1, *v2; 659 c->arrays.cull = vertex_t::CLIP_ALL; 660 c->arrays.compileElements(c, c->vc.vBuffer, first, 2); 661 first += 2; 662 count -= 2; 663 664 // vertex cache size must be multiple of 2. This is extremely important 665 // because it allows us to preserve the same winding when the whole 666 // batch is culled. We also need 2 extra vertices in the array, because 667 // we always keep the two first ones. 668 const GLsizei vcs = 669 ((vertex_cache_t::VERTEX_BUFFER_SIZE + 670 vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2; 671 do { 672 v0 = c->vc.vBuffer + 0; 673 v1 = c->vc.vBuffer + 1; 674 v = c->vc.vBuffer + 2; 675 GLsizei num = count > vcs ? vcs : count; 676 c->arrays.compileElements(c, v, first, num); 677 first += num; 678 count -= num; 679 if (!c->arrays.cull) { 680 // quick/trivial reject of the whole batch 681 do { 682 v2 = v++; 683 const uint32_t cc = v0->flags & v1->flags & v2->flags; 684 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 685 c->prims.renderTriangle(c, v0, v1, v2); 686 swap(((winding^=1) ? v1 : v0), v2); 687 num--; 688 } while (num); 689 } 690 if (count) { 691 v0 = c->vc.vBuffer + 2 + num - 2; 692 v1 = c->vc.vBuffer + 2 + num - 1; 693 if ((winding&2) == 0) { 694 // for strips copy back the two last compiled vertices 695 c->vc.vBuffer[0] = *v0; 696 } 697 c->vc.vBuffer[1] = *v1; 698 c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL; 699 } 700 } while (count > 0); 701} 702 703void drawPrimitivesTriangleStrip(ogles_context_t* c, 704 GLint first, GLsizei count) { 705 drawPrimitivesTriangleFanOrStrip(c, first, count, 1); 706} 707 708void drawPrimitivesTriangleFan(ogles_context_t* c, 709 GLint first, GLsizei count) { 710#ifdef LIBAGL_USE_GRALLOC_COPYBITS 711 if (drawTrangleFanWithCopybit(c, first, count)) { 712 return; 713 } 714#endif // LIBAGL_USE_GRALLOC_COPYBITS 715 716 drawPrimitivesTriangleFanOrStrip(c, first, count, 2); 717} 718 719void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count) 720{ 721 if (ggl_unlikely(count < 3)) 722 return; 723 724 // vertex cache size must be multiple of 3 725 const GLsizei vcs = 726 ((vertex_cache_t::VERTEX_BUFFER_SIZE + 727 vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3; 728 do { 729 vertex_t* v = c->vc.vBuffer; 730 GLsizei num = count > vcs ? vcs : count; 731 c->arrays.cull = vertex_t::CLIP_ALL; 732 c->arrays.compileElements(c, v, first, num); 733 first += num; 734 count -= num; 735 if (!c->arrays.cull) { 736 // quick/trivial reject of the whole batch 737 num -= 3; 738 do { 739 const uint32_t cc = v[0].flags & v[1].flags & v[2].flags; 740 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 741 c->prims.renderTriangle(c, v, v+1, v+2); 742 v += 3; 743 num -= 3; 744 } while (num >= 0); 745 } 746 } while (count >= 3); 747} 748 749// ---------------------------------------------------------------------------- 750#if 0 751#pragma mark - 752#endif 753 754// this looks goofy, but gcc does a great job with this... 755static inline unsigned int read_index(int type, const GLvoid*& p) { 756 unsigned int r; 757 if (type) { 758 r = *(const GLubyte*)p; 759 p = (const GLubyte*)p + 1; 760 } else { 761 r = *(const GLushort*)p; 762 p = (const GLushort*)p + 1; 763 } 764 return r; 765} 766 767// ---------------------------------------------------------------------------- 768 769void drawIndexedPrimitivesPoints(ogles_context_t* c, 770 GLsizei count, const GLvoid *indices) 771{ 772 if (ggl_unlikely(count < 1)) 773 return; 774 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); 775 do { 776 vertex_t * v = fetch_vertex(c, read_index(type, indices)); 777 if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL))) 778 c->prims.renderPoint(c, v); 779 v->locked = 0; 780 count--; 781 } while(count); 782} 783 784// ---------------------------------------------------------------------------- 785 786void drawIndexedPrimitivesLineStrip(ogles_context_t* c, 787 GLsizei count, const GLvoid *indices) 788{ 789 if (ggl_unlikely(count < 2)) 790 return; 791 792 vertex_t * const v = c->vc.vBuffer; 793 vertex_t* v0 = v; 794 vertex_t* v1; 795 796 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); 797 c->arrays.compileElement(c, v0, read_index(type, indices)); 798 count -= 1; 799 do { 800 v1 = fetch_vertex(c, read_index(type, indices)); 801 const uint32_t cc = v0->flags & v1->flags; 802 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 803 c->prims.renderLine(c, v0, v1); 804 v0->locked = 0; 805 v0 = v1; 806 count--; 807 } while (count); 808 v1->locked = 0; 809} 810 811void drawIndexedPrimitivesLineLoop(ogles_context_t* c, 812 GLsizei count, const GLvoid *indices) 813{ 814 if (ggl_unlikely(count <= 2)) { 815 drawIndexedPrimitivesLines(c, count, indices); 816 return; 817 } 818 819 vertex_t * const v = c->vc.vBuffer; 820 vertex_t* v0 = v; 821 vertex_t* v1; 822 823 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); 824 c->arrays.compileElement(c, v0, read_index(type, indices)); 825 count -= 1; 826 do { 827 v1 = fetch_vertex(c, read_index(type, indices)); 828 const uint32_t cc = v0->flags & v1->flags; 829 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 830 c->prims.renderLine(c, v0, v1); 831 v0->locked = 0; 832 v0 = v1; 833 count--; 834 } while (count); 835 v1->locked = 0; 836 837 v1 = c->vc.vBuffer; 838 const uint32_t cc = v0->flags & v1->flags; 839 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 840 c->prims.renderLine(c, v0, v1); 841} 842 843void drawIndexedPrimitivesLines(ogles_context_t* c, 844 GLsizei count, const GLvoid *indices) 845{ 846 if (ggl_unlikely(count < 2)) 847 return; 848 849 count -= 2; 850 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); 851 do { 852 vertex_t* const v0 = fetch_vertex(c, read_index(type, indices)); 853 vertex_t* const v1 = fetch_vertex(c, read_index(type, indices)); 854 const uint32_t cc = v0->flags & v1->flags; 855 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 856 c->prims.renderLine(c, v0, v1); 857 v0->locked = 0; 858 v1->locked = 0; 859 count -= 2; 860 } while (count >= 0); 861} 862 863// ---------------------------------------------------------------------------- 864 865static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c, 866 GLsizei count, const GLvoid *indices, int winding) 867{ 868 // winding == 2 : fan 869 // winding == 1 : strip 870 871 if (ggl_unlikely(count < 3)) 872 return; 873 874 vertex_t * const v = c->vc.vBuffer; 875 vertex_t* v0 = v; 876 vertex_t* v1 = v+1; 877 vertex_t* v2; 878 879 const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); 880 c->arrays.compileElement(c, v0, read_index(type, indices)); 881 c->arrays.compileElement(c, v1, read_index(type, indices)); 882 count -= 2; 883 884 // note: GCC 4.1.1 here makes a prety interesting optimization 885 // where it duplicates the loop below based on c->arrays.indicesType 886 887 do { 888 v2 = fetch_vertex(c, read_index(type, indices)); 889 const uint32_t cc = v0->flags & v1->flags & v2->flags; 890 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 891 c->prims.renderTriangle(c, v0, v1, v2); 892 vertex_t* & consumed = ((winding^=1) ? v1 : v0); 893 consumed->locked = 0; 894 consumed = v2; 895 count--; 896 } while (count); 897 v0->locked = v1->locked = 0; 898 v2->locked = 0; 899} 900 901void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c, 902 GLsizei count, const GLvoid *indices) { 903 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1); 904} 905 906void drawIndexedPrimitivesTriangleFan(ogles_context_t* c, 907 GLsizei count, const GLvoid *indices) { 908 drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2); 909} 910 911void drawIndexedPrimitivesTriangles(ogles_context_t* c, 912 GLsizei count, const GLvoid *indices) 913{ 914 if (ggl_unlikely(count < 3)) 915 return; 916 917 count -= 3; 918 if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) { 919 // This case is probably our most common case... 920 uint16_t const * p = (uint16_t const *)indices; 921 do { 922 vertex_t* const v0 = fetch_vertex(c, *p++); 923 vertex_t* const v1 = fetch_vertex(c, *p++); 924 vertex_t* const v2 = fetch_vertex(c, *p++); 925 const uint32_t cc = v0->flags & v1->flags & v2->flags; 926 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 927 c->prims.renderTriangle(c, v0, v1, v2); 928 v0->locked = 0; 929 v1->locked = 0; 930 v2->locked = 0; 931 count -= 3; 932 } while (count >= 0); 933 } else { 934 uint8_t const * p = (uint8_t const *)indices; 935 do { 936 vertex_t* const v0 = fetch_vertex(c, *p++); 937 vertex_t* const v1 = fetch_vertex(c, *p++); 938 vertex_t* const v2 = fetch_vertex(c, *p++); 939 const uint32_t cc = v0->flags & v1->flags & v2->flags; 940 if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) 941 c->prims.renderTriangle(c, v0, v1, v2); 942 v0->locked = 0; 943 v1->locked = 0; 944 v2->locked = 0; 945 count -= 3; 946 } while (count >= 0); 947 } 948} 949 950// ---------------------------------------------------------------------------- 951#if 0 952#pragma mark - 953#pragma mark Array compilers 954#endif 955 956void compileElement__generic(ogles_context_t* c, 957 vertex_t* v, GLint first) 958{ 959 v->flags = 0; 960 v->index = first; 961 first &= vertex_cache_t::INDEX_MASK; 962 const GLubyte* vp = c->arrays.vertex.element(first); 963 c->arrays.vertex.fetch(c, v->obj.v, vp); 964 c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj); 965 c->arrays.perspective(c, v); 966} 967 968void compileElements__generic(ogles_context_t* c, 969 vertex_t* v, GLint first, GLsizei count) 970{ 971 const GLubyte* vp = c->arrays.vertex.element( 972 first & vertex_cache_t::INDEX_MASK); 973 const size_t stride = c->arrays.vertex.stride; 974 transform_t const* const mvp = &c->transforms.mvp; 975 do { 976 v->flags = 0; 977 v->index = first++; 978 c->arrays.vertex.fetch(c, v->obj.v, vp); 979 c->arrays.mvp_transform(mvp, &v->clip, &v->obj); 980 c->arrays.perspective(c, v); 981 vp += stride; 982 v++; 983 } while (--count); 984} 985 986/* 987void compileElements__3x_full(ogles_context_t* c, 988 vertex_t* v, GLint first, GLsizei count) 989{ 990 const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first); 991 const size_t stride = c->arrays.vertex.stride / 4; 992// const GLfixed* const& m = c->transforms.mvp.matrix.m; 993 994 GLfixed m[16]; 995 memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m)); 996 997 do { 998 const GLfixed rx = vp[0]; 999 const GLfixed ry = vp[1]; 1000 const GLfixed rz = vp[2]; 1001 vp += stride; 1002 v->index = first++; 1003 v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); 1004 v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); 1005 v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); 1006 v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); 1007 1008 const GLfixed w = v->clip.w; 1009 uint32_t clip = 0; 1010 if (v->clip.x < -w) clip |= vertex_t::CLIP_L; 1011 if (v->clip.x > w) clip |= vertex_t::CLIP_R; 1012 if (v->clip.y < -w) clip |= vertex_t::CLIP_B; 1013 if (v->clip.y > w) clip |= vertex_t::CLIP_T; 1014 if (v->clip.z < -w) clip |= vertex_t::CLIP_N; 1015 if (v->clip.z > w) clip |= vertex_t::CLIP_F; 1016 v->flags = clip; 1017 c->arrays.cull &= clip; 1018 1019 //c->arrays.perspective(c, v); 1020 v++; 1021 } while (--count); 1022} 1023*/ 1024 1025// ---------------------------------------------------------------------------- 1026#if 0 1027#pragma mark - 1028#pragma mark clippers 1029#endif 1030 1031static void clipVec4(vec4_t& nv, 1032 GLfixed t, const vec4_t& s, const vec4_t& p) 1033{ 1034 for (int i=0; i<4 ; i++) 1035 nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28); 1036} 1037 1038static void clipVertex(ogles_context_t* c, vertex_t* nv, 1039 GLfixed t, const vertex_t* s, const vertex_t* p) 1040{ 1041 clipVec4(nv->clip, t, s->clip, p->clip); 1042 nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28); 1043 ogles_vertex_project(c, nv); 1044 nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT; 1045 nv->flags &= ~vertex_t::CLIP_ALL; 1046} 1047 1048static void clipVertexC(ogles_context_t* c, vertex_t* nv, 1049 GLfixed t, const vertex_t* s, const vertex_t* p) 1050{ 1051 clipVec4(nv->color, t, s->color, p->color); 1052 clipVertex(c, nv, t, s, p); 1053} 1054 1055static void clipVertexT(ogles_context_t* c, vertex_t* nv, 1056 GLfixed t, const vertex_t* s, const vertex_t* p) 1057{ 1058 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { 1059 if (c->rasterizer.state.texture[i].enable) 1060 clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]); 1061 } 1062 clipVertex(c, nv, t, s, p); 1063} 1064 1065static void clipVertexAll(ogles_context_t* c, vertex_t* nv, 1066 GLfixed t, const vertex_t* s, const vertex_t* p) 1067{ 1068 clipVec4(nv->color, t, s->color, p->color); 1069 clipVertexT(c, nv, t, s, p); 1070} 1071 1072static void clipEye(ogles_context_t* c, vertex_t* nv, 1073 GLfixed t, const vertex_t* s, const vertex_t* p) 1074{ 1075 nv->clear(); 1076 c->arrays.clipVertex(c, nv, t, p, s); 1077 clipVec4(nv->eye, t, s->eye, p->eye); 1078} 1079 1080// ---------------------------------------------------------------------------- 1081#if 0 1082#pragma mark - 1083#endif 1084 1085void validate_arrays(ogles_context_t* c, GLenum mode) 1086{ 1087 uint32_t enables = c->rasterizer.state.enables; 1088 1089 // Perspective correction is not need if Ortho transform, but 1090 // the user can still provide the w coordinate manually, so we can't 1091 // automatically turn it off (in fact we could when the 4th coordinate 1092 // is not spcified in the vertex array). 1093 // W interpolation is never needed for points. 1094 GLboolean perspective = 1095 c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS); 1096 c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective); 1097 1098 // set anti-aliasing 1099 GLboolean smooth = GL_FALSE; 1100 switch (mode) { 1101 case GL_POINTS: 1102 smooth = c->point.smooth; 1103 break; 1104 case GL_LINES: 1105 case GL_LINE_LOOP: 1106 case GL_LINE_STRIP: 1107 smooth = c->line.smooth; 1108 break; 1109 } 1110 if (((enables & GGL_ENABLE_AA)?1:0) != smooth) 1111 c->rasterizer.procs.enableDisable(c, GGL_AA, smooth); 1112 1113 // set the shade model for this primitive 1114 c->rasterizer.procs.shadeModel(c, 1115 (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel); 1116 1117 // compute all the matrices we'll need... 1118 uint32_t want = 1119 transform_state_t::MVP | 1120 transform_state_t::VIEWPORT; 1121 if (c->lighting.enable) { // needs normal transforms and eye coords 1122 want |= transform_state_t::MVUI; 1123 want |= transform_state_t::MODELVIEW; 1124 } 1125 if (enables & GGL_ENABLE_TMUS) { // needs texture transforms 1126 want |= transform_state_t::TEXTURE; 1127 } 1128 if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { 1129 want |= transform_state_t::MODELVIEW; // needs eye coords 1130 } 1131 ogles_validate_transform(c, want); 1132 1133 // textures... 1134 if (enables & GGL_ENABLE_TMUS) 1135 ogles_validate_texture(c); 1136 1137 // vertex compilers 1138 c->arrays.compileElement = compileElement__generic; 1139 c->arrays.compileElements = compileElements__generic; 1140 1141 // vertex transform 1142 c->arrays.mvp_transform = 1143 c->transforms.mvp.pointv[c->arrays.vertex.size - 2]; 1144 1145 c->arrays.mv_transform = 1146 c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2]; 1147 1148 /* 1149 * *********************************************************************** 1150 * pick fetchers 1151 * *********************************************************************** 1152 */ 1153 1154 array_machine_t& am = c->arrays; 1155 am.vertex.fetch = fetchNop; 1156 am.normal.fetch = currentNormal; 1157 am.color.fetch = currentColor; 1158 1159 if (am.vertex.enable) { 1160 am.vertex.resolve(); 1161 if (am.vertex.bo || am.vertex.pointer) { 1162 am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF]; 1163 } 1164 } 1165 1166 if (am.normal.enable) { 1167 am.normal.resolve(); 1168 if (am.normal.bo || am.normal.pointer) { 1169 am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF]; 1170 } 1171 } 1172 1173 if (am.color.enable) { 1174 am.color.resolve(); 1175 if (c->lighting.enable) { 1176 if (am.color.bo || am.color.pointer) { 1177 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF]; 1178 } 1179 } else { 1180 if (am.color.bo || am.color.pointer) { 1181 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF]; 1182 } 1183 } 1184 } 1185 1186 int activeTmuCount = 0; 1187 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) { 1188 am.texture[i].fetch = currentTexCoord; 1189 if (c->rasterizer.state.texture[i].enable) { 1190 1191 // texture fetchers... 1192 if (am.texture[i].enable) { 1193 am.texture[i].resolve(); 1194 if (am.texture[i].bo || am.texture[i].pointer) { 1195 am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF]; 1196 } 1197 } 1198 1199 // texture transform... 1200 const int index = c->arrays.texture[i].size - 2; 1201 c->arrays.tex_transform[i] = 1202 c->transforms.texture[i].transform.pointv[index]; 1203 1204 am.tmu = i; 1205 activeTmuCount++; 1206 } 1207 } 1208 1209 // pick the vertex-clipper 1210 uint32_t clipper = 0; 1211 // we must reload 'enables' here 1212 enables = c->rasterizer.state.enables; 1213 if (enables & GGL_ENABLE_SMOOTH) 1214 clipper |= 1; // we need to interpolate colors 1215 if (enables & GGL_ENABLE_TMUS) 1216 clipper |= 2; // we need to interpolate textures 1217 switch (clipper) { 1218 case 0: c->arrays.clipVertex = clipVertex; break; 1219 case 1: c->arrays.clipVertex = clipVertexC; break; 1220 case 2: c->arrays.clipVertex = clipVertexT; break; 1221 case 3: c->arrays.clipVertex = clipVertexAll; break; 1222 } 1223 c->arrays.clipEye = clipEye; 1224 1225 // pick the primitive rasterizer 1226 ogles_validate_primitives(c); 1227} 1228 1229// ---------------------------------------------------------------------------- 1230}; // namespace android 1231// ---------------------------------------------------------------------------- 1232 1233using namespace android; 1234 1235#if 0 1236#pragma mark - 1237#pragma mark array API 1238#endif 1239 1240void glVertexPointer( 1241 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) 1242{ 1243 ogles_context_t* c = ogles_context_t::get(); 1244 if (size<2 || size>4 || stride<0) { 1245 ogles_error(c, GL_INVALID_VALUE); 1246 return; 1247 } 1248 switch (type) { 1249 case GL_BYTE: 1250 case GL_SHORT: 1251 case GL_FIXED: 1252 case GL_FLOAT: 1253 break; 1254 default: 1255 ogles_error(c, GL_INVALID_ENUM); 1256 return; 1257 } 1258 c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0); 1259} 1260 1261void glColorPointer( 1262 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) 1263{ 1264 ogles_context_t* c = ogles_context_t::get(); 1265 // in theory ogles doesn't allow color arrays of size 3 1266 // but it is very useful to 'visualize' the normal array. 1267 if (size<3 || size>4 || stride<0) { 1268 ogles_error(c, GL_INVALID_VALUE); 1269 return; 1270 } 1271 switch (type) { 1272 case GL_UNSIGNED_BYTE: 1273 case GL_FIXED: 1274 case GL_FLOAT: 1275 break; 1276 default: 1277 ogles_error(c, GL_INVALID_ENUM); 1278 return; 1279 } 1280 c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0); 1281} 1282 1283void glNormalPointer( 1284 GLenum type, GLsizei stride, const GLvoid *pointer) 1285{ 1286 ogles_context_t* c = ogles_context_t::get(); 1287 if (stride<0) { 1288 ogles_error(c, GL_INVALID_VALUE); 1289 return; 1290 } 1291 switch (type) { 1292 case GL_BYTE: 1293 case GL_SHORT: 1294 case GL_FIXED: 1295 case GL_FLOAT: 1296 break; 1297 default: 1298 ogles_error(c, GL_INVALID_ENUM); 1299 return; 1300 } 1301 c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0); 1302} 1303 1304void glTexCoordPointer( 1305 GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) 1306{ 1307 ogles_context_t* c = ogles_context_t::get(); 1308 if (size<2 || size>4 || stride<0) { 1309 ogles_error(c, GL_INVALID_VALUE); 1310 return; 1311 } 1312 switch (type) { 1313 case GL_BYTE: 1314 case GL_SHORT: 1315 case GL_FIXED: 1316 case GL_FLOAT: 1317 break; 1318 default: 1319 ogles_error(c, GL_INVALID_ENUM); 1320 return; 1321 } 1322 const int tmu = c->arrays.activeTexture; 1323 c->arrays.texture[tmu].init(size, type, stride, pointer, 1324 c->arrays.array_buffer, 0); 1325} 1326 1327 1328void glEnableClientState(GLenum array) { 1329 ogles_context_t* c = ogles_context_t::get(); 1330 enableDisableClientState(c, array, true); 1331} 1332 1333void glDisableClientState(GLenum array) { 1334 ogles_context_t* c = ogles_context_t::get(); 1335 enableDisableClientState(c, array, false); 1336} 1337 1338void glClientActiveTexture(GLenum texture) 1339{ 1340 ogles_context_t* c = ogles_context_t::get(); 1341 if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) { 1342 ogles_error(c, GL_INVALID_ENUM); 1343 return; 1344 } 1345 c->arrays.activeTexture = texture - GL_TEXTURE0; 1346} 1347 1348void glDrawArrays(GLenum mode, GLint first, GLsizei count) 1349{ 1350 ogles_context_t* c = ogles_context_t::get(); 1351 if (count<0) { 1352 ogles_error(c, GL_INVALID_VALUE); 1353 return; 1354 } 1355 switch (mode) { 1356 case GL_POINTS: 1357 case GL_LINE_STRIP: 1358 case GL_LINE_LOOP: 1359 case GL_LINES: 1360 case GL_TRIANGLE_STRIP: 1361 case GL_TRIANGLE_FAN: 1362 case GL_TRIANGLES: 1363 break; 1364 default: 1365 ogles_error(c, GL_INVALID_ENUM); 1366 return; 1367 } 1368 1369 if (count == 0 || !c->arrays.vertex.enable) 1370 return; 1371 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) 1372 return; // all triangles are culled 1373 1374 1375 validate_arrays(c, mode); 1376 1377 const uint32_t enables = c->rasterizer.state.enables; 1378 if (enables & GGL_ENABLE_TMUS) 1379 ogles_lock_textures(c); 1380 1381 drawArraysPrims[mode](c, first, count); 1382 1383 if (enables & GGL_ENABLE_TMUS) 1384 ogles_unlock_textures(c); 1385 1386#if VC_CACHE_STATISTICS 1387 c->vc.total = count; 1388 c->vc.dump_stats(mode); 1389#endif 1390} 1391 1392void glDrawElements( 1393 GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) 1394{ 1395 ogles_context_t* c = ogles_context_t::get(); 1396 if (count<0) { 1397 ogles_error(c, GL_INVALID_VALUE); 1398 return; 1399 } 1400 switch (mode) { 1401 case GL_POINTS: 1402 case GL_LINE_STRIP: 1403 case GL_LINE_LOOP: 1404 case GL_LINES: 1405 case GL_TRIANGLE_STRIP: 1406 case GL_TRIANGLE_FAN: 1407 case GL_TRIANGLES: 1408 break; 1409 default: 1410 ogles_error(c, GL_INVALID_ENUM); 1411 return; 1412 } 1413 switch (type) { 1414 case GL_UNSIGNED_BYTE: 1415 case GL_UNSIGNED_SHORT: 1416 c->arrays.indicesType = type; 1417 break; 1418 default: 1419 ogles_error(c, GL_INVALID_ENUM); 1420 return; 1421 } 1422 if (count == 0 || !c->arrays.vertex.enable) 1423 return; 1424 if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) 1425 return; // all triangles are culled 1426 1427 // clear the vertex-cache 1428 c->vc.clear(); 1429 validate_arrays(c, mode); 1430 1431 // if indices are in a buffer object, the pointer is treated as an 1432 // offset in that buffer. 1433 if (c->arrays.element_array_buffer) { 1434 indices = c->arrays.element_array_buffer->data + uintptr_t(indices); 1435 } 1436 1437 const uint32_t enables = c->rasterizer.state.enables; 1438 if (enables & GGL_ENABLE_TMUS) 1439 ogles_lock_textures(c); 1440 1441 drawElementsPrims[mode](c, count, indices); 1442 1443 if (enables & GGL_ENABLE_TMUS) 1444 ogles_unlock_textures(c); 1445 1446 1447#if VC_CACHE_STATISTICS 1448 c->vc.total = count; 1449 c->vc.dump_stats(mode); 1450#endif 1451} 1452 1453// ---------------------------------------------------------------------------- 1454// buffers 1455// ---------------------------------------------------------------------------- 1456 1457void glBindBuffer(GLenum target, GLuint buffer) 1458{ 1459 ogles_context_t* c = ogles_context_t::get(); 1460 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { 1461 ogles_error(c, GL_INVALID_ENUM); 1462 return; 1463 } 1464 // create a buffer object, or bind an existing one 1465 buffer_t const* bo = 0; 1466 if (buffer) { 1467 bo = c->bufferObjectManager->bind(buffer); 1468 if (!bo) { 1469 ogles_error(c, GL_OUT_OF_MEMORY); 1470 return; 1471 } 1472 } 1473 ((target == GL_ARRAY_BUFFER) ? 1474 c->arrays.array_buffer : c->arrays.element_array_buffer) = bo; 1475} 1476 1477void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) 1478{ 1479 ogles_context_t* c = ogles_context_t::get(); 1480 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { 1481 ogles_error(c, GL_INVALID_ENUM); 1482 return; 1483 } 1484 if (size<0) { 1485 ogles_error(c, GL_INVALID_VALUE); 1486 return; 1487 } 1488 if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) { 1489 ogles_error(c, GL_INVALID_ENUM); 1490 return; 1491 } 1492 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? 1493 c->arrays.array_buffer : c->arrays.element_array_buffer); 1494 1495 if (bo == 0) { 1496 // can't modify buffer 0 1497 ogles_error(c, GL_INVALID_OPERATION); 1498 return; 1499 } 1500 1501 buffer_t* edit_bo = const_cast<buffer_t*>(bo); 1502 if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) { 1503 ogles_error(c, GL_OUT_OF_MEMORY); 1504 return; 1505 } 1506 if (data) { 1507 memcpy(bo->data, data, size); 1508 } 1509} 1510 1511void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) 1512{ 1513 ogles_context_t* c = ogles_context_t::get(); 1514 if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { 1515 ogles_error(c, GL_INVALID_ENUM); 1516 return; 1517 } 1518 if (offset<0 || size<0 || data==0) { 1519 ogles_error(c, GL_INVALID_VALUE); 1520 return; 1521 } 1522 buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? 1523 c->arrays.array_buffer : c->arrays.element_array_buffer); 1524 1525 if (bo == 0) { 1526 // can't modify buffer 0 1527 ogles_error(c, GL_INVALID_OPERATION); 1528 return; 1529 } 1530 if (offset+size > bo->size) { 1531 ogles_error(c, GL_INVALID_VALUE); 1532 return; 1533 } 1534 memcpy(bo->data + offset, data, size); 1535} 1536 1537void glDeleteBuffers(GLsizei n, const GLuint* buffers) 1538{ 1539 ogles_context_t* c = ogles_context_t::get(); 1540 if (n<0) { 1541 ogles_error(c, GL_INVALID_VALUE); 1542 return; 1543 } 1544 1545 for (int i=0 ; i<n ; i++) { 1546 GLuint name = buffers[i]; 1547 if (name) { 1548 // unbind bound deleted buffers... 1549 if (c->arrays.element_array_buffer->name == name) { 1550 c->arrays.element_array_buffer = 0; 1551 } 1552 if (c->arrays.array_buffer->name == name) { 1553 c->arrays.array_buffer = 0; 1554 } 1555 if (c->arrays.vertex.bo->name == name) { 1556 c->arrays.vertex.bo = 0; 1557 } 1558 if (c->arrays.normal.bo->name == name) { 1559 c->arrays.normal.bo = 0; 1560 } 1561 if (c->arrays.color.bo->name == name) { 1562 c->arrays.color.bo = 0; 1563 } 1564 for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) { 1565 if (c->arrays.texture[t].bo->name == name) { 1566 c->arrays.texture[t].bo = 0; 1567 } 1568 } 1569 } 1570 } 1571 c->bufferObjectManager->deleteBuffers(n, buffers); 1572 c->bufferObjectManager->recycleTokens(n, buffers); 1573} 1574 1575void glGenBuffers(GLsizei n, GLuint* buffers) 1576{ 1577 ogles_context_t* c = ogles_context_t::get(); 1578 if (n<0) { 1579 ogles_error(c, GL_INVALID_VALUE); 1580 return; 1581 } 1582 c->bufferObjectManager->getToken(n, buffers); 1583} 1584