Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/image.c
| Show First 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | static void image_foreach_cache(ID *id, | ||||
| LISTBASE_FOREACH (RenderSlot *, slot, &image->renderslots) { | LISTBASE_FOREACH (RenderSlot *, slot, &image->renderslots) { | ||||
| key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(slot->name); | key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(slot->name); | ||||
| key.cache_v = slot->render; | key.cache_v = slot->render; | ||||
| function_callback(id, &key, (void **)&slot->render, 0, user_data); | function_callback(id, &key, (void **)&slot->render, 0, user_data); | ||||
| } | } | ||||
| } | } | ||||
| /* When uncommented will dump the image to the console so we can check what part of the image isn't | |||||
| * the same. Unequal data between image write and read from the undo stack leads to | |||||
| * triggering clearing of GPU textures. | |||||
| * | |||||
| * It is not intended to commit this to master, but only for debugging T90593.*/ | |||||
| #define IMAGE_UNDO_HEX_DUMP | |||||
| #ifdef IMAGE_UNDO_HEX_DUMP | |||||
| # include <ctype.h> | |||||
| static uint8_t convert_to_ascii(uint8_t in) | |||||
| { | |||||
| if (isprint(in)) { | |||||
| return in; | |||||
| } | |||||
| return in == 0 ? ' ' : '.'; | |||||
| } | |||||
| static void print_image_hex(Image *image, const char *name) | |||||
| { | |||||
| /* Limiting to images so it doesn't dump render results. */ | |||||
| if (image->type != IMA_TYPE_IMAGE) { | |||||
| return; | |||||
| } | |||||
| uint8_t ascii[33]; | |||||
| memset(ascii, 0, sizeof(ascii)); | |||||
| printf(" %s\n", name); | |||||
| uint8_t *data = (uint8_t *)image; | |||||
| for (unsigned int i = 0; i < sizeof(Image); i++) { | |||||
| if (i % 32 == 0) { | |||||
| printf(" %s\n%08x: ", ascii, i); | |||||
| memset(ascii, 0, sizeof(ascii)); | |||||
| } | |||||
| else if (i % 8 == 0) { | |||||
| printf(" "); | |||||
| } | |||||
| /* Print hex data */ | |||||
| printf("%02x ", data[i]); | |||||
| ascii[i % 32] = convert_to_ascii(data[i]); | |||||
| } | |||||
| printf("\n"); | |||||
| } | |||||
| #endif | |||||
| static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address) | static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address) | ||||
| { | { | ||||
| Image *ima = (Image *)id; | Image *ima = (Image *)id; | ||||
| const bool is_undo = BLO_write_is_undo(writer); | const bool is_undo = BLO_write_is_undo(writer); | ||||
| if (ima->id.us > 0 || is_undo) { | if (ima->id.us > 0 || is_undo) { | ||||
| /* Clear all data that isn't read to reuse image during undo. */ | |||||
| Image prev_data = *ima; | |||||
mont29: No need to store previous data here, the pointer that those callbacks get is already a temp… | |||||
| ima->cache = NULL; | |||||
| ima->gpuflag = 0; | |||||
| BLI_listbase_clear(&ima->anims); | |||||
| BLI_listbase_clear(&ima->gpu_refresh_areas); | |||||
| for (int i = 0; i < 3; i++) { | |||||
| for (int j = 0; j < 2; j++) { | |||||
| ima->gputexture[i][j] = NULL; | |||||
| } | |||||
| } | |||||
| BKE_id_blend_write(writer, &ima->id); | |||||
mont29Unsubmitted Not Done Inline ActionsThis is a copy/paste mistake I guess? Obvious bug in any case, this needs to be called after everything has been cleared, and is already below in code. ;) mont29: This is a copy/paste mistake I guess? Obvious bug in any case, this needs to be called after… | |||||
| ImagePackedFile *imapf; | ImagePackedFile *imapf; | ||||
| BLI_assert(ima->packedfile == NULL); | BLI_assert(ima->packedfile == NULL); | ||||
| /* Do not store packed files in case this is a library override ID. */ | /* Do not store packed files in case this is a library override ID. */ | ||||
| if (ID_IS_OVERRIDE_LIBRARY(ima) && !is_undo) { | if (!is_undo) { | ||||
| if (ID_IS_OVERRIDE_LIBRARY(ima)) { | |||||
| BLI_listbase_clear(&ima->packedfiles); | BLI_listbase_clear(&ima->packedfiles); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Some trickery to keep forward compatibility of packed images. */ | /* Some trickery to keep forward compatibility of packed images. */ | ||||
| if (ima->packedfiles.first != NULL) { | if (ima->packedfiles.first != NULL) { | ||||
| imapf = ima->packedfiles.first; | imapf = ima->packedfiles.first; | ||||
| ima->packedfile = imapf->packedfile; | ima->packedfile = imapf->packedfile; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /* write LibData */ | /* write LibData */ | ||||
| #ifdef IMAGE_UNDO_HEX_DUMP | |||||
| print_image_hex(ima, __func__); | |||||
| #endif | |||||
| BLO_write_id_struct(writer, Image, id_address, &ima->id); | BLO_write_id_struct(writer, Image, id_address, &ima->id); | ||||
| BKE_id_blend_write(writer, &ima->id); | BKE_id_blend_write(writer, &ima->id); | ||||
| for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { | for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { | ||||
| BLO_write_struct(writer, ImagePackedFile, imapf); | BLO_write_struct(writer, ImagePackedFile, imapf); | ||||
| BKE_packedfile_blend_write(writer, imapf->packedfile); | BKE_packedfile_blend_write(writer, imapf->packedfile); | ||||
| } | } | ||||
| BKE_previewimg_blend_write(writer, ima->preview); | BKE_previewimg_blend_write(writer, ima->preview); | ||||
| LISTBASE_FOREACH (ImageView *, iv, &ima->views) { | LISTBASE_FOREACH (ImageView *, iv, &ima->views) { | ||||
| BLO_write_struct(writer, ImageView, iv); | BLO_write_struct(writer, ImageView, iv); | ||||
| } | } | ||||
| BLO_write_struct(writer, Stereo3dFormat, ima->stereo3d_format); | BLO_write_struct(writer, Stereo3dFormat, ima->stereo3d_format); | ||||
| BLO_write_struct_list(writer, ImageTile, &ima->tiles); | BLO_write_struct_list(writer, ImageTile, &ima->tiles); | ||||
| ima->packedfile = NULL; | |||||
| BLO_write_struct_list(writer, RenderSlot, &ima->renderslots); | BLO_write_struct_list(writer, RenderSlot, &ima->renderslots); | ||||
| /* Restore data that have been cleared to match the logic in image_blend_read_data. */ | |||||
| ima->packedfile = NULL; | |||||
| ima->cache = prev_data.cache; | |||||
| ima->gpuflag = prev_data.gpuflag; | |||||
| ima->gpu_refresh_areas = prev_data.gpu_refresh_areas; | |||||
| ima->anims = prev_data.anims; | |||||
| for (int i = 0; i < 3; i++) { | |||||
| for (int j = 0; j < 2; j++) { | |||||
| ima->gputexture[i][j] = prev_data.gputexture[i][j]; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| static void image_blend_read_data(BlendDataReader *reader, ID *id) | static void image_blend_read_data(BlendDataReader *reader, ID *id) | ||||
| { | { | ||||
| Image *ima = (Image *)id; | Image *ima = (Image *)id; | ||||
| #ifdef IMAGE_UNDO_HEX_DUMP | |||||
| print_image_hex(ima, __func__); | |||||
| #endif | |||||
mont29Unsubmitted Not Done Inline ActionsThis is not the proper place to call this, as generic readfile calling code (aka direct_link_id/direct_link_id_common) has already restored a lot of those ID runtime data. mont29: This is not the proper place to call this, as generic readfile calling code (aka… | |||||
| BLO_read_list(reader, &ima->tiles); | BLO_read_list(reader, &ima->tiles); | ||||
| BLO_read_list(reader, &(ima->renderslots)); | BLO_read_list(reader, &(ima->renderslots)); | ||||
| if (!BLO_read_data_is_undo(reader)) { | if (!BLO_read_data_is_undo(reader)) { | ||||
| /* We reset this last render slot index only when actually reading a file, not for undo. */ | /* We reset this last render slot index only when actually reading a file, not for undo. */ | ||||
| ima->last_render_slot = ima->render_slot; | ima->last_render_slot = ima->render_slot; | ||||
| } | } | ||||
| Show All 24 Lines | |||||
| static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id) | static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id) | ||||
| { | { | ||||
| Image *ima = (Image *)id; | Image *ima = (Image *)id; | ||||
| /* Images have some kind of 'main' cache, when NULL we should also clear all others. */ | /* Images have some kind of 'main' cache, when NULL we should also clear all others. */ | ||||
| /* Needs to be done *after* cache pointers are restored (call to | /* Needs to be done *after* cache pointers are restored (call to | ||||
| * `foreach_cache`/`blo_cache_storage_entry_restore_in_new`), easier for now to do it in | * `foreach_cache`/`blo_cache_storage_entry_restore_in_new`), easier for now to do it in | ||||
| * lib_link... */ | * lib_link... */ | ||||
| if (ima->cache == NULL) { | if (ima->cache == NULL) { | ||||
| #ifdef IMAGE_UNDO_HEX_DUMP | |||||
| /* We don't want to be here during undo. */ | |||||
| printf("%s Freeing textures.\n", __func__); | |||||
| #endif | |||||
| BKE_image_free_buffers(ima); | BKE_image_free_buffers(ima); | ||||
| } | } | ||||
| } | } | ||||
| IDTypeInfo IDType_ID_IM = { | IDTypeInfo IDType_ID_IM = { | ||||
| .id_code = ID_IM, | .id_code = ID_IM, | ||||
| .id_filter = FILTER_ID_IM, | .id_filter = FILTER_ID_IM, | ||||
| .main_listbase_index = INDEX_ID_IM, | .main_listbase_index = INDEX_ID_IM, | ||||
| ▲ Show 20 Lines • Show All 5,693 Lines • Show Last 20 Lines | |||||
No need to store previous data here, the pointer that those callbacks get is already a temp copy generated by write code, precisely to allow tempering with the ID struct data itself easily.