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