C 为什么这个SDL2程序会变慢?

C 为什么这个SDL2程序会变慢?,c,sdl,C,Sdl,我有一个从输入设备读取音频数据并显示一行表示音量的程序问题。开始正常,几秒钟后开始滞后。在我尝试添加一些代码来添加图像显示功能之前,它一直没有变慢,但没有成功,所以我删除了它,但现在它无法正常工作。我已经删除了大部分程序功能,如果我修复了它,我会重新添加这些功能。CPU和GPU的使用率仍然很低,因此没有问题。如果我切换到软件模式,它似乎工作。我在Windows上使用MinGW-w64 #include <stdio.h> #include <stdlib.h> #incl

我有一个从输入设备读取音频数据并显示一行表示音量的程序问题。开始正常,几秒钟后开始滞后。在我尝试添加一些代码来添加图像显示功能之前,它一直没有变慢,但没有成功,所以我删除了它,但现在它无法正常工作。我已经删除了大部分程序功能,如果我修复了它,我会重新添加这些功能。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;
}
#包括
#包括
#包括
#包括
#包括
int屏幕宽度=1024//违约
内部屏幕高度=768//违约
int全屏=0;
SDL_渲染器*rend;
//#定义软件渲染
//#在上定义VSYNC_
#定义程序名称“我的游戏”
#ifdef软件渲染
#定义渲染器SDL_渲染器_软件
#否则
#定义渲染器SDL\u渲染器\u加速
#恩迪夫
#如果!已定义(软件渲染)和已定义(VSYNC打开)
#定义VSYNC SDL\u呈现器\u呈现VSYNC
#否则
#定义VSYNC 0
#恩迪夫
////https://wiki.libsdl.org/SDL_AudioSpec#callback
void audioInCallback(void*userdata,Uint8*stream,int len)
{
float*floatStream=(float*)流;
if(流==NULL)
{
puts(“流为空”);
返回;
}
SDL_SetRenderDrawColor(格式,0,0,0,255);
SDL_渲染器(rend);
SDL_SetRenderDrawColor(rend,255,255,255);
浮动平均值=0;

对于(int i=0;i不要尝试在不同的线程中执行SDL_渲染器操作,就像通常调用音频回调的线程一样。正如@keltar指出的,这是:

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

而是通过你喜欢的方法在主线程上渲染音频样本(对于C++来说,对不起C,没有太多的C家伙R:线程原语):

#包括
#包括
#包括
#包括
//三重缓冲逻辑stol^H^H^H^H来自:
// https://stackoverflow.com/questions/49352853
标准:向量*g_ProducerBuffer;
标准:向量*g_消费者缓冲;
标准::原子<标准::向量*>g_CurrentBuffer;
void audioInCallback(void*userdata,Uint8*stream,int len)
{
常量float*floatStream=重新解释\u cast(流);
适用于(汽车和样品:*g_ProducerBuffer)
{
sample=*floatStream;
floatStream++;
}
//发布新缓冲区
g_ProducerBuffer=g_CurrentBuffer.exchange(g_ProducerBuffer);
}
int main(int argc,字符**argv)
{
SDL_Init(SDL_Init_EVERYTHING);
SDL_SetHint(SDL_HINT_RENDER_VSYNC,“1”);
//SDL_SetHint(SDL_HINT_RENDER_驱动程序,“软件”);
Uint32标志=显示的SDL窗口;
SDL_Window*Window=nullptr;
SDL_Renderer*Renderer=nullptr;
SDL_CreateWindowAndRenderer(1024、768、标志、窗口和渲染器);
//转储设备名称
int count=SDL_GetNumAudioDevices(1);
for(int i=0;i(*g_ConsumerBuffer)[i]*200+768/2);
点[i]=SDL_点{x,y};
}
SDL_SetRenderDrawColor(渲染器,255、255、255);
SDL_渲染绘制线(渲染器,points.data(),points.size());
SDL_渲染器呈现(渲染器);
}
SDL_闭合音频设备(dev);
SDL_渲染器(渲染器);
SDL_窗口(窗口);
SDL_退出();
返回0;
}

不要尝试在不同的线程中执行SDL_渲染器操作,就像通常调用音频回调的线程一样。正如@keltar指出的,这是:

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

而是通过你喜欢的方法在主线程上渲染音频样本(对于C++来说,对不起C,没有太多的C家伙R:线程原语):

#包括
#包括
#包括
#包括
//三重缓冲逻辑stol^H^H^H^H来自:
// https://stackoverflow.com/questions/49352853
标准:向量*g_ProducerBuffer;
标准:向量*g_消费者缓冲;
标准::原子<标准::向量*>g_CurrentBuffer;
void audioInCallback(void*userdata,Uint8*stream,int len)
{
常量float*floatStream=重新解释\u cast(流);
适用于(汽车和样品:*g_ProducerBuffer)
{
sample=*floatStream;
floatStream++;
}
//发布新缓冲区
g_ProducerBuffer=g_CurrentBuffer.exchange(g_ProducerBuffer);
}
int main(int argc,字符**argv)
{
SDL_Init(SDL_Init_EVERYTHING);
SDL_SetHint(SDL_HINT_RENDER_VSYNC,“1”);
//SDL_SetHint(SDL_HINT_RENDER_驱动程序,“软件”);
Uint32标志=显示的SDL窗口;
SDL_Window*Window=nullptr;
SDL_Renderer*Renderer=nullptr;
SDL_CreateWindowAndRenderer(1024、768、标志、窗口和渲染器);
//转储设备名称
int count=SDL_GetNumAudioDevices(1);
for(int i=0;i(*g_ConsumerBuffer)[i]*200+768/2);
点[i]=SDL_点{x,y};
}
SDL_SetRenderDrawColor(渲染器,255、255、255);
SDL_渲染绘制线(渲染器,points.data(),points.size());
SDL_渲染器呈现(渲染器);
}
SDL_闭合音频设备(dev);
SDL_渲染器(渲染器);
SDL_窗口(窗口);
SDL_退出();
返回0;
}

音频回调在单独的线程中运行,SDL graphics只能在初始化图形/创建窗口的线程中使用。音频回调在这种情况下似乎是错误的,因为您无法控制
len
,所以平均值只会在每个缓冲区更新一次,而不是每帧;如果这是您想要的,我建议更新平均值在回调中,但在主循环中无条件呈现。OT:regar
#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;
}