Skip to content

Instantly share code, notes, and snippets.

@DavidBuchanan314
Last active November 29, 2023 15:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidBuchanan314/2f68ff42df047a448be593b85f32a8fb to your computer and use it in GitHub Desktop.
Save DavidBuchanan314/2f68ff42df047a448be593b85f32a8fb to your computer and use it in GitHub Desktop.
/*
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