SDL3 and cairo

How well does SDL3 work with cairo-graphics?
Is cairo-graphics hardware accelerated?

Check this link Cairo and SDL.
In summary; they can work together very well, but be careful to ensure format of the SDL surface match those used in Cairo.

I tried something like that, is this the right approach?
On the SDL side, hardware is definitely used to accelerate it, as I have a renderer.
What about the cairo side?

#include <SDL3/SDL.h>
#include <cairo/cairo.h>

void CairoDraw(SDL_Texture *texture, int w, int h){
  void *pixels;
  int pitch;
  SDL_LockTexture(texture, nullptr, &pixels, &pitch);
  cairo_surface_t *surface = cairo_image_surface_create_for_data((char unsigned*)pixels, CAIRO_FORMAT_ARGB32, w, h, pitch);
  cairo_t *context = cairo_create(surface);

  cairo_set_source_rgba(context, 1.0, 1.0, 1.0, 1.0);
  cairo_arc(context, w / 2, h / 2, w / 4, 0, SDL_PI_D * 2);
  cairo_stroke(context);

  cairo_destroy(context);
  cairo_surface_destroy(surface);
  SDL_UnlockTexture(texture);
}

int main(int argc, char *argv[])
{
    int Width = 320;
    int Height = 200;
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window *win = SDL_CreateWindow("Test", 320, 200, SDL_WINDOW_RESIZABLE);
    SDL_Renderer *renderer = SDL_CreateRenderer(win, nullptr);

    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, Width, Height);

    SDL_bool quit = SDL_FALSE;
    while (!quit)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_EVENT_QUIT:
                    quit = SDL_TRUE;
                    break;
                case SDL_EVENT_WINDOW_RESIZED:
                    SDL_DestroyTexture(texture);
                    SDL_GetWindowSize(win, &Width, &Height);
                    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, Width, Height);
                    break;
            }
        }
        CairoDraw(texture, Width, Height);

        SDL_RenderTexture(renderer, texture, nullptr, nullptr);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_DestroyWindow(win);
    SDL_DestroyRenderer(renderer);
    SDL_Quit();

    return 0;
}

Do I understand correctly that the pointer from pixels in SDL_LockTexture() points directly to the VRAM?
And if so, does Cairo recognize this and then use the GPU for drawing?

No. It’s in RAM.

I’m no expert on Cairo but if I understand correctly all these cairo_image_* functions create things in RAM.

Apparently there was an experimental backend named cairo-gl, with it’s own set of cairo_gl_* functions, that used OpenGL but it was removed.


Update: found the following:

cairo-image: pure CPU rasterisation
cairo-gl: use OpenGL for GPU compositing and some rasterisation, depends upon driver quality
cairo-xlib: use XRender to send commands to X which uses the GPU for compositing and some rasterisation, depends upon driver quality
cairo-quartz: use Quartz to offload some commands to the GPU
cairo-win32: uses image + GDI blitting, one day should have a d2d backend

Source: [cairo] Does Cairo Use Hardware Acceleration?

When I read through your links, it looks like GPU acceleration is still a work in progress.
You have to bear in mind that the comments, apart from those posted by cairo_gl, are over 12 years old.
A lot could have happened in that time.
If xlib already supports it a little, let’s see what it looks like with Wayland.

Yeah, it’s old. I just thought it was a nice summary that explained that some “backends” use hardware acceleration if available but not cairo-image which you used in your code. I don’t think this has changed. The official docs says it’s for “rendering to memory buffers”.

Then it will probably be quite difficult to integrate this into SDL3, unless you take a detour via XLib_surfaces.
Unless it is integrated into SDL_Texture / SDL_Renderer at some point. As far as I know, these two also use the GPU/VRAM.

I did a test with cairo_libx and a long for loop.
You can clearly see that it is written directly to the VRAM.
Without any swap buffers.