Switch to using an index for sprite tracking
Frees up two bytes in GPUCell. Doesn't require a minimum texture row size. Makes a bunch of code faster. Index uses 31 bits which gives us 2,147,483,647 aka ~ 2 billion sprites.
This commit is contained in:
parent
203a5f4e00
commit
0fb49f4139
12 changed files with 97 additions and 71 deletions
|
|
@ -22,7 +22,7 @@ uniform uint draw_bg_bitfield;
|
|||
|
||||
// Have to use fixed locations here as all variants of the cell program share the same VAO
|
||||
layout(location=0) in uvec3 colors;
|
||||
layout(location=1) in uvec4 sprite_coords;
|
||||
layout(location=1) in uvec2 sprite_idx;
|
||||
layout(location=2) in uint is_selected;
|
||||
uniform float gamma_lut[256];
|
||||
|
||||
|
|
@ -58,8 +58,9 @@ out float effective_text_alpha;
|
|||
|
||||
// Utility functions {{{
|
||||
const uint BYTE_MASK = uint(0xFF);
|
||||
const uint Z_MASK = uint(0xFFF);
|
||||
const uint COLOR_MASK = uint(0x4000);
|
||||
const uint Z_MASK = uint(0x7fffffff);
|
||||
const uint COLOR_MASK = uint(0x80000000);
|
||||
const uint COLOR_SHIFT = uint(31);
|
||||
const uint ZERO = uint(0);
|
||||
const uint ONE = uint(1);
|
||||
const uint TWO = uint(2);
|
||||
|
|
@ -95,7 +96,12 @@ vec3 to_color(uint c, uint defval) {
|
|||
return color_to_vec(resolve_color(c, defval));
|
||||
}
|
||||
|
||||
vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) {
|
||||
vec3 to_sprite_pos(uvec2 pos, uint idx) {
|
||||
uint sprites_per_page = sprites_xnum * sprites_ynum;
|
||||
uint z = idx / sprites_per_page;
|
||||
uint num_on_last_page = idx % sprites_per_page;
|
||||
uint y = num_on_last_page / sprites_xnum;
|
||||
uint x = num_on_last_page % sprites_xnum;
|
||||
vec2 s_xpos = vec2(x, float(x) + 1.0f) * (1.0f / float(sprites_xnum));
|
||||
vec2 s_ypos = vec2(y, float(y) + 1.0f) * (1.0f / float(sprites_ynum));
|
||||
return vec3(s_xpos[pos.x], s_ypos[pos.y], z);
|
||||
|
|
@ -140,8 +146,8 @@ CellData set_vertex_position() {
|
|||
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
||||
#ifdef NEEDS_FOREGROUND
|
||||
// The character sprite being rendered
|
||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & Z_MASK);
|
||||
colored_sprite = float((sprite_coords.z & COLOR_MASK) >> 14);
|
||||
sprite_pos = to_sprite_pos(pos, sprite_idx[0] & Z_MASK);
|
||||
colored_sprite = float((sprite_idx[0] & COLOR_MASK) >> COLOR_SHIFT);
|
||||
#endif
|
||||
float is_block_cursor = step(float(cursor_fg_sprite_idx), 0.5);
|
||||
float has_cursor = is_cursor(c, r);
|
||||
|
|
@ -172,7 +178,7 @@ void main() {
|
|||
|
||||
// set cell color indices {{{
|
||||
uvec2 default_colors = uvec2(default_fg, bg_colors0);
|
||||
uint text_attrs = sprite_coords[3];
|
||||
uint text_attrs = sprite_idx[1];
|
||||
uint is_reversed = ((text_attrs >> REVERSE_SHIFT) & ONE);
|
||||
uint is_inverted = is_reversed + inverted;
|
||||
int fg_index = fg_index_map[is_inverted];
|
||||
|
|
@ -202,15 +208,15 @@ void main() {
|
|||
foreground = choose_color(float(is_selected & ONE), selection_color, foreground);
|
||||
decoration_fg = choose_color(float(is_selected & ONE), selection_color, decoration_fg);
|
||||
// Underline and strike through (rendered via sprites)
|
||||
underline_pos = choose_color(in_url, to_sprite_pos(cell_data.pos, url_style, ZERO, ZERO), to_sprite_pos(cell_data.pos, (text_attrs >> DECORATION_SHIFT) & DECORATION_MASK, ZERO, ZERO));
|
||||
strike_pos = to_sprite_pos(cell_data.pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * STRIKE_SPRITE_INDEX, ZERO, ZERO);
|
||||
underline_pos = choose_color(in_url, to_sprite_pos(cell_data.pos, url_style), to_sprite_pos(cell_data.pos, (text_attrs >> DECORATION_SHIFT) & DECORATION_MASK));
|
||||
strike_pos = to_sprite_pos(cell_data.pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * STRIKE_SPRITE_INDEX);
|
||||
|
||||
// Cursor
|
||||
cursor_color_premult = vec4(color_to_vec(cursor_bg) * cursor_opacity, cursor_opacity);
|
||||
vec3 final_cursor_text_color = mix(foreground, color_to_vec(cursor_fg), cursor_opacity);
|
||||
foreground = choose_color(cell_data.has_block_cursor, final_cursor_text_color, foreground);
|
||||
decoration_fg = choose_color(cell_data.has_block_cursor, final_cursor_text_color, decoration_fg);
|
||||
cursor_pos = to_sprite_pos(cell_data.pos, cursor_fg_sprite_idx * uint(cell_data.has_cursor), ZERO, ZERO);
|
||||
cursor_pos = to_sprite_pos(cell_data.pos, cursor_fg_sprite_idx * uint(cell_data.has_cursor));
|
||||
#endif
|
||||
// }}}
|
||||
|
||||
|
|
|
|||
|
|
@ -710,11 +710,6 @@ shift_to_first_set_bit(CellAttrs x) {
|
|||
EXPORTED PyMODINIT_FUNC
|
||||
PyInit_fast_data_types(void) {
|
||||
PyObject *m;
|
||||
if (sizeof(CellAttrs) != 2u) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Size of CellAttrs is not 2 on this platform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m = PyModule_Create(&module);
|
||||
if (m == NULL) return NULL;
|
||||
init_monotonic();
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ typedef uint16_t combining_type;
|
|||
typedef uint16_t glyph_index;
|
||||
typedef uint32_t pixel;
|
||||
typedef unsigned int index_type;
|
||||
typedef uint16_t sprite_index;
|
||||
typedef uint32_t sprite_index;
|
||||
typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, CURSOR_HOLLOW, NUM_OF_CURSOR_SHAPES } CursorShape;
|
||||
typedef enum { DISABLE_LIGATURES_NEVER, DISABLE_LIGATURES_CURSOR, DISABLE_LIGATURES_ALWAYS } DisableLigature;
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ typedef struct FontCellMetrics {
|
|||
#define FONTS_DATA_HEAD SPRITE_MAP_HANDLE sprite_map; double logical_dpi_x, logical_dpi_y, font_sz_in_pts; FontCellMetrics fcm;
|
||||
typedef struct {FONTS_DATA_HEAD} *FONTS_DATA_HANDLE;
|
||||
|
||||
#define clear_sprite_position(cell) (cell).sprite_x = 0; (cell).sprite_y = 0; (cell).sprite_z = 0;
|
||||
#define clear_sprite_position(cell) (cell).sprite_idx = 0;
|
||||
|
||||
#define ensure_space_for(base, array, type, num, capacity, initial_cap, zero_mem) \
|
||||
if ((base)->capacity < num) { \
|
||||
|
|
|
|||
|
|
@ -1108,8 +1108,7 @@ def parse_input_from_terminal(
|
|||
|
||||
class Line:
|
||||
|
||||
def sprite_at(self, cell: int) -> Tuple[int, int, int]:
|
||||
pass
|
||||
def sprite_at(self, cell: int) -> int: ...
|
||||
|
||||
|
||||
def test_shape(line: Line,
|
||||
|
|
@ -1719,6 +1718,7 @@ def cocoa_play_system_sound_by_id_async(sound_id: int) -> None: ...
|
|||
def glfw_get_system_color_theme(query_if_unintialized: bool = True) -> Literal['light', 'dark', 'no_preference']: ...
|
||||
def set_redirect_keys_to_overlay(os_window_id: int, tab_id: int, window_id: int, overlay_window_id: int) -> None: ...
|
||||
def buffer_keys_in_window(os_window_id: int, tab_id: int, window_id: int, enabled: bool = True) -> bool: ...
|
||||
def sprite_idx_to_pos(idx: int, xnum: int, ynum: int) -> tuple[int, int, int]: ...
|
||||
|
||||
class MousePosition(TypedDict):
|
||||
cell_x: int
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ typedef enum {
|
|||
|
||||
|
||||
typedef struct {
|
||||
size_t max_y;
|
||||
unsigned int x, y, z, xnum, ynum;
|
||||
unsigned x, y, z, xnum, ynum, max_y;
|
||||
} GPUSpriteTracker;
|
||||
|
||||
typedef struct RunFont {
|
||||
|
|
@ -263,6 +262,10 @@ do_increment(FontGroup *fg, int *error) {
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
current_sprite_index(GPUSpriteTracker *sprite_tracker) {
|
||||
return sprite_tracker->z * (sprite_tracker->xnum * sprite_tracker->ynum) + sprite_tracker->y * sprite_tracker->xnum + sprite_tracker->x;
|
||||
}
|
||||
|
||||
static SpritePosition*
|
||||
sprite_position_for(FontGroup *fg, RunFont rf, glyph_index *glyphs, unsigned glyph_count, uint8_t ligature_index, unsigned cell_count, int *error) {
|
||||
|
|
@ -274,7 +277,7 @@ sprite_position_for(FontGroup *fg, RunFont rf, glyph_index *glyphs, unsigned gly
|
|||
rf.scale, subscale, rf.multicell_y, rf.vertical_align, &created);
|
||||
if (!s) { *error = 1; return NULL; }
|
||||
if (created) {
|
||||
s->x = fg->sprite_tracker.x; s->y = fg->sprite_tracker.y; s->z = fg->sprite_tracker.z;
|
||||
s->idx = current_sprite_index(&fg->sprite_tracker);
|
||||
do_increment(fg, error);
|
||||
}
|
||||
return s;
|
||||
|
|
@ -405,9 +408,12 @@ free_font_groups(void) {
|
|||
}
|
||||
|
||||
static void
|
||||
python_send_to_gpu(FONTS_DATA_HANDLE fg, unsigned int x, unsigned int y, unsigned int z, pixel* buf) {
|
||||
python_send_to_gpu(FONTS_DATA_HANDLE fg_, unsigned int idx, pixel *buf) {
|
||||
FontGroup *fg = (FontGroup*)fg_;
|
||||
if (python_send_to_gpu_impl) {
|
||||
if (!num_font_groups) fatal("Cannot call send to gpu with no font groups");
|
||||
unsigned int x, y, z;
|
||||
sprite_index_to_pos(idx, fg->sprite_tracker.xnum, fg->sprite_tracker.ynum, &x, &y, &z);
|
||||
PyObject *ret = PyObject_CallFunction(python_send_to_gpu_impl, "IIIN", x, y, z, PyBytes_FromStringAndSize((const char*)buf, sizeof(pixel) * fg->fcm.cell_width * fg->fcm.cell_height));
|
||||
if (ret == NULL) PyErr_Print();
|
||||
else Py_DECREF(ret);
|
||||
|
|
@ -670,11 +676,6 @@ START_ALLOW_CASE_RANGE
|
|||
END_ALLOW_CASE_RANGE
|
||||
}
|
||||
|
||||
static void
|
||||
set_sprite(GPUCell *cell, sprite_index x, sprite_index y, sprite_index z) {
|
||||
cell->sprite_x = x; cell->sprite_y = y; cell->sprite_z = z;
|
||||
}
|
||||
|
||||
// Gives a unique (arbitrary) id to a box glyph
|
||||
static glyph_index
|
||||
box_glyph_id(char_type ch) {
|
||||
|
|
@ -855,6 +856,12 @@ dump_sprite(pixel *b, unsigned width, unsigned height, bool actual_pixel_values)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_cell_sprite(GPUCell *cell, const SpritePosition *sp) {
|
||||
cell->sprite_idx = sp->idx & 0x7fffffff;
|
||||
if (sp->colored) cell->sprite_idx |= 0x80000000;
|
||||
}
|
||||
|
||||
static void
|
||||
render_box_cell(FontGroup *fg, RunFont rf, CPUCell *cpu_cell, GPUCell *gpu_cell, const TextCache *tc) {
|
||||
int error = 0;
|
||||
|
|
@ -869,7 +876,7 @@ render_box_cell(FontGroup *fg, RunFont rf, CPUCell *cpu_cell, GPUCell *gpu_cell,
|
|||
else global_glyph_render_scratch.lc->chars[i] = 0;
|
||||
}
|
||||
if (!num_glyphs) {
|
||||
for (unsigned i = 0; i < rf.scale; i++) set_sprite(gpu_cell + i, 0, 0, 0);
|
||||
for (unsigned i = 0; i < rf.scale; i++) gpu_cell[i].sprite_idx = 0;
|
||||
return;
|
||||
}
|
||||
bool all_rendered = true;
|
||||
|
|
@ -878,11 +885,11 @@ render_box_cell(FontGroup *fg, RunFont rf, CPUCell *cpu_cell, GPUCell *gpu_cell,
|
|||
sp[ligature_index] = sprite_position_for(fg, rf, global_glyph_render_scratch.glyphs, num_glyphs, ligature_index, rf.scale, &error);
|
||||
if (sp[ligature_index] == NULL) {
|
||||
sprite_map_set_error(error); PyErr_Print();
|
||||
for (unsigned i = 0; i < rf.scale; i++) set_sprite(gpu_cell + i, 0, 0, 0);
|
||||
for (unsigned i = 0; i < rf.scale; i++) gpu_cell[i].sprite_idx = 0;
|
||||
return;
|
||||
}
|
||||
set_sprite(gpu_cell + ligature_index, sp[ligature_index]->x, sp[ligature_index]->y, sp[ligature_index]->z);
|
||||
sp[ligature_index]->colored = false;
|
||||
set_cell_sprite(gpu_cell + ligature_index, sp[ligature_index]);
|
||||
if (!sp[ligature_index]->rendered) all_rendered = false;
|
||||
}
|
||||
if (all_rendered) return;
|
||||
|
|
@ -915,7 +922,7 @@ render_box_cell(FontGroup *fg, RunFont rf, CPUCell *cpu_cell, GPUCell *gpu_cell,
|
|||
/*printf("Rendered char sz: (%u, %u)\n", width, height); dump_sprite(fg->canvas.buf, width, height, false);*/
|
||||
if (scale == 1.f && rf.scale == 1 && !rf.subscale_n) {
|
||||
sp[0]->rendered = true;
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[0]->x, sp[0]->y, sp[0]->z, fg->canvas.buf);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[0]->idx, fg->canvas.buf);
|
||||
} else {
|
||||
calculate_regions_for_line(rf, fg->fcm.cell_height, &src, &dest);
|
||||
/*printf("width: %u height: %u unscaled_cell_width: %u unscaled_cell_height: %u src.top: %u src.bottom: %u rf.scale: %u\n", width, height, fg->fcm.cell_width, fg->fcm.cell_height, src.top, src.bottom, rf.scale);*/
|
||||
|
|
@ -923,7 +930,7 @@ render_box_cell(FontGroup *fg, RunFont rf, CPUCell *cpu_cell, GPUCell *gpu_cell,
|
|||
pixel *b = extract_cell_region(&fg->canvas, i, &src, &dest, width, fg->fcm);
|
||||
/*printf("Sprite %u: pos: (%u, %u, %u) sz: (%u, %u)\n", i, sp[i]->x, sp[i]->y, sp[i]->z, fg->fcm.cell_width, fg->fcm.cell_height); dump_sprite(b, fg->fcm.cell_width, fg->fcm.cell_height, false);*/
|
||||
sp[i]->rendered = true;
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[i]->x, sp[i]->y, sp[i]->z, b);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[i]->idx, b);
|
||||
}
|
||||
}
|
||||
#undef sp
|
||||
|
|
@ -948,12 +955,6 @@ load_hb_buffer(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
set_cell_sprite(GPUCell *cell, const SpritePosition *sp) {
|
||||
cell->sprite_x = sp->x; cell->sprite_y = sp->y; cell->sprite_z = sp->z;
|
||||
if (sp->colored) cell->sprite_z |= 0x4000;
|
||||
}
|
||||
|
||||
static void
|
||||
render_filled_sprite(pixel *buf, unsigned num_glyphs, FontCellMetrics scaled_metrics, unsigned num_scaled_cells) {
|
||||
if (num_scaled_cells > num_glyphs) {
|
||||
|
|
@ -1014,10 +1015,10 @@ render_group(
|
|||
if (num_cells == num_scaled_cells && rf.scale == 1.f) {
|
||||
for (unsigned i = 0; i < num_cells; i++) {
|
||||
if (!sp[i]->rendered) {
|
||||
bool is_repeat_sprite = is_infinite_ligature && i > 0 && sp[i]->x == sp[i-1]->x && sp[i]->y == sp[i-1]->y && sp[i]->z == sp[i-1]->z;
|
||||
bool is_repeat_sprite = is_infinite_ligature && i > 0 && sp[i]->idx == sp[i-1]->idx;
|
||||
if (!is_repeat_sprite) {
|
||||
pixel *b = num_cells == 1 ? fg->canvas.buf : extract_cell_from_canvas(fg, i, num_cells);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[i]->x, sp[i]->y, sp[i]->z, b);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[i]->idx, b);
|
||||
}
|
||||
sp[i]->rendered = true; sp[i]->colored = was_colored;
|
||||
}
|
||||
|
|
@ -1031,7 +1032,7 @@ render_group(
|
|||
if (!sp[i]->rendered) {
|
||||
pixel *b = extract_cell_region(&fg->canvas, i, &src, &dest, scaled_metrics.cell_width * num_scaled_cells, unscaled_metrics);
|
||||
/*printf("cell %u src -> dest: (%u %u) -> (%u %u)\n", i, src.left, src.right, dest.left, dest.right);*/
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[i]->x, sp[i]->y, sp[i]->z, b);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp[i]->idx, b);
|
||||
/*dump_sprite(b, unscaled_metrics.cell_width, unscaled_metrics.cell_height, false);*/
|
||||
sp[i]->rendered = true; sp[i]->colored = was_colored;
|
||||
}
|
||||
|
|
@ -1583,7 +1584,7 @@ render_run(FontGroup *fg, CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, inde
|
|||
render_groups(fg, rf, center_glyph, tc);
|
||||
break;
|
||||
case BLANK_FONT:
|
||||
while(num_cells--) { set_sprite(first_gpu_cell, 0, 0, 0); first_cpu_cell++; first_gpu_cell++; }
|
||||
while(num_cells--) { first_gpu_cell->sprite_idx = 0; first_cpu_cell++; first_gpu_cell++; }
|
||||
break;
|
||||
case BOX_FONT:
|
||||
while(num_cells) {
|
||||
|
|
@ -1594,7 +1595,7 @@ render_run(FontGroup *fg, CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, inde
|
|||
}
|
||||
break;
|
||||
case MISSING_FONT:
|
||||
while(num_cells--) { set_sprite(first_gpu_cell, MISSING_GLYPH, 0, 0); first_cpu_cell++; first_gpu_cell++; }
|
||||
while(num_cells--) { first_gpu_cell->sprite_idx = MISSING_GLYPH; first_cpu_cell++; first_gpu_cell++; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1759,26 +1760,24 @@ set_font_data(PyObject UNUSED *m, PyObject *args) {
|
|||
static void
|
||||
send_prerendered_sprites(FontGroup *fg) {
|
||||
int error = 0;
|
||||
sprite_index x = 0, y = 0, z = 0;
|
||||
// blank cell
|
||||
ensure_canvas_can_fit(fg, 1, 1);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas.buf);
|
||||
do_increment(fg, &error);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, 0, fg->canvas.buf);
|
||||
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
||||
PyObject *args = PyObject_CallFunction(prerender_function, "IIIIIIIffdd", fg->fcm.cell_width, fg->fcm.cell_height, fg->fcm.baseline, fg->fcm.underline_position, fg->fcm.underline_thickness, fg->fcm.strikethrough_position, fg->fcm.strikethrough_thickness, OPT(cursor_beam_thickness), OPT(cursor_underline_thickness), fg->logical_dpi_x, fg->logical_dpi_y);
|
||||
if (args == NULL) { PyErr_Print(); fatal("Failed to pre-render cells"); }
|
||||
PyObject *cell_addresses = PyTuple_GET_ITEM(args, 0);
|
||||
for (ssize_t i = 0; i < PyTuple_GET_SIZE(cell_addresses); i++) {
|
||||
x = fg->sprite_tracker.x; y = fg->sprite_tracker.y; z = fg->sprite_tracker.z;
|
||||
if (y > 0) { fatal("Too many pre-rendered sprites for your GPU or the font size is too large"); }
|
||||
do_increment(fg, &error);
|
||||
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
||||
uint8_t *alpha_mask = PyLong_AsVoidPtr(PyTuple_GET_ITEM(cell_addresses, i));
|
||||
ensure_canvas_can_fit(fg, 1, 1); // clear canvas
|
||||
Region r = { .right = fg->fcm.cell_width, .bottom = fg->fcm.cell_height };
|
||||
render_alpha_mask(alpha_mask, fg->canvas.buf, &r, &r, fg->fcm.cell_width, fg->fcm.cell_width, 0xffffff);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas.buf);
|
||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, current_sprite_index(&fg->sprite_tracker), fg->canvas.buf);
|
||||
}
|
||||
do_increment(fg, &error);
|
||||
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
||||
Py_CLEAR(args);
|
||||
}
|
||||
|
||||
|
|
@ -1893,7 +1892,9 @@ test_sprite_position_for(PyObject UNUSED *self, PyObject *args) {
|
|||
RunFont rf = {.scale = 1, .font_idx=fg->medium_font_idx};
|
||||
SpritePosition *pos = sprite_position_for(fg, rf, glyphs, PyTuple_GET_SIZE(args), 0, 1, &error);
|
||||
if (pos == NULL) { sprite_map_set_error(error); return NULL; }
|
||||
return Py_BuildValue("HHH", pos->x, pos->y, pos->z);
|
||||
unsigned int x, y, z;
|
||||
sprite_index_to_pos(pos->idx, fg->sprite_tracker.xnum, fg->sprite_tracker.ynum, &x, &y, &z);
|
||||
return Py_BuildValue("III", x, y, z);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
|
@ -2125,8 +2126,17 @@ set_allow_use_of_box_fonts(PyObject *self UNUSED, PyObject *val) {
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
sprite_idx_to_pos(PyObject *self UNUSED, PyObject *args) {
|
||||
unsigned x, y, z, idx, xnum, ynum;
|
||||
if (!PyArg_ParseTuple(args, "III", &idx, &xnum, &ynum)) return NULL;
|
||||
sprite_index_to_pos(idx, xnum, ynum, &x, &y, &z);
|
||||
return Py_BuildValue("III", x, y, z);
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
METHODB(set_font_data, METH_VARARGS),
|
||||
METHODB(sprite_idx_to_pos, METH_VARARGS),
|
||||
METHODB(free_font_data, METH_NOARGS),
|
||||
METHODB(create_test_font_group, METH_VARARGS),
|
||||
METHODB(sprite_map_set_layout, METH_VARARGS),
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
set_font_data,
|
||||
set_options,
|
||||
set_send_sprite_to_gpu,
|
||||
sprite_idx_to_pos,
|
||||
sprite_map_set_limits,
|
||||
test_render_line,
|
||||
test_shape,
|
||||
|
|
@ -437,6 +438,9 @@ def render_box_drawing(codepoint: int, cell_width: int, cell_height: int, dpi: f
|
|||
|
||||
class setup_for_testing:
|
||||
|
||||
xnum = 100000
|
||||
ynum = 100
|
||||
|
||||
def __init__(self, family: str = 'monospace', size: float = 11.0, dpi: float = 96.0, main_face_path: str = ''):
|
||||
self.family, self.size, self.dpi = family, size, dpi
|
||||
self.main_face_path = main_face_path
|
||||
|
|
@ -450,7 +454,7 @@ def __enter__(self) -> tuple[dict[tuple[int, int, int], bytes], int, int]:
|
|||
def send_to_gpu(x: int, y: int, z: int, data: bytes) -> None:
|
||||
sprites[(x, y, z)] = data
|
||||
|
||||
sprite_map_set_limits(100000, 100)
|
||||
sprite_map_set_limits(self.xnum, self.ynum)
|
||||
set_send_sprite_to_gpu(send_to_gpu)
|
||||
self.orig_desc_overrides = descriptor_overrides
|
||||
descriptor_overrides = {}
|
||||
|
|
@ -479,13 +483,12 @@ def render_string(text: str, family: str = 'monospace', size: float = 11.0, dpi:
|
|||
cells = []
|
||||
found_content = False
|
||||
for i in reversed(range(s.columns)):
|
||||
sp = list(line.sprite_at(i))
|
||||
sp[2] &= 0xfff
|
||||
tsp = sp[0], sp[1], sp[2]
|
||||
if tsp == (0, 0, 0) and not found_content:
|
||||
sp = line.sprite_at(i)
|
||||
sp &= 0x7fffffff
|
||||
if not sp and not found_content:
|
||||
continue
|
||||
found_content = True
|
||||
cells.append(sprites[tsp])
|
||||
cells.append(sprites[sprite_idx_to_pos(sp, setup_for_testing.xnum, setup_for_testing.ynum)])
|
||||
return cell_width, cell_height, list(reversed(cells))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ void free_glyph_cache_global_resources(void);
|
|||
|
||||
typedef struct SpritePosition {
|
||||
bool rendered, colored;
|
||||
sprite_index x, y, z;
|
||||
sprite_index idx;
|
||||
} SpritePosition;
|
||||
|
||||
typedef struct {int x;} *SPRITE_POSITION_MAP_HANDLE;
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ sprite_at(Line* self, PyObject *x) {
|
|||
unsigned long xval = PyLong_AsUnsignedLong(x);
|
||||
if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
|
||||
GPUCell *c = self->gpu_cells + xval;
|
||||
return Py_BuildValue("HHH", c->sprite_x, c->sprite_y, c->sprite_z);
|
||||
return Py_BuildValue("I", (unsigned int)c->sprite_idx);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -682,7 +682,7 @@ line_apply_cursor(Line *self, const Cursor *cursor, unsigned int at, unsigned in
|
|||
} else {
|
||||
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
||||
gc.attrs.mark = self->gpu_cells[i].attrs.mark;
|
||||
gc.sprite_x = self->gpu_cells[i].sprite_x; gc.sprite_y = self->gpu_cells[i].sprite_y; gc.sprite_z = self->gpu_cells[i].sprite_z;
|
||||
gc.sprite_idx = self->gpu_cells[i].sprite_idx;
|
||||
memcpy(self->gpu_cells + i, &gc, sizeof(gc));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ typedef union CellAttrs {
|
|||
uint16_t strike : 1;
|
||||
uint16_t dim : 1;
|
||||
uint16_t mark : 2;
|
||||
uint16_t : 6;
|
||||
uint32_t : 22;
|
||||
};
|
||||
uint16_t val;
|
||||
uint32_t val;
|
||||
} CellAttrs;
|
||||
static_assert(sizeof(CellAttrs) == sizeof(uint16_t), "Fix the ordering of CellAttrs");
|
||||
static_assert(sizeof(CellAttrs) == sizeof(uint32_t), "Fix the ordering of CellAttrs");
|
||||
|
||||
#define WIDTH_MASK (3u)
|
||||
#define DECORATION_MASK (7u)
|
||||
|
|
@ -44,7 +44,7 @@ static_assert(sizeof(CellAttrs) == sizeof(uint16_t), "Fix the ordering of CellAt
|
|||
|
||||
typedef struct {
|
||||
color_type fg, bg, decoration_fg;
|
||||
sprite_index sprite_x, sprite_y, sprite_z;
|
||||
sprite_index sprite_idx;
|
||||
CellAttrs attrs;
|
||||
} GPUCell;
|
||||
static_assert(sizeof(GPUCell) == 20, "Fix the ordering of GPUCell");
|
||||
|
|
|
|||
|
|
@ -143,13 +143,17 @@ ensure_sprite_map(FONTS_DATA_HANDLE fg) {
|
|||
}
|
||||
|
||||
void
|
||||
send_sprite_to_gpu(FONTS_DATA_HANDLE fg, unsigned int x, unsigned int y, unsigned int z, pixel *buf) {
|
||||
send_sprite_to_gpu(FONTS_DATA_HANDLE fg, unsigned int idx, pixel *buf) {
|
||||
SpriteMap *sprite_map = (SpriteMap*)fg->sprite_map;
|
||||
unsigned int xnum, ynum, znum;
|
||||
unsigned int xnum, ynum, znum, x, y, z;
|
||||
sprite_tracker_current_layout(fg, &xnum, &ynum, &znum);
|
||||
if ((int)znum >= sprite_map->last_num_of_layers || (znum == 0 && (int)ynum > sprite_map->last_ynum)) realloc_sprite_texture(fg);
|
||||
if ((int)znum >= sprite_map->last_num_of_layers || (znum == 0 && (int)ynum > sprite_map->last_ynum)) {
|
||||
realloc_sprite_texture(fg);
|
||||
sprite_tracker_current_layout(fg, &xnum, &ynum, &znum);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map->texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
sprite_index_to_pos(idx, xnum, ynum, &x, &y, &z);
|
||||
x *= fg->fcm.cell_width; y *= fg->fcm.cell_height;
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, fg->fcm.cell_width, fg->fcm.cell_height, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf);
|
||||
}
|
||||
|
|
@ -228,7 +232,7 @@ init_cell_program(void) {
|
|||
// Sanity check to ensure the attribute location binding worked
|
||||
#define C(p, name, expected) { int aloc = attrib_location(p, #name); if (aloc != expected && aloc != -1) fatal("The attribute location for %s is %d != %d in program: %d", #name, aloc, expected, p); }
|
||||
for (int p = CELL_PROGRAM; p < BORDERS_PROGRAM; p++) {
|
||||
C(p, colors, 0); C(p, sprite_coords, 1); C(p, is_selected, 2);
|
||||
C(p, colors, 0); C(p, sprite_idx, 1); C(p, is_selected, 2);
|
||||
}
|
||||
#undef C
|
||||
for (int i = GRAPHICS_PROGRAM; i <= GRAPHICS_ALPHA_MASK_PROGRAM; i++) {
|
||||
|
|
@ -249,7 +253,7 @@ create_cell_vao(void) {
|
|||
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(GPUCell, offset)), sizeof(GPUCell))
|
||||
|
||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||
A1(sprite_coords, 4, GL_UNSIGNED_SHORT, sprite_x);
|
||||
A1(sprite_idx, 2, GL_UNSIGNED_INT, sprite_idx);
|
||||
A1(colors, 3, GL_UNSIGNED_INT, fg);
|
||||
|
||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||
|
|
|
|||
|
|
@ -338,6 +338,13 @@ extern GlobalState global_state;
|
|||
else Py_DECREF(cret_); \
|
||||
}
|
||||
|
||||
static inline void
|
||||
sprite_index_to_pos(unsigned idx, unsigned xnum, unsigned ynum, unsigned *x, unsigned *y, unsigned *z) {
|
||||
div_t r = div(idx & 0x7fffffff, ynum * xnum), r2 = div(r.rem, xnum);
|
||||
*z = r.quot; *y = r2.quot; *x = r2.rem;
|
||||
}
|
||||
|
||||
|
||||
void gl_init(void);
|
||||
void remove_vao(ssize_t vao_idx);
|
||||
bool remove_os_window(id_type os_window_id);
|
||||
|
|
@ -379,7 +386,7 @@ void update_surface_size(int, int, uint32_t);
|
|||
void free_texture(uint32_t*);
|
||||
void free_framebuffer(uint32_t*);
|
||||
void send_image_to_gpu(uint32_t*, const void*, int32_t, int32_t, bool, bool, bool, RepeatStrategy);
|
||||
void send_sprite_to_gpu(FONTS_DATA_HANDLE fg, unsigned int, unsigned int, unsigned int, pixel*);
|
||||
void send_sprite_to_gpu(FONTS_DATA_HANDLE fg, unsigned int, pixel*);
|
||||
void blank_canvas(float, color_type);
|
||||
void blank_os_window(OSWindow *);
|
||||
void set_os_window_chrome(OSWindow *w);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
ParsedFontFeature,
|
||||
get_fallback_font,
|
||||
set_allow_use_of_box_fonts,
|
||||
sprite_idx_to_pos,
|
||||
sprite_map_set_layout,
|
||||
sprite_map_set_limits,
|
||||
test_render_line,
|
||||
|
|
@ -231,7 +232,7 @@ def multiline_render(text, scale=1, width=1, **kw):
|
|||
line = s.line(y)
|
||||
test_render_line(line)
|
||||
for x in range(width * scale):
|
||||
ans.append(sprites[line.sprite_at(x)])
|
||||
ans.append(sprites[sprite_idx_to_pos(line.sprite_at(x), setup_for_testing.xnum, setup_for_testing.ynum)])
|
||||
return ans
|
||||
|
||||
def block_test(*expected, **kw):
|
||||
|
|
|
|||
Loading…
Reference in a new issue