You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Create test-vblank3.c and copy/paste code (see below)
Compile it with gcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image
Run it with ./test-vblank3 --driver x11
Press F1 to toggle swapInterval between 0,1,2,3
Expected result: setting swapInterval > 1 is accepted and properly processed. Fps should correspond to requested swapInterval value. For swapInterval=1 it should be equals to display refresh rate, for swapInterval=2 it should be half of the display refresh rate, etc.
Actual result: For x11 backend setting swapInterval > 1 leads to some weird and incorrect fps which randomly varies from time to time on every swapInterval change.
Repeat steps 4 and 5 with ./test-vblank3 --driver wayland
Actual result: For wayland backend setting swapInterval > 1 leads to actual set swapInterval = 1, so there is no way to set swapInterval > 1.
Switch to a virtual console and repeat steps 4 and 5 with ./test-vblank3 --driver KMSDRM
Actual result: For KMSDRM backend setting swapInterval > 1 leads to actual set swapInterval = 1, the same issue as for wayland backend.
Press F11 in a loop for x11 backend and notice that each time you get the same swapInterval 2 or 3, fps is different.
Expected result: each time you set swapInterval=2, fps should be the same
Actual result: each time you set swapInterval=2, fps is different: sometimes it is as expected 37.5 fps, sometimes 50 fps, sometimes 45 fps, etc.
Screenshots
x11 backend: swapInterval=2, expected 37.5 fps, actual value is 45.3 and varies and unstable...
x11 backend: swapInterval=3, expected 25.0 fps, actual value is 27.5 fps and unstable...
KMSDRM backend: swapInterval=3, expected 25.0 fps, actual swapInterval=1 and 75.0 fps...
Test code
test-vblank3.c
// sudo apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev// sudo pacman -S sdl2 sdl2_ttf sdl2_image// gcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image#include<stdio.h>#include<string.h>#include<time.h>#include<limits.h>#include<GL/gl.h>#include<SDL2/SDL.h>#include<SDL2/SDL_opengl.h>#include<SDL2/SDL_ttf.h>#include<SDL2/SDL_image.h>#ifdef_WIN32#include<limits.h>#defineMAX_PATH_LENGTH MAX_PATH
#else#include<limits.h>#defineMAX_PATH_LENGTH PATH_MAX
#endif// Simple queue implementationtypedefstruct {
uint64_t*data;
size_tfront;
size_trear;
size_tsize;
size_tcapacity;
} Queue64;
voidqueue_init(Queue64*q, size_tcapacity) {
q->capacity=capacity;
q->size=0;
q->front=0;
q->rear=0;
q->data= (uint64_t*)malloc(capacity*sizeof(uint64_t));
}
voidqueue_free(Queue64*q) {
free(q->data);
}
voidqueue_resize(Queue64*q, size_tnew_capacity) {
if (new_capacity<q->size) {
printf("warn: queue_resize(): new capacity %zu is smaller than current size %zu. The last %zu elements will be discarded.\n", new_capacity, q->size, q->size-new_capacity);
q->size=new_capacity; // Truncate elements if the new size is smaller than the current size
}
uint64_t*new_data= (uint64_t*)malloc(new_capacity*sizeof(uint64_t));
// copy elements to a new bufferfor (size_ti=0; i<q->size; i++) {
new_data[i] =q->data[(q->front+i) % q->capacity];
}
// Free the old buffer and update pointersfree(q->data);
q->data=new_data;
q->front=0;
q->rear=q->size;
q->capacity=new_capacity;
}
voidqueue_enqueue(Queue64*q, uint64_tvalue) {
// If the queue is full, resize itif (q->size==q->capacity) {
queue_resize(q, q->capacity*2); // Double the capacity
}
// Add the element to the queueq->data[q->rear] =value;
q->rear= (q->rear+1) % q->capacity; // Circular moveq->size++;
}
uint64_tqueue_dequeue(Queue64*q) {
if (q->size==0) {
printf("error: queue_dequeue() failed: queue is empty\n");
return0;
}
uint64_tvalue=q->data[q->front];
q->front= (q->front+1) % q->capacity;
q->size--;
returnvalue;
}
// Function to remove N oldest elements from the front of the queuevoidqueue_trimFront(Queue64*q, size_tn) {
if (n >= q->size) {
printf("warn: queue_trimFront(): trying to remove more elements (%zu) than the queue contains (%zu). Clearing the entire queue.\n", n, q->size);
q->front=0; // Reset the front pointerq->size=0; // Reset the size
} else {
// Directly update the front pointer to remove N elementsq->front= (q->front+n) % q->capacity;
q->size-=n;
}
}
size_tqueue_getSize(Queue64*q) {
returnq->size;
}
uint64_tqueue_getElement(Queue64*queue, intindex) {
if (index<0||index >= queue->size) {
printf("error: queue_getElement() failed: index %d is out of bounds\n", index);
return0; // or some default value for error
}
// Calculate the actual index in the circular queuesize_tactual_index= (queue->front+index) % queue->capacity;
returnqueue->data[actual_index];
}
Queue64_queue;
uint64_t_frameCounter;
voidfillRect(floatx, floaty, floatw, floath) {
GLfloatvertices[] = { x, y+h, x+w, y+h, x+w, y, x, y };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//glDisableClientState(GL_VERTEX_ARRAY);
}
voidfillTexturedRect(floatx, floaty, floatw, floath) {
GLfloatvertices[] = { x, y+h, x+w, y+h, x+w, y, x, y };
GLfloattexCoords[] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//glDisableClientState(GL_TEXTURE_COORD_ARRAY);//glDisableClientState(GL_VERTEX_ARRAY);
}
voiddrawLine(floatx1, floaty1, floatx2, floaty2) {
GLfloatvertices[2*2] = { x1,y1, x2,y2 };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_LINE_STRIP, 0, 2);
//glDisableClientState(GL_VERTEX_ARRAY);
}
voiddrawText(TTF_Font*font, constchar*text, intx, inty, SDL_Colorcolor) {
glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//TTF_SetFontOutline(font, outlineWidth);SDL_Surface*surface=TTF_RenderText_Blended(font, text, color);
if (surface==NULL) {
glPopAttrib();
printf("TTF_RenderText_Blended() failed: %s\n", TTF_GetError());
return;
}
GLuinttexture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / SDL_BYTESPERPIXEL(surface->format->format));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface->pixels);
// shadow imitation//glColor4f(0.0f, 0.0f, 0.0f, 1.0f); //fillTexturedRect(x+1, y+1, surface->w, surface->h);glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
fillTexturedRect(x, y, surface->w, surface->h);
SDL_FreeSurface(surface);
glDeleteTextures(1, &texture);
glPopAttrib();
}
#definemax(a, b) ((a) > (b) ? (a) : (b))
int_swapInterval=1;
int_fullscreen=0;
SDL_DisplayMode_displayMode;
voidwindow_onRender(SDL_Window*window, TTF_Font*font, intwidth, intheight) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
charbuf[128];
SDL_ColortextColor= {255, 255, 0}; // Greenintx=10, y=10, step=24;
if (SDL_GetDisplayMode(0, 0, &_displayMode) !=0) {
snprintf(buf, sizeof(buf), "SDL_GetDisplayMode() failed: %s\n", SDL_GetError());
drawText(font, buf, x, y, textColor);
y+=step;
//return;
}
intswapInterval=SDL_GL_GetSwapInterval();
doublefps=0.0;
uint64_ttmax=0;
uint64_ttmin=-1;
uint64_ttavg=0;
size_tlength=queue_getSize(&_queue);
if (length>0) {
// find tavg for the last second (for fps)size_tcounter=0;
for (size_ti=max(length-_displayMode.refresh_rate, 0); i<length; i++) {
uint64_tv=queue_getElement(&_queue, i);
tavg+=v;
counter++;
}
if (counter>0) {
tavg /= counter;
}
fps= (double)1000000000UL / tavg;
// find statisticstmax=0;
tmin=-1;
tavg=0;
for (size_ti=0; i<length; i++) {
uint64_tv=queue_getElement(&_queue, i);
if (v>tmax) tmax=v;
if (v<tmin) tmin=v;
tavg+=v;
}
tavg /= length;
}
floattargetRate=0.0;
floattargetTime=0.0;
floatviewMax=0.0;
if (abs(swapInterval) ==0||_displayMode.refresh_rate==0) {
targetRate=INFINITY;
targetTime=0;
viewMax=1000000000.0 / max(_displayMode.refresh_rate, 30);
} else {
targetRate= (double)_displayMode.refresh_rate / abs(swapInterval);
targetTime=1000000000.0 / targetRate;
viewMax=targetTime;
}
viewMax *= 1.2;
if (tmax>viewMax) viewMax=tmax;
floatscale=viewMax!=0 ? height / viewMax : 0;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Draw grid and limit lines glColor4f(1.0f, 1.0f, 1.0f, 0.2f); // White // horizontal grid for (uint64_tt=0; t<viewMax; t+=1000000.0) {
drawLine(0, height-scale*t, width-1, height-scale*t);
}
// vertical gridfor (intx=_frameCounter%_displayMode.refresh_rate; x<width; x+=_displayMode.refresh_rate) {
drawLine(width-x, 0, width-x, height);
}
// target time line//glColor4f(1.0f, 0.0f, 1.0f, 0.6f); // Magenta//drawLine(0, height - scale * targetTime, width-1, height - scale * targetTime); floatlimitMax;
floatlimitMin;
if (abs(swapInterval) ==0) {
limitMin=0.0;
limitMax=0.0;
} else {
limitMin=1000000000.0 / (targetRate+1);
limitMax=1000000000.0 / (targetRate-1);
}
floatlimitMinY=height-scale*limitMin;
floatlimitMaxY=height-scale*limitMax;
//glColor4f(1.0f, 0.0f, 0.0f, 0.6f);//drawLine(0, limitMinY, width-1, limitMinY);//drawLine(0, limitMinY, width-1, limitMaxY);// time graphintstartIndex=width-length;
GLfloatvertices[width*2]; // (x, y)for (inti=0; i<width; ++i) {
uint64_tv=0;
if (i >= startIndex) {
v=queue_getElement(&_queue, i-startIndex);
}
vertices[i*2] =i; // xvertices[i*2+1] =height-scale*v; // y (reversed)
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColor4f(0.0f, 1.0f, 0.0f, 0.8f); // GreenglDrawArrays(GL_LINE_STRIP, 0, sizeof(vertices)/(2*sizeof(GLfloat)));
glDisableClientState(GL_VERTEX_ARRAY);
// +-1 fps areaglColor4f(1.0f, 1.0f, 0.0f, 0.3f); // YellowfillRect(0, limitMinY, width-1, limitMaxY-limitMinY);
glDisable(GL_BLEND);
snprintf(buf, sizeof(buf), "real: %7.3f fps", fps);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "need: %7.3f fps", targetRate);
drawText(font, buf, x, y, textColor);
y+=step;
y+=step;
snprintf(buf, sizeof(buf), "tmin: %7.3f ms", tmin/1000000.0);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "tmax: %7.3f ms", tmax/1000000.0);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "tavg: %7.3f ms", tavg/1000000.0);
drawText(font, buf, x, y, textColor);
y+=step;
y+=step;
if (swapInterval<0)
snprintf(buf, sizeof(buf), "swap: %d, \"%s\"", swapInterval, SDL_GetError());
elsesnprintf(buf, sizeof(buf), "swap: %d", swapInterval);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "need: %d", _swapInterval);
drawText(font, buf, x, y, textColor);
y+=step;
y+=step;
snprintf(buf, sizeof(buf), "drv: %s", (constchar*)SDL_GetCurrentVideoDriver());
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "mode: %dx%d@%d", _displayMode.w, _displayMode.h, _displayMode.refresh_rate);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "size: %dx%d", width, height);
drawText(font, buf, x, y, textColor);
}
voidwindow_onResize(intwidth, intheight) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, width, height, 0.0, -1.0, 1.0); // coordinate setup: (0,0)=(left,top), (width,height)=(bottom,right)glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
intfindFont(constchar*font_name, char*buffer, size_tbuffer_size) {
charcommand[MAX_PATH_LENGTH];
snprintf(command, sizeof(command), "fc-match -f '%%{file}' %s", font_name);
FILE*fp=popen(command, "r");
if (fp==NULL) {
return0;
}
if (fgets(buffer, buffer_size, fp) ==NULL) {
pclose(fp);
return0;
}
buffer[strcspn(buffer, "\n")] ='\0';
pclose(fp);
return1;
}
voidsaveScreenshot(SDL_Window*window) {
intwidth, height;
SDL_GetWindowSize(window, &width, &height);
SDL_Surface*surface=SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA32);
if (!surface) {
printf("SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError());
return;
}
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
if (glGetError() !=GL_NO_ERROR) {
printf("glReadPixels failed\n");
SDL_FreeSurface(surface);
return;
}
Uint32*pixels= (Uint32*)surface->pixels;
for (inty=0; y<height / 2; ++y) {
for (intx=0; x<width; ++x) {
Uint32temp=pixels[y*width+x];
pixels[y*width+x] =pixels[(height-y-1) *width+x];
pixels[(height-y-1) *width+x] =temp;
}
}
// Create unique filenamecharfilename[128];
intcounter=1;
do {
snprintf(filename, sizeof(filename), "screenshot_%d.png", counter++);
} while (SDL_RWFromFile(filename, "rb") !=NULL);
// Saveif (IMG_SavePNG(surface, filename) !=0) {
printf("IMG_SavePNG() failed: %s\n", IMG_GetError());
} else {
printf("Screenshot saved to %s\n", filename);
}
SDL_FreeSurface(surface);
}
intmain(intargc, char*argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) <0) {
printf("Failed to initialize SDL: %s\n", SDL_GetError());
return-1;
}
//printf("SDL_GetCurrentVideoDriver(): %s\n", (const char*)SDL_GetCurrentVideoDriver());intwidth=800;
intheight=600;
intdoublebuffer=1;
constchar*drivername=NULL;
// parse command linefor (inti=1; i<argc; ++i) {
if (strcmp(argv[i], "--help") ==0) {
printf("USAGE: %s [options]\n", argv[0]);
printf(" F1 - toggle swapInterval\n");
printf(" F11 - toggle fullscreen mode\n");
printf(" F12 - save screenshot\n");
printf(" ESC - exit\n");
printf("options:\n");
printf(" --list list available SDL video drivers\n");
printf(" --driver <drivername> set SDL video driver (equals to SDL_VIDEODRIVER env.variable)\n");
printf(" --size <width,height> set initial window size\n");
printf(" --doublebuffer <1|0> set SDL_GL_DOUBLEBUFFER attribute value\n");
SDL_Quit();
return0;
} elseif (strcmp(argv[i], "--list") ==0) {
intnum_drivers=SDL_GetNumVideoDrivers();
printf("\nAvailable --driver values:\n");
for (intj=0; j<num_drivers; ++j) {
printf(" \"%s\"\n", SDL_GetVideoDriver(j));
}
SDL_Quit();
return0;
} elseif (strcmp(argv[i], "--driver") ==0&&i+1<argc) {
drivername=argv[i+1];
printf("--driver %s\n", drivername);
i++;
} elseif (strcmp(argv[i], "--size") ==0&&i+1<argc) {
if (sscanf(argv[i+1], "%d,%d", &width, &height) !=2) {
printf("Invalid --size format. Expected --size <width,height>\n");
SDL_Quit();
return-1;
}
printf("--size %d,%d\n", width, height);
i++;
} elseif (strcmp(argv[i], "--doublebuffer") ==0&&i+1<argc) {
if (sscanf(argv[i+1], "%d", &doublebuffer) !=1) {
printf("Invalid --doublebuffer format. Expected --doublebuffer <0|1>\n");
SDL_Quit();
return-1;
}
doublebuffer=doublebuffer ? 1 : 0;
printf("--doublebuffer %d\n", doublebuffer);
i++;
} else {
printf("error: unknown command line option \"%s\"\n", argv[i]);
SDL_Quit();
return-1;
}
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, doublebuffer);
if (SDL_VideoInit(drivername) <0) {
printf("SDL_VideoInit(\"%s\") failed: %s\n", drivername, SDL_GetError());
SDL_Quit();
return-1;
}
printf("SDL_GetCurrentVideoDriver(): %s\n", (constchar*)SDL_GetCurrentVideoDriver());
if (SDL_GetDisplayMode(0, 0, &_displayMode) !=0) {
printf("SDL_GetDisplayMode() failed: %s\n", SDL_GetError());
SDL_Quit();
return-1;
}
printf("SDL_GetDisplayMode(): %d x %d @ %d, format=0x%08x\n", _displayMode.w, _displayMode.h, _displayMode.refresh_rate, _displayMode.format);
if (TTF_Init() <0) {
printf("TTF_Init() failed: %s\n", TTF_GetError());
SDL_Quit();
return-1;
}
// find path: $ fc-match -f '%{file}\n' MonospacecharfontPath[MAX_PATH_LENGTH];
if (!findFont("Monospace", fontPath, sizeof(fontPath))) {
printf("findFont(\"Monospace\") failed\n");
return-1;
}
TTF_Font*font=TTF_OpenFont(fontPath, 20);
if (font==NULL) {
printf("TTF_OpenFont() failed: %s\n", TTF_GetError());
TTF_Quit();
SDL_Quit();
return-1;
}
if (IMG_Init(IMG_INIT_PNG) ==0) {
printf("IMG_Init failed: %s\n", IMG_GetError());
SDL_Quit();
return-1;
}
SDL_Window*window=SDL_CreateWindow(
"test-vblank3",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (window==NULL) {
printf("SDL_CreateWindow() failed: %s\n", SDL_GetError());
TTF_CloseFont(font);
TTF_Quit();
SDL_Quit();
return-1;
}
if (_fullscreen)
{
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
SDL_GLContextglContext=SDL_GL_CreateContext(window);
SDL_GL_SetSwapInterval(_swapInterval);
printf("SDL_GL_SetSwapInterval(%d) => SDL_GL_GetSwapInterval() = %d\n", _swapInterval, SDL_GL_GetSwapInterval());
constintprintAttrs[] = { SDL_GL_DOUBLEBUFFER, SDL_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLESAMPLES, 0 };
constchar*printNames[] = { "SDL_GL_DOUBLEBUFFER", "SDL_GL_MULTISAMPLEBUFFERS", "SDL_GL_MULTISAMPLESAMPLES", 0 };
for (inti=0; printAttrs[i] !=0; i++) {
intvalue;
if (SDL_GL_GetAttribute(printAttrs[i], &value)) {
printf("SDL_GL_GetAttribute(%s) failed: %s\n", printNames[i], SDL_GetError());
continue;
}
printf("%s = %d\n", printNames[i], value);
}
SDL_GetWindowSize(window, &width, &height);
printf("SDL_GetWindowSize(): %d, %d\n", width, height);
window_onResize(width, height);
intrunning=1;
structtimespects1, ts2;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
queue_init(&_queue, 16384);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
while (running) {
SDL_Eventevent;
while (SDL_PollEvent(&event)) {
if (event.type==SDL_QUIT) {
running=0;
}
if (event.type==SDL_KEYDOWN) {
if (event.key.keysym.sym==SDLK_ESCAPE) {
running=0;
}
if (event.key.keysym.sym==SDLK_F11) {
_fullscreen=_fullscreen ? 0:1;
printf("SDL_SetWindowFullscreen(%d)\n", _fullscreen);
SDL_SetWindowFullscreen(window, _fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}
if (event.key.keysym.sym==SDLK_F1) {
_swapInterval= (_swapInterval+1) &3;
SDL_GL_SetSwapInterval(_swapInterval);
printf("SDL_GL_SetSwapInterval(%d) => SDL_GL_GetSwapInterval() = %d\n", _swapInterval, SDL_GL_GetSwapInterval());
}
if (event.key.keysym.sym==SDLK_F12) {
saveScreenshot(window);
}
}
if (event.type==SDL_WINDOWEVENT) {
if (event.window.event==SDL_WINDOWEVENT_RESIZED||event.window.event==SDL_WINDOWEVENT_SIZE_CHANGED) {
width=event.window.data1;
height=event.window.data2;
window_onResize(width, height);
}
}
}
window_onRender(window, font, width, height);
SDL_GL_SwapWindow(window);
clock_gettime(CLOCK_MONOTONIC_RAW, &ts2);
uint64_tdt_ns= ((uint64_t)ts2.tv_sec- (uint64_t)ts1.tv_sec) *1000000000UL+ (ts2.tv_nsec-ts1.tv_nsec);
ts1=ts2;
_frameCounter++;
queue_enqueue(&_queue, dt_ns);
SDL_GetWindowSize(window, &width, &height);
ssize_texcess_elements= (ssize_t)queue_getSize(&_queue) -width;
if (excess_elements>0) {
queue_trimFront(&_queue, excess_elements);
}
}
queue_free(&_queue);
IMG_Quit();
TTF_CloseFont(font);
TTF_Quit();
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
return0;
}
The text was updated successfully, but these errors were encountered:
Attempting to set swapInterval greater than 1 for the X11 backend results in an incorrect buffer swap rate, which also varies each time.
For the Wayland and KMSDRM backends, setting swapInterval greater than 1 leads to actual set swapInterval = 1.
For some unknown reason, SDL_GL_GetSwapInterval() returns negative values with x11 and wayland backend if actual swapInterval > 0.
Steps to reproduce
sudo apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev
test-vblank3.c
and copy/paste code (see below)gcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image
./test-vblank3 --driver x11
Expected result: setting swapInterval > 1 is accepted and properly processed. Fps should correspond to requested swapInterval value. For swapInterval=1 it should be equals to display refresh rate, for swapInterval=2 it should be half of the display refresh rate, etc.
Actual result: For x11 backend setting swapInterval > 1 leads to some weird and incorrect fps which randomly varies from time to time on every swapInterval change.
./test-vblank3 --driver wayland
Actual result: For wayland backend setting swapInterval > 1 leads to actual set swapInterval = 1, so there is no way to set swapInterval > 1.
./test-vblank3 --driver KMSDRM
Actual result: For KMSDRM backend setting swapInterval > 1 leads to actual set swapInterval = 1, the same issue as for wayland backend.
Expected result: each time you set swapInterval=2, fps should be the same
Actual result: each time you set swapInterval=2, fps is different: sometimes it is as expected 37.5 fps, sometimes 50 fps, sometimes 45 fps, etc.
Screenshots
x11 backend: swapInterval=2, expected 37.5 fps, actual value is 45.3 and varies and unstable...
x11 backend: swapInterval=3, expected 25.0 fps, actual value is 27.5 fps and unstable...
KMSDRM backend: swapInterval=3, expected 25.0 fps, actual swapInterval=1 and 75.0 fps...
Test code
test-vblank3.c
The text was updated successfully, but these errors were encountered: