~mil/mepo

7764125f31dc0fd74f3335025551cf88f9f2ba76 — Miles Alan 2 years ago 82bd707 highdpi-debugging
Working POC for highdpi - store background tiles to surfaces; not as textures

GPU based SDL renderering must occur within a single thread; for the
software renderer it seems texture access / using the renderer across
multiple threads works fine but with SDL_RENDERER_ACCELERATED doing this
causes intermittent crashes.

This POC changes the background curl logic to load downloaded tiles
to surfaces and then within the primary (UI/rendering) thread load
to textures on the fly as needed. Will need cleanup to properly clear
old textures/surfaces; however this change does succesfully remove the
intermittent crashes while using SDL_RENDERER_ACCELERATED (which is more
compatible with wayland high-dpi scaling).
1 files changed, 19 insertions(+), 15 deletions(-)

M src/TileCache.zig
M src/TileCache.zig => src/TileCache.zig +19 -15
@@ 28,7 28,7 @@ const TransferDatum = struct {
    data_arraylist: std.ArrayList(u8),
    progress_dl_now: ?c_long,
    progress_dl_total: ?c_long,
    load_to_texture: bool,
    load_to_surface: bool,
};
const TileData = union(TileDataTag) {
    transfer_datum: TransferDatum,


@@ 53,6 53,7 @@ queue_lifo_bg: datastructure.QueueHashMap(types.XYZ, void),
renderer: ?*sdl.SDL_Renderer = null,
source_url: [:0]const u8 = undefned,
texture_map: datastructure.QueueHashMap(types.XYZ, *sdl.SDL_Texture),
surface_map: datastructure.QueueHashMap(types.XYZ, *sdl.SDL_Surface),
transfer_map: datastructure.QueueHashMap(types.XYZ, *TransferDatum),

/// Downloads tiles continuously


@@ 242,6 243,10 @@ pub fn tile_ui_retreive_or_queue(tile_cache: *@This(), coords: types.XYZ) !TileD

    if (tile_cache.texture_map.get(coords)) |tile| {
        return TileData{ .texture = tile };
    } else if (tile_cache.surface_map.get(coords)) |surface| {
        const texture = try utilsdl.errorcheck_ptr(sdl.SDL_Texture, sdl.SDL_CreateTextureFromSurface(tile_cache.renderer, surface));
        try tile_cache.texture_map.put(coords, texture);
        return TileData{ .texture = texture };
    } else if (tile_cache.transfer_map.get(coords)) |transfer| {
        return TileData{ .transfer_datum = transfer.* };
    } else if (tile_cache.cache_dir) |cache_dir| load_from_fs: {


@@ 255,10 260,12 @@ pub fn tile_ui_retreive_or_queue(tile_cache: *@This(), coords: types.XYZ) !TileD
            file_cached_png_opt = cache_dir.readFileAlloc(tile_cache.allocator, png, 500000) catch null;
            if (file_cached_png_opt) |file_cached_png| {
                defer tile_cache.allocator.free(file_cached_png);
                const text = tile_cache.load_data_to_texture(coords, file_cached_png) catch {
                const surface = tile_cache.load_data_to_surface(coords, file_cached_png) catch {
                    break :load_from_fs;
                };
                return TileData{ .texture = text };
                const texture = try utilsdl.errorcheck_ptr(sdl.SDL_Texture, sdl.SDL_CreateTextureFromSurface(tile_cache.renderer, surface));
                try tile_cache.texture_map.put(coords, texture);
                return TileData{ .texture = texture };
            }
        }
    }


@@ 276,7 283,7 @@ pub fn tile_ui_retreive_or_queue(tile_cache: *@This(), coords: types.XYZ) !TileD
// ////////////////////////////////////////////////////////////////////////////
// Private

fn curl_add_to_multi_and_register_transfer(tile_cache: *@This(), coords: types.XYZ, load_to_texture: bool) !void {
fn curl_add_to_multi_and_register_transfer(tile_cache: *@This(), coords: types.XYZ, load_to_surface: bool) !void {
    if (tile_cache.transfer_map.get(coords)) |_| return;

    var transfer_datum: *TransferDatum = datum: {


@@ 286,7 293,7 @@ fn curl_add_to_multi_and_register_transfer(tile_cache: *@This(), coords: types.X
        dat.data_arraylist = std.ArrayList(u8).init(tile_cache.allocator);
        dat.progress_dl_now = null;
        dat.progress_dl_total = null;
        dat.load_to_texture = load_to_texture;
        dat.load_to_surface = load_to_surface;
        break :datum dat;
    };
    try tile_cache.transfer_map.put(coords, transfer_datum);


@@ 411,9 418,9 @@ fn download_loop_transfer_complete(tile_cache: *@This(), msg: *curl.CURLMsg) !vo
                    const path = try png_path(tile_cache.allocator, tile_cache.source_url, coords);
                    try cache_dir.writeFile(path, datum_array);
                }
                if (tile_cache.transfer_map.get(coords).?.load_to_texture) {
                if (tile_cache.transfer_map.get(coords).?.load_to_surface) {
                    // Load to surface
                    _ = try tile_cache.load_data_to_texture(coords, datum_array);
                    _ = try tile_cache.load_data_to_surface(coords, datum_array);
                    utilsdl.sdl_push_resize_event();
                }
            } else {


@@ 444,18 451,14 @@ fn download_loop_transfer_cleanup(tile_cache: *@This(), client: ?*curl.CURL) !vo
    }
}

fn load_data_to_texture(tile_cache: *@This(), coords: types.XYZ, data: []u8) !*sdl.SDL_Texture {
fn load_data_to_surface(tile_cache: *@This(), coords: types.XYZ, data: []u8) !*sdl.SDL_Surface {
    if (data.len == 0) return error.LoadToSurfaceFailEmptyData;

    const memory = try utilsdl.errorcheck_ptr(sdl.SDL_RWops, sdl.SDL_RWFromConstMem(@ptrCast(*c_void, &data[0]), @intCast(c_int, data.len)));
    const surface = try utilsdl.errorcheck_ptr(sdl.SDL_Surface, sdl.IMG_Load_RW(memory, 1));
    defer sdl.SDL_FreeSurface(surface);
    const texture = try utilsdl.errorcheck_ptr(sdl.SDL_Texture, sdl.SDL_CreateTextureFromSurface(tile_cache.renderer, surface));
    // TODO: should there be some limit on size of texture map cache?
    //       currently memory will just accumulate there ad-infinitum
    //defer sdl.SDL_DestroyTexture(texture);
    try tile_cache.texture_map.put(coords, texture);
    return tile_cache.texture_map.get(coords).?;

    try tile_cache.surface_map.put(coords, surface);
    return tile_cache.surface_map.get(coords).?;
}

fn png_path(allocator: *std.mem.Allocator, source: []const u8, coords: types.XYZ) ![]u8 {


@@ 513,6 516,7 @@ pub fn init(allocator: *std.mem.Allocator) anyerror!@This() {
            .queue_lifo_ui = datastructure.QueueHashMap(types.XYZ, void).init(allocator),
            .queue_lifo_bg = datastructure.QueueHashMap(types.XYZ, void).init(allocator),
            .texture_map = datastructure.QueueHashMap(types.XYZ, *sdl.SDL_Texture).init(allocator),
            .surface_map = datastructure.QueueHashMap(types.XYZ, *sdl.SDL_Surface).init(allocator),
            .transfer_map = datastructure.QueueHashMap(types.XYZ, *TransferDatum).init(allocator),
        });
    } else {