Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/image_gpu.c
| Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | const bool store_premultiplied = | ||||
| (ibuf->rect_float ? (image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false) : | (ibuf->rect_float ? (image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false) : | ||||
| (image ? (image->alpha_mode == IMA_ALPHA_PREMUL) : true))); | (image ? (image->alpha_mode == IMA_ALPHA_PREMUL) : true))); | ||||
| return store_premultiplied; | return store_premultiplied; | ||||
| } | } | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name UDIM gpu texture | /** \name UDIM gpu texture | ||||
| * \{ */ | * \{ */ | ||||
| static bool is_over_resolution_limit(int w, int h, bool limit_gl_texture_size) | |||||
| static bool is_over_resolution_limit(int w, int h) | |||||
| { | { | ||||
| return (w > GPU_texture_size_with_limit(w) || h > GPU_texture_size_with_limit(h)); | return (w > GPU_texture_size_with_limit(w, limit_gl_texture_size) || | ||||
| h > GPU_texture_size_with_limit(h, limit_gl_texture_size)); | |||||
| } | } | ||||
| static int smaller_power_of_2_limit(int num) | static int smaller_power_of_2_limit(int num, bool limit_gl_texture_size) | ||||
| { | { | ||||
| return power_of_2_min_i(GPU_texture_size_with_limit(num)); | return power_of_2_min_i(GPU_texture_size_with_limit(num, limit_gl_texture_size)); | ||||
| } | } | ||||
| static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye) | static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye) | ||||
| { | { | ||||
| GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye]; | GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye]; | ||||
| if (tilearray == NULL) { | if (tilearray == NULL) { | ||||
| return 0; | return 0; | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static int compare_packtile(const void *a, const void *b) | ||||
| const PackTile *tile_a = (const PackTile *)a; | const PackTile *tile_a = (const PackTile *)a; | ||||
| const PackTile *tile_b = (const PackTile *)b; | const PackTile *tile_b = (const PackTile *)b; | ||||
| return tile_a->pack_score < tile_b->pack_score; | return tile_a->pack_score < tile_b->pack_score; | ||||
| } | } | ||||
| static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) | static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) | ||||
| { | { | ||||
| const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0; | |||||
| int arraywidth = 0, arrayheight = 0; | int arraywidth = 0, arrayheight = 0; | ||||
| ListBase boxes = {NULL}; | ListBase boxes = {NULL}; | ||||
| LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { | LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { | ||||
| ImageUser iuser; | ImageUser iuser; | ||||
| BKE_imageuser_default(&iuser); | BKE_imageuser_default(&iuser); | ||||
| iuser.tile = tile->tile_number; | iuser.tile = tile->tile_number; | ||||
| ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); | ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); | ||||
| if (ibuf) { | if (ibuf) { | ||||
| PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__); | PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__); | ||||
| packtile->tile = tile; | packtile->tile = tile; | ||||
| packtile->boxpack.w = ibuf->x; | packtile->boxpack.w = ibuf->x; | ||||
| packtile->boxpack.h = ibuf->y; | packtile->boxpack.h = ibuf->y; | ||||
| if (is_over_resolution_limit(packtile->boxpack.w, packtile->boxpack.h)) { | if (is_over_resolution_limit( | ||||
| packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w); | packtile->boxpack.w, packtile->boxpack.h, limit_gl_texture_size)) { | ||||
| packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h); | packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w, limit_gl_texture_size); | ||||
| packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h, limit_gl_texture_size); | |||||
| } | } | ||||
| arraywidth = max_ii(arraywidth, packtile->boxpack.w); | arraywidth = max_ii(arraywidth, packtile->boxpack.w); | ||||
| arrayheight = max_ii(arrayheight, packtile->boxpack.h); | arrayheight = max_ii(arrayheight, packtile->boxpack.h); | ||||
| /* We sort the tiles by decreasing size, with an additional penalty term | /* We sort the tiles by decreasing size, with an additional penalty term | ||||
| * for high aspect ratios. This improves packing efficiency. */ | * for high aspect ratios. This improves packing efficiency. */ | ||||
| float w = packtile->boxpack.w, h = packtile->boxpack.h; | float w = packtile->boxpack.w, h = packtile->boxpack.h; | ||||
| packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h; | packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h; | ||||
| ▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | static GPUTexture *image_get_gpu_texture(Image *ima, | ||||
| gpu_free_unused_buffers(); | gpu_free_unused_buffers(); | ||||
| /* Free GPU textures when requesting a different render pass/layer. | /* Free GPU textures when requesting a different render pass/layer. | ||||
| * When `iuser` isn't set (texture painting single image mode) we assume that | * When `iuser` isn't set (texture painting single image mode) we assume that | ||||
| * the current `pass` and `layer` should be 0. */ | * the current `pass` and `layer` should be 0. */ | ||||
| short requested_pass = iuser ? iuser->pass : 0; | short requested_pass = iuser ? iuser->pass : 0; | ||||
| short requested_layer = iuser ? iuser->layer : 0; | short requested_layer = iuser ? iuser->layer : 0; | ||||
| short requested_slot = ima->render_slot; | short requested_slot = ima->render_slot; | ||||
| const bool limit_resolution = U.glreslimit != 0 && | |||||
| ((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) || | |||||
| (iuser == NULL)); | |||||
| short requested_gpu_flags = limit_resolution ? 0 : IMA_GPU_MAX_RESOLUTION; | |||||
| #define GPU_FLAGS_TO_CHECK (IMA_GPU_MAX_RESOLUTION) | |||||
| if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer || | if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer || | ||||
| ima->gpu_slot != requested_slot) { | ima->gpu_slot != requested_slot || | ||||
| ((ima->gpuflag & GPU_FLAGS_TO_CHECK) != requested_gpu_flags)) { | |||||
| ima->gpu_pass = requested_pass; | ima->gpu_pass = requested_pass; | ||||
| ima->gpu_layer = requested_layer; | ima->gpu_layer = requested_layer; | ||||
| ima->gpu_slot = requested_slot; | ima->gpu_slot = requested_slot; | ||||
| ima->gpuflag |= IMA_GPU_REFRESH; | ima->gpuflag &= ~GPU_FLAGS_TO_CHECK; | ||||
| ima->gpuflag |= requested_gpu_flags | IMA_GPU_REFRESH; | |||||
| } | } | ||||
| #undef GPU_FLAGS_TO_CHECK | |||||
| /* currently, gpu refresh tagging is used by ima sequences */ | /* currently, gpu refresh tagging is used by ima sequences */ | ||||
| if (ima->gpuflag & IMA_GPU_REFRESH) { | if (ima->gpuflag & IMA_GPU_REFRESH) { | ||||
| image_free_gpu(ima, true); | image_free_gpu(ima, true); | ||||
| ima->gpuflag &= ~IMA_GPU_REFRESH; | ima->gpuflag &= ~IMA_GPU_REFRESH; | ||||
| } | } | ||||
| /* Tag as in active use for garbage collector. */ | /* Tag as in active use for garbage collector. */ | ||||
| Show All 31 Lines | #undef GPU_FLAGS_TO_CHECK | ||||
| } | } | ||||
| else if (textarget == TEXTARGET_TILE_MAPPING) { | else if (textarget == TEXTARGET_TILE_MAPPING) { | ||||
| *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0); | *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0); | ||||
| } | } | ||||
| else { | else { | ||||
| const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH); | const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH); | ||||
| const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, | const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, | ||||
| ibuf_intern); | ibuf_intern); | ||||
| const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0; | |||||
| *tex = IMB_create_gpu_texture( | *tex = IMB_create_gpu_texture(ima->id.name + 2, | ||||
| ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied); | ibuf_intern, | ||||
| use_high_bitdepth, | |||||
| store_premultiplied, | |||||
| limit_gl_texture_size); | |||||
| GPU_texture_wrap_mode(*tex, true, false); | GPU_texture_wrap_mode(*tex, true, false); | ||||
| if (GPU_mipmap_enabled()) { | if (GPU_mipmap_enabled()) { | ||||
| GPU_texture_generate_mipmap(*tex); | GPU_texture_generate_mipmap(*tex); | ||||
| if (ima) { | if (ima) { | ||||
| ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; | ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | static void gpu_texture_update_scaled(GPUTexture *tex, | ||||
| int full_w, | int full_w, | ||||
| int full_h, | int full_h, | ||||
| int x, | int x, | ||||
| int y, | int y, | ||||
| int layer, | int layer, | ||||
| const int *tile_offset, | const int *tile_offset, | ||||
| const int *tile_size, | const int *tile_size, | ||||
| int w, | int w, | ||||
| int h) | int h, | ||||
| bool limit_gl_texture_size) | |||||
| { | { | ||||
| ImBuf *ibuf; | ImBuf *ibuf; | ||||
| if (layer > -1) { | if (layer > -1) { | ||||
| ibuf = update_do_scale( | ibuf = update_do_scale( | ||||
| rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h); | rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h); | ||||
| /* Shift to account for tile packing. */ | /* Shift to account for tile packing. */ | ||||
| x += tile_offset[0]; | x += tile_offset[0]; | ||||
| y += tile_offset[1]; | y += tile_offset[1]; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Partial update with scaling. */ | /* Partial update with scaling. */ | ||||
| int limit_w = smaller_power_of_2_limit(full_w); | int limit_w = smaller_power_of_2_limit(full_w, limit_gl_texture_size); | ||||
| int limit_h = smaller_power_of_2_limit(full_h); | int limit_h = smaller_power_of_2_limit(full_h, limit_gl_texture_size); | ||||
| ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h); | ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h); | ||||
| } | } | ||||
| void *data = (ibuf->rect_float) ? (void *)(ibuf->rect_float) : (void *)(ibuf->rect); | void *data = (ibuf->rect_float) ? (void *)(ibuf->rect_float) : (void *)(ibuf->rect); | ||||
| eGPUDataFormat data_format = (ibuf->rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE; | eGPUDataFormat data_format = (ibuf->rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE; | ||||
| GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1); | GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1); | ||||
| Show All 30 Lines | static void gpu_texture_update_unscaled(GPUTexture *tex, | ||||
| /* Restore default. */ | /* Restore default. */ | ||||
| GPU_unpack_row_length_set(0); | GPU_unpack_row_length_set(0); | ||||
| } | } | ||||
| static void gpu_texture_update_from_ibuf( | static void gpu_texture_update_from_ibuf( | ||||
| GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h) | GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h) | ||||
| { | { | ||||
| bool scaled; | bool scaled; | ||||
| const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0; | |||||
| if (tile != NULL) { | if (tile != NULL) { | ||||
| int *tilesize = tile->runtime.tilearray_size; | int *tilesize = tile->runtime.tilearray_size; | ||||
| scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]); | scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]); | ||||
| } | } | ||||
| else { | else { | ||||
| scaled = is_over_resolution_limit(ibuf->x, ibuf->y); | scaled = is_over_resolution_limit(ibuf->x, ibuf->y, limit_gl_texture_size); | ||||
| } | } | ||||
| if (scaled) { | if (scaled) { | ||||
| /* Extra padding to account for bleed from neighboring pixels. */ | /* Extra padding to account for bleed from neighboring pixels. */ | ||||
| const int padding = 4; | const int padding = 4; | ||||
| const int xmax = min_ii(x + w + padding, ibuf->x); | const int xmax = min_ii(x + w + padding, ibuf->x); | ||||
| const int ymax = min_ii(y + h + padding, ibuf->y); | const int ymax = min_ii(y + h + padding, ibuf->y); | ||||
| x = max_ii(x - padding, 0); | x = max_ii(x - padding, 0); | ||||
| ▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | static void gpu_texture_update_from_ibuf( | ||||
| } | } | ||||
| if (scaled) { | if (scaled) { | ||||
| /* Slower update where we first have to scale the input pixels. */ | /* Slower update where we first have to scale the input pixels. */ | ||||
| if (tile != NULL) { | if (tile != NULL) { | ||||
| int *tileoffset = tile->runtime.tilearray_offset; | int *tileoffset = tile->runtime.tilearray_offset; | ||||
| int *tilesize = tile->runtime.tilearray_size; | int *tilesize = tile->runtime.tilearray_size; | ||||
| int tilelayer = tile->runtime.tilearray_layer; | int tilelayer = tile->runtime.tilearray_layer; | ||||
| gpu_texture_update_scaled( | gpu_texture_update_scaled(tex, | ||||
| tex, rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h); | rect, | ||||
| } | rect_float, | ||||
| else { | ibuf->x, | ||||
| gpu_texture_update_scaled( | ibuf->y, | ||||
| tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, NULL, NULL, w, h); | x, | ||||
| y, | |||||
| tilelayer, | |||||
| tileoffset, | |||||
| tilesize, | |||||
| w, | |||||
| h, | |||||
| limit_gl_texture_size); | |||||
| } | |||||
| else { | |||||
| gpu_texture_update_scaled(tex, | |||||
| rect, | |||||
| rect_float, | |||||
| ibuf->x, | |||||
| ibuf->y, | |||||
| x, | |||||
| y, | |||||
| -1, | |||||
| NULL, | |||||
| NULL, | |||||
| w, | |||||
| h, | |||||
| limit_gl_texture_size); | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* Fast update at same resolution. */ | /* Fast update at same resolution. */ | ||||
| if (tile != NULL) { | if (tile != NULL) { | ||||
| int *tileoffset = tile->runtime.tilearray_offset; | int *tileoffset = tile->runtime.tilearray_offset; | ||||
| int tilelayer = tile->runtime.tilearray_layer; | int tilelayer = tile->runtime.tilearray_layer; | ||||
| gpu_texture_update_unscaled( | gpu_texture_update_unscaled( | ||||
| ▲ Show 20 Lines • Show All 84 Lines • Show Last 20 Lines | |||||