Ticket #931: snd_remove_source_suballoc.patch
File snd_remove_source_suballoc.patch, 5.8 KB (added by , 13 years ago) |
---|
-
snd_mgr.cpp
409 409 410 410 411 411 //----------------------------------------------------------------------------- 412 // AL source suballocator: allocate all available sources up-front and 413 // pass them out as needed (alGenSources is quite slow, taking 3..5 ms per 414 // source returned). also responsible for enforcing user-specified limit 415 // on total number of sources (to reduce mixing cost on low-end systems). 412 // AL source suballocator 416 413 //----------------------------------------------------------------------------- 417 414 418 // regardless of HW capabilities, we won't use more than this ("enough"). 419 // necessary in case OpenAL doesn't limit #sources (e.g. if SW mixing). 420 static const size_t AL_SRC_MAX = 64; 415 // a suballocator used to be necessary because alGenSources took 3-5 ms per 416 // source returned on NVidia's native OpenAL. however, OS X CoreAudio can't 417 // deal with immediate source reuse (race condition?), and the easiest way 418 // to get around this is to generate/delete sources on demand. fortunately, 419 // OpenALsoft only takes a few microseconds to do this. 420 // this layer is also responsible for enforcing the user-specified limit on 421 // the total number of sources (to reduce mixing cost on low-end systems). 421 422 422 // (allow changing at runtime)423 static size_t al_src_maxNumToUse = AL_SRC_MAX;423 // 64 is probably "enough", but the value can be changed at runtime. 424 static size_t al_src_maxNumToUse = 64; 424 425 425 static size_t al_src_numPreallocated;426 static volatile intptr_t al_src_inUse; 426 427 427 enum AllocationState428 {429 kAvailable = 0, // (must match zero-initialization of al_srcs_allocationStates)430 kInUse431 };432 428 433 // note: we want to catch double-free bugs and ensure all sources434 // are released at exit, but OpenAL doesn't specify an always-invalid435 // source name, so we need a separate array of AllocationState.436 static ALuint al_srcs[AL_SRC_MAX];437 static intptr_t al_srcs_allocationStates[AL_SRC_MAX];438 439 /**440 * grab as many sources as possible up to the limit.441 * called from al_init.442 */443 429 static void al_src_init() 444 430 { 445 // grab as many sources as possible and count how many we get.446 for(size_t i = 0; i < al_src_maxNumToUse; i++)447 {448 ALuint al_src;449 alGenSources(1, &al_src);450 // we've reached the limit, no more are available.451 if(alGetError() != AL_NO_ERROR)452 break;453 ENSURE(alIsSource(al_src));454 al_srcs[i] = al_src;455 al_src_numPreallocated++;456 }457 458 // limit user's cap to what we actually got.459 // (in case snd_set_max_src was called before this)460 if(al_src_maxNumToUse > al_src_numPreallocated)461 al_src_maxNumToUse = al_src_numPreallocated;462 463 // make sure we got the minimum guaranteed by OpenAL.464 ENSURE(al_src_numPreallocated >= 16);465 431 } 466 432 467 433 468 434 /** 469 * release all sources on free list.470 * all sources must already have been released via al_src_free.471 435 * called from al_shutdown. 436 * all sources must already have been released via al_src_free. 472 437 */ 473 438 static void al_src_shutdown() 474 439 { 475 for(size_t i = 0; i < al_src_numPreallocated; i++) 476 ENSURE(al_srcs_allocationStates[i] == kAvailable); 477 478 AL_CHECK; 479 alDeleteSources((ALsizei)al_src_numPreallocated, al_srcs); 480 AL_CHECK; 481 482 al_src_numPreallocated = 0; 440 // (we no longer bother keeping a list of extant sources, 441 // because they will be freed at exit anyway.) 442 ENSURE(al_src_inUse == 0); 483 443 } 484 444 485 445 446 TIMER_ADD_CLIENT(tc_OpenAL_source); 447 486 448 /** 487 449 * try to allocate a source. 488 450 * 489 * @return whether a source was allocated (see al_srcs_allocationStates).451 * @return whether a source was allocated. 490 452 * @param al_src receives the new source name iff true is returned. 491 453 */ 492 454 static bool al_src_alloc(ALuint& al_src) 493 455 { 494 for(size_t i = 0; i < al_src_numPreallocated; i++) 495 { 496 if(cpu_CAS(&al_srcs_allocationStates[i], kAvailable, kInUse)) 497 { 498 al_src = al_srcs[i]; 499 return true; 500 } 501 } 456 TIMER_ACCRUE(tc_OpenAL_source); 502 457 503 return false; // no more to give 458 if((size_t)al_src_inUse >= al_src_maxNumToUse) 459 return false; // allocated too many already 460 cpu_AtomicAdd(&al_src_inUse, +1); 461 462 AL_CHECK; 463 alGenSources(1, &al_src); 464 AL_CHECK; 465 return true; 504 466 } 505 467 506 468 … … 511 473 */ 512 474 static void al_src_free(ALuint al_src) 513 475 { 476 TIMER_ACCRUE(tc_OpenAL_source); 514 477 ENSURE(alIsSource(al_src)); 515 478 516 const ALuint* pos = std::find(al_srcs, al_srcs+al_src_numPreallocated, al_src); 517 if(pos != al_srcs+al_src_numPreallocated) // found it 518 { 519 const size_t i = pos - al_srcs; 520 ENSURE(cpu_CAS(&al_srcs_allocationStates[i], kInUse, kAvailable)); 521 } 522 else 523 DEBUG_WARN_ERR(ERR::LOGIC); // al_src wasn't in al_srcs 479 cpu_AtomicAdd(&al_src_inUse, -1); 480 481 AL_CHECK; 482 alDeleteSources(1, &al_src); 483 AL_CHECK; 524 484 } 525 485 526 486 … … 528 488 * set maximum number of voices to play simultaneously, 529 489 * to reduce mixing cost on low-end systems. 530 490 * this limit may be ignored if e.g. there's a stricter 531 * implementation- 491 * implementation-defined ceiling anyway. 532 492 * 533 493 * @param limit max. number of sources 534 494 * @return Status 535 495 */ 536 496 Status snd_set_max_voices(size_t limit) 537 497 { 538 // valid if cap is legit (less than what we allocated in al_src_init), 539 // or if al_src_init hasn't been called yet. note: we accept anything 540 // in the second case, as al_src_init will sanity-check al_src_cap. 541 if(!al_src_numPreallocated || limit < al_src_numPreallocated) 542 { 543 al_src_maxNumToUse = limit; 544 return INFO::OK; 545 } 546 // user is requesting a cap higher than what we actually allocated. 547 // that's fine (not an error), but we won't set the cap, since it 548 // determines how many sources may be returned. 549 // there's no return value to indicate this because the cap is 550 // precisely that - an upper limit only, we don't care if it can't be met. 551 else 552 return INFO::OK; 498 al_src_maxNumToUse = limit; 499 return INFO::OK; 553 500 } 554 501 555 502