Skip to content

Instantly share code, notes, and snippets.

@gcatlin
Last active April 20, 2024 13:04
Show Gist options
  • Star 33 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gcatlin/b89e0efed78dd91364609ca4095da346 to your computer and use it in GitHub Desktop.
Save gcatlin/b89e0efed78dd91364609ca4095da346 to your computer and use it in GitHub Desktop.
Minimal C SDL2 Metal example
//
// cc sdl-metal-example.m `sdl2-config --cflags --libs` -framework Metal -framework QuartzCore && ./a.out
//
#include <SDL.h>
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
int main (int argc, char *args[])
{
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
SDL_InitSubSystem(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("SDL Metal", -1, -1, 640, 480, SDL_WINDOW_ALLOW_HIGHDPI);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
const CAMetalLayer *swapchain = (__bridge CAMetalLayer *)SDL_RenderGetMetalLayer(renderer);
const id<MTLDevice> gpu = swapchain.device;
const id<MTLCommandQueue> queue = [gpu newCommandQueue];
MTLClearColor color = MTLClearColorMake(0, 0, 0, 1);
bool quit = false;
SDL_Event e;
while (!quit) {
while (SDL_PollEvent(&e) != 0) {
switch (e.type) {
case SDL_QUIT: quit = true; break;
}
}
@autoreleasepool {
id<CAMetalDrawable> surface = [swapchain nextDrawable];
color.red = (color.red > 1.0) ? 0 : color.red + 0.01;
MTLRenderPassDescriptor *pass = [MTLRenderPassDescriptor renderPassDescriptor];
pass.colorAttachments[0].clearColor = color;
pass.colorAttachments[0].loadAction = MTLLoadActionClear;
pass.colorAttachments[0].storeAction = MTLStoreActionStore;
pass.colorAttachments[0].texture = surface.texture;
id<MTLCommandBuffer> buffer = [queue commandBuffer];
id<MTLRenderCommandEncoder> encoder = [buffer renderCommandEncoderWithDescriptor:pass];
[encoder endEncoding];
[buffer presentDrawable:surface];
[buffer commit];
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
@slightlybeige
Copy link

For anyone who is stuck here with a black screen, you need to remove the "SDL_DestroyRenderer(renderer);" on line 17. This function in SDL destroys the View as well as the renderer which will prevent you from having anything draw to the screen. SDL_RenderGetMetalLayer will flush all the buffers before returning so there shouldn't be any conflicts.
I haven't tested on iOS, I'm guessing perhaps the UIKit based renderer on iOS behaves differently hence the author adding the destroy?

@gcatlin
Copy link
Author

gcatlin commented Jul 14, 2020

@slightlybeige thanks for figuring out the issue. It used to work as is -- I'm not sure what changed, maybe something in SDL. I moved SDL_DestroyRenderer below the loop and updated the gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment