I noticed an unexpected change in performance while tweaking a program, and put together a test case help clarify the reason for the change.
Basically, on my system, when the render target is set to a texture, using SDL_RenderClear() takes a horrific amount of time (over 100 ms). But on the same target, doing a SDL_RenderFillRect() of the entire texture is quite reasonable (about 1.5 ms). This only happens with a texture as a target, and if I’ve specified SDL_RENDERER_ACCELERATED when creating the renderer. With SDL_RENDERER_SOFTWARE, the times for everything are much longer (no surprise), but they are consistent between SDL_RenderClear() and SDL_RenderFillRect().
I don’t see how this could be an SDL bug - I don’t see anything in the code that could cause SDL_RenderClear() to behave differently for a texture target rather than a screen target. So I’m assuming the bug is at a lower level (Mesa, or the video driver).
For the record - my “play around” system is an older Celeron, using an older Radeon card. System runs Xubuntu Precise, Mesa 1.2, and xserver-xorg-video-radeon 1.6.14.
Could a few others please run this code, and verify that it’s a “my machine” type issue (I suspect the Radeon driver as a culprit, but I’d like some confirmation). Here’s my teset results:
Code:
lloyd at Dell:~/src/test$ ./testcase
Hardware Render to screen - SDL_FillRect, average 1540.02 microseconds
Hardware Render to screen - SDL_RenderClear, average 1618.40 microseconds
Hardware Render to texture - SDL_FillRect, average 1594.33 microseconds
Hardware Render to texture - SDL_RenderClear, average 100435.69 microseconds
Software Render to screen - SDL_FillRect, average 11118.92 microseconds
Software Render to screen - SDL_RenderClear, average 11218.12 microseconds
Software Render to texture - SDL_FillRect, average 11255.74 microseconds
Software Render to texture - SDL_RenderClear, average 11253.91 microseconds
lloyd at Dell:~/src/test$
And the test case code
Code:
#include <stdio.h>
#include <sys/time.h>
#include <SDL2/SDL.h>
void test_loop(struct SDL_Renderer * rend, const char * ident)
{
int x, start, start2, stop, elapsed;
float average1, average2;
struct SDL_Rect rect;
struct timeval tv;
struct timezone tz;
rect.x = 0;
rect.y = 0;
rect.h = 480;
rect.w = 640;
for(x = 0; x < 255; x++) {
gettimeofday(&tv, &tz);
start = tv.tv_usec;
start2 = tv.tv_sec;
SDL_SetRenderDrawColor(rend, x, x, x, 255);
SDL_RenderFillRect(rend, &rect);
SDL_RenderPresent(rend);
gettimeofday(&tv, &tz);
stop = tv.tv_usec;
if (start2 < tv.tv_sec)
stop += ((tv.tv_sec - start2) * 1000000);
elapsed = stop - start;
if (x == 0) {
average1 = elapsed;
} else {
average1 = ((average1 * x) + elapsed) / (x + 1);
}
}
printf("%s - SDL_FillRect, average %9.2f microseconds\n", ident, average1);
for(x = 0; x < 255; x++) {
gettimeofday(&tv, &tz);
start = tv.tv_usec;
start2 = tv.tv_sec;
SDL_SetRenderDrawColor(rend, (255 - x), (255 - x), (255 - x), 255);
SDL_RenderClear(rend);
SDL_RenderPresent(rend);
gettimeofday(&tv, &tz);
stop = tv.tv_usec;
if (start2 < tv.tv_sec)
stop += ((tv.tv_sec - start2) * 1000000);
elapsed = stop - start;
if (x == 0) {
average2 = elapsed;
} else {
average2 = ((average2 * x) + elapsed) / (x + 1);
}
}
printf("%s - SDL_RenderClear, average %9.2f microseconds\n", ident, average2);
}
int main(int argc, char** argv) {
struct SDL_Window * wind[2] = {NULL, NULL};
struct SDL_Renderer * rend[2] = {NULL, NULL};
struct SDL_Texture * text[2] = {NULL, NULL};
struct SDL_RendererInfo info;
int x;
SDL_Init(SDL_INIT_EVERYTHING);
for (x = 0; x < 2; x++) {
wind[x] = SDL_CreateWindow("Testing", (x * 100) + 100, 100,
640, 480, SDL_WINDOW_SHOWN);
if ( wind[x] == NULL ) {
printf("Couldn't create window %d - %s\n", x, SDL_GetError());
return -1;
}
if ( x == 0 ) {
rend[0] = SDL_CreateRenderer(wind[0], -1, SDL_RENDERER_ACCELERATED |
SDL_RENDERER_TARGETTEXTURE);
if ( rend[0] == NULL) {
printf("Error creating hardware renderer - %s\n", SDL_GetError());
return -1;
}
} else {
rend[1] = SDL_CreateRenderer(wind[1], -1, SDL_RENDERER_SOFTWARE |
SDL_RENDERER_TARGETTEXTURE);
if ( rend[1] == NULL ) {
printf("Error creating software renderer - %s\n", SDL_GetError());
return -1;
}
}
SDL_RenderClear(rend[x]);
SDL_RenderPresent(rend[x]);
text[x] = SDL_CreateTexture(rend[x], 0, SDL_TEXTUREACCESS_TARGET, 640, 480);
if ( text[x] == NULL ) {
printf("Error creating texutre %d - %s\n", x, SDL_GetError());
return -1;
}
}
test_loop(rend[0], "Hardware Render to screen");
SDL_SetRenderTarget(rend[0], text[0]);
test_loop(rend[0], "Hardware Render to texture");
test_loop(rend[1], "Software Render to screen");
SDL_SetRenderTarget(rend[1], text[1]);
test_loop(rend[1], "Software Render to texture");
SDL_DestroyTexture(text[0]);
SDL_DestroyTexture(text[1]);
SDL_DestroyRenderer(rend[0]);
SDL_DestroyRenderer(rend[1]);
SDL_Quit();
return 0;
}