WIP: testing usage of SDL renderer

It does segfault.
This commit is contained in:
Francesco Abbate 2021-04-23 11:58:53 +02:00
parent 9d9c7f291c
commit 685b8c82d0
3 changed files with 164 additions and 5 deletions

View File

@ -0,0 +1,97 @@
## Window creation for Retina displays
The file info.plist sets NSHighResolutionCapable to true. This is fine for High-DPI
and retina displays.
The `SDL_CreateWindow` is called with the flag `SDL_WINDOW_ALLOW_HIGHDPI`.
On Mac OS it means that, in source file `video/cocoa/SDL_cocoawindow.m`, from
function `Cocoa_CreateWindow`, SDL calls:
```objc
/* highdpi will be TRUE below */
BOOL highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
[contentView setWantsBestResolutionOpenGLSurface:highdpi]
```
Documentation for `setWantsBestResolutionOpenGLSurface`:
https://developer.apple.com/documentation/appkit/nsview/1414938-wantsbestresolutionopenglsurface
with more details in "OpenGL Programming Guide for Mac", chapter
"Optimizing OpenGL for High Resolution":
https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/EnablingOpenGLforHighResolution/EnablingOpenGLforHighResolution.html#//apple_ref/doc/uid/TP40001987-CH1001-SW4
Citation from the official documentation:
You can opt in to high resolution by calling the method
`setWantsBestResolutionOpenGLSurface:` when you initialize the view, and
supplying YES as an argument:
```objc
[self setWantsBestResolutionOpenGLSurface:YES];
```
If you dont opt in, the system magnifies the rendered results.
The wantsBestResolutionOpenGLSurface property is relevant only for views to
which an NSOpenGLContext object is bound. Its value does not affect the behavior
of other views. For compatibility, wantsBestResolutionOpenGLSurface defaults to
NO, providing a 1-pixel-per-point framebuffer regardless of the backing scale
factor for the display the view occupies. Setting this property to YES for a
given view causes AppKit to allocate a higher-resolution framebuffer when
appropriate for the backing scale factor and target display.
To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view
must perform correct conversions between view units (points) and pixel units as
needed. For example, the common practice of passing the width and height of
[self bounds] to glViewport() will yield incorrect results at high resolution,
because the parameters passed to the glViewport() function must be in pixels. As
a result, youll get only partial instead of complete coverage of the render
surface. Instead, use the backing store bounds:
```objc
[self convertRectToBacking:[self bounds]];
```
## Coordinates
The SDL function `SDL_GL_GetDrawableSize` will provide the size of the underlying drawable
in pixels. From the `SDL_video.h` header.
```c
/**
* \brief Get the size of a window's underlying drawable in pixels (for use
* with glViewport).
*
* \param window Window from which the drawable size should be queried
* \param w Pointer to variable for storing the width in pixels, may be NULL
* \param h Pointer to variable for storing the height in pixels, may be NULL
*
* This may differ from SDL_GetWindowSize() if we're rendering to a high-DPI
* drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a
* platform with high-DPI support (Apple calls this "Retina"), and not disabled
* by the SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
*
* \sa SDL_GetWindowSize()
* \sa SDL_CreateWindow()
*/
extern DECLSPEC void SDLCALL SDL_GL_GetDrawableSize(SDL_Window * window, int *w,
int *h);
```
In turns it calls `Cocoa_GL_GetDrawableSize` from source file
`video/cocoa/SDL_cocoaopengl.m`. The function use the method
`[contentView convertRectToBacking:viewport]`:
```objc
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
/* This gives us the correct viewport for a Retina-enabled view, only
* supported on 10.7+. */
if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
viewport = [contentView convertRectToBacking:viewport];
}
}
```
to give back the sizes in pixels.

View File

@ -125,6 +125,9 @@ int main(int argc, char **argv) {
window = SDL_CreateWindow( window = SDL_CreateWindow(
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8, "", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
fprintf(stderr, "New window: %p\n", window); fflush(stderr);
init_window_icon(); init_window_icon();
ren_init(window); ren_init(window);

View File

@ -33,6 +33,11 @@ struct RenFont {
static SDL_Window *window; static SDL_Window *window;
static SDL_Renderer *window_renderer = NULL;
static SDL_Texture *window_texture = NULL;
static SDL_Surface *window_surface = NULL;
static int window_w = -1, window_h = -1;
static FR_Clip_Area clip; static FR_Clip_Area clip;
static void* check_alloc(void *ptr) { static void* check_alloc(void *ptr) {
@ -61,6 +66,30 @@ static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
} }
static SDL_Surface *get_window_surface(SDL_Window *this_window) {
int w, h;
// fprintf(stderr, "get_window_surface: %p\n", this_window); fflush(stderr);
SDL_GL_GetDrawableSize(this_window, &w, &h);
// FIXME: check for errors ?
if (window_surface && w == window_w && h == window_h) {
fprintf(stderr, "get_window_surface: return current surface: %p\n", window_surface); fflush(stderr);
return window_surface;
}
if (window_surface) {
fprintf(stderr, "going to free: %p\n", window_surface); fflush(stderr);
SDL_FreeSurface(window_surface);
}
window_surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 24, SDL_PIXELFORMAT_BGR24);
fprintf(stderr, "NEW surface: %p, size: %d %d\n", window_surface, w, h); fflush(stderr);
window_w = w;
window_h = h;
return window_surface;
}
void ren_cp_replace_init(CPReplaceTable *rep_table) { void ren_cp_replace_init(CPReplaceTable *rep_table) {
rep_table->size = 0; rep_table->size = 0;
rep_table->replacements = NULL; rep_table->replacements = NULL;
@ -95,18 +124,42 @@ void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char *
void ren_init(SDL_Window *win) { void ren_init(SDL_Window *win) {
assert(win); assert(win);
window = win; window = win;
SDL_Surface *surf = SDL_GetWindowSurface(window); SDL_Surface *surf = get_window_surface(window); //SDL_GetWindowSurface(window);
fprintf(stderr, "New surface %p\n", surf); fflush(stderr);
ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } ); ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } );
} }
void ren_update_rects(RenRect *rects, int count) { void ren_update_rects(RenRect *rects, int count) {
#if 0
SDL_UpdateWindowSurfaceRects(window, (SDL_Rect*) rects, count); SDL_UpdateWindowSurfaceRects(window, (SDL_Rect*) rects, count);
#endif
fprintf(stderr, "ren_update_rects\n"); fflush(stderr);
static bool initial_frame = true; static bool initial_frame = true;
if (initial_frame) { if (initial_frame) {
SDL_ShowWindow(window); SDL_ShowWindow(window);
initial_frame = false; initial_frame = false;
} }
int w, h;
SDL_GL_GetDrawableSize(window, &w, &h);
if (window_renderer && (w != window_w || h != window_h)) {
SDL_DestroyTexture(window_texture);
SDL_DestroyRenderer(window_renderer);
window_renderer = NULL;
}
if (!window_renderer) {
window_renderer = SDL_CreateRenderer(window, -1, 0);
// SDL_CreateTextureFromSurface(sdlRenderer, mySurface);
window_texture = SDL_CreateTexture(window_renderer, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, w, h);
fprintf(stderr, "got new renderer and texture: %p %p\n", window_renderer, window_texture); fflush(stderr);
}
// FIXME: we ignore the rects here.
SDL_UpdateTexture(window_texture, NULL, window_surface->pixels, window_w * 3);
SDL_RenderCopy(window_renderer, window_texture, NULL, NULL);
SDL_RenderPresent(window_renderer);
} }
@ -119,7 +172,7 @@ void ren_set_clip_rect(RenRect rect) {
void ren_get_size(int *x, int *y) { void ren_get_size(int *x, int *y) {
SDL_Surface *surf = SDL_GetWindowSurface(window); SDL_Surface *surf = get_window_surface(window); //SDL_GetWindowSurface(window);
*x = surf->w; *x = surf->w;
*y = surf->h; *y = surf->h;
} }
@ -278,7 +331,10 @@ void ren_draw_rect(RenRect rect, RenColor color) {
x2 = x2 > clip.right ? clip.right : x2; x2 = x2 > clip.right ? clip.right : x2;
y2 = y2 > clip.bottom ? clip.bottom : y2; y2 = y2 > clip.bottom ? clip.bottom : y2;
SDL_Surface *surf = SDL_GetWindowSurface(window); // fprintf(stderr, "ren_draw_rect: clipped rect: (%d, %d) (%d, %d)\n", x1, y1, x2, y2);
// SDL_Surface *surf = SDL_GetWindowSurface(window);
SDL_Surface *surf = get_window_surface(window);
RenColor *d = (RenColor*) surf->pixels; RenColor *d = (RenColor*) surf->pixels;
d += x1 + y1 * surf->w; d += x1 + y1 * surf->w;
int dr = surf->w - (x2 - x1); int dr = surf->w - (x2 - x1);
@ -290,6 +346,8 @@ void ren_draw_rect(RenRect rect, RenColor color) {
} }
} }
// FIXME: this function is never used
#if 0
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) { void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
if (color.a == 0) { return; } if (color.a == 0) { return; }
@ -304,7 +362,7 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color)
} }
/* draw */ /* draw */
SDL_Surface *surf = SDL_GetWindowSurface(window); SDL_Surface *surf = get_window_surface(window); //SDL_GetWindowSurface(window);
RenColor *s = image->pixels; RenColor *s = image->pixels;
RenColor *d = (RenColor*) surf->pixels; RenColor *d = (RenColor*) surf->pixels;
s += sub->x + sub->y * image->width; s += sub->x + sub->y * image->width;
@ -322,6 +380,7 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color)
s += sr; s += sr;
} }
} }
#endif
static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) { static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) {
for (int i = 0; i < rep_table->size; i++) { for (int i = 0; i < rep_table->size; i++) {
@ -340,7 +399,7 @@ void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int
{ {
const char *p = text; const char *p = text;
unsigned codepoint; unsigned codepoint;
SDL_Surface *surf = SDL_GetWindowSurface(window); SDL_Surface *surf = get_window_surface(window); // SDL_GetWindowSurface(window);
const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b }; const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
while (*p) { while (*p) {
FR_Color color_rep; FR_Color color_rep;