Blender V4.3
image_gpu.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_boxpack_2d.h"
12#include "BLI_linklist.h"
13#include "BLI_listbase.h"
14#include "BLI_threads.h"
15#include "BLI_time.h"
16
17#include "DNA_image_types.h"
18#include "DNA_userdef_types.h"
19
21#include "IMB_imbuf.hh"
22#include "IMB_imbuf_types.hh"
23
24#include "BKE_global.hh"
25#include "BKE_image.hh"
27#include "BKE_main.hh"
28
29#include "GPU_capabilities.hh"
30#include "GPU_state.hh"
31#include "GPU_texture.hh"
32
34
35/* Prototypes. */
36static void gpu_free_unused_buffers();
37static void image_free_gpu(Image *ima, const bool immediate);
39 Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h);
40
42{
43 if (image) {
44 /* Render result and compositor output are always premultiplied */
45 if (ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
46 return true;
47 }
48 /* Generated images use pre multiplied float buffer, but straight alpha for byte buffers. */
49 if (image->type == IMA_TYPE_UV_TEST && ibuf) {
50 return ibuf->float_buffer.data != nullptr;
51 }
52 }
53 if (ibuf) {
54 if (ibuf->float_buffer.data) {
55 return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
56 }
57
58 return image ? (image->alpha_mode == IMA_ALPHA_PREMUL) : true;
59 }
60 return false;
61}
62
63/* -------------------------------------------------------------------- */
67static bool is_over_resolution_limit(int w, int h)
68{
70}
71
72static int smaller_power_of_2_limit(int num)
73{
75}
76
77static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
78{
79 GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
80
81 if (tilearray == nullptr) {
82 return nullptr;
83 }
84
85 float array_w = GPU_texture_width(tilearray);
86 float array_h = GPU_texture_height(tilearray);
87
88 /* Determine maximum tile number. */
90 ImageTile *last_tile = (ImageTile *)ima->tiles.last;
91 int max_tile = last_tile->tile_number - 1001;
92
93 /* create image */
94 int width = max_tile + 1;
95 float *data = (float *)MEM_callocN(width * 8 * sizeof(float), __func__);
96 for (int i = 0; i < width; i++) {
97 data[4 * i] = -1.0f;
98 }
100 int i = tile->tile_number - 1001;
101 ImageTile_Runtime *tile_runtime = &tile->runtime;
102 data[4 * i] = tile_runtime->tilearray_layer;
103
104 float *tile_info = &data[4 * width + 4 * i];
105 tile_info[0] = tile_runtime->tilearray_offset[0] / array_w;
106 tile_info[1] = tile_runtime->tilearray_offset[1] / array_h;
107 tile_info[2] = tile_runtime->tilearray_size[0] / array_w;
108 tile_info[3] = tile_runtime->tilearray_size[1] / array_h;
109 }
110
111 GPUTexture *tex = GPU_texture_create_1d_array(
112 ima->id.name + 2, width, 2, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_SHADER_READ, data);
113 GPU_texture_mipmap_mode(tex, false, false);
114
115 MEM_freeN(data);
116
117 return tex;
118}
119
125
126static int compare_packtile(const void *a, const void *b)
127{
128 const PackTile *tile_a = (const PackTile *)a;
129 const PackTile *tile_b = (const PackTile *)b;
130
131 return tile_a->pack_score < tile_b->pack_score;
132}
133
134static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
135{
136 int arraywidth = 0, arrayheight = 0;
137 ListBase boxes = {nullptr};
138
139 int planes = 0;
140
142 ImageUser iuser;
143 BKE_imageuser_default(&iuser);
144 iuser.tile = tile->tile_number;
145 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
146
147 if (ibuf) {
148 PackTile *packtile = MEM_cnew<PackTile>(__func__);
149 packtile->tile = tile;
150 packtile->boxpack.w = ibuf->x;
151 packtile->boxpack.h = ibuf->y;
152
153 if (is_over_resolution_limit(packtile->boxpack.w, packtile->boxpack.h)) {
154 packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
155 packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
156 }
157 arraywidth = max_ii(arraywidth, packtile->boxpack.w);
158 arrayheight = max_ii(arrayheight, packtile->boxpack.h);
159
160 /* We sort the tiles by decreasing size, with an additional penalty term
161 * for high aspect ratios. This improves packing efficiency. */
162 float w = packtile->boxpack.w, h = packtile->boxpack.h;
163 packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h;
164
165 BKE_image_release_ibuf(ima, ibuf, nullptr);
166 BLI_addtail(&boxes, packtile);
167 planes = max_ii(planes, ibuf->planes);
168 }
169 }
170
171 BLI_assert(arraywidth > 0 && arrayheight > 0);
172
174 int arraylayers = 0;
175 /* Keep adding layers until all tiles are packed. */
176 while (boxes.first != nullptr) {
177 ListBase packed = {nullptr};
178 BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
179 BLI_assert(packed.first != nullptr);
180
181 LISTBASE_FOREACH (PackTile *, packtile, &packed) {
182 ImageTile *tile = packtile->tile;
183 ImageTile_Runtime *tile_runtime = &tile->runtime;
184 int *tileoffset = tile_runtime->tilearray_offset;
185 int *tilesize = tile_runtime->tilearray_size;
186
187 tileoffset[0] = packtile->boxpack.x;
188 tileoffset[1] = packtile->boxpack.y;
189 tilesize[0] = packtile->boxpack.w;
190 tilesize[1] = packtile->boxpack.h;
191 tile_runtime->tilearray_layer = arraylayers;
192 }
193
194 BLI_freelistN(&packed);
195 arraylayers++;
196 }
197
198 const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
199 const bool use_grayscale = planes <= 8;
200 /* Create Texture without content. */
201 GPUTexture *tex = IMB_touch_gpu_texture(ima->id.name + 2,
202 main_ibuf,
203 arraywidth,
204 arrayheight,
205 arraylayers,
206 use_high_bitdepth,
207 use_grayscale);
208
209 /* Upload each tile one by one. */
211 const ImageTile_Runtime *tile_runtime = &tile->runtime;
212 const int tilelayer = tile_runtime->tilearray_layer;
213 const int *tileoffset = tile_runtime->tilearray_offset;
214 const int *tilesize = tile_runtime->tilearray_size;
215
216 if (tilesize[0] == 0 || tilesize[1] == 0) {
217 continue;
218 }
219
220 ImageUser iuser;
221 BKE_imageuser_default(&iuser);
222 iuser.tile = tile->tile_number;
223 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
224
225 if (ibuf) {
226 const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
228 ibuf,
229 UNPACK2(tileoffset),
230 tilelayer,
231 UNPACK2(tilesize),
232 use_high_bitdepth,
233 use_grayscale,
234 store_premultiplied);
235 }
236
237 BKE_image_release_ibuf(ima, ibuf, nullptr);
238 }
239
240 if (GPU_mipmap_enabled()) {
242 GPU_texture_mipmap_mode(tex, true, true);
243 if (ima) {
245 }
246 }
247 else {
248 GPU_texture_mipmap_mode(tex, false, true);
249 }
250
251 return tex;
252}
253
256/* -------------------------------------------------------------------- */
260static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
261 eGPUTextureTarget textarget,
262 const int multiview_eye)
263{
264 const bool in_range = (int(textarget) >= 0) && (textarget < TEXTARGET_COUNT);
265 BLI_assert(in_range);
266 BLI_assert(ELEM(multiview_eye, 0, 1));
267
268 if (in_range) {
269 return &(ima->gputexture[textarget][multiview_eye]);
270 }
271 return nullptr;
272}
273
275{
276 fprintf(stderr, "GPUTexture: Blender Texture Not Loaded!\n");
277 switch (textarget) {
279 return GPU_texture_create_error(2, true);
281 return GPU_texture_create_error(1, true);
282 case TEXTARGET_2D:
283 default:
284 return GPU_texture_create_error(2, false);
285 }
286}
287
290{
291 while (changes.get_next_change() == ePartialUpdateIterResult::ChangeAvailable) {
292 /* Calculate the clipping region with the tile buffer.
293 * TODO(jbakker): should become part of ImageTileData to deduplicate with image engine. */
294 rcti buffer_rect;
296 &buffer_rect, 0, changes.tile_data.tile_buffer->x, 0, changes.tile_data.tile_buffer->y);
297 rcti clipped_update_region;
298 const bool has_overlap = BLI_rcti_isect(
299 &buffer_rect, &changes.changed_region.region, &clipped_update_region);
300 if (!has_overlap) {
301 continue;
302 }
303
305 changes.tile_data.tile,
306 changes.tile_data.tile_buffer,
307 clipped_update_region.xmin,
308 clipped_update_region.ymin,
309 BLI_rcti_size_x(&clipped_update_region),
310 BLI_rcti_size_y(&clipped_update_region));
311 }
312}
313
315{
316 PartialUpdateChecker<ImageTileData> checker(image, iuser, image->runtime.partial_update_user);
318 switch (changes.get_result_code()) {
319 case ePartialUpdateCollectResult::FullUpdateNeeded: {
320 image_free_gpu(image, true);
321 break;
322 }
323
324 case ePartialUpdateCollectResult::PartialChangesDetected: {
326 break;
327 }
328
329 case ePartialUpdateCollectResult::NoChangesDetected: {
330 /* GPUTextures are up to date. */
331 break;
332 }
333 }
334}
335
337{
338 if (!image) {
339 return;
340 }
341
342 /* Note that the image can cache both stereo views, so we only invalidate the cache if the view
343 * index is more than 2. */
344 if (image->gpu_pass != image_user->pass || image->gpu_layer != image_user->layer ||
345 (image->gpu_view != image_user->multi_index && image_user->multi_index >= 2))
346 {
348 }
349}
350
352 ImageUser *iuser,
353 const bool use_viewers,
354 const bool use_tile_mapping)
355{
356 ImageGPUTextures result = {};
357
358 if (ima == nullptr) {
359 return result;
360 }
361
362 /* Free any unused GPU textures, since we know we are in a thread with OpenGL
363 * context and might as well ensure we have as much space free as possible. */
365
366 /* Free GPU textures when requesting a different render pass/layer.
367 * When `iuser` isn't set (texture painting single image mode) we assume that
368 * the current `pass` and `layer` should be 0. */
369 short requested_pass = iuser ? iuser->pass : 0;
370 short requested_layer = iuser ? iuser->layer : 0;
371 short requested_view = iuser ? iuser->multi_index : 0;
372 /* There is room for 2 multiview textures. When a higher number is requested we should always
373 * target the first view slot. This is fine as multi view images aren't used together. */
374 if (requested_view < 2) {
375 requested_view = 0;
376 }
377 if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer ||
378 ima->gpu_view != requested_view)
379 {
380 ima->gpu_pass = requested_pass;
381 ima->gpu_layer = requested_layer;
382 ima->gpu_view = requested_view;
383 /* The cache should be invalidated here, but it is intentionally isn't due to possible
384 * performance implications, see the BKE_image_ensure_gpu_texture function for more
385 * information. */
386 }
387#undef GPU_FLAGS_TO_CHECK
388
389 if (ima->runtime.partial_update_user == nullptr) {
391 }
392
394
395 /* Tag as in active use for garbage collector. */
397
398 /* Test if we need to get a tiled array texture. */
399 eGPUTextureTarget textarget = (use_tile_mapping && ima->source == IMA_SRC_TILED) ?
402
403 /* Test if we already have a texture. */
404 int current_view = iuser ? iuser->multi_index : 0;
405 if (current_view >= 2) {
406 current_view = 0;
407 }
408 GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view);
409 if (*tex) {
410 result.texture = *tex;
411 result.tile_mapping = *get_image_gpu_texture_ptr(ima, TEXTARGET_TILE_MAPPING, current_view);
412 return result;
413 }
414
415 /* Check if we have a valid image. If not, we return a dummy
416 * texture with zero bind-code so we don't keep trying. */
418 if (tile == nullptr) {
420 result.texture = *tex;
421 return result;
422 }
423
424 /* check if we have a valid image buffer */
425 void *lock;
426 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, (use_viewers) ? &lock : nullptr);
427 if (ibuf == nullptr) {
428 BKE_image_release_ibuf(ima, ibuf, (use_viewers) ? lock : nullptr);
430 result.texture = *tex;
431
432 return result;
433 }
434
435 if (textarget == TEXTARGET_2D_ARRAY) {
436 /* For materials, array and tile mapping in case there are UDIM tiles. */
438 result.texture = *tex;
439
440 GPUTexture **tile_mapping_tex = get_image_gpu_texture_ptr(
441 ima, TEXTARGET_TILE_MAPPING, current_view);
442 *tile_mapping_tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
443 result.tile_mapping = *tile_mapping_tex;
444 }
445 else {
446 /* Single image texture. */
447 const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
448 const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
449
450 *tex = IMB_create_gpu_texture(ima->id.name + 2, ibuf, use_high_bitdepth, store_premultiplied);
451 result.texture = *tex;
452
453 if (*tex) {
455
456 if (GPU_mipmap_enabled()) {
459 GPU_texture_mipmap_mode(*tex, true, true);
460 }
461 else {
462 GPU_texture_mipmap_mode(*tex, false, true);
463 }
464 }
465 }
466
467 if (*tex) {
468 GPU_texture_original_size_set(*tex, ibuf->x, ibuf->y);
469 }
470
471 BKE_image_release_ibuf(ima, ibuf, (use_viewers) ? lock : nullptr);
472
473 return result;
474}
475
476GPUTexture *BKE_image_get_gpu_texture(Image *image, ImageUser *iuser)
477{
478 return image_get_gpu_texture(image, iuser, false, false).texture;
479}
480
482{
483 return image_get_gpu_texture(image, iuser, true, false).texture;
484}
485
487 ImageUser *iuser,
488 const bool use_tile_mapping)
489{
490 return image_get_gpu_texture(image, iuser, false, use_tile_mapping);
491}
492
495/* -------------------------------------------------------------------- */
504
506{
507 if (gpu_texture_free_queue == nullptr) {
508 return;
509 }
510
512
513 while (gpu_texture_free_queue != nullptr) {
514 GPUTexture *tex = static_cast<GPUTexture *>(BLI_linklist_pop(&gpu_texture_free_queue));
516 }
517
519}
520
527
530/* -------------------------------------------------------------------- */
534static void image_free_gpu(Image *ima, const bool immediate)
535{
536 for (int eye = 0; eye < 2; eye++) {
537 for (int i = 0; i < TEXTARGET_COUNT; i++) {
538 if (ima->gputexture[i][eye] != nullptr) {
539 if (immediate) {
540 GPU_texture_free(ima->gputexture[i][eye]);
541 }
542 else {
546 }
547
548 ima->gputexture[i][eye] = nullptr;
549 }
550 }
551 }
552
553 ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
554}
555
560
562{
563 if (bmain) {
564 LISTBASE_FOREACH (Image *, ima, &bmain->images) {
566 }
567 }
568}
569
571{
572 if (bmain) {
573 LISTBASE_FOREACH (Image *, ima, &bmain->images) {
574 if (BKE_image_is_animated(ima)) {
576 }
577 }
578 }
579}
580
582{
583 static int lasttime = 0;
584 int ctime = int(BLI_time_now_seconds());
585
586 /*
587 * Run garbage collector once for every collecting period of time
588 * if textimeout is 0, that's the option to NOT run the collector
589 */
590 if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) {
591 return;
592 }
593
594 /* of course not! */
595 if (G.is_rendering) {
596 return;
597 }
598
599 lasttime = ctime;
600
601 LISTBASE_FOREACH (Image *, ima, &bmain->images) {
602 if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
603 /* If it's in GL memory, deallocate and set time tag to current time
604 * This gives textures a "second chance" to be used before dying. */
607 ima->lastused = ctime;
608 }
609 /* Otherwise, just kill the buffers */
610 else {
612 }
613 }
614 }
615}
616
619/* -------------------------------------------------------------------- */
623static ImBuf *update_do_scale(const uchar *rect,
624 const float *rect_float,
625 int *x,
626 int *y,
627 int *w,
628 int *h,
629 int limit_w,
630 int limit_h,
631 int full_w,
632 int full_h)
633{
634 /* Partial update with scaling. */
635 float xratio = limit_w / float(full_w);
636 float yratio = limit_h / float(full_h);
637
638 int part_w = *w, part_h = *h;
639
640 /* Find sub coordinates in scaled image. Take ceiling because we will be
641 * losing 1 pixel due to rounding errors in x,y. */
642 *x *= xratio;
643 *y *= yratio;
644 *w = int(ceil(xratio * (*w)));
645 *h = int(ceil(yratio * (*h)));
646
647 /* ...but take back if we are over the limit! */
648 if (*x + *w > limit_w) {
649 (*w)--;
650 }
651 if (*y + *h > limit_h) {
652 (*h)--;
653 }
654
655 /* Scale pixels. */
656 ImBuf *ibuf = IMB_allocFromBuffer(rect, rect_float, part_w, part_h, 4);
657 IMB_scale(ibuf, *w, *h, IMBScaleFilter::Box, false);
658
659 return ibuf;
660}
661
662static void gpu_texture_update_scaled(GPUTexture *tex,
663 const uchar *rect,
664 const float *rect_float,
665 int full_w,
666 int full_h,
667 int x,
668 int y,
669 int layer,
670 const int *tile_offset,
671 const int *tile_size,
672 int w,
673 int h)
674{
675 ImBuf *ibuf;
676 if (layer > -1) {
677 ibuf = update_do_scale(
678 rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h);
679
680 /* Shift to account for tile packing. */
681 x += tile_offset[0];
682 y += tile_offset[1];
683 }
684 else {
685 /* Partial update with scaling. */
686 int limit_w = GPU_texture_width(tex);
687 int limit_h = GPU_texture_height(tex);
688
689 ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
690 }
691
692 void *data = (ibuf->float_buffer.data) ? (void *)(ibuf->float_buffer.data) :
693 (void *)(ibuf->byte_buffer.data);
695
696 GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
697
698 IMB_freeImBuf(ibuf);
699}
700
701static void gpu_texture_update_unscaled(GPUTexture *tex,
702 uchar *rect,
703 float *rect_float,
704 int x,
705 int y,
706 int layer,
707 const int tile_offset[2],
708 int w,
709 int h,
710 int tex_stride,
711 int tex_offset)
712{
713 if (layer > -1) {
714 /* Shift to account for tile packing. */
715 x += tile_offset[0];
716 y += tile_offset[1];
717 }
718
719 void *data = (rect_float) ? (void *)(rect_float + tex_offset) : (void *)(rect + tex_offset);
720 eGPUDataFormat data_format = (rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
721
722 /* Partial update without scaling. Stride and offset are used to copy only a
723 * subset of a possible larger buffer than what we are updating. */
724 GPU_unpack_row_length_set(tex_stride);
725
726 GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
727 /* Restore default. */
729}
730
732 GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
733{
734 bool scaled;
735 if (tile != nullptr) {
736 ImageTile_Runtime *tile_runtime = &tile->runtime;
737 int *tilesize = tile_runtime->tilearray_size;
738 scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
739 }
740 else {
741 scaled = (GPU_texture_width(tex) != ibuf->x) || (GPU_texture_height(tex) != ibuf->y);
742 }
743
744 if (scaled) {
745 /* Extra padding to account for bleed from neighboring pixels. */
746 const int padding = 4;
747 const int xmax = min_ii(x + w + padding, ibuf->x);
748 const int ymax = min_ii(y + h + padding, ibuf->y);
749 x = max_ii(x - padding, 0);
750 y = max_ii(y - padding, 0);
751 w = xmax - x;
752 h = ymax - y;
753 }
754
755 /* Get texture data pointers. */
756 float *rect_float = ibuf->float_buffer.data;
757 uchar *rect = ibuf->byte_buffer.data;
758 int tex_stride = ibuf->x;
759 int tex_offset = ibuf->channels * (y * ibuf->x + x);
760
761 const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
762 if (rect_float) {
763 /* Float image is already in scene linear colorspace or non-color data by
764 * convention, no colorspace conversion needed. But we do require 4 channels
765 * currently. */
766 if (ibuf->channels != 4 || scaled || !store_premultiplied) {
767 rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
768 if (rect_float == nullptr) {
769 return;
770 }
771
772 tex_stride = w;
773 tex_offset = 0;
774
776 rect_float, x, y, w, h, ibuf, store_premultiplied);
777 }
778 }
779 else {
780 /* Byte image is in original colorspace from the file, and may need conversion. */
782 /* Not scaled Non-color data, just store buffer as is. */
783 }
787 {
788 /* sRGB or scene linear or scaled down non-color data, store as byte texture that the GPU
789 * can decode directly. */
790 rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
791 if (rect == nullptr) {
792 return;
793 }
794
795 tex_stride = w;
796 tex_offset = 0;
797
798 /* Convert to scene linear with sRGB compression, and premultiplied for
799 * correct texture interpolation. */
800 IMB_colormanagement_imbuf_to_byte_texture(rect, x, y, w, h, ibuf, store_premultiplied);
801 }
802 else {
803 /* Other colorspace, store as float texture to avoid precision loss. */
804 rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
805 if (rect_float == nullptr) {
806 return;
807 }
808
809 tex_stride = w;
810 tex_offset = 0;
811
813 rect_float, x, y, w, h, ibuf, store_premultiplied);
814 }
815 }
816
817 if (scaled) {
818 /* Slower update where we first have to scale the input pixels. */
819 if (tile != nullptr) {
820 ImageTile_Runtime *tile_runtime = &tile->runtime;
821 int *tileoffset = tile_runtime->tilearray_offset;
822 int *tilesize = tile_runtime->tilearray_size;
823 int tilelayer = tile_runtime->tilearray_layer;
825 tex, rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
826 }
827 else {
829 tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, nullptr, nullptr, w, h);
830 }
831 }
832 else {
833 /* Fast update at same resolution. */
834 if (tile != nullptr) {
835 ImageTile_Runtime *tile_runtime = &tile->runtime;
836 int *tileoffset = tile_runtime->tilearray_offset;
837 int tilelayer = tile_runtime->tilearray_layer;
839 tex, rect, rect_float, x, y, tilelayer, tileoffset, w, h, tex_stride, tex_offset);
840 }
841 else {
843 tex, rect, rect_float, x, y, -1, nullptr, w, h, tex_stride, tex_offset);
844 }
845 }
846
847 /* Free buffers if needed. */
848 if (rect && rect != ibuf->byte_buffer.data) {
849 MEM_freeN(rect);
850 }
851 if (rect_float && rect_float != ibuf->float_buffer.data) {
852 MEM_freeN(rect_float);
853 }
854
855 if (GPU_mipmap_enabled()) {
857 }
858 else {
859 ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
860 }
861
863}
864
866 Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h)
867{
868 const int eye = 0;
869 GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye];
870 /* Check if we need to update the main gputexture. */
871 if (tex != nullptr && tile == ima->tiles.first) {
872 gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h);
873 }
874
875 /* Check if we need to update the array gputexture. */
876 tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye];
877 if (tex != nullptr) {
878 gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
879 }
880}
881
882void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
883{
884 ImageTile *image_tile = BKE_image_get_tile_from_iuser(ima, iuser);
885 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, nullptr);
886 BKE_image_update_gputexture_delayed(ima, image_tile, ibuf, x, y, w, h);
887 BKE_image_release_ibuf(ima, ibuf, nullptr);
888}
889
891 Image *ima, ImageTile *image_tile, ImBuf *ibuf, int x, int y, int w, int h)
892{
893 /* Check for full refresh. */
894 if (ibuf != nullptr && ima->source != IMA_SRC_TILED && x == 0 && y == 0 && w == ibuf->x &&
895 h == ibuf->y)
896 {
898 }
899 else {
900 rcti dirty_region;
901 BLI_rcti_init(&dirty_region, x, x + w, y, y + h);
902 BKE_image_partial_update_mark_region(ima, image_tile, ibuf, &dirty_region);
903 }
904}
905
906void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
907{
908 LISTBASE_FOREACH (Image *, ima, &bmain->images) {
910 if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
911 for (int a = 0; a < TEXTARGET_COUNT; a++) {
913 for (int eye = 0; eye < 2; eye++) {
914 GPUTexture *tex = ima->gputexture[a][eye];
915 if (tex != nullptr) {
916 GPU_texture_mipmap_mode(tex, mipmap, true);
917 }
918 }
919 }
920 }
921 }
922 else {
924 }
925 }
926 else {
927 ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
928 }
929 }
930}
931
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_partial_update_mark_region(Image *image, const ImageTile *image_tile, const ImBuf *image_buffer, const rcti *updated_region)
Mark a region of the image to update.
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_tag_time(Image *ima)
void BKE_image_sort_tiles(Image *ima)
bool BKE_image_has_opengl_texture(Image *ima)
void BKE_imageuser_default(ImageUser *iuser)
PartialUpdateUser * BKE_image_partial_update_create(const Image *image)
Create a new PartialUpdateUser. An Object that contains data to use partial updates.
bool BKE_image_is_animated(Image *image)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes, int width, int height, struct ListBase *packed)
Definition boxpack_2d.c:663
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE int power_of_2_min_i(int n)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
unsigned char uchar
#define BLI_MUTEX_INITIALIZER
Definition BLI_threads.h:84
int BLI_thread_is_main(void)
Definition threads.cc:179
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:83
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define UNPACK2(a)
#define ELEM(...)
@ IMA_GPU_MIPMAP_COMPLETE
@ IMA_SRC_TILED
@ IMA_TYPE_UV_TEST
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_NOCOLLECT
@ IMA_HIGH_BITDEPTH
@ IMA_ALPHA_STRAIGHT
@ IMA_ALPHA_PREMUL
eGPUTextureTarget
@ TEXTARGET_2D
@ TEXTARGET_2D_ARRAY
@ TEXTARGET_COUNT
@ TEXTARGET_TILE_MAPPING
int GPU_texture_size_with_limit(int res)
bool GPU_mipmap_enabled()
Definition gpu_state.cc:282
int GPU_texture_height(const GPUTexture *texture)
void GPU_texture_free(GPUTexture *texture)
int GPU_texture_width(const GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
GPUTexture * GPU_texture_create_error(int dimension, bool array)
eGPUDataFormat
@ GPU_DATA_UBYTE
@ GPU_DATA_FLOAT
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_REPEAT
void GPU_texture_update_sub(GPUTexture *texture, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
void GPU_texture_mipmap_mode(GPUTexture *texture, bool use_mipmap, bool use_filter)
void GPU_texture_update_mipmap_chain(GPUTexture *texture)
GPUTexture * GPU_texture_create_1d_array(const char *name, int width, int layer_len, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_unpack_row_length_set(uint len)
void GPU_texture_original_size_set(GPUTexture *texture, int width, int height)
bool IMB_colormanagement_space_is_data(ColorSpace *colorspace)
bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace)
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, int offset_x, int offset_y, int width, int height, const ImBuf *ibuf, bool store_premultiplied)
bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace)
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, int offset_x, int offset_y, int width, int height, const ImBuf *ibuf, bool store_premultiplied)
GPUTexture * IMB_touch_gpu_texture(const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth, bool use_grayscale)
Definition util_gpu.cc:255
void IMB_update_gpu_texture_sub(GPUTexture *tex, ImBuf *ibuf, int x, int y, int z, int w, int h, bool use_high_bitdepth, bool use_grayscale, bool use_premult)
Definition util_gpu.cc:281
GPUTexture * IMB_create_gpu_texture(const char *name, ImBuf *ibuf, bool use_high_bitdepth, bool use_premult)
Definition util_gpu.cc:312
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:779
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
volatile int lock
unsigned int U
Definition btGjkEpa3.h:78
btMatrix3x3 scaled(const btVector3 &s) const
Create a scaled copy of the matrix.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_float_shared") .push_constant(Type additional_info("compositor_sum_float_shared") .push_constant(Type GPU_RGBA32F
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
struct ImBuf * IMB_allocFromBuffer(const uint8_t *, const float *, unsigned int, unsigned int, unsigned int)
void IMB_freeImBuf(ImBuf *)
uint padding(uint offset, uint alignment)
static int compare_packtile(const void *a, const void *b)
Definition image_gpu.cc:126
static void gpu_free_unused_buffers()
Definition image_gpu.cc:505
static void image_gpu_texture_partial_update_changes_available(Image *image, PartialUpdateChecker< ImageTileData >::CollectResult &changes)
Definition image_gpu.cc:288
void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
Definition image_gpu.cc:882
static GPUTexture * gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
Definition image_gpu.cc:134
void BKE_image_free_anim_gputextures(Main *bmain)
Definition image_gpu.cc:570
void BKE_image_ensure_gpu_texture(Image *image, ImageUser *image_user)
Definition image_gpu.cc:336
static void gpu_texture_update_from_ibuf(GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
Definition image_gpu.cc:731
GPUTexture * BKE_image_get_gpu_viewer_texture(Image *image, ImageUser *iuser)
Definition image_gpu.cc:481
bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
Definition image_gpu.cc:41
ImageGPUTextures BKE_image_get_gpu_material_texture(Image *image, ImageUser *iuser, const bool use_tile_mapping)
Definition image_gpu.cc:486
static void image_gpu_texture_try_partial_update(Image *image, ImageUser *iuser)
Definition image_gpu.cc:314
void BKE_image_update_gputexture_delayed(Image *ima, ImageTile *image_tile, ImBuf *ibuf, int x, int y, int w, int h)
Definition image_gpu.cc:890
static ThreadMutex gpu_texture_queue_mutex
Definition image_gpu.cc:503
static GPUTexture * image_gpu_texture_error_create(eGPUTextureTarget textarget)
Definition image_gpu.cc:274
static void image_free_gpu(Image *ima, const bool immediate)
Definition image_gpu.cc:534
void BKE_image_free_gputextures(Image *ima)
Definition image_gpu.cc:556
static bool is_over_resolution_limit(int w, int h)
Definition image_gpu.cc:67
GPUTexture * BKE_image_get_gpu_texture(Image *image, ImageUser *iuser)
Definition image_gpu.cc:476
void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
Definition image_gpu.cc:906
static GPUTexture ** get_image_gpu_texture_ptr(Image *ima, eGPUTextureTarget textarget, const int multiview_eye)
Definition image_gpu.cc:260
static void gpu_texture_update_unscaled(GPUTexture *tex, uchar *rect, float *rect_float, int x, int y, int layer, const int tile_offset[2], int w, int h, int tex_stride, int tex_offset)
Definition image_gpu.cc:701
static int smaller_power_of_2_limit(int num)
Definition image_gpu.cc:72
static GPUTexture * gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
Definition image_gpu.cc:77
static void image_update_gputexture_ex(Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h)
Definition image_gpu.cc:865
static ImBuf * update_do_scale(const uchar *rect, const float *rect_float, int *x, int *y, int *w, int *h, int limit_w, int limit_h, int full_w, int full_h)
Definition image_gpu.cc:623
static LinkNode * gpu_texture_free_queue
Definition image_gpu.cc:502
static ImageGPUTextures image_get_gpu_texture(Image *ima, ImageUser *iuser, const bool use_viewers, const bool use_tile_mapping)
Definition image_gpu.cc:351
static void gpu_texture_update_scaled(GPUTexture *tex, const uchar *rect, const float *rect_float, int full_w, int full_h, int x, int y, int layer, const int *tile_offset, const int *tile_size, int w, int h)
Definition image_gpu.cc:662
void BKE_image_free_all_gputextures(Main *bmain)
Definition image_gpu.cc:561
void BKE_image_free_unused_gpu_textures()
Definition image_gpu.cc:521
void BKE_image_free_old_gputextures(Main *bmain)
Definition image_gpu.cc:581
ccl_global const KernelWorkTile * tile
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float3 ceil(const float3 a)
#define G(x, y, z)
char name[66]
Definition DNA_ID.h:425
ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
GPUTexture * texture
Definition BKE_image.hh:583
short multi_index
struct PartialUpdateUser * partial_update_user
Partial update user for GPUTextures stored inside the Image.
short gpuflag
Image_Runtime runtime
short gpu_pass
short gpu_layer
short gpu_view
ListBase tiles
struct GPUTexture * gputexture[3][2]
short source
void * last
void * first
ListBase images
Definition BKE_main.hh:218
ImageTile * tile
Definition image_gpu.cc:122
float pack_score
Definition image_gpu.cc:123
FixedSizeBoxPack boxpack
Definition image_gpu.cc:121
CollectResult collect_changes()
Check for new changes since the last time this method was invoked for this user.
int ymin
int xmin
void * BKE_image_free_buffers
Definition stubs.c:35
void * BKE_image_get_tile_from_iuser
Definition stubs.c:37
void * BKE_image_get_tile
Definition stubs.c:36