Tôi đã kết hợp một vòng lặp trò chơi rất cơ bản trong C++ bằng SDL2 và tôi nhận thấy rằng cứ sau vài giây, SDL_PollEvent dường như chậm bất thường, ngay cả khi không có gì xảy ra.
Tôi đã gửi deltaTime để kiểm soát từng vòng lặp và SDL_PollEvent bị trễ đối với các vòng lặp có chênh lệch khoảng 100 mili giây. Tôi đã xác nhận rằng vấn đề này có liên quan đến tính năng này bằng cách di chuyển bộ đếm thời gian của tôi nhưng tôi không chắc chắn để chẩn đoán thêm vấn đề ở đâu.
Vòng lặp của tôi:
trong khi (!bỏ) {
uint32_t startTime = SDL_GetTicks();
while (SDL_PollEvent(&e) != 0) {
std::cout << "Sự kiện: "<< e.type << std::endl; // Đã thêm sau, đọc cập nhật
if (e.type == SDL_QUIT) {
bỏ = đúng;
}
}
if (engine.AllowUpdate()) { // Hạn chế cập nhật sau mỗi 20 mili giây
GameState::Cập nhật();
}
engine.rMan.BeginRender();
//^v Nghĩa đen chỉ là SDL_RenderClear và SDL_RenderPresent
engine.rMan.FinishRender();
engine.deltaTime = SDL_GetTicks() - startTime;
std::cout << std::setw(10) << engine.deltaTime;
}
Không có đầu ra console của Vsync, vui lòng lưu ý 106. Đây là độ trễ của tôi:
Sử dụng đồng bộ hóa dọc. Lưu ý rằng delta sau độ trễ ngắn hơn một chút. Không biết tại sao:
Tôi cũng nhận thấy rằng sự cố này xảy ra ngay cả khi tôi không gỡ lỗi và ít nhất là không xảy ra trên máy khác. Mọi đề xuất về cách tiến hành đều rất được hoan nghênh.
Chỉnh sửa 1: Thử in để kiểm soát tất cả các sự kiện đang diễn ra trong hàng đợi để xem liệu một trong số chúng có gây ra sự cố hay không. Đã thêm dòng in ở mã trên. Dường như không có sự kiện nào xảy ra khi có độ trễ, nếu không tôi sẽ không hoạt động.
Chỉnh sửa 2: Theo yêu cầu, một số mã có thể chạy được, được xây dựng bằng SDL2-2.0.9 trên VS2017 bằng C++ 14:
#include
#include
void InitSDL();
void BuildWindow();
void BuildRenderer();
cửa sổ SDL_Window*;
trình kết xuất SDL_Renderer*;
int main(int argc, char* args[]) {
InitSDL();
BuildWindow();
BuildRenderer();
bool thoát = sai;
uint32_t deltaTime = 0;
trong khi (!bỏ) {
uint32_t startTime = SDL_GetTicks();
SDL_Sự kiện e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
bỏ = đúng;
}
}
deltaTime = SDL_GetTicks() - thời gian bắt đầu;
std::cout << deltaTime << std::endl;
SDL_SetRenderDrawColor(trình kết xuất, 0, 0, 0, 255);
SDL_RenderClear(trình kết xuất);
SDL_RenderPresent(trình kết xuất);
}
return 0;
}
khoảng trống InitSDL() {
Cờ Uint32 = SDL_INIT_VIDEO |
SDL_Init(cờ);
}
khoảng trống BuildWindow() {
cửa sổ = SDL_CreateWindow
("Cửa sổ SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800, 600, KHÔNG CÓ);
}
void BuildRenderer() {
trình kết xuất = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
}
Trong khi sắp xếp lại điều này, tôi nhận thấy một số điều:
1. Không bị giật nếu không có SDL_RenderPresent Khi kiểm tra kỹ hơn, điều này dường như không xảy ra, tuy nhiên, SDL_RenderPresent dường như bị ảnh hưởng bởi tình trạng nói lắp.
Sự gia tăng deltaTime trùng với tình trạng nói lắp dường như xảy ra ở đâu đó trong SDL_PollEvent, bằng chứng là vị trí phân bổ deltaTime
DeltaTime đầu tiên luôn dài hơn, nhưng tôi nghi ngờ điều này có liên quan đến một số sự kiện mặc định được kích hoạt khi khởi động.
Chỉnh sửa 3: Đã đào sâu thêm. Đang cố gắng di chuyển phân bổ delta của tôi chỉ xung quanh SDL_RenderPresent.
Đoạn ví dụ:
SDL_Sự kiện e;
while (SDL_PollEvent(&e) != 0) {
std::cout << "Sự kiện: "<< e.type << std::endl;
if (e.type == SDL_QUIT) {
bỏ = đúng;
}
}
uint32_t startTime = SDL_GetTicks();
//SDL_SetRenderDrawColor(trình kết xuất, 0, 0, 0, 255);
//SDL_RenderClear(trình kết xuất);
SDL_RenderPresent(trình kết xuất);
deltaTime = SDL_GetTicks() - thời gian bắt đầu;
std::cout << deltaTime << std::endl;
Sau khi bật đồng bộ hóa dọc, tôi nhận được đầu ra bảng điều khiển sau:
Chỉnh sửa 4: Thêm dữ liệu. Có vẻ như hiện tượng nói lắp xảy ra gần như cứ sau 3000 mili giây. Tôi chỉ có đầu ra của bàn điều khiển với mức tăng lớn hơn 50 mili giây. Định dạng trong hình là: Số chu kỳ vòng lặp trò chơi | thời gian tăng dần|
Tôi cũng nghĩ đó là sự cố phần cứng vì tôi không gặp sự cố này trên máy khác và tôi cũng đã tải xuống một số trò chơi SDL nguồn mở khác và gặp phải tình trạng giật hình tương tự, cách nhau 3000 mili giây. Tôi cũng gặp vấn đề tương tự trên Windows 10 và Windows 7 trên cùng một phần cứng. Tôi sẽ không đăng thông số kỹ thuật của mình trừ khi ai đó thấy cần thiết, nhưng tôi đã loại trừ khả năng GPU chuyên dụng của mình bị lỗi bằng cách nhận được kết quả tương tự khi chạy trò chơi qua RDP với câu hỏi Chính xác về GPU của tôi.
Chỉnh sửa 5: Có vẻ như độ trễ có liên quan đến thiết bị USB. SDL có tìm kiếm tất cả các thiết bị cứ sau 3000 mili giây hoặc vào thời điểm khác không?
Sau khi lắp GPU trở lại máy, tôi nhận thấy độ trễ giảm đáng kể, điểm khác biệt duy nhất tôi nhận thấy giữa trước và sau là tai nghe USB của tôi không còn được cắm nữa.
Theo trực giác, tôi chạy lại vòng lặp của mình, lần này quan sát bất kỳ deltaTime nào dài hơn 3 mili giây. Tôi đã quan sát thấy những thay đổi trong bảng điều khiển khi tháo thiết bị:
Eureka! Khi không cắm thiết bị USB, deltaTime luôn duy trì ở mức dưới 3 mili giây. Máy phụ mà tôi đang thử nghiệm là máy tính xách tay nên không có thiết bị USB nào được cắm vào. Tôi đã quay lại và thử nghiệm nó với cùng một con chuột USB và đúng như dự đoán, tôi thấy hiện tượng giật hình đáng chú ý sau mỗi 3000 mili giây.
Vì vậy, câu hỏi hiện tại là: Làm thế nào một thiết bị USB lại gây ra tình trạng nói lắp này? SDL thực hiện thao tác nào sau mỗi 3000 mili giây liên quan đến (a) thiết bị USB và (b) SDL_RenderPresent()?
Tôi là một lập trình viên xuất sắc, rất giỏi!