Skip to content

Commit

Permalink
Fix most mode 0 bugs in the sdlaccel renderer.
Browse files Browse the repository at this point in the history
  • Loading branch information
AliceLR committed Jan 24, 2024
1 parent e93bfa6 commit 51d2e92
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 53 deletions.
5 changes: 2 additions & 3 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ DEVELOPERS
+ Updated the "sdlaccel" renderer, which can now be enabled with
--enable-sdlaccel in config.sh. This renderer uses the SDL
renderer API for hardware rendering and has an experimental
threaded charset texture update routine. It is still buggy,
SMZX isn't implemented yet, and it's too slow to be useful for
users, so it's disabled by default.
threaded charset texture update routine. SMZX isn't currently
implemented and it's slow, so it's disabled by default.
+ Moved SDL renderer window creation to render_sdl.c so both of
the SDL renderer-based renderers can benefit from it.
+ Removed floating point division usage in render_gl2.c.
Expand Down
28 changes: 14 additions & 14 deletions src/render_sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ void sdl_destruct_window(struct graphics_data *graphics)
struct sdl_render_data *render_data = graphics->render_data;

#if SDL_VERSION_ATLEAST(2,0,0)
size_t i;

// Used by the software renderer as a fallback if the window surface doesn't
// match the pixel format MZX wants.
Expand All @@ -319,18 +320,14 @@ void sdl_destruct_window(struct graphics_data *graphics)
render_data->pixel_format = NULL;
}

// Used by the softscale renderer for HW acceleration.
if(render_data->texture)
// Used by the SDL renderer-based renderers for HW acceleration.
for(i = 0; i < ARRAY_SIZE(render_data->texture); i++)
{
SDL_DestroyTexture(render_data->texture);
render_data->texture = NULL;
}

// Used by the SDL hardware accelerated renderer in mode 0.
if(render_data->texture2)
{
SDL_DestroyTexture(render_data->texture2);
render_data->texture2 = NULL;
if(render_data->texture[i])
{
SDL_DestroyTexture(render_data->texture[i]);
render_data->texture[i] = NULL;
}
}

// Used by the softscale renderer for HW acceleration. Don't use for software.
Expand Down Expand Up @@ -670,7 +667,8 @@ static void find_texture_format(struct graphics_data *graphics)
* on the scaling ratio and window size.
*/
boolean sdlrender_set_video_mode(struct graphics_data *graphics,
int width, int height, int depth, boolean fullscreen, boolean resize)
int width, int height, int depth, boolean fullscreen, boolean resize,
uint32_t sdl_rendererflags)
{
struct sdl_render_data *render_data = graphics->render_data;
boolean fullscreen_windowed = graphics->fullscreen_windowed;
Expand Down Expand Up @@ -706,12 +704,14 @@ boolean sdlrender_set_video_mode(struct graphics_data *graphics,
}

render_data->renderer =
SDL_CreateRenderer(render_data->window, BEST_RENDERER, SDL_RENDERER_ACCELERATED);
SDL_CreateRenderer(render_data->window, BEST_RENDERER,
SDL_RENDERER_ACCELERATED | sdl_rendererflags);

if(!render_data->renderer)
{
render_data->renderer =
SDL_CreateRenderer(render_data->window, BEST_RENDERER, SDL_RENDERER_SOFTWARE);
SDL_CreateRenderer(render_data->window, BEST_RENDERER,
SDL_RENDERER_SOFTWARE | sdl_rendererflags);

if(!render_data->renderer)
{
Expand Down
6 changes: 3 additions & 3 deletions src/render_sdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ struct sdl_render_data
{
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_Renderer *renderer;
SDL_Texture *texture;
SDL_Texture *texture2;
SDL_Texture *texture[3];
SDL_Palette *palette;
SDL_Window *window;
SDL_GLContext context;
Expand Down Expand Up @@ -77,7 +76,8 @@ boolean sdl_check_video_mode(struct graphics_data *graphics, int width,

#if SDL_VERSION_ATLEAST(2,0,0)
boolean sdlrender_set_video_mode(struct graphics_data *graphics,
int width, int height, int depth, boolean fullscreen, boolean resize);
int width, int height, int depth, boolean fullscreen, boolean resize,
uint32_t sdl_rendererflags);

void sdlrender_update_colors(struct graphics_data *graphics,
struct rgb_color *palette, unsigned int count);
Expand Down
98 changes: 71 additions & 27 deletions src/render_sdlaccel.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
* be useful to keep around for reference. SMZX is not implemented yet.
*
* The old SDL_RenderTexture implementation (<2.0.18) is just plain slow.
* SDL_RenderGeometry seems support depth buffering, but large foreground
* layers stop working in busy scenes for some reason. Even this is about
* half to one third the speed of the opengl2 renderer.
* SDL_RenderGeometry is better, but not enough to justify using it currently.
*
* The other main performance problem here is writes to the chars texture.
* There's no compelling way to make it faster, and even a few rows updated can
Expand All @@ -47,6 +45,10 @@
#define RENDER_GEOMETRY
#endif

#define TEX_SCREEN 0
#define TEX_CHARS 1
#define TEX_BACKGROUND 2

// 32 * 6 * 8 = 1536 px
// 128 * 1 * 14 = 1792 px
#define CHARS_ROW_SIZE 32
Expand All @@ -67,6 +69,9 @@
#define TEX_CHAR_W ((float)CHAR_W / 2048.0)
#define TEX_CHAR_H ((float)CHAR_H / 2048.0)

#define TEX_SCREEN_W 1024
#define TEX_SCREEN_H 512

#define TEX_BG_W 128
#define TEX_BG_H 32

Expand Down Expand Up @@ -101,6 +106,8 @@ struct sdlaccel_render_data
boolean chars_needed_row[CHARS_NUM_ROWS];
boolean join;
#endif
int w;
int h;
};

static void write_char_byte_mzx(uint32_t **_char_data, uint8_t byte)
Expand Down Expand Up @@ -259,6 +266,8 @@ static boolean sdlaccel_init_video(struct graphics_data *graphics,
memset(render_data->chars_dirty_row, true, CHARS_NUM_ROWS);
render_data->chars_dirty = true;
graphics->render_data = render_data;
graphics->allow_resize = conf->allow_resize;
graphics->ratio = conf->video_ratio;
graphics->bits_per_pixel = 32;

if(!set_video_mode())
Expand Down Expand Up @@ -287,18 +296,27 @@ static boolean sdlaccel_set_video_mode(struct graphics_data *graphics,
struct sdlaccel_render_data *render_data =
(struct sdlaccel_render_data *)graphics->render_data;

SDL_Rect screen = { 0, 0, SCREEN_PIX_W, SCREEN_PIX_H };
SDL_Texture **texture = render_data->sdl.texture;
int tex_chars_w;
int tex_chars_h;

if(!sdlrender_set_video_mode(graphics, width, height, depth, fullscreen, resize))
// This requires that the underlying driver supports framebuffer objects.
if(!sdlrender_set_video_mode(graphics, width, height,
depth, fullscreen, resize, SDL_RENDERER_TARGETTEXTURE))
return false;

if(SDL_RenderSetLogicalSize(render_data->sdl.renderer, screen.w, screen.h))
warn("Failed to set renderer locical size!\n");
texture[TEX_SCREEN] =
SDL_CreateTexture(render_data->sdl.renderer, render_data->sdl.texture_format,
SDL_TEXTUREACCESS_TARGET, TEX_SCREEN_W, TEX_SCREEN_H);

if(!texture[TEX_SCREEN])
{
warn("Failed to create screen texture: %s\n", SDL_GetError());
goto err_free;
}

if(SDL_RenderSetClipRect(render_data->sdl.renderer, &screen))
warn("Failed to set clip rectangle!\n");
// Always use nearest neighbor for the charset and background textures.
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");

tex_chars_w = round_to_power_of_two(TEX_CHARS_PIX_W);
tex_chars_h = round_to_power_of_two(TEX_CHARS_PIX_H);
Expand All @@ -310,32 +328,35 @@ static boolean sdlaccel_set_video_mode(struct graphics_data *graphics,
// requires locking the whole thing, after which the whole thing will be
// uploaded (SLOW). It's better for the typical use case to write to a
// smaller local version and only upload recently updated parts.
render_data->sdl.texture =
texture[TEX_CHARS] =
SDL_CreateTexture(render_data->sdl.renderer, render_data->sdl.texture_format,
SDL_TEXTUREACCESS_STREAMING, tex_chars_w, tex_chars_h);

if(!render_data->sdl.texture)
if(!texture[TEX_CHARS])
{
warn("Failed to create texture: %s\n", SDL_GetError());
goto err_free;
}

// Initialize the background texture.
render_data->sdl.texture2 =
texture[TEX_BACKGROUND] =
SDL_CreateTexture(render_data->sdl.renderer, render_data->sdl.texture_format,
SDL_TEXTUREACCESS_STREAMING, TEX_BG_W, TEX_BG_H);

if(!render_data->sdl.texture2)
if(!texture[TEX_BACKGROUND])
{
warn("Failed to create texture2: %s\n", SDL_GetError());
goto err_free;
}

if(SDL_SetTextureBlendMode(render_data->sdl.texture, SDL_BLENDMODE_BLEND))
warn("Failed to set texture blend mode: %s\n", SDL_GetError());
if(SDL_SetTextureBlendMode(render_data->sdl.texture2, SDL_BLENDMODE_BLEND))
warn("Failed to set texture2 blend mode: %s\n", SDL_GetError());
if(SDL_SetTextureBlendMode(texture[TEX_CHARS], SDL_BLENDMODE_BLEND))
warn("Failed to set char texture blend mode: %s\n", SDL_GetError());
if(SDL_SetTextureBlendMode(texture[TEX_BACKGROUND], SDL_BLENDMODE_BLEND))
warn("Failed to set bg texture blend mode: %s\n", SDL_GetError());

SDL_SetRenderTarget(render_data->sdl.renderer, texture[TEX_SCREEN]);
render_data->w = width;
render_data->h = height;
return true;

err_free:
Expand Down Expand Up @@ -419,11 +440,11 @@ static void sdlaccel_do_remap_chars(struct graphics_data *graphics,
if(render_data->chars_dirty_row[i])
{
rect.y = i * CHAR_H;
SDL_LockTexture(render_data->sdl.texture, &rect, &pixels, &pitch);
SDL_LockTexture(render_data->sdl.texture[TEX_CHARS], &rect, &pixels, &pitch);

sdlaccel_do_remap_row(graphics, render_data, pixels, pitch, i);

SDL_UnlockTexture(render_data->sdl.texture);
SDL_UnlockTexture(render_data->sdl.texture[TEX_CHARS]);
render_data->chars_dirty_row[i] = false;
}
}
Expand Down Expand Up @@ -459,7 +480,7 @@ static void sdlaccel_do_remap_chars(struct graphics_data *graphics,

rect.y = start * CHAR_H;
rect.h = (i - start) * CHARS_RAW_ROW_H;
SDL_UpdateTexture(render_data->sdl.texture, &rect, pixels, pitch);
SDL_UpdateTexture(render_data->sdl.texture[TEX_CHARS], &rect, pixels, pitch);
}
}

Expand Down Expand Up @@ -506,7 +527,7 @@ static void sdlaccel_set_color(struct graphics_data *graphics, int color, int mo
if(!mode && color >= 16)
color = graphics->protected_pal_position + (color % 16);

SDL_SetTextureColorMod(render_data->sdl.texture,
SDL_SetTextureColorMod(render_data->sdl.texture[TEX_CHARS],
palette[color * 3], palette[color * 3 + 1], palette[color * 3 + 2]);
}

Expand All @@ -527,8 +548,8 @@ static void sdlaccel_render_layer(struct graphics_data *graphics,
unsigned chr;

SDL_Renderer *renderer = render_data->sdl.renderer;
SDL_Texture *chars_tex = render_data->sdl.texture;
SDL_Texture *bg_tex = render_data->sdl.texture2;
SDL_Texture *chars_tex = render_data->sdl.texture[TEX_CHARS];
SDL_Texture *bg_tex = render_data->sdl.texture[TEX_BACKGROUND];

SDL_Rect dest_bg = { offx, offy, w * CHAR_W, h * CHAR_H };
SDL_Rect src_bg = { 0, 0, w, h };
Expand Down Expand Up @@ -593,7 +614,7 @@ static void sdlaccel_render_layer(struct graphics_data *graphics,
if(next->bg_color != transparent_color)
{
color = next->bg_color;
tex_x += CHAR_W;
tex_x += TEX_CHAR_W;
}
else
continue;
Expand Down Expand Up @@ -715,11 +736,34 @@ static void sdlaccel_render_mouse(struct graphics_data *graphics, unsigned x,
static void sdlaccel_sync_screen(struct graphics_data *graphics)
{
struct sdlaccel_render_data *render_data = graphics->render_data;
SDL_Renderer *renderer = render_data->sdl.renderer;
SDL_Texture *screen_tex = render_data->sdl.texture[TEX_SCREEN];
SDL_Rect src;
SDL_Rect dest;
int width = render_data->w;
int height = render_data->h;
int v_width, v_height;

src.x = 0;
src.y = 0;
src.w = SCREEN_PIX_W;
src.h = SCREEN_PIX_H;

fix_viewport_ratio(width, height, &v_width, &v_height, graphics->ratio);
dest.x = (width - v_width) / 2;
dest.y = (height - v_height) / 2;
dest.w = v_width;
dest.h = v_height;

SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, screen_tex, &src, &dest);

SDL_RenderPresent(renderer);

SDL_RenderPresent(render_data->sdl.renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);

SDL_SetRenderDrawColor(render_data->sdl.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(render_data->sdl.renderer);
SDL_SetRenderTarget(renderer, screen_tex);
}

void render_sdlaccel_register(struct renderer *renderer)
Expand Down
13 changes: 7 additions & 6 deletions src/render_softscale.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ static boolean softscale_set_video_mode(struct graphics_data *graphics,
struct softscale_render_data *render_data =
(struct softscale_render_data *)graphics->render_data;

if(!sdlrender_set_video_mode(graphics, width, height, depth, fullscreen, resize))
if(!sdlrender_set_video_mode(graphics, width, height,
depth, fullscreen, resize, 0))
return false;

// YUV texture modes are effectively 16-bit to SDL, but MegaZeux treats them
Expand All @@ -107,11 +108,11 @@ static boolean softscale_set_video_mode(struct graphics_data *graphics,
render_data->texture_pixels = NULL;

// Initialize the screen texture.
render_data->sdl.texture =
render_data->sdl.texture[0] =
SDL_CreateTexture(render_data->sdl.renderer, render_data->sdl.texture_format,
SDL_TEXTUREACCESS_STREAMING, render_data->texture_width, SCREEN_PIX_H);

if(!render_data->sdl.texture)
if(!render_data->sdl.texture[0])
{
warn("Failed to create texture: %s\n", SDL_GetError());
goto err_free;
Expand Down Expand Up @@ -155,7 +156,7 @@ static void softscale_lock_texture(struct softscale_render_data *render_data,
else
render_data->enable_subsampling = false;

SDL_LockTexture(render_data->sdl.texture, texture_rect, &pixels, &pitch);
SDL_LockTexture(render_data->sdl.texture[0], texture_rect, &pixels, &pitch);
render_data->texture_pixels = pixels;
render_data->texture_pitch = pitch;
}
Expand All @@ -173,7 +174,7 @@ static void softscale_unlock_texture(struct softscale_render_data *render_data)
{
if(render_data->texture_pixels)
{
SDL_UnlockTexture(render_data->sdl.texture);
SDL_UnlockTexture(render_data->sdl.texture[0]);
render_data->texture_pixels = NULL;
}
}
Expand Down Expand Up @@ -263,7 +264,7 @@ static void softscale_sync_screen(struct graphics_data *graphics)
{
struct softscale_render_data *render_data = graphics->render_data;
SDL_Renderer *renderer = render_data->sdl.renderer;
SDL_Texture *texture = render_data->sdl.texture;
SDL_Texture *texture = render_data->sdl.texture[0];
SDL_Rect *src_rect = &(render_data->texture_rect);
SDL_Rect dest_rect;
int width = render_data->w;
Expand Down

0 comments on commit 51d2e92

Please sign in to comment.