- Make image result/info structs readonly; improve error handling and memory safety in image library - Introduce IJobScheduler interface; move job scheduling docs to interface - Remove "index 0 invalid" convention from slot/sparse maps; fix Count logic - Add Owner<T> for disposable value types in low-level utilities - Improve ObjectPool<T> thread safety and logic - Change List<T>.RemoveAndSwapBack to return bool - Remove unsafe methods from generated math types; add debug range checks - Update benchmarks and enable collection checks in tests - Improve documentation, comments, and error messages - Bump assembly versions across all projects
681 lines
22 KiB
C#
681 lines
22 KiB
C#
// Generated by Sichem at 12/24/2021 8:28:15 PM
|
|
|
|
using Misaki.HighPerformance.Image.Runtime;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Misaki.HighPerformance.Image
|
|
{
|
|
public unsafe partial class StbImage
|
|
{
|
|
public static int stbi__gif_test(stbi__context s)
|
|
{
|
|
var r = stbi__gif_test_raw(s);
|
|
stbi__rewind(s);
|
|
return r;
|
|
}
|
|
|
|
public static void* stbi__gif_load(stbi__context s, int* x, int* y, int* comp, int req_comp,
|
|
stbi__result_info* ri)
|
|
{
|
|
byte* u = null;
|
|
var g = new stbi__gif();
|
|
u = stbi__gif_load_next(s, g, comp, req_comp, null);
|
|
if (u != null)
|
|
{
|
|
*x = g.w;
|
|
*y = g.h;
|
|
if (req_comp != 0 && req_comp != 4)
|
|
{
|
|
u = stbi__convert_format(u, 4, req_comp, (uint)g.w, (uint)g.h);
|
|
}
|
|
}
|
|
else if (g._out_ != null)
|
|
{
|
|
CRuntime.free(g._out_);
|
|
}
|
|
|
|
CRuntime.free(g.history);
|
|
CRuntime.free(g.background);
|
|
return u;
|
|
}
|
|
|
|
public static void* stbi__load_gif_main(stbi__context s, int** delays, int* x, int* y, int* z, int* comp,
|
|
int req_comp)
|
|
{
|
|
if (stbi__gif_test(s) != 0)
|
|
{
|
|
var layers = 0;
|
|
byte* u = null;
|
|
byte* _out_ = null;
|
|
byte* two_back = null;
|
|
var g = new stbi__gif();
|
|
var stride = 0;
|
|
var out_size = 0;
|
|
var delays_size = 0;
|
|
if (delays != null)
|
|
{
|
|
*delays = null;
|
|
}
|
|
|
|
do
|
|
{
|
|
u = stbi__gif_load_next(s, g, comp, req_comp, two_back);
|
|
if (u != null)
|
|
{
|
|
*x = g.w;
|
|
*y = g.h;
|
|
++layers;
|
|
stride = g.w * g.h * 4;
|
|
if (_out_ != null)
|
|
{
|
|
void* tmp = (byte*)CRuntime.realloc(_out_, (ulong)(layers * stride));
|
|
if (tmp == null)
|
|
{
|
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
|
}
|
|
|
|
_out_ = (byte*)tmp;
|
|
out_size = layers * stride;
|
|
if (delays != null)
|
|
{
|
|
var new_delays = (int*)CRuntime.realloc(*delays, (ulong)(sizeof(int) * layers));
|
|
if (new_delays == null)
|
|
{
|
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
|
}
|
|
|
|
*delays = new_delays;
|
|
delays_size = layers * sizeof(int);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_out_ = (byte*)stbi__malloc((ulong)(layers * stride));
|
|
if (_out_ == null)
|
|
{
|
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
|
}
|
|
|
|
out_size = layers * stride;
|
|
if (delays != null)
|
|
{
|
|
*delays = (int*)stbi__malloc((ulong)(layers * sizeof(int)));
|
|
if (*delays == null)
|
|
{
|
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
|
}
|
|
|
|
delays_size = layers * sizeof(int);
|
|
}
|
|
}
|
|
|
|
CRuntime.memcpy(_out_ + (layers - 1) * stride, u, (ulong)stride);
|
|
if (layers >= 2)
|
|
{
|
|
two_back = _out_ - 2 * stride;
|
|
}
|
|
|
|
if (delays != null)
|
|
{
|
|
(*delays)[layers - 1U] = g.delay;
|
|
}
|
|
}
|
|
} while (u != null);
|
|
|
|
CRuntime.free(g._out_);
|
|
CRuntime.free(g.history);
|
|
CRuntime.free(g.background);
|
|
if (req_comp != 0 && req_comp != 4)
|
|
{
|
|
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)(layers * g.w), (uint)g.h);
|
|
}
|
|
|
|
*z = layers;
|
|
return _out_;
|
|
}
|
|
|
|
return (byte*)(ulong)(stbi__err("not GIF") != 0 ? 0 : 0);
|
|
}
|
|
|
|
public static int stbi__gif_info(stbi__context s, int* x, int* y, int* comp)
|
|
{
|
|
return stbi__gif_info_raw(s, x, y, comp);
|
|
}
|
|
|
|
public static int stbi__gif_test_raw(stbi__context s)
|
|
{
|
|
var sz = 0;
|
|
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
sz = stbi__get8(s);
|
|
if (sz != 57 && sz != 55)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (stbi__get8(s) != 97)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
public static void stbi__gif_parse_colortable(stbi__context s, byte[][] pal, int num_entries, int transp)
|
|
{
|
|
var i = 0;
|
|
for (i = 0; i < num_entries; ++i)
|
|
{
|
|
pal[i][2] = stbi__get8(s);
|
|
pal[i][1] = stbi__get8(s);
|
|
pal[i][0] = stbi__get8(s);
|
|
pal[i][3] = (byte)(transp == i ? 0 : 255);
|
|
}
|
|
}
|
|
|
|
public static int stbi__gif_header(stbi__context s, stbi__gif g, int* comp, int is_info)
|
|
{
|
|
byte version = 0;
|
|
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
|
{
|
|
return stbi__err("not GIF");
|
|
}
|
|
|
|
version = stbi__get8(s);
|
|
if (version != 55 && version != 57)
|
|
{
|
|
return stbi__err("not GIF");
|
|
}
|
|
|
|
if (stbi__get8(s) != 97)
|
|
{
|
|
return stbi__err("not GIF");
|
|
}
|
|
|
|
stbi__g_failure_reason = "";
|
|
g.w = stbi__get16le(s);
|
|
g.h = stbi__get16le(s);
|
|
g.flags = stbi__get8(s);
|
|
g.bgindex = stbi__get8(s);
|
|
g.ratio = stbi__get8(s);
|
|
g.transparent = -1;
|
|
if (g.w > 1 << 24)
|
|
{
|
|
return stbi__err("too large");
|
|
}
|
|
|
|
if (g.h > 1 << 24)
|
|
{
|
|
return stbi__err("too large");
|
|
}
|
|
|
|
if (comp != null)
|
|
{
|
|
*comp = 4;
|
|
}
|
|
|
|
if (is_info != 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if ((g.flags & 0x80) != 0)
|
|
{
|
|
stbi__gif_parse_colortable(s, g.pal, 2 << (g.flags & 7), -1);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
public static int stbi__gif_info_raw(stbi__context s, int* x, int* y, int* comp)
|
|
{
|
|
var g = new stbi__gif();
|
|
if (g == null)
|
|
{
|
|
return stbi__err("outofmem");
|
|
}
|
|
|
|
if (stbi__gif_header(s, g, comp, 1) == 0)
|
|
{
|
|
stbi__rewind(s);
|
|
return 0;
|
|
}
|
|
|
|
if (x != null)
|
|
{
|
|
*x = g.w;
|
|
}
|
|
|
|
if (y != null)
|
|
{
|
|
*y = g.h;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
public static void stbi__out_gif_code(stbi__gif g, ushort code)
|
|
{
|
|
byte* p;
|
|
var idx = 0;
|
|
if (g.codes[code].prefix >= 0)
|
|
{
|
|
stbi__out_gif_code(g, (ushort)g.codes[code].prefix);
|
|
}
|
|
|
|
if (g.cur_y >= g.max_y)
|
|
{
|
|
return;
|
|
}
|
|
|
|
idx = g.cur_x + g.cur_y;
|
|
p = &g._out_[idx];
|
|
g.history[idx / 4] = 1;
|
|
var c = g.color_table[g.codes[code].suffix];
|
|
if (c[3] > 128)
|
|
{
|
|
p[0] = c[2];
|
|
p[1] = c[1];
|
|
p[2] = c[0];
|
|
p[3] = c[3];
|
|
}
|
|
|
|
g.cur_x += 4;
|
|
if (g.cur_x >= g.max_x)
|
|
{
|
|
g.cur_x = g.start_x;
|
|
g.cur_y += g.step;
|
|
while (g.cur_y >= g.max_y && g.parse > 0)
|
|
{
|
|
g.step = (1 << g.parse) * g.line_size;
|
|
g.cur_y = g.start_y + (g.step >> 1);
|
|
--g.parse;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static byte* stbi__process_gif_raster(stbi__context s, stbi__gif g)
|
|
{
|
|
byte lzw_cs = 0;
|
|
var len = 0;
|
|
var init_code = 0;
|
|
uint first = 0;
|
|
var codesize = 0;
|
|
var codemask = 0;
|
|
var avail = 0;
|
|
var oldcode = 0;
|
|
var bits = 0;
|
|
var valid_bits = 0;
|
|
var clear = 0;
|
|
stbi__gif_lzw* p;
|
|
lzw_cs = stbi__get8(s);
|
|
if (lzw_cs > 12)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
clear = 1 << lzw_cs;
|
|
first = 1;
|
|
codesize = lzw_cs + 1;
|
|
codemask = (1 << codesize) - 1;
|
|
bits = 0;
|
|
valid_bits = 0;
|
|
for (init_code = 0; init_code < clear; init_code++)
|
|
{
|
|
g.codes[init_code].prefix = -1;
|
|
g.codes[init_code].first = (byte)init_code;
|
|
g.codes[init_code].suffix = (byte)init_code;
|
|
}
|
|
|
|
avail = clear + 2;
|
|
oldcode = -1;
|
|
len = 0;
|
|
for (; ; )
|
|
{
|
|
if (valid_bits < codesize)
|
|
{
|
|
if (len == 0)
|
|
{
|
|
len = stbi__get8(s);
|
|
if (len == 0)
|
|
{
|
|
return g._out_;
|
|
}
|
|
}
|
|
|
|
--len;
|
|
bits |= stbi__get8(s) << valid_bits;
|
|
valid_bits += 8;
|
|
}
|
|
else
|
|
{
|
|
var code = bits & codemask;
|
|
bits >>= codesize;
|
|
valid_bits -= codesize;
|
|
if (code == clear)
|
|
{
|
|
codesize = lzw_cs + 1;
|
|
codemask = (1 << codesize) - 1;
|
|
avail = clear + 2;
|
|
oldcode = -1;
|
|
first = 0;
|
|
}
|
|
else if (code == clear + 1)
|
|
{
|
|
stbi__skip(s, len);
|
|
while ((len = stbi__get8(s)) > 0)
|
|
{
|
|
stbi__skip(s, len);
|
|
}
|
|
|
|
return g._out_;
|
|
}
|
|
else if (code <= avail)
|
|
{
|
|
if (first != 0)
|
|
{
|
|
return (byte*)(ulong)(stbi__err("no clear code") != 0 ? 0 : 0);
|
|
}
|
|
|
|
if (oldcode >= 0)
|
|
{
|
|
fixed (stbi__gif_lzw* p2 = &g.codes[avail++])
|
|
{
|
|
p = p2;
|
|
if (avail > 8192)
|
|
{
|
|
return (byte*)(ulong)(stbi__err("too many codes") != 0 ? 0 : 0);
|
|
}
|
|
|
|
p->prefix = (short)oldcode;
|
|
p->first = g.codes[oldcode].first;
|
|
p->suffix = code == avail ? p->first : g.codes[code].first;
|
|
}
|
|
}
|
|
else if (code == avail)
|
|
{
|
|
return (byte*)(ulong)(stbi__err("illegal code in raster") != 0 ? 0 : 0);
|
|
}
|
|
|
|
stbi__out_gif_code(g, (ushort)code);
|
|
if ((avail & codemask) == 0 && avail <= 0x0FFF)
|
|
{
|
|
codesize++;
|
|
codemask = (1 << codesize) - 1;
|
|
}
|
|
|
|
oldcode = code;
|
|
}
|
|
else
|
|
{
|
|
return (byte*)(ulong)(stbi__err("illegal code in raster") != 0 ? 0 : 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static byte* stbi__gif_load_next(stbi__context s, stbi__gif g, int* comp, int req_comp, byte* two_back)
|
|
{
|
|
var dispose = 0;
|
|
var first_frame = 0;
|
|
var pi = 0;
|
|
var pcount = 0;
|
|
first_frame = 0;
|
|
if (g._out_ == null)
|
|
{
|
|
if (stbi__gif_header(s, g, comp, 0) == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (stbi__mad3sizes_valid(4, g.w, g.h, 0) == 0)
|
|
{
|
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
|
}
|
|
|
|
pcount = g.w * g.h;
|
|
g._out_ = (byte*)stbi__malloc((ulong)(4 * pcount));
|
|
g.background = (byte*)stbi__malloc((ulong)(4 * pcount));
|
|
g.history = (byte*)stbi__malloc((ulong)pcount);
|
|
if (g._out_ == null || g.background == null || g.history == null)
|
|
{
|
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
|
}
|
|
|
|
CRuntime.memset(g._out_, 0x00, (ulong)(4 * pcount));
|
|
CRuntime.memset(g.background, 0x00, (ulong)(4 * pcount));
|
|
CRuntime.memset(g.history, 0x00, (ulong)pcount);
|
|
first_frame = 1;
|
|
}
|
|
else
|
|
{
|
|
dispose = (g.eflags & 0x1C) >> 2;
|
|
pcount = g.w * g.h;
|
|
if (dispose == 3 && two_back == null)
|
|
{
|
|
dispose = 2;
|
|
}
|
|
|
|
if (dispose == 3)
|
|
{
|
|
for (pi = 0; pi < pcount; ++pi)
|
|
{
|
|
if (g.history[pi] != 0)
|
|
{
|
|
CRuntime.memcpy(&g._out_[pi * 4], &two_back[pi * 4], (ulong)4);
|
|
}
|
|
}
|
|
}
|
|
else if (dispose == 2)
|
|
{
|
|
for (pi = 0; pi < pcount; ++pi)
|
|
{
|
|
if (g.history[pi] != 0)
|
|
{
|
|
CRuntime.memcpy(&g._out_[pi * 4], &g.background[pi * 4], (ulong)4);
|
|
}
|
|
}
|
|
}
|
|
|
|
CRuntime.memcpy(g.background, g._out_, (ulong)(4 * g.w * g.h));
|
|
}
|
|
|
|
CRuntime.memset(g.history, 0x00, (ulong)(g.w * g.h));
|
|
for (; ; )
|
|
{
|
|
int tag = stbi__get8(s);
|
|
switch (tag)
|
|
{
|
|
case 0x2C:
|
|
{
|
|
var x = 0;
|
|
var y = 0;
|
|
var w = 0;
|
|
var h = 0;
|
|
byte* o;
|
|
x = stbi__get16le(s);
|
|
y = stbi__get16le(s);
|
|
w = stbi__get16le(s);
|
|
h = stbi__get16le(s);
|
|
if (x + w > g.w || y + h > g.h)
|
|
{
|
|
return (byte*)(ulong)(stbi__err("bad Image Descriptor") != 0 ? 0 : 0);
|
|
}
|
|
|
|
g.line_size = g.w * 4;
|
|
g.start_x = x * 4;
|
|
g.start_y = y * g.line_size;
|
|
g.max_x = g.start_x + w * 4;
|
|
g.max_y = g.start_y + h * g.line_size;
|
|
g.cur_x = g.start_x;
|
|
g.cur_y = g.start_y;
|
|
if (w == 0)
|
|
{
|
|
g.cur_y = g.max_y;
|
|
}
|
|
|
|
g.lflags = stbi__get8(s);
|
|
if ((g.lflags & 0x40) != 0)
|
|
{
|
|
g.step = 8 * g.line_size;
|
|
g.parse = 3;
|
|
}
|
|
else
|
|
{
|
|
g.step = g.line_size;
|
|
g.parse = 0;
|
|
}
|
|
|
|
if ((g.lflags & 0x80) != 0)
|
|
{
|
|
stbi__gif_parse_colortable(s, g.lpal, 2 << (g.lflags & 7),
|
|
(g.eflags & 0x01) != 0 ? g.transparent : -1);
|
|
g.color_table = g.lpal;
|
|
}
|
|
else if ((g.flags & 0x80) != 0)
|
|
{
|
|
g.color_table = g.pal;
|
|
}
|
|
else
|
|
{
|
|
return (byte*)(ulong)(stbi__err("missing color table") != 0 ? 0 : 0);
|
|
}
|
|
|
|
o = stbi__process_gif_raster(s, g);
|
|
if (o == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
pcount = g.w * g.h;
|
|
if (first_frame != 0 && g.bgindex > 0)
|
|
{
|
|
for (pi = 0; pi < pcount; ++pi)
|
|
{
|
|
if (g.history[pi] == 0)
|
|
{
|
|
g.pal[g.bgindex][3] = 255;
|
|
fixed (byte* ptr = &g.pal[g.bgindex][0])
|
|
{
|
|
CRuntime.memcpy(&g._out_[pi * 4], ptr, (ulong)4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
case 0x21:
|
|
{
|
|
var len = 0;
|
|
int ext = stbi__get8(s);
|
|
if (ext == 0xF9)
|
|
{
|
|
len = stbi__get8(s);
|
|
if (len == 4)
|
|
{
|
|
g.eflags = stbi__get8(s);
|
|
g.delay = 10 * stbi__get16le(s);
|
|
if (g.transparent >= 0)
|
|
{
|
|
g.pal[g.transparent][3] = 255;
|
|
}
|
|
|
|
if ((g.eflags & 0x01) != 0)
|
|
{
|
|
g.transparent = stbi__get8(s);
|
|
if (g.transparent >= 0)
|
|
{
|
|
g.pal[g.transparent][3] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stbi__skip(s, 1);
|
|
g.transparent = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stbi__skip(s, len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
while ((len = stbi__get8(s)) != 0)
|
|
{
|
|
stbi__skip(s, len);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 0x3B:
|
|
return null;
|
|
default:
|
|
return (byte*)(ulong)(stbi__err("unknown code") != 0 ? 0 : 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void* stbi__load_gif_main_outofmem(stbi__gif g, byte* _out_, int** delays)
|
|
{
|
|
CRuntime.free(g._out_);
|
|
CRuntime.free(g.history);
|
|
CRuntime.free(g.background);
|
|
if (_out_ != null)
|
|
{
|
|
CRuntime.free(_out_);
|
|
}
|
|
|
|
if (delays != null && *delays != null)
|
|
{
|
|
CRuntime.free(*delays);
|
|
}
|
|
|
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
|
}
|
|
|
|
public class stbi__gif
|
|
{
|
|
public byte* _out_;
|
|
public byte* background;
|
|
public int bgindex;
|
|
public stbi__gif_lzw[] codes = new stbi__gif_lzw[8192];
|
|
public byte[][] color_table;
|
|
public int cur_x;
|
|
public int cur_y;
|
|
public int delay;
|
|
public int eflags;
|
|
public int flags;
|
|
public int h;
|
|
public byte* history;
|
|
public int lflags;
|
|
public int line_size;
|
|
public byte[][] lpal = Utility.CreateArray<byte>(256, 4);
|
|
public int max_x;
|
|
public int max_y;
|
|
public byte[][] pal = Utility.CreateArray<byte>(256, 4);
|
|
public int parse;
|
|
public int ratio;
|
|
public int start_x;
|
|
public int start_y;
|
|
public int step;
|
|
public int transparent;
|
|
public int w;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct stbi__gif_lzw
|
|
{
|
|
public short prefix;
|
|
public byte first;
|
|
public byte suffix;
|
|
}
|
|
}
|
|
}
|