Last active
November 29, 2023 15:20
-
-
Save DavidBuchanan314/2f68ff42df047a448be593b85f32a8fb to your computer and use it in GitHub Desktop.
SDL2 framebuffer graphics demo, based on https://wiki.libsdl.org/SDL2/MigrationGuide#if-your-game-just-wants-to-get-fully-rendered-frames-to-the-screen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc main.c -o main -O3 -lSDL2 | |
This hits 240fps at 4K resolution, on my M1 Pro | |
*/ | |
#include <SDL2/SDL.h> | |
#include <stdio.h> | |
#define FB_WIDTH 3840 | |
#define FB_HEIGHT 2160 | |
#define FPS_AVG_WINDOW 32 | |
/* | |
fb is an FB_WIDTH*FB_HEIGHT array of ARGB8888 Uint32s | |
if your value of FB_WIDTH isn't a round number, you might want to mess around | |
with different strides | |
*/ | |
void render(Uint32 *fb, Uint32 ticks) | |
{ | |
for (int y=0; y<FB_HEIGHT; y++) { | |
for (int x=0; x<FB_WIDTH; x++) { | |
Uint32 val = ((x-ticks/4)^(y-ticks/4)) & 0xff; // moving xor texture | |
fb[y*FB_WIDTH+x] = 0xff000000 | (val << 16) | (val << 8) | val; // pack into ARGB8888 | |
} | |
} | |
} | |
int main(int argc, char* argv[]) | |
{ | |
SDL_Window* window = NULL; | |
SDL_Renderer *renderer = NULL; | |
SDL_Texture *texture = NULL; | |
if (SDL_Init(SDL_INIT_VIDEO) < 0) { | |
SDL_Log("Could not init SDL2: %s", SDL_GetError()); | |
return -1; | |
} | |
// create window | |
window = SDL_CreateWindow( | |
"SDL2 Framebuffer Test", | |
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, | |
FB_WIDTH, FB_HEIGHT, | |
SDL_WINDOW_SHOWN | |
); | |
if (window == NULL) { | |
SDL_Log("Could not create window: %s", SDL_GetError()); | |
return -1; | |
} | |
// create renderer | |
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); | |
if (renderer == NULL) { | |
SDL_Log("Could not create renderer: %s", SDL_GetError()); | |
return -1; | |
} | |
// create texture | |
texture = SDL_CreateTexture( | |
renderer, | |
SDL_PIXELFORMAT_ARGB8888, | |
SDL_TEXTUREACCESS_STREAMING, | |
FB_WIDTH, FB_HEIGHT | |
); | |
if (texture == NULL) { | |
SDL_Log("Could not create texture: %s", SDL_GetError()); | |
return -1; | |
} | |
Uint32 *fb = malloc(FB_WIDTH * FB_HEIGHT * sizeof(Uint32)); | |
if (fb == NULL) { | |
perror("fb malloc"); | |
return -1; | |
} | |
Uint32 prev_ticks[32] = {0}; | |
size_t prev_ticks_idx = 0; | |
for (;;) { | |
// drain SDL event queue | |
SDL_Event event; | |
while (SDL_PollEvent(&event)) { | |
if (event.type == SDL_QUIT) { | |
goto cleanup; | |
} | |
} | |
// do the rendering work | |
Uint32 tick_before = SDL_GetTicks(); | |
render(fb, tick_before); | |
Uint32 tick_after = SDL_GetTicks(); | |
// calculate average FPS over the previous FPS_AVG_WINDOW frames | |
int fps_delta = (int)tick_before - prev_ticks[prev_ticks_idx]; | |
prev_ticks[prev_ticks_idx] = tick_before; | |
prev_ticks_idx = (prev_ticks_idx + 1) % FPS_AVG_WINDOW; | |
SDL_Log( | |
"Rendered %ux%u pixels in %dms (%.1f fps avg)", | |
FB_WIDTH, FB_HEIGHT, | |
(int)tick_after-tick_before, | |
(1000.0 * FPS_AVG_WINDOW) / fps_delta | |
); | |
// send the texture to the GPU | |
SDL_UpdateTexture( | |
texture, | |
NULL /* rect to update (NULL defaults to whole texture) */, | |
fb, | |
FB_WIDTH * sizeof(Uint32) /* pitch (aka stride) */ | |
); | |
SDL_RenderClear(renderer); | |
SDL_RenderCopy(renderer, texture, NULL, NULL); | |
SDL_RenderPresent(renderer); | |
} | |
cleanup: | |
SDL_DestroyTexture(texture); | |
SDL_DestroyRenderer(renderer); | |
SDL_DestroyWindow(window); | |
SDL_Quit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment