为什么此SDL2程序会变慢?

时间:2019-06-30 12:19:55

标签: c sdl

该程序有问题,该程序从输入设备读取音频数据并显示代表音量的一行。它开始正常,然后在几秒钟后开始滞后。直到我尝试添加一些代码来添加图像显示功能时,它都运行缓慢,该方法无法正常工作,因此我将其删除,但现在程序无法正常运行。我已经删除了大多数程序功能,如果修复了这些功能,我会重新添加。 CPU和GPU的使用率仍然很低,因此没有问题。如果我切换到软件模式,它似乎可以工作。我在Windows上使用MinGW-w64。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <math.h>

int SCREEN_WIDTH = 1024; //default
int SCREEN_HEIGHT = 768; //default
int FULLSCREEN = 0;

SDL_Renderer *rend;

//#define SOFTWARE_RENDER
//#define VSYNC_ON

#define PROGRAM_NAME "My Game"
#ifdef SOFTWARE_RENDER
#define RENDERER SDL_RENDERER_SOFTWARE
#else
#define RENDERER SDL_RENDERER_ACCELERATED
#endif

#if !defined(SOFTWARE_RENDER) && defined(VSYNC_ON)
#define VSYNC SDL_RENDERER_PRESENTVSYNC
#else
#define VSYNC 0
#endif


////https://wiki.libsdl.org/SDL_AudioSpec#callback
void audioInCallback(void *userdata, Uint8 *stream,int len)
{
    float *floatStream = (float*)stream;

    if (stream == NULL)
    {
        puts("Stream is NULL.");
        return;
    }
    SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
    SDL_RenderClear(rend);
    SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);

    float avg = 0;

    for (int i=0;i<len;i++)
        avg += fabs(floatStream[i]);

    avg /= len;

    SDL_RenderDrawLine(rend, 0,
                               SCREEN_HEIGHT/2 + round(SCREEN_HEIGHT/2.0 * avg),
                               SCREEN_WIDTH,
                               SCREEN_HEIGHT/2 + round(SCREEN_HEIGHT/2.0 * avg)
                               );

    return;
}

int main(int argv, char *argc[])
{
    int bufferSize = 8;
    SDL_Window* window = NULL;
    rend = NULL;
    SDL_Event event;
    bool loopIsActive = true;
    SDL_AudioSpec want, have;
    SDL_AudioDeviceID dev;


    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
    {
        printf("Unable to initialize SDL: %s", SDL_GetError());
        return 1;
    }

    if( (window = SDL_CreateWindow( PROGRAM_NAME, SDL_WINDOWPOS_UNDEFINED,
                                    SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
                                    SCREEN_HEIGHT, SDL_WINDOW_SHOWN )) == NULL )
    {
        printf("Window could not be created! %s\n", SDL_GetError());
        SDL_Quit();
        return 0;
    }

    if ( (rend = SDL_CreateRenderer(window, -1, RENDERER | VSYNC)) == NULL )
    {
        printf("Error creating renderer. %s\n", SDL_GetError());
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 0;
    }
    int count = SDL_GetNumAudioDevices(1);

    for (int i=0;i<count;i++)
    {
        printf("%d. %s\n", i, SDL_GetAudioDeviceName(i, 1));
    }

    SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */
    want.freq = 44100;
    want.format = AUDIO_S16;
    want.channels = 1;
    want.samples = pow(2,bufferSize);
    want.callback = audioInCallback;

    dev = SDL_OpenAudioDevice(NULL, 1, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);


    if (dev == 0)
        printf("Failed to open audio: %s", SDL_GetError());
    else
    {
        printf("have.samples = %u\n", have.samples);
        printf("Opened device %s\nAudio format: ", SDL_GetAudioDeviceName(0, 1));
        if (SDL_AUDIO_ISFLOAT(have.format))
            printf("%d-bit %s\n", SDL_AUDIO_BITSIZE(have.format), SDL_AUDIO_ISFLOAT(have.format) ? "float" :
                                                                  SDL_AUDIO_ISSIGNED(have.format) ? "signed" : "unsigned");
        SDL_PauseAudioDevice(dev, 0); /* start audio playing. */
    }

    while (loopIsActive == true)
    {
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_QUIT:
                    loopIsActive = false;
                    break;
                case SDL_KEYDOWN:
                    if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
                    {
                        loopIsActive = false;
                    }
                    break;
            }
        }

        SDL_RenderPresent(rend);
        SDL_Delay(16);
    }


    if (dev != 0) SDL_CloseAudioDevice(dev);
    SDL_DestroyRenderer(rend);
    SDL_DestroyWindow(window);
    SDL_Quit();

    puts("Hello world!");
    return 0;
}

1 个答案:

答案 0 :(得分:0)

不要尝试在另一个线程中执行SDL_Renderer操作,例如通常从中调用音频回调的线程。正如@keltar指出的,这是prohibited by SDL

  

这些函数必须从主线程中调用。

相反,请通过您喜欢的方法将音频样本捆绑在一起,以便在主线程上进行渲染(对C ++来说很抱歉,对于C Guy re:线程基元来说不多):

#include <SDL.h>
#include <vector>
#include <atomic>
#include <iostream>

// triple-buffering logic stol^H^H^H^Hborrowed from:
// https://stackoverflow.com/questions/49352853
std::vector< float >* g_ProducerBuffer;
std::vector< float >* g_ConsumerBuffer;
std::atomic< std::vector< float >* > g_CurrentBuffer;
void audioInCallback( void* userdata, Uint8* stream, int len )
{
    const float* floatStream = reinterpret_cast< float* >( stream );

    for( auto& sample : *g_ProducerBuffer )
    {
        sample = *floatStream;
        floatStream++;
    }

    // post new buffer
    g_ProducerBuffer = g_CurrentBuffer.exchange( g_ProducerBuffer );
}

int main( int argc, char** argv )
{
    SDL_Init( SDL_INIT_EVERYTHING );
    SDL_SetHint( SDL_HINT_RENDER_VSYNC, "1" );
    //SDL_SetHint( SDL_HINT_RENDER_DRIVER, "software" );
    Uint32 flags = SDL_WINDOW_SHOWN;
    SDL_Window* window = nullptr;
    SDL_Renderer* renderer = nullptr;
    SDL_CreateWindowAndRenderer( 1024, 768, flags, &window, &renderer );

    // dump device names
    int count = SDL_GetNumAudioDevices( 1 );
    for( int i = 0; i < count; i++ )
    {
        std::cout << i << ": " << SDL_GetAudioDeviceName( i, 1 ) << '\n';
    }

    SDL_AudioSpec spec = { 0 };
    spec.freq = 44100;
    spec.format = AUDIO_F32LSB;
    spec.channels = 1;
    spec.samples = 1024;
    spec.callback = audioInCallback;

    const unsigned int deviceIndex = 0;
    const std::string deviceName = SDL_GetAudioDeviceName( deviceIndex, 1 );
    SDL_AudioDeviceID dev = SDL_OpenAudioDevice( deviceName.c_str(), 1, &spec, nullptr, 0 );

    // set up audio buffers
    std::vector< float > buffers[ 3 ];
    buffers[ 0 ].resize( spec.samples );
    buffers[ 1 ].resize( spec.samples );
    buffers[ 2 ].resize( spec.samples );
    g_ProducerBuffer = &buffers[ 0 ];
    g_ConsumerBuffer = &buffers[ 1 ];
    g_CurrentBuffer = &buffers[ 2 ];

    // start audio capture
    SDL_PauseAudioDevice( dev, 0 );

    bool running = true;
    while( running )
    {
        SDL_Event ev;
        while( running && SDL_PollEvent( &ev ) )
        {
            if( SDL_QUIT == ev.type ||
                SDL_KEYDOWN == ev.type && SDL_SCANCODE_ESCAPE == ev.key.keysym.scancode )
            {
                running = false;
            }
        }

        SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
        SDL_RenderClear( renderer );

        // grab latest audio buffer
        // (this *seems* to work on my system but I'm not 100% sure it's correct)
        while( !g_CurrentBuffer.compare_exchange_weak( g_ConsumerBuffer, g_ConsumerBuffer ) );

        // draw audio sample waveform
        std::vector< SDL_Point > points( g_ConsumerBuffer->size() );
        for( size_t i = 0; i < g_ConsumerBuffer->size(); ++i )
        {
            const int x = static_cast< int >( i );
            const int y = static_cast< int >( (*g_ConsumerBuffer)[ i ] * 200 + 768 / 2 );
            points[ i ] = SDL_Point{ x, y };
        }
        SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
        SDL_RenderDrawLines( renderer, points.data(), points.size() );

        SDL_RenderPresent( renderer );
    }

    SDL_CloseAudioDevice( dev );
    SDL_DestroyRenderer( renderer );
    SDL_DestroyWindow( window );
    SDL_Quit();
    return 0;
}