Ticket #931: snd_remove_source_suballoc.patch

File snd_remove_source_suballoc.patch, 5.8 KB (added by Jan Wassenberg, 13 years ago)
  • snd_mgr.cpp

     
    409409
    410410
    411411//-----------------------------------------------------------------------------
    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
    416413//-----------------------------------------------------------------------------
    417414
    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).
    421422
    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.
     424static size_t al_src_maxNumToUse = 64;
    424425
    425 static size_t al_src_numPreallocated;
     426static volatile intptr_t al_src_inUse;
    426427
    427 enum AllocationState
    428 {
    429     kAvailable = 0, // (must match zero-initialization of al_srcs_allocationStates)
    430     kInUse
    431 };
    432428
    433 // note: we want to catch double-free bugs and ensure all sources
    434 // are released at exit, but OpenAL doesn't specify an always-invalid
    435 // 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  */
    443429static void al_src_init()
    444430{
    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);
    465431}
    466432
    467433
    468434/**
    469  * release all sources on free list.
    470  * all sources must already have been released via al_src_free.
    471435 * called from al_shutdown.
     436 * all sources must already have been released via al_src_free.
    472437 */
    473438static void al_src_shutdown()
    474439{
    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);
    483443}
    484444
    485445
     446TIMER_ADD_CLIENT(tc_OpenAL_source);
     447
    486448/**
    487449 * try to allocate a source.
    488450 *
    489  * @return whether a source was allocated (see al_srcs_allocationStates).
     451 * @return whether a source was allocated.
    490452 * @param al_src receives the new source name iff true is returned.
    491453 */
    492454static bool al_src_alloc(ALuint& al_src)
    493455{
    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     }
     456TIMER_ACCRUE(tc_OpenAL_source);
    502457
    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;
    504466}
    505467
    506468
     
    511473 */
    512474static void al_src_free(ALuint al_src)
    513475{
     476TIMER_ACCRUE(tc_OpenAL_source);
    514477    ENSURE(alIsSource(al_src));
    515478
    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;
    524484}
    525485
    526486
     
    528488 * set maximum number of voices to play simultaneously,
    529489 * to reduce mixing cost on low-end systems.
    530490 * this limit may be ignored if e.g. there's a stricter
    531  * implementation- defined ceiling anyway.
     491 * implementation-defined ceiling anyway.
    532492 *
    533493 * @param limit max. number of sources
    534494 * @return Status
    535495 */
    536496Status snd_set_max_voices(size_t limit)
    537497{
    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;
    553500}
    554501
    555502