我很难解决导致我的街机老虎机 SDL2 游戏在我的双显示器 linux 主板上运行不佳的错误。
void Rendering::Update()
{
Time::Tick("RENDERING: ");
bool anythingVGA = false; /**< Flag that says if the VGA has anything to render. */
bool anythingHDMI = false; /**< Flag that says if the HDMI has anything to render. */
/* I reserve my final vector the necessary memory.*/
Rendering::vPObjects.reserve(RESERVED_VECTOR_MEMORY);
/* I process objects and push their texture, destination and layer into my final VPObjects vector.
* This is necessary to process layered rendering of multiple classes members. */
Rendering::ProcessImages(anythingVGA, anythingHDMI);
Rendering::ProcessSymbols(anythingVGA, anythingHDMI);
Rendering::ProcessEFX(anythingVGA);
Rendering::ProcessAwards(anythingVGA);
Rendering::ProcessTexts(anythingVGA);
/* I sort my final vector based on its members layer, from the lowest to the highest.*/
std::sort(Rendering::vPObjects.begin(), Rendering::vPObjects.end(), Compare(Compare::CRITERIA_LAYER));
if(anythingVGA)
{
/* Clearing must be done just once per refresh. */
MONITOR_VGA.Clear();
}
if(anythingHDMI)
{
/* Clearing must be done just once per refresh. */
MONITOR_HDMI.Clear();
}
for(const auto& k: Rendering::vPObjects)
{
/* I put each object into the SDL Buffer, ready to be rendered. */
if(k.renderer == RENDERER_VGA)
MONITOR_VGA.RenderCopy(k.texture, k.destination);
else if(k.renderer == RENDERER_HDMI && HDMI_FLAG)
MONITOR_HDMI.RenderCopy(k.texture, k.destination);
}
/* I call the RenderPresent function only
* if the renderer has something to operate on.*/
if(anythingVGA)
{
SDL_RenderPresent(MONITOR_VGA.renderer);
}
/* I call the RenderPresent function only
* if the renderer has something to operate on.*/
if(anythingHDMI)
{
SDL_RenderPresent(MONITOR_HDMI.renderer);
}
/* I clear my vector, so that it will be ready for the next frame later.*/
Rendering::vPObjects.clear();
/* I clear the fonts objects vector and free its textures. */
Text::Clear();
Time::Tock();
Time::PrintTickTockLapse();
}
我有多个具有不同数据的对象,所以我正在处理包含每个类的所有成员的向量,并将它们放在一个名为“VPObjects”的最终向量上,我已经根据对象的层对它进行了排序,这样我就可以轻松在不同的图层上渲染。
VPObjects 是 ProcessedObjects 的向量,即:
struct ProcessedObject
{
SDL_Texture* texture;
SDL_Renderer* renderer;
SDL_Rect destination;
uint8_t layer;
};
本质上,我在每个“Rendering::Process...()”函数中所做的是检查对象是否被标记为“可见”,它是否具有来自 nullptr 的纹理 != 以及它是否具有有效的渲染器。如果满足所有这些条件,我将其作为“ProcessedObject”推入我的 vPObjects 向量中。
如果我使用带有单个屏幕的街机老虎机,代码运行非常流畅,但如果我也打开第二个屏幕,它会在“SDL_RenderPresent()”调用中开始出现延迟。
我觉得VSYNC有问题。两台显示器均为 1680x1050 60HZ。正如预期的那样,如果我使用 SDL_RENDERER_PRESENTVSYNC 在单个监视器上运行我的代码,每个游戏循环的执行时间为 16 毫秒,因此我得到稳定的 60fps。但是,如果我在机器上有 2 个显示器时运行代码,游戏循环执行时间就会混乱。一次需要 16 毫秒,然后是 0 毫秒,然后是 4 毫秒,然后是 87 毫秒。对每个函数进行基准测试,我发现只有当代码需要执行“SDL_RenderPresent()”时才会出现延迟。
如果我从我的代码中删除“MONITOR_HDMI”部分,它不会修复任何东西,只有一些东西会在双屏打开时弄乱我的代码,即使它不处理任何对象。要解决问题,我需要关闭机器,然后再次打开它,但要断开第二台显示器的连接。
这就是我创建渲染器和 Windows 的方式:
void Screen::Create()
{
static uint8_t screens_number = 0;
if(!this->exists)
{
this->window = SDL_CreateWindow(this->name, Screen::WIDTH * screens_number, 0, this->w, this->h, SDL_WINDOW_OPENGL);
SDL_SetWindowBrightness(this->window, WINDOWS_BRIGHTNESS);
this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
this->SetDrawColor(&DRAW_COLOR);
SDL_SetRenderDrawBlendMode(this->renderer, SDL_BLENDMODE_BLEND);
++screens_number;
this->exists = true;
return;
}
}
我尝试了窗口和渲染器的每个 SDL 标志。如果我关闭 SDL_RENDERER_PRESENTVSYNC,我会按预期调用 0 毫秒的 SDL_RenderPresent() 并调用 90+ 毫秒,这完全破坏了我的性能。我试过弄乱 xrandr 设置,但我没有解决任何问题。
这不是机器本身的问题,因为我们在上面测试了另一个SDL游戏,运行良好。