paint: use less memory

This commit is contained in:
luboslenco
2026-08-26 16:26:29 +02:00
parent d7235b3646
commit b449ece1e3
7 changed files with 86 additions and 46 deletions
+2 -1
View File
@@ -192,9 +192,10 @@ void base_init_undo_layers() {
for (i32 i = 0; i < g_config->undo_steps; ++i) {
i32 len = history_undo_layers->length;
char *ext = string("_undo%s", i32_to_string(len));
slot_layer_t *l = slot_layer_create(ext, LAYER_SLOT_TYPE_LAYER, NULL);
slot_layer_t *l = slot_layer_create_undo(ext);
any_array_push(history_undo_layers, l);
}
slot_layer_alloc_textures(history_undo_layers->buffer[history_undo_i]);
}
}
+3
View File
@@ -22,6 +22,8 @@ void tab_swatches_draw(ui_handle_t *htab);
void tab_swatches_accept_swatch_drop(swatch_color_t *swatch);
slot_brush_t *slot_brush_create(ui_node_canvas_t *c);
slot_layer_t *slot_layer_create(char *ext, layer_slot_type_t type, slot_layer_t *parent);
slot_layer_t *slot_layer_create_undo(char *ext);
void slot_layer_alloc_textures(slot_layer_t *raw);
void slot_layer_delete(slot_layer_t *raw);
void slot_layer_unload(slot_layer_t *raw);
void slot_layer_swap(slot_layer_t *raw, slot_layer_t *other);
@@ -307,6 +309,7 @@ void render_path_deferred_commands();
void box_projects_show();
void box_projects_recent_tab();
node_shader_context_t *make_node_preview_run(material_t *data, ui_node_t *node, ui_node_canvas_t *group, ui_node_t_array_t *parents);
slot_layer_t *history_undo_slot(i32 i);
void history_undo();
void history_redo();
void history_reset();
+24 -15
View File
@@ -325,7 +325,7 @@ void history_undo() {
array_insert(g_project->_->layers, step->layer, l);
context_set_layer(l);
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(l, lay);
l->mask_opacity = step->layer_opacity;
l->blending = step->layer_blending;
@@ -339,7 +339,7 @@ void history_undo() {
}
else if (step->action == HISTORY_ACTION_CLEAR_LAYER) {
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
g_context->layer_preview_dirty = true;
}
@@ -368,7 +368,7 @@ void history_undo() {
context_set_layer(l);
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
l = slot_layer_create("", step->layer_type, parent);
@@ -376,7 +376,7 @@ void history_undo() {
context_set_layer(l);
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
lay = history_undo_layers->buffer[history_undo_i];
lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
g_context->layer->mask_opacity = step->layer_opacity;
@@ -415,13 +415,13 @@ void history_undo() {
// Replace the current layer's content with the old one
g_context->layer = layer;
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *old_layer = history_undo_layers->buffer[history_undo_i];
slot_layer_t *old_layer = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, old_layer);
}
// Now restore the applied mask
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *mask = history_undo_layers->buffer[history_undo_i];
slot_layer_t *mask = history_undo_slot(history_undo_i);
layers_new_mask(false, current_layer, mask_pos);
slot_layer_swap(g_context->layer, mask);
g_context->layers_preview_dirty = true;
@@ -432,7 +432,7 @@ void history_undo() {
}
else if (step->action == HISTORY_ACTION_APPLY_FILTER) {
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
context_set_layer(g_project->_->layers->buffer[step->layer]);
slot_layer_swap(g_context->layer, lay);
layers_new_mask(false, g_context->layer, -1);
@@ -442,12 +442,12 @@ void history_undo() {
else if (step->action == HISTORY_ACTION_TO_FILL_LAYER || step->action == HISTORY_ACTION_TO_FILL_MASK) {
slot_layer_to_paint_layer(g_context->layer);
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
}
else if (step->action == HISTORY_ACTION_TO_PAINT_LAYER || step->action == HISTORY_ACTION_TO_PAINT_MASK) {
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
g_context->layer->fill_material = g_project->_->materials->buffer[step->material];
}
@@ -514,7 +514,7 @@ void history_undo() {
}
else { // Paint operation
history_undo_i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
context_select_paint_object(g_project->_->paint_objects->buffer[step->object]);
context_set_layer(g_project->_->layers->buffer[step->layer]);
slot_layer_swap(g_context->layer, lay);
@@ -554,9 +554,18 @@ void history_redo_merge_layers2(void *_) {
layers_merge_down();
}
slot_layer_t *history_undo_slot(i32 i) {
slot_layer_t *l = history_undo_layers->buffer[i];
slot_layer_alloc_textures(l);
return l;
}
void history_copy_to_undo(i32 from_id, i32 to_id, bool is_mask) {
char *to_id_s = i32_to_string(to_id);
char *from_id_s = i32_to_string(from_id);
if (history_undo_layers != NULL && to_id < history_undo_layers->length) {
history_undo_slot(to_id);
}
if (is_mask) {
render_path_set_target(string_tmp("texpaint_undo%s", to_id_s), NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
render_path_bind_target(string("texpaint%s", from_id_s), "tex");
@@ -640,7 +649,7 @@ void history_redo_new_black_mask(slot_layer_t *l) {
}
void history_swap_active() {
slot_layer_t *undo_layer = history_undo_layers->buffer[history_undo_i];
slot_layer_t *undo_layer = history_undo_slot(history_undo_i);
slot_layer_swap(undo_layer, g_context->layer);
history_undo_i = (history_undo_i + 1) % g_config->undo_steps;
}
@@ -736,7 +745,7 @@ void history_redo() {
sys_notify_on_next_frame(&history_redo_invert_mask, step);
}
else if (step->action == HISTORY_ACTION_APPLY_FILTER) {
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
context_set_layer(g_project->_->layers->buffer[step->layer]);
slot_layer_swap(g_context->layer, lay);
layers_new_mask(false, lay, -1);
@@ -745,14 +754,14 @@ void history_redo() {
history_undo_i = (history_undo_i + 1) % g_config->undo_steps;
}
else if (step->action == HISTORY_ACTION_TO_FILL_LAYER || step->action == HISTORY_ACTION_TO_FILL_MASK) {
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
g_context->layer->fill_material = g_project->_->materials->buffer[step->material];
history_undo_i = (history_undo_i + 1) % g_config->undo_steps;
}
else if (step->action == HISTORY_ACTION_TO_PAINT_LAYER || step->action == HISTORY_ACTION_TO_PAINT_MASK) {
slot_layer_to_paint_layer(g_context->layer);
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
slot_layer_swap(g_context->layer, lay);
history_undo_i = (history_undo_i + 1) % g_config->undo_steps;
}
@@ -819,7 +828,7 @@ void history_redo() {
ui_nodes_hwnd->redraws = 2;
}
else { // Paint operation
slot_layer_t *lay = history_undo_layers->buffer[history_undo_i];
slot_layer_t *lay = history_undo_slot(history_undo_i);
context_select_paint_object(g_project->_->paint_objects->buffer[step->object]);
context_set_layer(g_project->_->layers->buffer[step->layer]);
slot_layer_swap(g_context->layer, lay);
@@ -118,7 +118,10 @@ bool render_path_raytrace_bake_commands(void (*parse_paint_material)(bool)) {
}
else {
render_target_t *texpaint_undo = any_map_get(render_path_render_targets, string("texpaint_undo%d", history_undo_i));
tex2 = texpaint_undo->_image;
if (texpaint_undo == NULL) {
texpaint_undo = any_map_get(render_path_render_targets, "empty_black");
}
tex2 = texpaint_undo->_image;
}
gpu_raytrace_set_textures(baketex0->_image, baketex1->_image, tex2, saved_envmap, bnoise_sobol, bnoise_scramble, bnoise_rank, NULL);
+51 -27
View File
@@ -1,6 +1,49 @@
#include "global.h"
bool slot_layer_defer_alloc = false;
void slot_layer_alloc_textures(slot_layer_t *raw) {
if (raw->texpaint != NULL) {
return;
}
char *ext = raw->ext;
char *format = base_bits_handle->i == TEXTURE_BITS_BITS8 ? "RGBA32" : base_bits_handle->i == TEXTURE_BITS_BITS16 ? "RGBA64" : "RGBA128";
{
render_target_t *t = render_target_create();
t->name = string("texpaint%s", ext);
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = string_copy(format);
raw->texpaint = render_path_create_render_target(t)->_image;
}
{
render_target_t *t = render_target_create();
t->name = string("texpaint_nor%s", ext);
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = string_copy(format);
raw->texpaint_nor = render_path_create_render_target(t)->_image;
}
{
render_target_t *t = render_target_create();
t->name = string("texpaint_pack%s", ext);
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = string_copy(format);
raw->texpaint_pack = render_path_create_render_target(t)->_image;
}
}
slot_layer_t *slot_layer_create_undo(char *ext) {
slot_layer_defer_alloc = true;
slot_layer_t *l = slot_layer_create(ext, LAYER_SLOT_TYPE_LAYER, NULL);
slot_layer_defer_alloc = false;
return l;
}
slot_layer_t *slot_layer_create(char *ext, layer_slot_type_t type, slot_layer_t *parent) {
slot_layer_t *raw = ALLOC_INIT(slot_layer_t, {0});
raw->id = 0;
@@ -44,34 +87,11 @@ slot_layer_t *slot_layer_create(char *ext, layer_slot_type_t type, slot_layer_t
raw->name = string("Group %d", id);
}
else if (type == LAYER_SLOT_TYPE_LAYER) {
i32 id = (raw->id + 1);
raw->name = string("Layer %d", id);
char *format = base_bits_handle->i == TEXTURE_BITS_BITS8 ? "RGBA32" : base_bits_handle->i == TEXTURE_BITS_BITS16 ? "RGBA64" : "RGBA128";
i32 id = (raw->id + 1);
raw->name = string("Layer %d", id);
{
render_target_t *t = render_target_create();
t->name = string("texpaint%s", ext);
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = string_copy(format);
raw->texpaint = render_path_create_render_target(t)->_image;
}
{
render_target_t *t = render_target_create();
t->name = string("texpaint_nor%s", ext);
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = string_copy(format);
raw->texpaint_nor = render_path_create_render_target(t)->_image;
}
{
render_target_t *t = render_target_create();
t->name = string("texpaint_pack%s", ext);
t->width = config_get_texture_res_x();
t->height = config_get_texture_res_y();
t->format = string_copy(format);
raw->texpaint_pack = render_path_create_render_target(t)->_image;
if (!slot_layer_defer_alloc) {
slot_layer_alloc_textures(raw);
}
raw->texpaint_preview = gpu_create_render_target(util_render_layer_preview_size, util_render_layer_preview_size, GPU_TEXTURE_FORMAT_RGBA32);
@@ -144,6 +164,10 @@ void slot_layer_delete(slot_layer_t *raw) {
void slot_layer_unload(slot_layer_t *raw) {
if (slot_layer_is_group(raw)) {
if (raw->texpaint_preview != NULL) {
gpu_delete_texture(raw->texpaint_preview);
raw->texpaint_preview = NULL;
}
return;
}
+1 -1
View File
@@ -372,7 +372,7 @@ void box_preferences_usage_tab() {
if (history_undo_layers != NULL) {
while (history_undo_layers->length < g_config->undo_steps) {
i32 len = history_undo_layers->length;
slot_layer_t *l = slot_layer_create(string("_undo%s", i32_to_string(len)), LAYER_SLOT_TYPE_LAYER, NULL);
slot_layer_t *l = slot_layer_create_undo(string("_undo%s", i32_to_string(len)));
any_array_push(history_undo_layers, l);
}
while (history_undo_layers->length > g_config->undo_steps) {
+1 -1
View File
@@ -68,7 +68,7 @@ void layers_init() {
}
void layers_resize() {
if (config_get_texture_res_x() >= 16384 || config_get_texture_res_y() >= 16384) { // Save memory for >=16k
if (config_get_texture_res_x() >= 8192 || config_get_texture_res_y() >= 8192) { // Save memory for >=8k
g_config->undo_steps = 1;
while (history_undo_layers->length > g_config->undo_steps) {
slot_layer_t *l = array_pop(history_undo_layers);