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