Blender V4.5
vk_texture.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "GPU_capabilities.hh"
10
11/* vk_common needs to be included first to ensure win32 vulkan API is fully initialized, before
12 * working with it. */
13#include "vk_common.hh"
14
15#include "vk_texture.hh"
16
17#include "vk_buffer.hh"
18#include "vk_context.hh"
19#include "vk_data_conversion.hh"
20#include "vk_framebuffer.hh"
21#include "vk_pixel_buffer.hh"
22#include "vk_shader.hh"
24#include "vk_state_manager.hh"
25#include "vk_vertex_buffer.hh"
26
27#include "BLI_math_vector.hh"
28
29#include "BKE_global.hh"
30
31namespace blender::gpu {
32
33static VkImageAspectFlags to_vk_image_aspect_single_bit(const VkImageAspectFlags format,
34 bool stencil)
35{
36 switch (format) {
37 case VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT:
38 return (stencil) ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
39 default:
40 break;
41 }
42 return format;
43}
44
46{
47 if (vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE) {
48 VKDiscardPool::discard_pool_get().discard_image(vk_image_, allocation_);
49 vk_image_ = VK_NULL_HANDLE;
50 allocation_ = VK_NULL_HANDLE;
51 }
52}
53
55{
56 BLI_assert(!is_texture_view());
57 if (mipmaps_ <= 1) {
58 return;
59 }
60 /* Allow users to provide mipmaps stored in compressed textures.
61 * Skip generating mipmaps to avoid overriding the existing ones. */
63 return;
64 }
65
66 VKContext &context = *VKContext::get();
68 update_mipmaps.vk_image = vk_image_handle();
69 update_mipmaps.l0_size = int3(1);
70 mip_size_get(0, update_mipmaps.l0_size);
71 if (ELEM(this->type_get(), GPU_TEXTURE_1D_ARRAY)) {
72 update_mipmaps.l0_size.y = 1;
73 update_mipmaps.l0_size.z = 1;
74 }
75 else if (ELEM(this->type_get(), GPU_TEXTURE_2D_ARRAY)) {
76 update_mipmaps.l0_size.z = 1;
77 }
78 update_mipmaps.vk_image_aspect = to_vk_image_aspect_flag_bits(device_format_);
79 update_mipmaps.mipmaps = mipmaps_;
80 update_mipmaps.layer_count = vk_layer_count(1);
81 context.render_graph().add_node(update_mipmaps);
82}
83
84void VKTexture::copy_to(VKTexture &dst_texture, VkImageAspectFlags vk_image_aspect)
85{
87 copy_image.node_data.src_image = vk_image_handle();
88 copy_image.node_data.dst_image = dst_texture.vk_image_handle();
89 copy_image.node_data.region.srcSubresource.aspectMask = vk_image_aspect;
90 copy_image.node_data.region.srcSubresource.mipLevel = 0;
91 copy_image.node_data.region.srcSubresource.layerCount = vk_layer_count(1);
92 copy_image.node_data.region.dstSubresource.aspectMask = vk_image_aspect;
93 copy_image.node_data.region.dstSubresource.mipLevel = 0;
94 copy_image.node_data.region.dstSubresource.layerCount = vk_layer_count(1);
95 copy_image.node_data.region.extent = vk_extent_3d(0);
97
98 VKContext &context = *VKContext::get();
99 context.render_graph().add_node(copy_image);
100}
101
103{
104 VKTexture *dst = unwrap(tex);
105 VKTexture *src = this;
106 BLI_assert(dst);
107 BLI_assert(src->w_ == dst->w_ && src->h_ == dst->h_ && src->d_ == dst->d_);
108 BLI_assert(src->device_format_ == dst->device_format_);
109 BLI_assert(!is_texture_view());
111
112 copy_to(*dst, to_vk_image_aspect_flag_bits(device_format_));
113}
114
116{
117 if (format == GPU_DATA_UINT_24_8) {
118 float clear_depth = 0.0f;
121 clear_depth_stencil(GPU_DEPTH_BIT | GPU_STENCIL_BIT, clear_depth, 0u, std::nullopt);
122 return;
123 }
124
127 clear_color_image.vk_image = vk_image_handle();
128 clear_color_image.vk_image_subresource_range.aspectMask = to_vk_image_aspect_flag_bits(
129 device_format_);
130
131 IndexRange layers = layer_range();
132 clear_color_image.vk_image_subresource_range.baseArrayLayer = layers.start();
133 clear_color_image.vk_image_subresource_range.layerCount = layers.size();
134 IndexRange levels = mip_map_range();
135 clear_color_image.vk_image_subresource_range.baseMipLevel = levels.start();
136 clear_color_image.vk_image_subresource_range.levelCount = levels.size();
137
138 VKContext &context = *VKContext::get();
139
140 context.render_graph().add_node(clear_color_image);
141}
142
144 float clear_depth,
145 uint clear_stencil,
146 std::optional<int> layer)
147{
149 VkImageAspectFlags vk_image_aspect_device = to_vk_image_aspect_flag_bits(device_format_get());
150 VkImageAspectFlags vk_image_aspect = to_vk_image_aspect_flag_bits(
152 vk_image_aspect_device;
153 if (vk_image_aspect == VK_IMAGE_ASPECT_NONE) {
154 /* Early exit: texture doesn't have any aspect that needs to be cleared. */
155 return;
156 }
157
158 render_graph::VKClearDepthStencilImageNode::CreateInfo clear_depth_stencil_image = {};
159 clear_depth_stencil_image.node_data.vk_image = vk_image_handle();
160 clear_depth_stencil_image.vk_image_aspects = vk_image_aspect_device;
161 clear_depth_stencil_image.node_data.vk_clear_depth_stencil_value.depth = clear_depth;
162 clear_depth_stencil_image.node_data.vk_clear_depth_stencil_value.stencil = clear_stencil;
163 clear_depth_stencil_image.node_data.vk_image_subresource_range.aspectMask = vk_image_aspect;
164 clear_depth_stencil_image.node_data.vk_image_subresource_range.layerCount =
165 VK_REMAINING_ARRAY_LAYERS;
166 if (layer.has_value()) {
167 clear_depth_stencil_image.node_data.vk_image_subresource_range.baseArrayLayer = *layer;
168 clear_depth_stencil_image.node_data.vk_image_subresource_range.layerCount = 1;
169 }
170 clear_depth_stencil_image.node_data.vk_image_subresource_range.levelCount =
171 VK_REMAINING_MIP_LEVELS;
172
173 VKContext &context = *VKContext::get();
174 context.render_graph().add_node(clear_depth_stencil_image);
175}
176
177void VKTexture::swizzle_set(const char swizzle_mask[4])
178{
179 memcpy(swizzle_, swizzle_mask, 4);
180}
181
183{
184 mip_min_ = min;
185 mip_max_ = max;
186}
187
189 int mip, eGPUDataFormat format, const int region[6], const IndexRange layers, void *r_data)
190{
191 const int3 extent = int3(region[3] - region[0], region[4] - region[1], region[5] - region[2]);
192 size_t sample_len = extent.x * extent.y * extent.z * layers.size();
193
194 /* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */
195 VKBuffer staging_buffer;
196 size_t device_memory_size = sample_len * to_bytesize(device_format_);
197 staging_buffer.create(device_memory_size,
198 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
199 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
200 VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
201 /* Although we are only reading, we need to set the host access random bit
202 * to improve the performance on AMD GPUs. */
203 VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT |
204 VMA_ALLOCATION_CREATE_MAPPED_BIT,
205 0.2f);
206
208 render_graph::VKCopyImageToBufferNode::Data &node_data = copy_image_to_buffer.node_data;
209 node_data.src_image = vk_image_handle();
210 node_data.dst_buffer = staging_buffer.vk_handle();
211 node_data.region.imageOffset.x = region[0];
212 node_data.region.imageOffset.y = region[1];
213 node_data.region.imageOffset.z = region[2];
214 node_data.region.imageExtent.width = extent.x;
215 node_data.region.imageExtent.height = extent.y;
216 node_data.region.imageExtent.depth = extent.z;
217 VkImageAspectFlags vk_image_aspects = to_vk_image_aspect_flag_bits(device_format_);
218 copy_image_to_buffer.vk_image_aspects = vk_image_aspects;
219 node_data.region.imageSubresource.aspectMask = to_vk_image_aspect_single_bit(vk_image_aspects,
220 false);
221 node_data.region.imageSubresource.mipLevel = mip;
222 node_data.region.imageSubresource.baseArrayLayer = layers.start();
223 node_data.region.imageSubresource.layerCount = layers.size();
224
225 VKContext &context = *VKContext::get();
226 context.rendering_end();
227 context.render_graph().add_node(copy_image_to_buffer);
228
229 context.flush_render_graph(RenderGraphFlushFlags::SUBMIT |
232
234 r_data, staging_buffer.mapped_memory_get(), sample_len, format, format_, device_format_);
235}
236
238{
240
241 int mip_size[3] = {1, 1, 1};
242 VkImageType vk_image_type = to_vk_image_type(type_);
243 mip_size_get(mip, mip_size);
244 switch (vk_image_type) {
245 case VK_IMAGE_TYPE_1D: {
246 mip_size[1] = 1;
247 mip_size[2] = 1;
248 } break;
249 case VK_IMAGE_TYPE_2D: {
250 mip_size[2] = 1;
251 } break;
252 case VK_IMAGE_TYPE_3D:
253 default:
254 break;
255 }
256
257 if (mip_size[2] == 0) {
258 mip_size[2] = 1;
259 }
260 IndexRange layers = IndexRange(layer_offset_, vk_layer_count(1));
261 size_t sample_len = mip_size[0] * mip_size[1] * mip_size[2] * layers.size();
262 size_t host_memory_size = sample_len * to_bytesize(format_, format);
263
264 void *data = MEM_mallocN(host_memory_size, __func__);
265 int region[6] = {0, 0, 0, mip_size[0], mip_size[1], mip_size[2]};
266 read_sub(mip, format, region, layers, data);
267 return data;
268}
269
271 int offset_[3],
272 int extent_[3],
274 const void *data,
275 VKPixelBuffer *pixel_buffer)
276{
277 BLI_assert(!is_texture_view());
278
279 const bool is_compressed = (format_flag_ & GPU_FORMAT_COMPRESSED);
280
281 int3 extent = int3(extent_[0], max_ii(extent_[1], 1), max_ii(extent_[2], 1));
282 int3 offset = int3(offset_[0], offset_[1], offset_[2]);
283 int layers = 1;
284 int start_layer = 0;
285 if (type_ & GPU_TEXTURE_1D) {
286 layers = extent.y;
287 start_layer = offset.y;
288 extent.y = 1;
289 extent.z = 1;
290 offset.y = 0;
291 offset.z = 0;
292 }
294 layers = extent.z;
295 start_layer = offset.z;
296 extent.z = 1;
297 offset.z = 0;
298 }
299
300 /* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */
301 VKContext &context = *VKContext::get();
302 size_t sample_len = size_t(extent.x) * extent.y * extent.z * layers;
303 size_t device_memory_size = sample_len * to_bytesize(device_format_);
304
305 if (is_compressed) {
306 BLI_assert_msg(extent.z == 1, "Compressed 3D textures are not supported");
307 size_t block_size = to_block_size(device_format_);
308 size_t blocks_x = divide_ceil_u(extent.x, 4);
309 size_t blocks_y = divide_ceil_u(extent.y, 4);
310 device_memory_size = blocks_x * blocks_y * block_size;
311 /* `convert_buffer` later on will use `sample_len * to_bytesize(device_format_)`
312 * as total memory size calculation. Make that work for compressed case. */
313 sample_len = device_memory_size / to_bytesize(device_format_);
314 }
315
316 VKBuffer staging_buffer;
317 VkBuffer vk_buffer = VK_NULL_HANDLE;
318 if (data) {
319 staging_buffer.create(device_memory_size,
320 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
321 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
322 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
323 VMA_ALLOCATION_CREATE_MAPPED_BIT |
324 VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
325 0.4f);
326 vk_buffer = staging_buffer.vk_handle();
327 /* Rows are sequentially stored, when unpack row length is 0, or equal to the extent width. In
328 * other cases we unpack the rows to reduce the size of the staging buffer and data transfer.
329 */
330 const uint texture_unpack_row_length =
331 context.state_manager_get().texture_unpack_row_length_get();
332 if (ELEM(texture_unpack_row_length, 0, extent.x)) {
334 staging_buffer.mapped_memory_get(), data, sample_len, format, format_, device_format_);
335 }
336 else {
337 BLI_assert_msg(!is_compressed,
338 "Compressed data with texture_unpack_row_length != 0 is not supported.");
339 size_t dst_row_stride = extent.x * to_bytesize(device_format_);
340 size_t src_row_stride = texture_unpack_row_length * to_bytesize(format_, format);
341 uint8_t *dst_ptr = static_cast<uint8_t *>(staging_buffer.mapped_memory_get());
342 const uint8_t *src_ptr = static_cast<const uint8_t *>(data);
343 for (int x = 0; x < extent.x; x++) {
344 convert_host_to_device(dst_ptr, src_ptr, extent.x, format, format_, device_format_);
345 src_ptr += src_row_stride;
346 dst_ptr += dst_row_stride;
347 }
348 }
349 }
350 else {
351 BLI_assert(pixel_buffer);
352 vk_buffer = pixel_buffer->buffer_get().vk_handle();
353 }
354
356 render_graph::VKCopyBufferToImageNode::Data &node_data = copy_buffer_to_image.node_data;
357 node_data.src_buffer = vk_buffer;
358 node_data.dst_image = vk_image_handle();
359 node_data.region.imageExtent.width = extent.x;
360 node_data.region.imageExtent.height = extent.y;
361 node_data.region.imageExtent.depth = extent.z;
362 node_data.region.imageOffset.x = offset.x;
363 node_data.region.imageOffset.y = offset.y;
364 node_data.region.imageOffset.z = offset.z;
365 VkImageAspectFlags vk_image_aspects = to_vk_image_aspect_flag_bits(device_format_);
366 copy_buffer_to_image.vk_image_aspects = vk_image_aspects;
367 node_data.region.imageSubresource.aspectMask = to_vk_image_aspect_single_bit(vk_image_aspects,
368 false);
369 node_data.region.imageSubresource.mipLevel = mip;
370 node_data.region.imageSubresource.baseArrayLayer = start_layer;
371 node_data.region.imageSubresource.layerCount = layers;
372
373 context.render_graph().add_node(copy_buffer_to_image);
374}
375
377 int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data)
378{
379 update_sub(mip, offset, extent, format, data, nullptr);
380}
381
382void VKTexture::update_sub(int offset[3],
383 int extent[3],
385 GPUPixelBuffer *pixbuf)
386{
387 VKPixelBuffer &pixel_buffer = *unwrap(unwrap(pixbuf));
388 update_sub(0, offset, extent, format, nullptr, &pixel_buffer);
389}
390
392{
393 /* TODO(fclem): Legacy. Should be removed at some point. */
394
395 return 0;
396}
397
398VKMemoryExport VKTexture::export_memory(VkExternalMemoryHandleTypeFlagBits handle_type)
399{
400 const VKDevice &device = VKBackend::get().device;
403 "Can only import external memory when usage flag contains GPU_TEXTURE_USAGE_MEMORY_EXPORT.");
404 BLI_assert_msg(allocation_ != nullptr,
405 "Cannot export memory when the texture is not backed by any device memory.");
407 "Requested to export memory, but isn't supported by the device");
408 if (handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) {
409 VkMemoryGetFdInfoKHR vk_memory_get_fd_info = {VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
410 nullptr,
411 allocation_info_.deviceMemory,
412 handle_type};
413 int fd_handle = 0;
414 device.functions.vkGetMemoryFd(device.vk_handle(), &vk_memory_get_fd_info, &fd_handle);
415 return {uint64_t(fd_handle), allocation_info_.size, allocation_info_.offset};
416 }
417
418#ifdef _WIN32
419 if (handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
420 VkMemoryGetWin32HandleInfoKHR vk_memory_get_win32_handle_info = {
421 VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
422 nullptr,
423 allocation_info_.deviceMemory,
424 handle_type};
425 HANDLE win32_handle = nullptr;
426 device.functions.vkGetMemoryWin32Handle(
427 device.vk_handle(), &vk_memory_get_win32_handle_info, &win32_handle);
428 return {uint64_t(win32_handle), allocation_info_.size, allocation_info_.offset};
429 }
430#endif
432 return {};
433}
434
436{
437 const VKDevice &device = VKBackend::get().device;
438 const VKWorkarounds &workarounds = device.workarounds_get();
439 device_format_ = format_;
440 if (device_format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
441 device_format_ = GPU_DEPTH_COMPONENT32F;
442 }
443 if (device_format_ == GPU_DEPTH24_STENCIL8 && workarounds.not_aligned_pixel_formats) {
444 device_format_ = GPU_DEPTH32F_STENCIL8;
445 }
446 /* R16G16F16 formats are typically not supported (<1%) but R16G16B16A16 is
447 * typically supported (+90%). */
448 if (device_format_ == GPU_RGB16F) {
449 device_format_ = GPU_RGBA16F;
450 }
451 if (device_format_ == GPU_RGB32F) {
452 device_format_ = GPU_RGBA32F;
453 }
454
455 if (!allocate()) {
456 return false;
457 }
458 this->mip_range_set(0, mipmaps_ - 1);
459
460 return true;
461}
462
464{
465 BLI_assert(source_buffer_ == nullptr);
466 device_format_ = format_;
467 source_buffer_ = unwrap(vbo);
468 return true;
469}
470
471bool VKTexture::init_internal(GPUTexture *src, int mip_offset, int layer_offset, bool use_stencil)
472{
473 BLI_assert(source_texture_ == nullptr);
474 BLI_assert(src);
475
477 source_texture_ = texture;
478 device_format_ = texture->device_format_;
479 mip_min_ = mip_offset;
480 mip_max_ = mip_offset;
481 layer_offset_ = layer_offset;
482 use_stencil_ = use_stencil;
483
484 return true;
485}
486
487bool VKTexture::is_texture_view() const
488{
489 return source_texture_ != nullptr;
490}
491
492static VkImageUsageFlags to_vk_image_usage(const eGPUTextureUsage usage,
493 const eGPUTextureFormatFlag format_flag)
494{
495 const VKDevice &device = VKBackend::get().device;
496 const bool supports_local_read = device.extensions_get().dynamic_rendering_local_read;
497 const bool supports_dynamic_rendering = device.extensions_get().dynamic_rendering;
498
499 VkImageUsageFlags result = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
500 VK_IMAGE_USAGE_SAMPLED_BIT;
501 if (usage & GPU_TEXTURE_USAGE_SHADER_READ) {
502 result |= VK_IMAGE_USAGE_STORAGE_BIT;
503 }
504 if (usage & GPU_TEXTURE_USAGE_SHADER_WRITE) {
505 result |= VK_IMAGE_USAGE_STORAGE_BIT;
506 }
507 if (usage & GPU_TEXTURE_USAGE_ATTACHMENT) {
508 if (format_flag & GPU_FORMAT_COMPRESSED) {
509 /* These formats aren't supported as an attachment. When using GPU_TEXTURE_USAGE_DEFAULT they
510 * are still being evaluated to be attachable. So we need to skip them. */
511 }
512 else {
513 if (format_flag & (GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL)) {
514 result |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
515 }
516 else {
517 result |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
518 if (supports_local_read || (!supports_dynamic_rendering)) {
519 result |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
520 }
521 }
522 }
523 }
524 if (usage & GPU_TEXTURE_USAGE_HOST_READ) {
525 result |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
526 }
527
528 /* Disable some usages based on the given format flag to support more devices. */
529 if (format_flag & GPU_FORMAT_SRGB) {
530 /* NVIDIA devices don't create SRGB textures when it storage bit is set. */
531 result &= ~VK_IMAGE_USAGE_STORAGE_BIT;
532 }
533 if (format_flag & (GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL)) {
534 /* NVIDIA devices don't create depth textures when it storage bit is set. */
535 result &= ~VK_IMAGE_USAGE_STORAGE_BIT;
536 }
537
538 return result;
539}
540
541static VkImageCreateFlags to_vk_image_create(const eGPUTextureType texture_type,
542 const eGPUTextureFormatFlag format_flag,
543 const eGPUTextureUsage usage)
544{
545 VkImageCreateFlags result = 0;
546
547 if (ELEM(texture_type, GPU_TEXTURE_CUBE, GPU_TEXTURE_CUBE_ARRAY)) {
548 result |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
549 }
550
551 /* sRGB textures needs to be mutable as they can be used as non-sRGB frame-buffer attachments. */
552 if (usage & GPU_TEXTURE_USAGE_ATTACHMENT && format_flag & GPU_FORMAT_SRGB) {
553 result |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
554 }
555
556 return result;
557}
558
559static float memory_priority(const eGPUTextureUsage texture_usage)
560{
561 if (bool(texture_usage & GPU_TEXTURE_USAGE_MEMORY_EXPORT)) {
562 return 0.8f;
563 }
564 if (bool(texture_usage & GPU_TEXTURE_USAGE_ATTACHMENT)) {
565 return 1.0f;
566 }
567 return 0.5f;
568}
569
570bool VKTexture::allocate()
571{
572 BLI_assert(vk_image_ == VK_NULL_HANDLE);
573 BLI_assert(!is_texture_view());
574
575 VkExtent3D vk_extent = vk_extent_3d(0);
576 const uint32_t limit = (type_ == GPU_TEXTURE_3D) ? GPU_max_texture_3d_size() :
578 if (vk_extent.depth > limit || vk_extent.height > limit || vk_extent.depth > limit) {
579 return false;
580 }
581
582 const eGPUTextureUsage texture_usage = usage_get();
583
584 VKDevice &device = VKBackend::get().device;
585 VkImageCreateInfo image_info = {};
586 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
587 image_info.flags = to_vk_image_create(type_, format_flag_, texture_usage);
588 image_info.imageType = to_vk_image_type(type_);
589 image_info.extent = vk_extent;
590 image_info.mipLevels = max_ii(mipmaps_, 1);
591 image_info.arrayLayers = vk_layer_count(1);
592 image_info.format = to_vk_format(device_format_);
593 /* Some platforms (NVIDIA) requires that attached textures are always tiled optimal.
594 *
595 * As image data are always accessed via an staging buffer we can enable optimal tiling for all
596 * texture. Tilings based on actual usages should be done in `VKFramebuffer`.
597 */
598 image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
599 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
601 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
602
603 VkResult result;
604 if (G.debug & G_DEBUG_GPU) {
605 VkImageFormatProperties image_format = {};
606 result = vkGetPhysicalDeviceImageFormatProperties(device.physical_device_get(),
607 image_info.format,
608 image_info.imageType,
609 image_info.tiling,
610 image_info.usage,
611 image_info.flags,
612 &image_format);
613 if (result != VK_SUCCESS) {
614 printf("Image type not supported on device.\n");
615 return false;
616 }
617 }
618
619 VkExternalMemoryImageCreateInfo external_memory_create_info = {
620 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, nullptr, 0};
621
622 VmaAllocationCreateInfo allocCreateInfo = {};
623 allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
624 allocCreateInfo.priority = memory_priority(texture_usage);
625
626 if (bool(texture_usage & GPU_TEXTURE_USAGE_MEMORY_EXPORT)) {
627 image_info.pNext = &external_memory_create_info;
628#ifdef _WIN32
629 external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
630#else
631 external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
632#endif
633 allocCreateInfo.pool = device.vma_pools.external_memory;
634 }
635 result = vmaCreateImage(device.mem_allocator_get(),
636 &image_info,
637 &allocCreateInfo,
638 &vk_image_,
639 &allocation_,
640 &allocation_info_);
641 if (result != VK_SUCCESS) {
642 return false;
643 }
644 debug::object_label(vk_image_, name_);
645
646 device.resources.add_image(vk_image_, image_info.arrayLayers, name_);
647
648 return result == VK_SUCCESS;
649}
650
651/* -------------------------------------------------------------------- */
654
655IndexRange VKTexture::mip_map_range() const
656{
657 return IndexRange(mip_min_, mip_max_ - mip_min_ + 1);
658}
659
660IndexRange VKTexture::layer_range() const
661{
662 if (is_texture_view()) {
663 return IndexRange(layer_offset_, layer_count());
664 }
665 else {
666 return IndexRange(
667 0, ELEM(type_, GPU_TEXTURE_CUBE, GPU_TEXTURE_CUBE_ARRAY) ? d_ : VK_REMAINING_ARRAY_LAYERS);
668 }
669}
670
671int VKTexture::vk_layer_count(int non_layered_value) const
672{
673 if (is_texture_view()) {
674 return layer_count();
675 }
676 return type_ == GPU_TEXTURE_CUBE ? d_ :
678 non_layered_value;
679}
680
681VkExtent3D VKTexture::vk_extent_3d(int mip_level) const
682{
683 int extent[3] = {1, 1, 1};
684 mip_size_get(mip_level, extent);
686 extent[2] = 1;
687 }
689 extent[1] = 1;
690 extent[2] = 1;
691 }
692
693 VkExtent3D result{uint32_t(extent[0]), uint32_t(extent[1]), uint32_t(extent[2])};
694 return result;
695}
696
698{
699 if (is_texture_view()) {
700 /* TODO: API should be improved as we don't support image view specialization.
701 * In the current API this is still possible to setup when using attachments. */
703 }
704 for (const VKImageView &image_view : image_views_) {
705 if (image_view.info == info) {
706 return image_view;
707 }
708 }
709
710 image_views_.append(VKImageView(*this, info, name_));
711 return image_views_.last();
712}
713
715{
716 image_view_info_.mip_range = mip_map_range();
717 image_view_info_.use_srgb = true;
718 image_view_info_.use_stencil = use_stencil_;
719 image_view_info_.arrayed = arrayed;
720 image_view_info_.layer_range = layer_range();
721
722 if (arrayed == VKImageViewArrayed::NOT_ARRAYED) {
723 image_view_info_.layer_range = image_view_info_.layer_range.slice(
725 }
726
727 if (bool(flags & VKImageViewFlags::NO_SWIZZLING)) {
728 image_view_info_.swizzle[0] = 'r';
729 image_view_info_.swizzle[1] = 'g';
730 image_view_info_.swizzle[2] = 'b';
731 image_view_info_.swizzle[3] = 'a';
732 }
733 else {
734 image_view_info_.swizzle[0] = swizzle_[0];
735 image_view_info_.swizzle[1] = swizzle_[1];
736 image_view_info_.swizzle[2] = swizzle_[2];
737 image_view_info_.swizzle[3] = swizzle_[3];
738 }
739
740 if (is_texture_view()) {
741 return source_texture_->image_view_get(image_view_info_);
742 }
743 return image_view_get(image_view_info_);
744}
745
747
748} // namespace blender::gpu
@ G_DEBUG_GPU
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE uint divide_ceil_u(uint a, uint b)
MINLINE int max_ii(int a, int b)
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
int GPU_max_texture_3d_size()
int GPU_max_texture_size()
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
eGPUDataFormat
@ GPU_DATA_UINT_24_8
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_MEMORY_EXPORT
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
@ GPU_TEXTURE_USAGE_HOST_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_DEPTH32F_STENCIL8
@ GPU_DEPTH24_STENCIL8
@ GPU_RGBA32F
@ GPU_RGBA16F
@ GPU_RGB32F
@ GPU_DEPTH_COMPONENT24
@ GPU_RGB16F
@ GPU_DEPTH_COMPONENT32F
BMesh const char void * data
unsigned long long int uint64_t
constexpr int64_t size() const
constexpr int64_t start() const
eGPUTextureFormatFlag format_flag_
eGPUTextureUsage gpu_image_usage_flags_
eGPUTextureUsage usage_get() const
char name_[DEBUG_NAME_LEN]
eGPUTextureType type_get() const
void mip_size_get(int mip, int r_size[3]) const
Texture(const char *name)
static VKBackend & get()
Definition vk_backend.hh:91
bool create(size_t size, VkBufferUsageFlags buffer_usage, VkMemoryPropertyFlags required_flags, VkMemoryPropertyFlags preferred_flags, VmaAllocationCreateFlags vma_allocation_flags, float priority, bool export_memory=false)
Definition vk_buffer.cc:23
VkBuffer vk_handle() const
Definition vk_buffer.hh:102
void * mapped_memory_get() const
Definition vk_buffer.hh:135
static VKContext * get()
PFN_vkGetMemoryFdKHR vkGetMemoryFd
Definition vk_device.hh:266
VkDevice vk_handle() const
Definition vk_device.hh:336
const VKExtensions & extensions_get() const
Definition vk_device.hh:396
const VKWorkarounds & workarounds_get() const
Definition vk_device.hh:392
struct blender::gpu::VKDevice::@164322360241203077355133066050124027157363067003 functions
static VKDiscardPool & discard_pool_get()
void discard_image(VkImage vk_image, VmaAllocation vma_allocation)
VKMemoryExport export_memory(VkExternalMemoryHandleTypeFlagBits handle_type)
void clear_depth_stencil(const eGPUFrameBufferBits buffer, float clear_depth, uint clear_stencil, std::optional< int > layer)
uint gl_bindcode_get() const override
void copy_to(Texture *tex) override
void clear(eGPUDataFormat format, const void *data) override
virtual ~VKTexture() override
Definition vk_texture.cc:45
void generate_mipmap() override
Definition vk_texture.cc:54
eGPUTextureFormat device_format_get() const
bool init_internal() override
void update_sub(int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data, VKPixelBuffer *pixel_buffer)
VkImage vk_image_handle() const
const VKImageView & image_view_get(const VKImageViewInfo &info)
void swizzle_set(const char swizzle_mask[4]) override
VKTexture(const char *name)
Definition vk_texture.hh:76
void mip_range_set(int min, int max) override
void read_sub(int mip, eGPUDataFormat format, const int region[6], IndexRange layers, void *r_data)
void * read(int mip, eGPUDataFormat format) override
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define printf(...)
format
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
#define G(x, y, z)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:329
static Context * unwrap(GPUContext *ctx)
void convert_host_to_device(void *dst_buffer, const void *src_buffer, size_t buffer_size, eGPUDataFormat host_format, eGPUTextureFormat host_texture_format, eGPUTextureFormat device_format)
size_t to_block_size(eGPUTextureFormat data_type)
static VkImageAspectFlags to_vk_image_aspect_single_bit(const VkImageAspectFlags format, bool stencil)
Definition vk_texture.cc:33
void convert_device_to_host(void *dst_buffer, const void *src_buffer, size_t buffer_size, eGPUDataFormat host_format, eGPUTextureFormat host_texture_format, eGPUTextureFormat device_format)
VkImageType to_vk_image_type(const eGPUTextureType type)
Definition vk_common.cc:601
int to_bytesize(const DataFormat format)
VkFormat to_vk_format(const eGPUTextureFormat format)
Definition vk_common.cc:131
VkClearColorValue to_vk_clear_color_value(const eGPUDataFormat format, const void *data)
Definition vk_common.cc:724
static VkImageCreateFlags to_vk_image_create(const eGPUTextureType texture_type, const eGPUTextureFormatFlag format_flag, const eGPUTextureUsage usage)
VkImageAspectFlags to_vk_image_aspect_flag_bits(const eGPUTextureFormat format)
Definition vk_common.cc:14
static float memory_priority(const eGPUTextureUsage texture_usage)
static VkImageUsageFlags to_vk_image_usage(const eGPUTextureUsage usage, const eGPUTextureFormatFlag format_flag)
VecBase< int32_t, 3 > int3
#define min(a, b)
Definition sort.cc:36
max
Definition text_draw.cc:251
char * buffers[2]