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