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