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
8
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 */
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/* -------------------------------------------------------------------- */
66
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
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
255
256/* -------------------------------------------------------------------- */
259
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{
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()) {
320 image_free_gpu(image, true);
321 break;
322 }
323
326 break;
327 }
328
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{
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) {
419 *tex = image_gpu_texture_error_create(textarget);
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);
429 *tex = image_gpu_texture_error_create(textarget);
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. */
437 *tex = gpu_texture_create_tile_array(ima, ibuf);
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
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
494
495/* -------------------------------------------------------------------- */
501
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));
515 GPU_texture_free(tex);
516 }
517
519}
520
527
529
530/* -------------------------------------------------------------------- */
533
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
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
618
619/* -------------------------------------------------------------------- */
622
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 {
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_ALPHA_STRAIGHT
@ IMA_ALPHA_PREMUL
@ IMA_NOCOLLECT
@ IMA_HIGH_BITDEPTH
@ IMA_SRC_TILED
@ IMA_TYPE_UV_TEST
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_GPU_MIPMAP_COMPLETE
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
#define U
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
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
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)
@ PartialChangesDetected
Changes detected since the last time requested.
@ FullUpdateNeeded
Unable to construct partial updates. Caller should perform a full update.
@ NoChangesDetected
No changes detected since the last time requested.
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
ePartialUpdateIterResult get_next_change()
Load the next changed region.
CollectResult collect_changes()
Check for new changes since the last time this method was invoked for this user.
struct rcti region
region of the image that has been updated. Region can be bigger than actual changes.
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