# How scrcpy Manages Window Rendering and OpenGL Display: SDL2 Architecture and Pipeline Deep Dive

> Discover how scrcpy uses SDL2 and OpenGL for efficient window rendering and display. Learn about its layered architecture and pipeline for enhanced visual quality and performance.

- Repository: [Genymobile/scrcpy](https://github.com/Genymobile/scrcpy)
- Tags: internals
- Published: 2026-02-25

---

**scrcpy leverages SDL2 for cross-platform window management while automatically detecting and utilizing OpenGL renderers to enable trilinear filtering, mipmapping, and efficient YUV-to-RGB conversion through a layered architecture implemented in [`screen.c`](https://github.com/Genymobile/scrcpy/blob/main/screen.c) and [`display.c`](https://github.com/Genymobile/scrcpy/blob/main/display.c).**

scrcpy (Screen Copy) is an open-source application that mirrors and controls Android devices from a desktop environment. Understanding how scrcpy handles window rendering and OpenGL display reveals a sophisticated architecture built on SDL2 that manages HiDPI scaling, dynamic orientation changes, and hardware-accelerated video processing.

## SDL2 Window Management and HiDPI Handling ([`screen.c`](https://github.com/Genymobile/scrcpy/blob/main/screen.c))

The window lifecycle begins in [`app/src/screen.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/screen.c), where `sc_screen_init()` constructs the SDL window with flags for high-DPI support, resizing, and positioning.

### Window Creation

At lines 397-410, the code calls `SDL_CreateWindow` with accumulated window flags:

```c
screen->window = SDL_CreateWindow(title, x, y, width, height, window_flags);

```

### HiDPI Scaling

To handle Retina and other high-density displays, `sc_screen_init()` calculates scaling factors by comparing drawable size against window size (lines 439-447):

```c
*x = (int64_t)*x * dw / ww;
*y = (int64_t)*y * dh / wh;

```

### Dynamic Resizing and Orientation

When content size changes, `sc_screen_update_content_rect()` (lines 165-199) recomputes the destination rectangle to preserve aspect ratio and remove black borders. Fullscreen toggling is handled by `sc_screen_toggle_fullscreen()` (lines 389-453) using `SDL_SetWindowFullscreen`.

## OpenGL Display Pipeline ([`display.c`](https://github.com/Genymobile/scrcpy/blob/main/display.c))

The rendering abstraction lives in [`app/src/display.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/display.c) within the `sc_display` structure, which encapsulates the SDL renderer, texture, and optional OpenGL context.

### Renderer Detection and Context Creation

`sc_display_init()` (lines 34-40) creates an accelerated SDL renderer:

```c
display->renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

```

OpenGL detection occurs at lines 52-55 by inspecting the renderer name:

```c
bool use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);

```

When compiled with `SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE`, the code requests an explicit core-profile context (lines 56-68):

```c
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
display->gl_context = SDL_GL_CreateContext(window);

```

### OpenGL Symbol Loading

The [`app/src/opengl.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/opengl.c) module handles symbol loading. `sc_opengl_init()` (lines 9-21) retrieves function pointers via `SDL_GL_GetProcAddress`, while `sc_opengl_version_at_least()` validates support for advanced features.

### Mipmap Generation and Trilinear Filtering

If the user enables `--mipmaps` and the OpenGL version supports it (≥3.0 desktop or ≥2.0 ES), `sc_display_init()` enables mipmap generation (lines 71-88).

During texture setup (lines 40-52), the code configures trilinear filtering:

```c
SDL_GL_BindTexture(texture, NULL, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
gl->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -1.f);
SDL_GL_UnbindTexture(texture);

```

### Frame Rendering Pipeline

When a new frame arrives, `sc_display_update_texture()` (lines 66-71) uploads YUV data:

```c
SDL_UpdateYUVTexture(display->texture, NULL,
                     frame->data[0], frame->linesize[0],
                     frame->data[1], frame->linesize[1],
                     frame->data[2], frame->linesize[2]);

```

If mipmaps are enabled, `sc_display_render()` generates the mipmap chain (lines 76-80):

```c
gl->GenerateMipmap(GL_TEXTURE_2D);

```

Orientation handling (lines 22-45) uses `SDL_RenderCopyEx` with rotation angles and horizontal flipping:

```c
SDL_RenderCopyEx(display->renderer, display->texture, NULL, &rect,
                 rotation_angle, NULL, flip);

```

Finally, `SDL_RenderPresent` (lines 48-50) displays the frame.

## Complete Rendering Flow Example

The following pseudo-code illustrates the typical initialization and rendering sequence:

```c
// 1. Initialize screen (creates SDL window)
struct sc_screen screen;
struct sc_screen_params params = {/* … user options … */};
sc_screen_init(&screen, &params);

// 2. Initialize display (creates renderer, optional GL context)
sc_display_init(&screen.display, screen.window, icon_surface, params.mipmaps);

// 3. First frame arrives (from the decoder)
AVFrame *frame = ...;                     // YUV420P
sc_display_set_texture_size(&screen.display,
                            (struct sc_size){frame->width, frame->height});
sc_display_update_texture(&screen.display, frame);

// 4. Render loop (called for every new frame)
sc_screen_render(&screen, true);   // true → recompute content rect if needed

```

## Summary

- **SDL2** provides the cross-platform windowing foundation, handling HiDPI scaling, resizing, and event loops through [`app/src/screen.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/screen.c).
- **OpenGL integration** is automatically detected in [`app/src/display.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/display.c), enabling hardware-accelerated YUV-to-RGB conversion, trilinear filtering, and mipmap generation when the `--mipmaps` flag is used.
- **Texture management** uses SDL's streaming textures with optional OpenGL binding for advanced filtering, while [`app/src/opengl.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/opengl.c) handles symbol loading and version detection.
- **Orientation support** is implemented via `SDL_RenderCopyEx` rotations, ensuring the video displays correctly regardless of device orientation changes.

## Frequently Asked Questions

### How does scrcpy detect whether OpenGL is available?

scrcpy checks the renderer name returned by `SDL_GetRendererInfo` in [`app/src/display.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/display.c) (lines 52-55). If the name begins with `"opengl"`, the code sets up an OpenGL context and loads necessary function pointers via `SDL_GL_GetProcAddress` in [`app/src/opengl.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/opengl.c).

### What is the purpose of the `--mipmaps` option in scrcpy?

The `--mipmaps` flag enables trilinear filtering (`GL_LINEAR_MIPMAP_LINEAR`) and automatic mipmap generation using `glGenerateMipmap`. This improves visual quality when the window is significantly smaller than the native video resolution by reducing aliasing artifacts. The feature requires OpenGL 3.0+ on desktop or OpenGL ES 2.0+.

### How does scrcpy handle device rotation and orientation changes?

scrcpy uses `SDL_RenderCopyEx` in [`app/src/display.c`](https://github.com/Genymobile/scrcpy/blob/main/app/src/display.c) (lines 22-45) to apply rotation angles (90°, 180°, 270°) and horizontal flipping based on the current device orientation. This occurs during the rendering phase after the YUV texture is updated but before `SDL_RenderPresent` displays the frame.

### Why does scrcpy use SDL2 instead of raw OpenGL or platform-specific APIs?

SDL2 provides cross-platform window creation, event handling, and renderer abstraction that works consistently across Windows, macOS, and Linux. By using SDL2's high-level texture and renderer APIs while optionally binding to OpenGL for advanced features like mipmaps, scrcpy maintains portability without sacrificing performance or visual quality.