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