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