1 | /**************************************************************************/ |
2 | /* rendering_device_vulkan.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "rendering_device_vulkan.h" |
32 | |
33 | #include "core/config/project_settings.h" |
34 | #include "core/io/compression.h" |
35 | #include "core/io/dir_access.h" |
36 | #include "core/io/file_access.h" |
37 | #include "core/io/marshalls.h" |
38 | #include "core/os/os.h" |
39 | #include "core/templates/hashfuncs.h" |
40 | #include "drivers/vulkan/vulkan_context.h" |
41 | |
42 | #include "thirdparty/misc/smolv.h" |
43 | |
44 | //#define FORCE_FULL_BARRIER |
45 | |
46 | static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096; |
47 | |
48 | // Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values). |
49 | RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &r_stage_mask, VkAccessFlags &r_access_mask, BitField<BarrierMask> p_post_barrier) { |
50 | Buffer *buffer = nullptr; |
51 | if (vertex_buffer_owner.owns(p_buffer)) { |
52 | buffer = vertex_buffer_owner.get_or_null(p_buffer); |
53 | |
54 | r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; |
55 | r_access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; |
56 | if (buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) { |
57 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
58 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
59 | r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
60 | } |
61 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
62 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
63 | r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
64 | } |
65 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
66 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
67 | r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
68 | } |
69 | } |
70 | } else if (index_buffer_owner.owns(p_buffer)) { |
71 | r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; |
72 | r_access_mask |= VK_ACCESS_INDEX_READ_BIT; |
73 | buffer = index_buffer_owner.get_or_null(p_buffer); |
74 | } else if (uniform_buffer_owner.owns(p_buffer)) { |
75 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
76 | r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
77 | } |
78 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
79 | r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
80 | } |
81 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
82 | r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
83 | } |
84 | r_access_mask |= VK_ACCESS_UNIFORM_READ_BIT; |
85 | buffer = uniform_buffer_owner.get_or_null(p_buffer); |
86 | } else if (texture_buffer_owner.owns(p_buffer)) { |
87 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
88 | r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
89 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT; |
90 | } |
91 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
92 | r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
93 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT; |
94 | } |
95 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
96 | r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
97 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT; |
98 | } |
99 | |
100 | buffer = &texture_buffer_owner.get_or_null(p_buffer)->buffer; |
101 | } else if (storage_buffer_owner.owns(p_buffer)) { |
102 | buffer = storage_buffer_owner.get_or_null(p_buffer); |
103 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
104 | r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
105 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
106 | } |
107 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
108 | r_stage_mask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
109 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
110 | } |
111 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
112 | r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
113 | r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
114 | } |
115 | |
116 | if (buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT) { |
117 | r_stage_mask |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; |
118 | r_access_mask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; |
119 | } |
120 | } |
121 | return buffer; |
122 | } |
123 | |
124 | static void update_external_dependency_for_store(VkSubpassDependency2KHR &dependency, bool is_sampled, bool is_storage, bool is_depth) { |
125 | // Transitioning from write to read, protect the shaders that may use this next. |
126 | // Allow for copies/image layout transitions. |
127 | dependency.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
128 | dependency.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; |
129 | |
130 | if (is_sampled) { |
131 | dependency.dstStageMask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
132 | dependency.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT; |
133 | } else if (is_storage) { |
134 | dependency.dstStageMask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
135 | dependency.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
136 | } else { |
137 | dependency.dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; |
138 | dependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
139 | } |
140 | |
141 | if (is_depth) { |
142 | // Depth resources have additional stages that may be interested in them. |
143 | dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; |
144 | dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; |
145 | } |
146 | } |
147 | |
148 | void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { |
149 | if (!dependency_map.has(p_depends_on)) { |
150 | dependency_map[p_depends_on] = HashSet<RID>(); |
151 | } |
152 | |
153 | dependency_map[p_depends_on].insert(p_id); |
154 | |
155 | if (!reverse_dependency_map.has(p_id)) { |
156 | reverse_dependency_map[p_id] = HashSet<RID>(); |
157 | } |
158 | |
159 | reverse_dependency_map[p_id].insert(p_depends_on); |
160 | } |
161 | |
162 | void RenderingDeviceVulkan::_free_dependencies(RID p_id) { |
163 | // Direct dependencies must be freed. |
164 | |
165 | HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id); |
166 | if (E) { |
167 | while (E->value.size()) { |
168 | free(*E->value.begin()); |
169 | } |
170 | dependency_map.remove(E); |
171 | } |
172 | |
173 | // Reverse dependencies must be unreferenced. |
174 | E = reverse_dependency_map.find(p_id); |
175 | |
176 | if (E) { |
177 | for (const RID &F : E->value) { |
178 | HashMap<RID, HashSet<RID>>::Iterator G = dependency_map.find(F); |
179 | ERR_CONTINUE(!G); |
180 | ERR_CONTINUE(!G->value.has(p_id)); |
181 | G->value.erase(p_id); |
182 | } |
183 | |
184 | reverse_dependency_map.remove(E); |
185 | } |
186 | } |
187 | |
188 | const VkFormat RenderingDeviceVulkan::vulkan_formats[RenderingDevice::DATA_FORMAT_MAX] = { |
189 | VK_FORMAT_R4G4_UNORM_PACK8, |
190 | VK_FORMAT_R4G4B4A4_UNORM_PACK16, |
191 | VK_FORMAT_B4G4R4A4_UNORM_PACK16, |
192 | VK_FORMAT_R5G6B5_UNORM_PACK16, |
193 | VK_FORMAT_B5G6R5_UNORM_PACK16, |
194 | VK_FORMAT_R5G5B5A1_UNORM_PACK16, |
195 | VK_FORMAT_B5G5R5A1_UNORM_PACK16, |
196 | VK_FORMAT_A1R5G5B5_UNORM_PACK16, |
197 | VK_FORMAT_R8_UNORM, |
198 | VK_FORMAT_R8_SNORM, |
199 | VK_FORMAT_R8_USCALED, |
200 | VK_FORMAT_R8_SSCALED, |
201 | VK_FORMAT_R8_UINT, |
202 | VK_FORMAT_R8_SINT, |
203 | VK_FORMAT_R8_SRGB, |
204 | VK_FORMAT_R8G8_UNORM, |
205 | VK_FORMAT_R8G8_SNORM, |
206 | VK_FORMAT_R8G8_USCALED, |
207 | VK_FORMAT_R8G8_SSCALED, |
208 | VK_FORMAT_R8G8_UINT, |
209 | VK_FORMAT_R8G8_SINT, |
210 | VK_FORMAT_R8G8_SRGB, |
211 | VK_FORMAT_R8G8B8_UNORM, |
212 | VK_FORMAT_R8G8B8_SNORM, |
213 | VK_FORMAT_R8G8B8_USCALED, |
214 | VK_FORMAT_R8G8B8_SSCALED, |
215 | VK_FORMAT_R8G8B8_UINT, |
216 | VK_FORMAT_R8G8B8_SINT, |
217 | VK_FORMAT_R8G8B8_SRGB, |
218 | VK_FORMAT_B8G8R8_UNORM, |
219 | VK_FORMAT_B8G8R8_SNORM, |
220 | VK_FORMAT_B8G8R8_USCALED, |
221 | VK_FORMAT_B8G8R8_SSCALED, |
222 | VK_FORMAT_B8G8R8_UINT, |
223 | VK_FORMAT_B8G8R8_SINT, |
224 | VK_FORMAT_B8G8R8_SRGB, |
225 | VK_FORMAT_R8G8B8A8_UNORM, |
226 | VK_FORMAT_R8G8B8A8_SNORM, |
227 | VK_FORMAT_R8G8B8A8_USCALED, |
228 | VK_FORMAT_R8G8B8A8_SSCALED, |
229 | VK_FORMAT_R8G8B8A8_UINT, |
230 | VK_FORMAT_R8G8B8A8_SINT, |
231 | VK_FORMAT_R8G8B8A8_SRGB, |
232 | VK_FORMAT_B8G8R8A8_UNORM, |
233 | VK_FORMAT_B8G8R8A8_SNORM, |
234 | VK_FORMAT_B8G8R8A8_USCALED, |
235 | VK_FORMAT_B8G8R8A8_SSCALED, |
236 | VK_FORMAT_B8G8R8A8_UINT, |
237 | VK_FORMAT_B8G8R8A8_SINT, |
238 | VK_FORMAT_B8G8R8A8_SRGB, |
239 | VK_FORMAT_A8B8G8R8_UNORM_PACK32, |
240 | VK_FORMAT_A8B8G8R8_SNORM_PACK32, |
241 | VK_FORMAT_A8B8G8R8_USCALED_PACK32, |
242 | VK_FORMAT_A8B8G8R8_SSCALED_PACK32, |
243 | VK_FORMAT_A8B8G8R8_UINT_PACK32, |
244 | VK_FORMAT_A8B8G8R8_SINT_PACK32, |
245 | VK_FORMAT_A8B8G8R8_SRGB_PACK32, |
246 | VK_FORMAT_A2R10G10B10_UNORM_PACK32, |
247 | VK_FORMAT_A2R10G10B10_SNORM_PACK32, |
248 | VK_FORMAT_A2R10G10B10_USCALED_PACK32, |
249 | VK_FORMAT_A2R10G10B10_SSCALED_PACK32, |
250 | VK_FORMAT_A2R10G10B10_UINT_PACK32, |
251 | VK_FORMAT_A2R10G10B10_SINT_PACK32, |
252 | VK_FORMAT_A2B10G10R10_UNORM_PACK32, |
253 | VK_FORMAT_A2B10G10R10_SNORM_PACK32, |
254 | VK_FORMAT_A2B10G10R10_USCALED_PACK32, |
255 | VK_FORMAT_A2B10G10R10_SSCALED_PACK32, |
256 | VK_FORMAT_A2B10G10R10_UINT_PACK32, |
257 | VK_FORMAT_A2B10G10R10_SINT_PACK32, |
258 | VK_FORMAT_R16_UNORM, |
259 | VK_FORMAT_R16_SNORM, |
260 | VK_FORMAT_R16_USCALED, |
261 | VK_FORMAT_R16_SSCALED, |
262 | VK_FORMAT_R16_UINT, |
263 | VK_FORMAT_R16_SINT, |
264 | VK_FORMAT_R16_SFLOAT, |
265 | VK_FORMAT_R16G16_UNORM, |
266 | VK_FORMAT_R16G16_SNORM, |
267 | VK_FORMAT_R16G16_USCALED, |
268 | VK_FORMAT_R16G16_SSCALED, |
269 | VK_FORMAT_R16G16_UINT, |
270 | VK_FORMAT_R16G16_SINT, |
271 | VK_FORMAT_R16G16_SFLOAT, |
272 | VK_FORMAT_R16G16B16_UNORM, |
273 | VK_FORMAT_R16G16B16_SNORM, |
274 | VK_FORMAT_R16G16B16_USCALED, |
275 | VK_FORMAT_R16G16B16_SSCALED, |
276 | VK_FORMAT_R16G16B16_UINT, |
277 | VK_FORMAT_R16G16B16_SINT, |
278 | VK_FORMAT_R16G16B16_SFLOAT, |
279 | VK_FORMAT_R16G16B16A16_UNORM, |
280 | VK_FORMAT_R16G16B16A16_SNORM, |
281 | VK_FORMAT_R16G16B16A16_USCALED, |
282 | VK_FORMAT_R16G16B16A16_SSCALED, |
283 | VK_FORMAT_R16G16B16A16_UINT, |
284 | VK_FORMAT_R16G16B16A16_SINT, |
285 | VK_FORMAT_R16G16B16A16_SFLOAT, |
286 | VK_FORMAT_R32_UINT, |
287 | VK_FORMAT_R32_SINT, |
288 | VK_FORMAT_R32_SFLOAT, |
289 | VK_FORMAT_R32G32_UINT, |
290 | VK_FORMAT_R32G32_SINT, |
291 | VK_FORMAT_R32G32_SFLOAT, |
292 | VK_FORMAT_R32G32B32_UINT, |
293 | VK_FORMAT_R32G32B32_SINT, |
294 | VK_FORMAT_R32G32B32_SFLOAT, |
295 | VK_FORMAT_R32G32B32A32_UINT, |
296 | VK_FORMAT_R32G32B32A32_SINT, |
297 | VK_FORMAT_R32G32B32A32_SFLOAT, |
298 | VK_FORMAT_R64_UINT, |
299 | VK_FORMAT_R64_SINT, |
300 | VK_FORMAT_R64_SFLOAT, |
301 | VK_FORMAT_R64G64_UINT, |
302 | VK_FORMAT_R64G64_SINT, |
303 | VK_FORMAT_R64G64_SFLOAT, |
304 | VK_FORMAT_R64G64B64_UINT, |
305 | VK_FORMAT_R64G64B64_SINT, |
306 | VK_FORMAT_R64G64B64_SFLOAT, |
307 | VK_FORMAT_R64G64B64A64_UINT, |
308 | VK_FORMAT_R64G64B64A64_SINT, |
309 | VK_FORMAT_R64G64B64A64_SFLOAT, |
310 | VK_FORMAT_B10G11R11_UFLOAT_PACK32, |
311 | VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, |
312 | VK_FORMAT_D16_UNORM, |
313 | VK_FORMAT_X8_D24_UNORM_PACK32, |
314 | VK_FORMAT_D32_SFLOAT, |
315 | VK_FORMAT_S8_UINT, |
316 | VK_FORMAT_D16_UNORM_S8_UINT, |
317 | VK_FORMAT_D24_UNORM_S8_UINT, |
318 | VK_FORMAT_D32_SFLOAT_S8_UINT, |
319 | VK_FORMAT_BC1_RGB_UNORM_BLOCK, |
320 | VK_FORMAT_BC1_RGB_SRGB_BLOCK, |
321 | VK_FORMAT_BC1_RGBA_UNORM_BLOCK, |
322 | VK_FORMAT_BC1_RGBA_SRGB_BLOCK, |
323 | VK_FORMAT_BC2_UNORM_BLOCK, |
324 | VK_FORMAT_BC2_SRGB_BLOCK, |
325 | VK_FORMAT_BC3_UNORM_BLOCK, |
326 | VK_FORMAT_BC3_SRGB_BLOCK, |
327 | VK_FORMAT_BC4_UNORM_BLOCK, |
328 | VK_FORMAT_BC4_SNORM_BLOCK, |
329 | VK_FORMAT_BC5_UNORM_BLOCK, |
330 | VK_FORMAT_BC5_SNORM_BLOCK, |
331 | VK_FORMAT_BC6H_UFLOAT_BLOCK, |
332 | VK_FORMAT_BC6H_SFLOAT_BLOCK, |
333 | VK_FORMAT_BC7_UNORM_BLOCK, |
334 | VK_FORMAT_BC7_SRGB_BLOCK, |
335 | VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, |
336 | VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, |
337 | VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, |
338 | VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, |
339 | VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, |
340 | VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, |
341 | VK_FORMAT_EAC_R11_UNORM_BLOCK, |
342 | VK_FORMAT_EAC_R11_SNORM_BLOCK, |
343 | VK_FORMAT_EAC_R11G11_UNORM_BLOCK, |
344 | VK_FORMAT_EAC_R11G11_SNORM_BLOCK, |
345 | VK_FORMAT_ASTC_4x4_UNORM_BLOCK, |
346 | VK_FORMAT_ASTC_4x4_SRGB_BLOCK, |
347 | VK_FORMAT_ASTC_5x4_UNORM_BLOCK, |
348 | VK_FORMAT_ASTC_5x4_SRGB_BLOCK, |
349 | VK_FORMAT_ASTC_5x5_UNORM_BLOCK, |
350 | VK_FORMAT_ASTC_5x5_SRGB_BLOCK, |
351 | VK_FORMAT_ASTC_6x5_UNORM_BLOCK, |
352 | VK_FORMAT_ASTC_6x5_SRGB_BLOCK, |
353 | VK_FORMAT_ASTC_6x6_UNORM_BLOCK, |
354 | VK_FORMAT_ASTC_6x6_SRGB_BLOCK, |
355 | VK_FORMAT_ASTC_8x5_UNORM_BLOCK, |
356 | VK_FORMAT_ASTC_8x5_SRGB_BLOCK, |
357 | VK_FORMAT_ASTC_8x6_UNORM_BLOCK, |
358 | VK_FORMAT_ASTC_8x6_SRGB_BLOCK, |
359 | VK_FORMAT_ASTC_8x8_UNORM_BLOCK, |
360 | VK_FORMAT_ASTC_8x8_SRGB_BLOCK, |
361 | VK_FORMAT_ASTC_10x5_UNORM_BLOCK, |
362 | VK_FORMAT_ASTC_10x5_SRGB_BLOCK, |
363 | VK_FORMAT_ASTC_10x6_UNORM_BLOCK, |
364 | VK_FORMAT_ASTC_10x6_SRGB_BLOCK, |
365 | VK_FORMAT_ASTC_10x8_UNORM_BLOCK, |
366 | VK_FORMAT_ASTC_10x8_SRGB_BLOCK, |
367 | VK_FORMAT_ASTC_10x10_UNORM_BLOCK, |
368 | VK_FORMAT_ASTC_10x10_SRGB_BLOCK, |
369 | VK_FORMAT_ASTC_12x10_UNORM_BLOCK, |
370 | VK_FORMAT_ASTC_12x10_SRGB_BLOCK, |
371 | VK_FORMAT_ASTC_12x12_UNORM_BLOCK, |
372 | VK_FORMAT_ASTC_12x12_SRGB_BLOCK, |
373 | VK_FORMAT_G8B8G8R8_422_UNORM, |
374 | VK_FORMAT_B8G8R8G8_422_UNORM, |
375 | VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, |
376 | VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, |
377 | VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, |
378 | VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, |
379 | VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, |
380 | VK_FORMAT_R10X6_UNORM_PACK16, |
381 | VK_FORMAT_R10X6G10X6_UNORM_2PACK16, |
382 | VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, |
383 | VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, |
384 | VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, |
385 | VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, |
386 | VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, |
387 | VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, |
388 | VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, |
389 | VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, |
390 | VK_FORMAT_R12X4_UNORM_PACK16, |
391 | VK_FORMAT_R12X4G12X4_UNORM_2PACK16, |
392 | VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, |
393 | VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, |
394 | VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, |
395 | VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, |
396 | VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, |
397 | VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, |
398 | VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, |
399 | VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, |
400 | VK_FORMAT_G16B16G16R16_422_UNORM, |
401 | VK_FORMAT_B16G16R16G16_422_UNORM, |
402 | VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, |
403 | VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, |
404 | VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, |
405 | VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, |
406 | VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, |
407 | }; |
408 | |
409 | const char *RenderingDeviceVulkan::named_formats[RenderingDevice::DATA_FORMAT_MAX] = { |
410 | "R4G4_Unorm_Pack8" , |
411 | "R4G4B4A4_Unorm_Pack16" , |
412 | "B4G4R4A4_Unorm_Pack16" , |
413 | "R5G6B5_Unorm_Pack16" , |
414 | "B5G6R5_Unorm_Pack16" , |
415 | "R5G5B5A1_Unorm_Pack16" , |
416 | "B5G5R5A1_Unorm_Pack16" , |
417 | "A1R5G5B5_Unorm_Pack16" , |
418 | "R8_Unorm" , |
419 | "R8_Snorm" , |
420 | "R8_Uscaled" , |
421 | "R8_Sscaled" , |
422 | "R8_Uint" , |
423 | "R8_Sint" , |
424 | "R8_Srgb" , |
425 | "R8G8_Unorm" , |
426 | "R8G8_Snorm" , |
427 | "R8G8_Uscaled" , |
428 | "R8G8_Sscaled" , |
429 | "R8G8_Uint" , |
430 | "R8G8_Sint" , |
431 | "R8G8_Srgb" , |
432 | "R8G8B8_Unorm" , |
433 | "R8G8B8_Snorm" , |
434 | "R8G8B8_Uscaled" , |
435 | "R8G8B8_Sscaled" , |
436 | "R8G8B8_Uint" , |
437 | "R8G8B8_Sint" , |
438 | "R8G8B8_Srgb" , |
439 | "B8G8R8_Unorm" , |
440 | "B8G8R8_Snorm" , |
441 | "B8G8R8_Uscaled" , |
442 | "B8G8R8_Sscaled" , |
443 | "B8G8R8_Uint" , |
444 | "B8G8R8_Sint" , |
445 | "B8G8R8_Srgb" , |
446 | "R8G8B8A8_Unorm" , |
447 | "R8G8B8A8_Snorm" , |
448 | "R8G8B8A8_Uscaled" , |
449 | "R8G8B8A8_Sscaled" , |
450 | "R8G8B8A8_Uint" , |
451 | "R8G8B8A8_Sint" , |
452 | "R8G8B8A8_Srgb" , |
453 | "B8G8R8A8_Unorm" , |
454 | "B8G8R8A8_Snorm" , |
455 | "B8G8R8A8_Uscaled" , |
456 | "B8G8R8A8_Sscaled" , |
457 | "B8G8R8A8_Uint" , |
458 | "B8G8R8A8_Sint" , |
459 | "B8G8R8A8_Srgb" , |
460 | "A8B8G8R8_Unorm_Pack32" , |
461 | "A8B8G8R8_Snorm_Pack32" , |
462 | "A8B8G8R8_Uscaled_Pack32" , |
463 | "A8B8G8R8_Sscaled_Pack32" , |
464 | "A8B8G8R8_Uint_Pack32" , |
465 | "A8B8G8R8_Sint_Pack32" , |
466 | "A8B8G8R8_Srgb_Pack32" , |
467 | "A2R10G10B10_Unorm_Pack32" , |
468 | "A2R10G10B10_Snorm_Pack32" , |
469 | "A2R10G10B10_Uscaled_Pack32" , |
470 | "A2R10G10B10_Sscaled_Pack32" , |
471 | "A2R10G10B10_Uint_Pack32" , |
472 | "A2R10G10B10_Sint_Pack32" , |
473 | "A2B10G10R10_Unorm_Pack32" , |
474 | "A2B10G10R10_Snorm_Pack32" , |
475 | "A2B10G10R10_Uscaled_Pack32" , |
476 | "A2B10G10R10_Sscaled_Pack32" , |
477 | "A2B10G10R10_Uint_Pack32" , |
478 | "A2B10G10R10_Sint_Pack32" , |
479 | "R16_Unorm" , |
480 | "R16_Snorm" , |
481 | "R16_Uscaled" , |
482 | "R16_Sscaled" , |
483 | "R16_Uint" , |
484 | "R16_Sint" , |
485 | "R16_Sfloat" , |
486 | "R16G16_Unorm" , |
487 | "R16G16_Snorm" , |
488 | "R16G16_Uscaled" , |
489 | "R16G16_Sscaled" , |
490 | "R16G16_Uint" , |
491 | "R16G16_Sint" , |
492 | "R16G16_Sfloat" , |
493 | "R16G16B16_Unorm" , |
494 | "R16G16B16_Snorm" , |
495 | "R16G16B16_Uscaled" , |
496 | "R16G16B16_Sscaled" , |
497 | "R16G16B16_Uint" , |
498 | "R16G16B16_Sint" , |
499 | "R16G16B16_Sfloat" , |
500 | "R16G16B16A16_Unorm" , |
501 | "R16G16B16A16_Snorm" , |
502 | "R16G16B16A16_Uscaled" , |
503 | "R16G16B16A16_Sscaled" , |
504 | "R16G16B16A16_Uint" , |
505 | "R16G16B16A16_Sint" , |
506 | "R16G16B16A16_Sfloat" , |
507 | "R32_Uint" , |
508 | "R32_Sint" , |
509 | "R32_Sfloat" , |
510 | "R32G32_Uint" , |
511 | "R32G32_Sint" , |
512 | "R32G32_Sfloat" , |
513 | "R32G32B32_Uint" , |
514 | "R32G32B32_Sint" , |
515 | "R32G32B32_Sfloat" , |
516 | "R32G32B32A32_Uint" , |
517 | "R32G32B32A32_Sint" , |
518 | "R32G32B32A32_Sfloat" , |
519 | "R64_Uint" , |
520 | "R64_Sint" , |
521 | "R64_Sfloat" , |
522 | "R64G64_Uint" , |
523 | "R64G64_Sint" , |
524 | "R64G64_Sfloat" , |
525 | "R64G64B64_Uint" , |
526 | "R64G64B64_Sint" , |
527 | "R64G64B64_Sfloat" , |
528 | "R64G64B64A64_Uint" , |
529 | "R64G64B64A64_Sint" , |
530 | "R64G64B64A64_Sfloat" , |
531 | "B10G11R11_Ufloat_Pack32" , |
532 | "E5B9G9R9_Ufloat_Pack32" , |
533 | "D16_Unorm" , |
534 | "X8_D24_Unorm_Pack32" , |
535 | "D32_Sfloat" , |
536 | "S8_Uint" , |
537 | "D16_Unorm_S8_Uint" , |
538 | "D24_Unorm_S8_Uint" , |
539 | "D32_Sfloat_S8_Uint" , |
540 | "Bc1_Rgb_Unorm_Block" , |
541 | "Bc1_Rgb_Srgb_Block" , |
542 | "Bc1_Rgba_Unorm_Block" , |
543 | "Bc1_Rgba_Srgb_Block" , |
544 | "Bc2_Unorm_Block" , |
545 | "Bc2_Srgb_Block" , |
546 | "Bc3_Unorm_Block" , |
547 | "Bc3_Srgb_Block" , |
548 | "Bc4_Unorm_Block" , |
549 | "Bc4_Snorm_Block" , |
550 | "Bc5_Unorm_Block" , |
551 | "Bc5_Snorm_Block" , |
552 | "Bc6H_Ufloat_Block" , |
553 | "Bc6H_Sfloat_Block" , |
554 | "Bc7_Unorm_Block" , |
555 | "Bc7_Srgb_Block" , |
556 | "Etc2_R8G8B8_Unorm_Block" , |
557 | "Etc2_R8G8B8_Srgb_Block" , |
558 | "Etc2_R8G8B8A1_Unorm_Block" , |
559 | "Etc2_R8G8B8A1_Srgb_Block" , |
560 | "Etc2_R8G8B8A8_Unorm_Block" , |
561 | "Etc2_R8G8B8A8_Srgb_Block" , |
562 | "Eac_R11_Unorm_Block" , |
563 | "Eac_R11_Snorm_Block" , |
564 | "Eac_R11G11_Unorm_Block" , |
565 | "Eac_R11G11_Snorm_Block" , |
566 | "Astc_4X4_Unorm_Block" , |
567 | "Astc_4X4_Srgb_Block" , |
568 | "Astc_5X4_Unorm_Block" , |
569 | "Astc_5X4_Srgb_Block" , |
570 | "Astc_5X5_Unorm_Block" , |
571 | "Astc_5X5_Srgb_Block" , |
572 | "Astc_6X5_Unorm_Block" , |
573 | "Astc_6X5_Srgb_Block" , |
574 | "Astc_6X6_Unorm_Block" , |
575 | "Astc_6X6_Srgb_Block" , |
576 | "Astc_8X5_Unorm_Block" , |
577 | "Astc_8X5_Srgb_Block" , |
578 | "Astc_8X6_Unorm_Block" , |
579 | "Astc_8X6_Srgb_Block" , |
580 | "Astc_8X8_Unorm_Block" , |
581 | "Astc_8X8_Srgb_Block" , |
582 | "Astc_10X5_Unorm_Block" , |
583 | "Astc_10X5_Srgb_Block" , |
584 | "Astc_10X6_Unorm_Block" , |
585 | "Astc_10X6_Srgb_Block" , |
586 | "Astc_10X8_Unorm_Block" , |
587 | "Astc_10X8_Srgb_Block" , |
588 | "Astc_10X10_Unorm_Block" , |
589 | "Astc_10X10_Srgb_Block" , |
590 | "Astc_12X10_Unorm_Block" , |
591 | "Astc_12X10_Srgb_Block" , |
592 | "Astc_12X12_Unorm_Block" , |
593 | "Astc_12X12_Srgb_Block" , |
594 | "G8B8G8R8_422_Unorm" , |
595 | "B8G8R8G8_422_Unorm" , |
596 | "G8_B8_R8_3Plane_420_Unorm" , |
597 | "G8_B8R8_2Plane_420_Unorm" , |
598 | "G8_B8_R8_3Plane_422_Unorm" , |
599 | "G8_B8R8_2Plane_422_Unorm" , |
600 | "G8_B8_R8_3Plane_444_Unorm" , |
601 | "R10X6_Unorm_Pack16" , |
602 | "R10X6G10X6_Unorm_2Pack16" , |
603 | "R10X6G10X6B10X6A10X6_Unorm_4Pack16" , |
604 | "G10X6B10X6G10X6R10X6_422_Unorm_4Pack16" , |
605 | "B10X6G10X6R10X6G10X6_422_Unorm_4Pack16" , |
606 | "G10X6_B10X6_R10X6_3Plane_420_Unorm_3Pack16" , |
607 | "G10X6_B10X6R10X6_2Plane_420_Unorm_3Pack16" , |
608 | "G10X6_B10X6_R10X6_3Plane_422_Unorm_3Pack16" , |
609 | "G10X6_B10X6R10X6_2Plane_422_Unorm_3Pack16" , |
610 | "G10X6_B10X6_R10X6_3Plane_444_Unorm_3Pack16" , |
611 | "R12X4_Unorm_Pack16" , |
612 | "R12X4G12X4_Unorm_2Pack16" , |
613 | "R12X4G12X4B12X4A12X4_Unorm_4Pack16" , |
614 | "G12X4B12X4G12X4R12X4_422_Unorm_4Pack16" , |
615 | "B12X4G12X4R12X4G12X4_422_Unorm_4Pack16" , |
616 | "G12X4_B12X4_R12X4_3Plane_420_Unorm_3Pack16" , |
617 | "G12X4_B12X4R12X4_2Plane_420_Unorm_3Pack16" , |
618 | "G12X4_B12X4_R12X4_3Plane_422_Unorm_3Pack16" , |
619 | "G12X4_B12X4R12X4_2Plane_422_Unorm_3Pack16" , |
620 | "G12X4_B12X4_R12X4_3Plane_444_Unorm_3Pack16" , |
621 | "G16B16G16R16_422_Unorm" , |
622 | "B16G16R16G16_422_Unorm" , |
623 | "G16_B16_R16_3Plane_420_Unorm" , |
624 | "G16_B16R16_2Plane_420_Unorm" , |
625 | "G16_B16_R16_3Plane_422_Unorm" , |
626 | "G16_B16R16_2Plane_422_Unorm" , |
627 | "G16_B16_R16_3Plane_444_Unorm" , |
628 | }; |
629 | |
630 | int RenderingDeviceVulkan::get_format_vertex_size(DataFormat p_format) { |
631 | switch (p_format) { |
632 | case DATA_FORMAT_R8_UNORM: |
633 | case DATA_FORMAT_R8_SNORM: |
634 | case DATA_FORMAT_R8_UINT: |
635 | case DATA_FORMAT_R8_SINT: |
636 | case DATA_FORMAT_R8G8_UNORM: |
637 | case DATA_FORMAT_R8G8_SNORM: |
638 | case DATA_FORMAT_R8G8_UINT: |
639 | case DATA_FORMAT_R8G8_SINT: |
640 | case DATA_FORMAT_R8G8B8_UNORM: |
641 | case DATA_FORMAT_R8G8B8_SNORM: |
642 | case DATA_FORMAT_R8G8B8_UINT: |
643 | case DATA_FORMAT_R8G8B8_SINT: |
644 | case DATA_FORMAT_B8G8R8_UNORM: |
645 | case DATA_FORMAT_B8G8R8_SNORM: |
646 | case DATA_FORMAT_B8G8R8_UINT: |
647 | case DATA_FORMAT_B8G8R8_SINT: |
648 | case DATA_FORMAT_R8G8B8A8_UNORM: |
649 | case DATA_FORMAT_R8G8B8A8_SNORM: |
650 | case DATA_FORMAT_R8G8B8A8_UINT: |
651 | case DATA_FORMAT_R8G8B8A8_SINT: |
652 | case DATA_FORMAT_B8G8R8A8_UNORM: |
653 | case DATA_FORMAT_B8G8R8A8_SNORM: |
654 | case DATA_FORMAT_B8G8R8A8_UINT: |
655 | case DATA_FORMAT_B8G8R8A8_SINT: |
656 | case DATA_FORMAT_A2B10G10R10_UNORM_PACK32: |
657 | return 4; |
658 | case DATA_FORMAT_R16_UNORM: |
659 | case DATA_FORMAT_R16_SNORM: |
660 | case DATA_FORMAT_R16_UINT: |
661 | case DATA_FORMAT_R16_SINT: |
662 | case DATA_FORMAT_R16_SFLOAT: |
663 | return 4; |
664 | case DATA_FORMAT_R16G16_UNORM: |
665 | case DATA_FORMAT_R16G16_SNORM: |
666 | case DATA_FORMAT_R16G16_UINT: |
667 | case DATA_FORMAT_R16G16_SINT: |
668 | case DATA_FORMAT_R16G16_SFLOAT: |
669 | return 4; |
670 | case DATA_FORMAT_R16G16B16_UNORM: |
671 | case DATA_FORMAT_R16G16B16_SNORM: |
672 | case DATA_FORMAT_R16G16B16_UINT: |
673 | case DATA_FORMAT_R16G16B16_SINT: |
674 | case DATA_FORMAT_R16G16B16_SFLOAT: |
675 | return 8; |
676 | case DATA_FORMAT_R16G16B16A16_UNORM: |
677 | case DATA_FORMAT_R16G16B16A16_SNORM: |
678 | case DATA_FORMAT_R16G16B16A16_UINT: |
679 | case DATA_FORMAT_R16G16B16A16_SINT: |
680 | case DATA_FORMAT_R16G16B16A16_SFLOAT: |
681 | return 8; |
682 | case DATA_FORMAT_R32_UINT: |
683 | case DATA_FORMAT_R32_SINT: |
684 | case DATA_FORMAT_R32_SFLOAT: |
685 | return 4; |
686 | case DATA_FORMAT_R32G32_UINT: |
687 | case DATA_FORMAT_R32G32_SINT: |
688 | case DATA_FORMAT_R32G32_SFLOAT: |
689 | return 8; |
690 | case DATA_FORMAT_R32G32B32_UINT: |
691 | case DATA_FORMAT_R32G32B32_SINT: |
692 | case DATA_FORMAT_R32G32B32_SFLOAT: |
693 | return 12; |
694 | case DATA_FORMAT_R32G32B32A32_UINT: |
695 | case DATA_FORMAT_R32G32B32A32_SINT: |
696 | case DATA_FORMAT_R32G32B32A32_SFLOAT: |
697 | return 16; |
698 | case DATA_FORMAT_R64_UINT: |
699 | case DATA_FORMAT_R64_SINT: |
700 | case DATA_FORMAT_R64_SFLOAT: |
701 | return 8; |
702 | case DATA_FORMAT_R64G64_UINT: |
703 | case DATA_FORMAT_R64G64_SINT: |
704 | case DATA_FORMAT_R64G64_SFLOAT: |
705 | return 16; |
706 | case DATA_FORMAT_R64G64B64_UINT: |
707 | case DATA_FORMAT_R64G64B64_SINT: |
708 | case DATA_FORMAT_R64G64B64_SFLOAT: |
709 | return 24; |
710 | case DATA_FORMAT_R64G64B64A64_UINT: |
711 | case DATA_FORMAT_R64G64B64A64_SINT: |
712 | case DATA_FORMAT_R64G64B64A64_SFLOAT: |
713 | return 32; |
714 | default: |
715 | return 0; |
716 | } |
717 | } |
718 | |
719 | uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) { |
720 | switch (p_format) { |
721 | case DATA_FORMAT_R4G4_UNORM_PACK8: |
722 | return 1; |
723 | case DATA_FORMAT_R4G4B4A4_UNORM_PACK16: |
724 | case DATA_FORMAT_B4G4R4A4_UNORM_PACK16: |
725 | case DATA_FORMAT_R5G6B5_UNORM_PACK16: |
726 | case DATA_FORMAT_B5G6R5_UNORM_PACK16: |
727 | case DATA_FORMAT_R5G5B5A1_UNORM_PACK16: |
728 | case DATA_FORMAT_B5G5R5A1_UNORM_PACK16: |
729 | case DATA_FORMAT_A1R5G5B5_UNORM_PACK16: |
730 | return 2; |
731 | case DATA_FORMAT_R8_UNORM: |
732 | case DATA_FORMAT_R8_SNORM: |
733 | case DATA_FORMAT_R8_USCALED: |
734 | case DATA_FORMAT_R8_SSCALED: |
735 | case DATA_FORMAT_R8_UINT: |
736 | case DATA_FORMAT_R8_SINT: |
737 | case DATA_FORMAT_R8_SRGB: |
738 | return 1; |
739 | case DATA_FORMAT_R8G8_UNORM: |
740 | case DATA_FORMAT_R8G8_SNORM: |
741 | case DATA_FORMAT_R8G8_USCALED: |
742 | case DATA_FORMAT_R8G8_SSCALED: |
743 | case DATA_FORMAT_R8G8_UINT: |
744 | case DATA_FORMAT_R8G8_SINT: |
745 | case DATA_FORMAT_R8G8_SRGB: |
746 | return 2; |
747 | case DATA_FORMAT_R8G8B8_UNORM: |
748 | case DATA_FORMAT_R8G8B8_SNORM: |
749 | case DATA_FORMAT_R8G8B8_USCALED: |
750 | case DATA_FORMAT_R8G8B8_SSCALED: |
751 | case DATA_FORMAT_R8G8B8_UINT: |
752 | case DATA_FORMAT_R8G8B8_SINT: |
753 | case DATA_FORMAT_R8G8B8_SRGB: |
754 | case DATA_FORMAT_B8G8R8_UNORM: |
755 | case DATA_FORMAT_B8G8R8_SNORM: |
756 | case DATA_FORMAT_B8G8R8_USCALED: |
757 | case DATA_FORMAT_B8G8R8_SSCALED: |
758 | case DATA_FORMAT_B8G8R8_UINT: |
759 | case DATA_FORMAT_B8G8R8_SINT: |
760 | case DATA_FORMAT_B8G8R8_SRGB: |
761 | return 3; |
762 | case DATA_FORMAT_R8G8B8A8_UNORM: |
763 | case DATA_FORMAT_R8G8B8A8_SNORM: |
764 | case DATA_FORMAT_R8G8B8A8_USCALED: |
765 | case DATA_FORMAT_R8G8B8A8_SSCALED: |
766 | case DATA_FORMAT_R8G8B8A8_UINT: |
767 | case DATA_FORMAT_R8G8B8A8_SINT: |
768 | case DATA_FORMAT_R8G8B8A8_SRGB: |
769 | case DATA_FORMAT_B8G8R8A8_UNORM: |
770 | case DATA_FORMAT_B8G8R8A8_SNORM: |
771 | case DATA_FORMAT_B8G8R8A8_USCALED: |
772 | case DATA_FORMAT_B8G8R8A8_SSCALED: |
773 | case DATA_FORMAT_B8G8R8A8_UINT: |
774 | case DATA_FORMAT_B8G8R8A8_SINT: |
775 | case DATA_FORMAT_B8G8R8A8_SRGB: |
776 | return 4; |
777 | case DATA_FORMAT_A8B8G8R8_UNORM_PACK32: |
778 | case DATA_FORMAT_A8B8G8R8_SNORM_PACK32: |
779 | case DATA_FORMAT_A8B8G8R8_USCALED_PACK32: |
780 | case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32: |
781 | case DATA_FORMAT_A8B8G8R8_UINT_PACK32: |
782 | case DATA_FORMAT_A8B8G8R8_SINT_PACK32: |
783 | case DATA_FORMAT_A8B8G8R8_SRGB_PACK32: |
784 | case DATA_FORMAT_A2R10G10B10_UNORM_PACK32: |
785 | case DATA_FORMAT_A2R10G10B10_SNORM_PACK32: |
786 | case DATA_FORMAT_A2R10G10B10_USCALED_PACK32: |
787 | case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32: |
788 | case DATA_FORMAT_A2R10G10B10_UINT_PACK32: |
789 | case DATA_FORMAT_A2R10G10B10_SINT_PACK32: |
790 | case DATA_FORMAT_A2B10G10R10_UNORM_PACK32: |
791 | case DATA_FORMAT_A2B10G10R10_SNORM_PACK32: |
792 | case DATA_FORMAT_A2B10G10R10_USCALED_PACK32: |
793 | case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32: |
794 | case DATA_FORMAT_A2B10G10R10_UINT_PACK32: |
795 | case DATA_FORMAT_A2B10G10R10_SINT_PACK32: |
796 | return 4; |
797 | case DATA_FORMAT_R16_UNORM: |
798 | case DATA_FORMAT_R16_SNORM: |
799 | case DATA_FORMAT_R16_USCALED: |
800 | case DATA_FORMAT_R16_SSCALED: |
801 | case DATA_FORMAT_R16_UINT: |
802 | case DATA_FORMAT_R16_SINT: |
803 | case DATA_FORMAT_R16_SFLOAT: |
804 | return 2; |
805 | case DATA_FORMAT_R16G16_UNORM: |
806 | case DATA_FORMAT_R16G16_SNORM: |
807 | case DATA_FORMAT_R16G16_USCALED: |
808 | case DATA_FORMAT_R16G16_SSCALED: |
809 | case DATA_FORMAT_R16G16_UINT: |
810 | case DATA_FORMAT_R16G16_SINT: |
811 | case DATA_FORMAT_R16G16_SFLOAT: |
812 | return 4; |
813 | case DATA_FORMAT_R16G16B16_UNORM: |
814 | case DATA_FORMAT_R16G16B16_SNORM: |
815 | case DATA_FORMAT_R16G16B16_USCALED: |
816 | case DATA_FORMAT_R16G16B16_SSCALED: |
817 | case DATA_FORMAT_R16G16B16_UINT: |
818 | case DATA_FORMAT_R16G16B16_SINT: |
819 | case DATA_FORMAT_R16G16B16_SFLOAT: |
820 | return 6; |
821 | case DATA_FORMAT_R16G16B16A16_UNORM: |
822 | case DATA_FORMAT_R16G16B16A16_SNORM: |
823 | case DATA_FORMAT_R16G16B16A16_USCALED: |
824 | case DATA_FORMAT_R16G16B16A16_SSCALED: |
825 | case DATA_FORMAT_R16G16B16A16_UINT: |
826 | case DATA_FORMAT_R16G16B16A16_SINT: |
827 | case DATA_FORMAT_R16G16B16A16_SFLOAT: |
828 | return 8; |
829 | case DATA_FORMAT_R32_UINT: |
830 | case DATA_FORMAT_R32_SINT: |
831 | case DATA_FORMAT_R32_SFLOAT: |
832 | return 4; |
833 | case DATA_FORMAT_R32G32_UINT: |
834 | case DATA_FORMAT_R32G32_SINT: |
835 | case DATA_FORMAT_R32G32_SFLOAT: |
836 | return 8; |
837 | case DATA_FORMAT_R32G32B32_UINT: |
838 | case DATA_FORMAT_R32G32B32_SINT: |
839 | case DATA_FORMAT_R32G32B32_SFLOAT: |
840 | return 12; |
841 | case DATA_FORMAT_R32G32B32A32_UINT: |
842 | case DATA_FORMAT_R32G32B32A32_SINT: |
843 | case DATA_FORMAT_R32G32B32A32_SFLOAT: |
844 | return 16; |
845 | case DATA_FORMAT_R64_UINT: |
846 | case DATA_FORMAT_R64_SINT: |
847 | case DATA_FORMAT_R64_SFLOAT: |
848 | return 8; |
849 | case DATA_FORMAT_R64G64_UINT: |
850 | case DATA_FORMAT_R64G64_SINT: |
851 | case DATA_FORMAT_R64G64_SFLOAT: |
852 | return 16; |
853 | case DATA_FORMAT_R64G64B64_UINT: |
854 | case DATA_FORMAT_R64G64B64_SINT: |
855 | case DATA_FORMAT_R64G64B64_SFLOAT: |
856 | return 24; |
857 | case DATA_FORMAT_R64G64B64A64_UINT: |
858 | case DATA_FORMAT_R64G64B64A64_SINT: |
859 | case DATA_FORMAT_R64G64B64A64_SFLOAT: |
860 | return 32; |
861 | case DATA_FORMAT_B10G11R11_UFLOAT_PACK32: |
862 | case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: |
863 | return 4; |
864 | case DATA_FORMAT_D16_UNORM: |
865 | return 2; |
866 | case DATA_FORMAT_X8_D24_UNORM_PACK32: |
867 | return 4; |
868 | case DATA_FORMAT_D32_SFLOAT: |
869 | return 4; |
870 | case DATA_FORMAT_S8_UINT: |
871 | return 1; |
872 | case DATA_FORMAT_D16_UNORM_S8_UINT: |
873 | return 4; |
874 | case DATA_FORMAT_D24_UNORM_S8_UINT: |
875 | return 4; |
876 | case DATA_FORMAT_D32_SFLOAT_S8_UINT: |
877 | return 5; // ? |
878 | case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: |
879 | case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: |
880 | case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: |
881 | case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: |
882 | case DATA_FORMAT_BC2_UNORM_BLOCK: |
883 | case DATA_FORMAT_BC2_SRGB_BLOCK: |
884 | case DATA_FORMAT_BC3_UNORM_BLOCK: |
885 | case DATA_FORMAT_BC3_SRGB_BLOCK: |
886 | case DATA_FORMAT_BC4_UNORM_BLOCK: |
887 | case DATA_FORMAT_BC4_SNORM_BLOCK: |
888 | case DATA_FORMAT_BC5_UNORM_BLOCK: |
889 | case DATA_FORMAT_BC5_SNORM_BLOCK: |
890 | case DATA_FORMAT_BC6H_UFLOAT_BLOCK: |
891 | case DATA_FORMAT_BC6H_SFLOAT_BLOCK: |
892 | case DATA_FORMAT_BC7_UNORM_BLOCK: |
893 | case DATA_FORMAT_BC7_SRGB_BLOCK: |
894 | return 1; |
895 | case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: |
896 | case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: |
897 | case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: |
898 | case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: |
899 | case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: |
900 | case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: |
901 | return 1; |
902 | case DATA_FORMAT_EAC_R11_UNORM_BLOCK: |
903 | case DATA_FORMAT_EAC_R11_SNORM_BLOCK: |
904 | case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: |
905 | case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: |
906 | return 1; |
907 | case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: |
908 | case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: |
909 | case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: |
910 | case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: |
911 | case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: |
912 | case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: |
913 | case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: |
914 | case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: |
915 | case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: |
916 | case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: |
917 | case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: |
918 | case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: |
919 | case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: |
920 | case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: |
921 | case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: |
922 | case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: |
923 | case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: |
924 | case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: |
925 | case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: |
926 | case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: |
927 | case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: |
928 | case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: |
929 | case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: |
930 | case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: |
931 | case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: |
932 | case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: |
933 | case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: |
934 | case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: |
935 | return 1; |
936 | case DATA_FORMAT_G8B8G8R8_422_UNORM: |
937 | case DATA_FORMAT_B8G8R8G8_422_UNORM: |
938 | return 4; |
939 | case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM: |
940 | case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM: |
941 | case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM: |
942 | case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM: |
943 | case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM: |
944 | return 4; |
945 | case DATA_FORMAT_R10X6_UNORM_PACK16: |
946 | case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16: |
947 | case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: |
948 | case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: |
949 | case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: |
950 | case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: |
951 | case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: |
952 | case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: |
953 | case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: |
954 | case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: |
955 | case DATA_FORMAT_R12X4_UNORM_PACK16: |
956 | case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16: |
957 | case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: |
958 | case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: |
959 | case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: |
960 | case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: |
961 | case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: |
962 | case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: |
963 | case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: |
964 | case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: |
965 | return 2; |
966 | case DATA_FORMAT_G16B16G16R16_422_UNORM: |
967 | case DATA_FORMAT_B16G16R16G16_422_UNORM: |
968 | case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM: |
969 | case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM: |
970 | case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM: |
971 | case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM: |
972 | case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM: |
973 | return 8; |
974 | default: { |
975 | ERR_PRINT("Format not handled, bug" ); |
976 | } |
977 | } |
978 | |
979 | return 1; |
980 | } |
981 | |
982 | // https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf |
983 | |
984 | void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) { |
985 | switch (p_format) { |
986 | case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: |
987 | case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: |
988 | case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: |
989 | case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: |
990 | case DATA_FORMAT_BC2_UNORM_BLOCK: |
991 | case DATA_FORMAT_BC2_SRGB_BLOCK: |
992 | case DATA_FORMAT_BC3_UNORM_BLOCK: |
993 | case DATA_FORMAT_BC3_SRGB_BLOCK: |
994 | case DATA_FORMAT_BC4_UNORM_BLOCK: |
995 | case DATA_FORMAT_BC4_SNORM_BLOCK: |
996 | case DATA_FORMAT_BC5_UNORM_BLOCK: |
997 | case DATA_FORMAT_BC5_SNORM_BLOCK: |
998 | case DATA_FORMAT_BC6H_UFLOAT_BLOCK: |
999 | case DATA_FORMAT_BC6H_SFLOAT_BLOCK: |
1000 | case DATA_FORMAT_BC7_UNORM_BLOCK: |
1001 | case DATA_FORMAT_BC7_SRGB_BLOCK: |
1002 | case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: |
1003 | case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: |
1004 | case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: |
1005 | case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: |
1006 | case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: |
1007 | case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: |
1008 | case DATA_FORMAT_EAC_R11_UNORM_BLOCK: |
1009 | case DATA_FORMAT_EAC_R11_SNORM_BLOCK: |
1010 | case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: |
1011 | case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: |
1012 | case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc. |
1013 | case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: { |
1014 | r_w = 4; |
1015 | r_h = 4; |
1016 | } break; |
1017 | case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported |
1018 | case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: |
1019 | case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: |
1020 | case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: |
1021 | case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: |
1022 | case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: |
1023 | case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: |
1024 | case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: |
1025 | case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: |
1026 | case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: |
1027 | case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: |
1028 | case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: { |
1029 | r_w = 4; |
1030 | r_h = 4; |
1031 | } break; |
1032 | case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: |
1033 | case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: { |
1034 | r_w = 8; |
1035 | r_h = 8; |
1036 | } break; |
1037 | case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: // Unsupported |
1038 | case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: |
1039 | case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: |
1040 | case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: |
1041 | case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: |
1042 | case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: |
1043 | case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: |
1044 | case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: |
1045 | case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: |
1046 | case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: |
1047 | case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: |
1048 | case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: |
1049 | r_w = 4; |
1050 | r_h = 4; |
1051 | return; |
1052 | default: { |
1053 | r_w = 1; |
1054 | r_h = 1; |
1055 | } |
1056 | } |
1057 | } |
1058 | |
1059 | uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(DataFormat p_format) { |
1060 | switch (p_format) { |
1061 | case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: |
1062 | case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: |
1063 | case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: |
1064 | case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: |
1065 | return 8; |
1066 | case DATA_FORMAT_BC2_UNORM_BLOCK: |
1067 | case DATA_FORMAT_BC2_SRGB_BLOCK: |
1068 | return 16; |
1069 | case DATA_FORMAT_BC3_UNORM_BLOCK: |
1070 | case DATA_FORMAT_BC3_SRGB_BLOCK: |
1071 | return 16; |
1072 | case DATA_FORMAT_BC4_UNORM_BLOCK: |
1073 | case DATA_FORMAT_BC4_SNORM_BLOCK: |
1074 | return 8; |
1075 | case DATA_FORMAT_BC5_UNORM_BLOCK: |
1076 | case DATA_FORMAT_BC5_SNORM_BLOCK: |
1077 | return 16; |
1078 | case DATA_FORMAT_BC6H_UFLOAT_BLOCK: |
1079 | case DATA_FORMAT_BC6H_SFLOAT_BLOCK: |
1080 | return 16; |
1081 | case DATA_FORMAT_BC7_UNORM_BLOCK: |
1082 | case DATA_FORMAT_BC7_SRGB_BLOCK: |
1083 | return 16; |
1084 | case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: |
1085 | case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: |
1086 | return 8; |
1087 | case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: |
1088 | case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: |
1089 | return 8; |
1090 | case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: |
1091 | case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: |
1092 | return 16; |
1093 | case DATA_FORMAT_EAC_R11_UNORM_BLOCK: |
1094 | case DATA_FORMAT_EAC_R11_SNORM_BLOCK: |
1095 | return 8; |
1096 | case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: |
1097 | case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: |
1098 | return 16; |
1099 | case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc. |
1100 | case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: |
1101 | case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: |
1102 | case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: |
1103 | case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: |
1104 | case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: |
1105 | case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: |
1106 | case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: |
1107 | case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: |
1108 | case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: |
1109 | case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: |
1110 | case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: |
1111 | case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: |
1112 | case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: |
1113 | case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: |
1114 | case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: |
1115 | case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: |
1116 | case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: |
1117 | case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: |
1118 | case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: |
1119 | case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: |
1120 | case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: |
1121 | case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: |
1122 | case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: |
1123 | case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: |
1124 | case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: |
1125 | case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: |
1126 | case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: |
1127 | return 16; |
1128 | default: { |
1129 | } |
1130 | } |
1131 | return 1; |
1132 | } |
1133 | |
1134 | uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFormat p_format) { |
1135 | switch (p_format) { |
1136 | case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: // These formats are half byte size, so rshift is 1. |
1137 | case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: |
1138 | case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: |
1139 | case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: |
1140 | case DATA_FORMAT_BC4_UNORM_BLOCK: |
1141 | case DATA_FORMAT_BC4_SNORM_BLOCK: |
1142 | case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: |
1143 | case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: |
1144 | case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: |
1145 | case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: |
1146 | case DATA_FORMAT_EAC_R11_UNORM_BLOCK: |
1147 | case DATA_FORMAT_EAC_R11_SNORM_BLOCK: |
1148 | return 1; |
1149 | case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: |
1150 | case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: { |
1151 | return 2; |
1152 | } |
1153 | default: { |
1154 | } |
1155 | } |
1156 | |
1157 | return 0; |
1158 | } |
1159 | |
1160 | bool RenderingDeviceVulkan::format_has_stencil(DataFormat p_format) { |
1161 | switch (p_format) { |
1162 | case DATA_FORMAT_S8_UINT: |
1163 | case DATA_FORMAT_D16_UNORM_S8_UINT: |
1164 | case DATA_FORMAT_D24_UNORM_S8_UINT: |
1165 | case DATA_FORMAT_D32_SFLOAT_S8_UINT: { |
1166 | return true; |
1167 | } |
1168 | default: { |
1169 | } |
1170 | } |
1171 | return false; |
1172 | } |
1173 | |
1174 | uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { |
1175 | ERR_FAIL_COND_V(p_mipmaps == 0, 0); |
1176 | uint32_t w = p_width; |
1177 | uint32_t h = p_height; |
1178 | uint32_t d = p_depth; |
1179 | |
1180 | uint32_t size = 0; |
1181 | |
1182 | uint32_t pixel_size = get_image_format_pixel_size(p_format); |
1183 | uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format); |
1184 | uint32_t blockw, blockh; |
1185 | get_compressed_image_format_block_dimensions(p_format, blockw, blockh); |
1186 | |
1187 | for (uint32_t i = 0; i < p_mipmaps; i++) { |
1188 | uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; |
1189 | uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; |
1190 | |
1191 | uint32_t s = bw * bh; |
1192 | |
1193 | s *= pixel_size; |
1194 | s >>= pixel_rshift; |
1195 | size += s * d; |
1196 | if (r_blockw) { |
1197 | *r_blockw = bw; |
1198 | } |
1199 | if (r_blockh) { |
1200 | *r_blockh = bh; |
1201 | } |
1202 | if (r_depth) { |
1203 | *r_depth = d; |
1204 | } |
1205 | w = MAX(blockw, w >> 1); |
1206 | h = MAX(blockh, h >> 1); |
1207 | d = MAX(1u, d >> 1); |
1208 | } |
1209 | |
1210 | return size; |
1211 | } |
1212 | |
1213 | uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) { |
1214 | // Formats and block size don't really matter here since they can all go down to 1px (even if block is larger). |
1215 | uint32_t w = p_width; |
1216 | uint32_t h = p_height; |
1217 | uint32_t d = p_depth; |
1218 | |
1219 | uint32_t mipmaps = 1; |
1220 | |
1221 | while (true) { |
1222 | if (w == 1 && h == 1 && d == 1) { |
1223 | break; |
1224 | } |
1225 | |
1226 | w = MAX(1u, w >> 1); |
1227 | h = MAX(1u, h >> 1); |
1228 | d = MAX(1u, d >> 1); |
1229 | |
1230 | mipmaps++; |
1231 | } |
1232 | |
1233 | return mipmaps; |
1234 | } |
1235 | |
1236 | /////////////////////// |
1237 | |
1238 | const VkCompareOp RenderingDeviceVulkan::compare_operators[RenderingDevice::COMPARE_OP_MAX] = { |
1239 | VK_COMPARE_OP_NEVER, |
1240 | VK_COMPARE_OP_LESS, |
1241 | VK_COMPARE_OP_EQUAL, |
1242 | VK_COMPARE_OP_LESS_OR_EQUAL, |
1243 | VK_COMPARE_OP_GREATER, |
1244 | VK_COMPARE_OP_NOT_EQUAL, |
1245 | VK_COMPARE_OP_GREATER_OR_EQUAL, |
1246 | VK_COMPARE_OP_ALWAYS |
1247 | }; |
1248 | |
1249 | const VkStencilOp RenderingDeviceVulkan::stencil_operations[RenderingDevice::STENCIL_OP_MAX] = { |
1250 | VK_STENCIL_OP_KEEP, |
1251 | VK_STENCIL_OP_ZERO, |
1252 | VK_STENCIL_OP_REPLACE, |
1253 | VK_STENCIL_OP_INCREMENT_AND_CLAMP, |
1254 | VK_STENCIL_OP_DECREMENT_AND_CLAMP, |
1255 | VK_STENCIL_OP_INVERT, |
1256 | VK_STENCIL_OP_INCREMENT_AND_WRAP, |
1257 | VK_STENCIL_OP_DECREMENT_AND_WRAP |
1258 | }; |
1259 | |
1260 | const VkSampleCountFlagBits RenderingDeviceVulkan::rasterization_sample_count[RenderingDevice::TEXTURE_SAMPLES_MAX] = { |
1261 | VK_SAMPLE_COUNT_1_BIT, |
1262 | VK_SAMPLE_COUNT_2_BIT, |
1263 | VK_SAMPLE_COUNT_4_BIT, |
1264 | VK_SAMPLE_COUNT_8_BIT, |
1265 | VK_SAMPLE_COUNT_16_BIT, |
1266 | VK_SAMPLE_COUNT_32_BIT, |
1267 | VK_SAMPLE_COUNT_64_BIT, |
1268 | }; |
1269 | |
1270 | const VkLogicOp RenderingDeviceVulkan::logic_operations[RenderingDevice::LOGIC_OP_MAX] = { |
1271 | VK_LOGIC_OP_CLEAR, |
1272 | VK_LOGIC_OP_AND, |
1273 | VK_LOGIC_OP_AND_REVERSE, |
1274 | VK_LOGIC_OP_COPY, |
1275 | VK_LOGIC_OP_AND_INVERTED, |
1276 | VK_LOGIC_OP_NO_OP, |
1277 | VK_LOGIC_OP_XOR, |
1278 | VK_LOGIC_OP_OR, |
1279 | VK_LOGIC_OP_NOR, |
1280 | VK_LOGIC_OP_EQUIVALENT, |
1281 | VK_LOGIC_OP_INVERT, |
1282 | VK_LOGIC_OP_OR_REVERSE, |
1283 | VK_LOGIC_OP_COPY_INVERTED, |
1284 | VK_LOGIC_OP_OR_INVERTED, |
1285 | VK_LOGIC_OP_NAND, |
1286 | VK_LOGIC_OP_SET |
1287 | }; |
1288 | |
1289 | const VkBlendFactor RenderingDeviceVulkan::blend_factors[RenderingDevice::BLEND_FACTOR_MAX] = { |
1290 | VK_BLEND_FACTOR_ZERO, |
1291 | VK_BLEND_FACTOR_ONE, |
1292 | VK_BLEND_FACTOR_SRC_COLOR, |
1293 | VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, |
1294 | VK_BLEND_FACTOR_DST_COLOR, |
1295 | VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, |
1296 | VK_BLEND_FACTOR_SRC_ALPHA, |
1297 | VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, |
1298 | VK_BLEND_FACTOR_DST_ALPHA, |
1299 | VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, |
1300 | VK_BLEND_FACTOR_CONSTANT_COLOR, |
1301 | VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, |
1302 | VK_BLEND_FACTOR_CONSTANT_ALPHA, |
1303 | VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, |
1304 | VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, |
1305 | VK_BLEND_FACTOR_SRC1_COLOR, |
1306 | VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, |
1307 | VK_BLEND_FACTOR_SRC1_ALPHA, |
1308 | VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA |
1309 | }; |
1310 | const VkBlendOp RenderingDeviceVulkan::blend_operations[RenderingDevice::BLEND_OP_MAX] = { |
1311 | VK_BLEND_OP_ADD, |
1312 | VK_BLEND_OP_SUBTRACT, |
1313 | VK_BLEND_OP_REVERSE_SUBTRACT, |
1314 | VK_BLEND_OP_MIN, |
1315 | VK_BLEND_OP_MAX |
1316 | }; |
1317 | |
1318 | const VkSamplerAddressMode RenderingDeviceVulkan::address_modes[RenderingDevice::SAMPLER_REPEAT_MODE_MAX] = { |
1319 | VK_SAMPLER_ADDRESS_MODE_REPEAT, |
1320 | VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, |
1321 | VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
1322 | VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
1323 | VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE |
1324 | }; |
1325 | |
1326 | const VkBorderColor RenderingDeviceVulkan::sampler_border_colors[RenderingDevice::SAMPLER_BORDER_COLOR_MAX] = { |
1327 | VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, |
1328 | VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, |
1329 | VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, |
1330 | VK_BORDER_COLOR_INT_OPAQUE_BLACK, |
1331 | VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, |
1332 | VK_BORDER_COLOR_INT_OPAQUE_WHITE |
1333 | }; |
1334 | |
1335 | const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXTURE_TYPE_MAX] = { |
1336 | VK_IMAGE_TYPE_1D, |
1337 | VK_IMAGE_TYPE_2D, |
1338 | VK_IMAGE_TYPE_3D, |
1339 | VK_IMAGE_TYPE_2D, |
1340 | VK_IMAGE_TYPE_1D, |
1341 | VK_IMAGE_TYPE_2D, |
1342 | VK_IMAGE_TYPE_2D |
1343 | }; |
1344 | |
1345 | /***************************/ |
1346 | /**** BUFFER MANAGEMENT ****/ |
1347 | /***************************/ |
1348 | |
1349 | Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mem_usage, VmaAllocationCreateFlags p_mem_flags) { |
1350 | VkBufferCreateInfo bufferInfo; |
1351 | bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
1352 | bufferInfo.pNext = nullptr; |
1353 | bufferInfo.flags = 0; |
1354 | bufferInfo.size = p_size; |
1355 | bufferInfo.usage = p_usage; |
1356 | bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
1357 | bufferInfo.queueFamilyIndexCount = 0; |
1358 | bufferInfo.pQueueFamilyIndices = nullptr; |
1359 | |
1360 | VmaAllocationCreateInfo allocInfo; |
1361 | allocInfo.flags = p_mem_flags; |
1362 | allocInfo.usage = p_mem_usage; |
1363 | allocInfo.requiredFlags = 0; |
1364 | allocInfo.preferredFlags = 0; |
1365 | allocInfo.memoryTypeBits = 0; |
1366 | allocInfo.pool = nullptr; |
1367 | allocInfo.pUserData = nullptr; |
1368 | if (p_size <= SMALL_ALLOCATION_MAX_SIZE) { |
1369 | uint32_t mem_type_index = 0; |
1370 | vmaFindMemoryTypeIndexForBufferInfo(allocator, &bufferInfo, &allocInfo, &mem_type_index); |
1371 | allocInfo.pool = _find_or_create_small_allocs_pool(mem_type_index); |
1372 | } |
1373 | |
1374 | VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, nullptr); |
1375 | ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size) + ", error " + itos(err) + "." ); |
1376 | p_buffer->size = p_size; |
1377 | p_buffer->buffer_info.buffer = p_buffer->buffer; |
1378 | p_buffer->buffer_info.offset = 0; |
1379 | p_buffer->buffer_info.range = p_size; |
1380 | p_buffer->usage = p_usage; |
1381 | |
1382 | buffer_memory += p_size; |
1383 | |
1384 | return OK; |
1385 | } |
1386 | |
1387 | Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { |
1388 | ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER); |
1389 | |
1390 | buffer_memory -= p_buffer->size; |
1391 | vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation); |
1392 | p_buffer->buffer = VK_NULL_HANDLE; |
1393 | p_buffer->allocation = nullptr; |
1394 | p_buffer->size = 0; |
1395 | |
1396 | return OK; |
1397 | } |
1398 | |
1399 | Error RenderingDeviceVulkan::_insert_staging_block() { |
1400 | VkBufferCreateInfo bufferInfo; |
1401 | bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
1402 | bufferInfo.pNext = nullptr; |
1403 | bufferInfo.flags = 0; |
1404 | bufferInfo.size = staging_buffer_block_size; |
1405 | bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
1406 | bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
1407 | bufferInfo.queueFamilyIndexCount = 0; |
1408 | bufferInfo.pQueueFamilyIndices = nullptr; |
1409 | |
1410 | VmaAllocationCreateInfo allocInfo; |
1411 | allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; |
1412 | allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; |
1413 | allocInfo.requiredFlags = 0; |
1414 | allocInfo.preferredFlags = 0; |
1415 | allocInfo.memoryTypeBits = 0; |
1416 | allocInfo.pool = nullptr; |
1417 | allocInfo.pUserData = nullptr; |
1418 | |
1419 | StagingBufferBlock block; |
1420 | |
1421 | VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &block.buffer, &block.allocation, nullptr); |
1422 | ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vmaCreateBuffer failed with error " + itos(err) + "." ); |
1423 | |
1424 | block.frame_used = 0; |
1425 | block.fill_amount = 0; |
1426 | |
1427 | staging_buffer_blocks.insert(staging_buffer_current, block); |
1428 | return OK; |
1429 | } |
1430 | |
1431 | Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) { |
1432 | // Determine a block to use. |
1433 | |
1434 | r_alloc_size = p_amount; |
1435 | |
1436 | while (true) { |
1437 | r_alloc_offset = 0; |
1438 | |
1439 | // See if we can use current block. |
1440 | if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) { |
1441 | // We used this block this frame, let's see if there is still room. |
1442 | |
1443 | uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount; |
1444 | |
1445 | { |
1446 | uint32_t align_remainder = write_from % p_required_align; |
1447 | if (align_remainder != 0) { |
1448 | write_from += p_required_align - align_remainder; |
1449 | } |
1450 | } |
1451 | |
1452 | int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from); |
1453 | |
1454 | if ((int32_t)p_amount < available_bytes) { |
1455 | // All is good, we should be ok, all will fit. |
1456 | r_alloc_offset = write_from; |
1457 | } else if (p_can_segment && available_bytes >= (int32_t)p_required_align) { |
1458 | // Ok all won't fit but at least we can fit a chunkie. |
1459 | // All is good, update what needs to be written to. |
1460 | r_alloc_offset = write_from; |
1461 | r_alloc_size = available_bytes - (available_bytes % p_required_align); |
1462 | |
1463 | } else { |
1464 | // Can't fit it into this buffer. |
1465 | // Will need to try next buffer. |
1466 | |
1467 | staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); |
1468 | |
1469 | // Before doing anything, though, let's check that we didn't manage to fill all blocks. |
1470 | // Possible in a single frame. |
1471 | if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) { |
1472 | // Guess we did.. ok, let's see if we can insert a new block. |
1473 | if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) { |
1474 | // We can, so we are safe. |
1475 | Error err = _insert_staging_block(); |
1476 | if (err) { |
1477 | return err; |
1478 | } |
1479 | // Claim for this frame. |
1480 | staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; |
1481 | } else { |
1482 | // Ok, worst case scenario, all the staging buffers belong to this frame |
1483 | // and this frame is not even done. |
1484 | // If this is the main thread, it means the user is likely loading a lot of resources at once,. |
1485 | // Otherwise, the thread should just be blocked until the next frame (currently unimplemented). |
1486 | |
1487 | if (false) { // Separate thread from render. |
1488 | |
1489 | //block_until_next_frame() |
1490 | continue; |
1491 | } else { |
1492 | // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands. |
1493 | _flush(true); |
1494 | |
1495 | // Clear the whole staging buffer. |
1496 | for (int i = 0; i < staging_buffer_blocks.size(); i++) { |
1497 | staging_buffer_blocks.write[i].frame_used = 0; |
1498 | staging_buffer_blocks.write[i].fill_amount = 0; |
1499 | } |
1500 | // Claim current. |
1501 | staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; |
1502 | } |
1503 | } |
1504 | |
1505 | } else { |
1506 | // Not from current frame, so continue and try again. |
1507 | continue; |
1508 | } |
1509 | } |
1510 | |
1511 | } else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) { |
1512 | // This is an old block, which was already processed, let's reuse. |
1513 | staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; |
1514 | staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0; |
1515 | } else { |
1516 | // This block may still be in use, let's not touch it unless we have to, so.. can we create a new one? |
1517 | if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) { |
1518 | // We are still allowed to create a new block, so let's do that and insert it for current pos. |
1519 | Error err = _insert_staging_block(); |
1520 | if (err) { |
1521 | return err; |
1522 | } |
1523 | // Claim for this frame. |
1524 | staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; |
1525 | } else { |
1526 | // Oops, we are out of room and we can't create more. |
1527 | // Let's flush older frames. |
1528 | // The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway. |
1529 | // If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though). |
1530 | |
1531 | if (false) { |
1532 | // Separate thread from render. |
1533 | //block_until_next_frame() |
1534 | continue; // And try again. |
1535 | } else { |
1536 | _flush(false); |
1537 | |
1538 | for (int i = 0; i < staging_buffer_blocks.size(); i++) { |
1539 | // Clear all blocks but the ones from this frame. |
1540 | int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size(); |
1541 | if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) { |
1542 | break; // Ok, we reached something from this frame, abort. |
1543 | } |
1544 | |
1545 | staging_buffer_blocks.write[block_idx].frame_used = 0; |
1546 | staging_buffer_blocks.write[block_idx].fill_amount = 0; |
1547 | } |
1548 | |
1549 | // Claim for current frame. |
1550 | staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; |
1551 | } |
1552 | } |
1553 | } |
1554 | |
1555 | // All was good, break. |
1556 | break; |
1557 | } |
1558 | |
1559 | staging_buffer_used = true; |
1560 | |
1561 | return OK; |
1562 | } |
1563 | |
1564 | Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) { |
1565 | // Submitting may get chunked for various reasons, so convert this to a task. |
1566 | size_t to_submit = p_data_size; |
1567 | size_t submit_from = 0; |
1568 | |
1569 | while (to_submit > 0) { |
1570 | uint32_t block_write_offset; |
1571 | uint32_t block_write_amount; |
1572 | |
1573 | Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount); |
1574 | if (err) { |
1575 | return err; |
1576 | } |
1577 | |
1578 | // Map staging buffer (It's CPU and coherent). |
1579 | |
1580 | void *data_ptr = nullptr; |
1581 | { |
1582 | VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); |
1583 | ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + "." ); |
1584 | } |
1585 | |
1586 | // Copy to staging buffer. |
1587 | memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount); |
1588 | |
1589 | // Unmap. |
1590 | vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); |
1591 | // Insert a command to copy this. |
1592 | |
1593 | VkBufferCopy region; |
1594 | region.srcOffset = block_write_offset; |
1595 | region.dstOffset = submit_from + p_offset; |
1596 | region.size = block_write_amount; |
1597 | |
1598 | vkCmdCopyBuffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, p_buffer->buffer, 1, ®ion); |
1599 | |
1600 | staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount; |
1601 | |
1602 | to_submit -= block_write_amount; |
1603 | submit_from += block_write_amount; |
1604 | } |
1605 | |
1606 | return OK; |
1607 | } |
1608 | |
1609 | void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw) { |
1610 | VkMemoryBarrier mem_barrier; |
1611 | mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; |
1612 | mem_barrier.pNext = nullptr; |
1613 | mem_barrier.srcAccessMask = p_src_access; |
1614 | mem_barrier.dstAccessMask = p_dst_access; |
1615 | |
1616 | if (p_src_stage_mask == 0 || p_dst_stage_mask == 0) { |
1617 | return; // No barrier, since this is invalid. |
1618 | } |
1619 | vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, nullptr, 0, nullptr); |
1620 | } |
1621 | |
1622 | void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) { |
1623 | // Used for debug. |
1624 | _memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, |
1625 | VK_ACCESS_INDIRECT_COMMAND_READ_BIT | |
1626 | VK_ACCESS_INDEX_READ_BIT | |
1627 | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | |
1628 | VK_ACCESS_UNIFORM_READ_BIT | |
1629 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
1630 | VK_ACCESS_SHADER_READ_BIT | |
1631 | VK_ACCESS_SHADER_WRITE_BIT | |
1632 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
1633 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
1634 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
1635 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
1636 | VK_ACCESS_TRANSFER_READ_BIT | |
1637 | VK_ACCESS_TRANSFER_WRITE_BIT | |
1638 | VK_ACCESS_HOST_READ_BIT | |
1639 | VK_ACCESS_HOST_WRITE_BIT, |
1640 | VK_ACCESS_INDIRECT_COMMAND_READ_BIT | |
1641 | VK_ACCESS_INDEX_READ_BIT | |
1642 | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | |
1643 | VK_ACCESS_UNIFORM_READ_BIT | |
1644 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
1645 | VK_ACCESS_SHADER_READ_BIT | |
1646 | VK_ACCESS_SHADER_WRITE_BIT | |
1647 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
1648 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
1649 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
1650 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
1651 | VK_ACCESS_TRANSFER_READ_BIT | |
1652 | VK_ACCESS_TRANSFER_WRITE_BIT | |
1653 | VK_ACCESS_HOST_READ_BIT | |
1654 | VK_ACCESS_HOST_WRITE_BIT, |
1655 | p_sync_with_draw); |
1656 | } |
1657 | |
1658 | void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw) { |
1659 | VkBufferMemoryBarrier buffer_mem_barrier; |
1660 | buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; |
1661 | buffer_mem_barrier.pNext = nullptr; |
1662 | buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
1663 | buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
1664 | buffer_mem_barrier.srcAccessMask = p_src_access; |
1665 | buffer_mem_barrier.dstAccessMask = p_dst_access; |
1666 | buffer_mem_barrier.buffer = buffer; |
1667 | buffer_mem_barrier.offset = p_from; |
1668 | buffer_mem_barrier.size = p_size; |
1669 | |
1670 | vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, nullptr, 1, &buffer_mem_barrier, 0, nullptr); |
1671 | } |
1672 | |
1673 | /*****************/ |
1674 | /**** TEXTURE ****/ |
1675 | /*****************/ |
1676 | |
1677 | RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) { |
1678 | _THREAD_SAFE_METHOD_ |
1679 | |
1680 | VkImageCreateInfo image_create_info; |
1681 | image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
1682 | image_create_info.pNext = nullptr; |
1683 | image_create_info.flags = 0; |
1684 | |
1685 | VkImageFormatListCreateInfoKHR format_list_create_info; // Keep out of the if, needed for creation. |
1686 | Vector<VkFormat> allowed_formats; // Keep out of the if, needed for creation. |
1687 | if (p_format.shareable_formats.size()) { |
1688 | image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
1689 | |
1690 | if (context->is_device_extension_enabled(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME)) { |
1691 | for (int i = 0; i < p_format.shareable_formats.size(); i++) { |
1692 | allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]); |
1693 | } |
1694 | |
1695 | format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; |
1696 | format_list_create_info.pNext = nullptr; |
1697 | format_list_create_info.viewFormatCount = allowed_formats.size(); |
1698 | format_list_create_info.pViewFormats = allowed_formats.ptr(); |
1699 | image_create_info.pNext = &format_list_create_info; |
1700 | |
1701 | ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(), |
1702 | "If supplied a list of shareable formats, the current format must be present in the list" ); |
1703 | ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(), |
1704 | "If supplied a list of shareable formats, the current view format override must be present in the list" ); |
1705 | } |
1706 | } |
1707 | |
1708 | if (p_format.texture_type == TEXTURE_TYPE_CUBE || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) { |
1709 | image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; |
1710 | } |
1711 | /*if (p_format.type == TEXTURE_TYPE_2D || p_format.type == TEXTURE_TYPE_2D_ARRAY) { |
1712 | image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; |
1713 | }*/ |
1714 | |
1715 | ERR_FAIL_INDEX_V(p_format.texture_type, TEXTURE_TYPE_MAX, RID()); |
1716 | |
1717 | image_create_info.imageType = vulkan_image_type[p_format.texture_type]; |
1718 | |
1719 | ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures" ); |
1720 | |
1721 | image_create_info.format = vulkan_formats[p_format.format]; |
1722 | |
1723 | image_create_info.extent.width = p_format.width; |
1724 | if (image_create_info.imageType == VK_IMAGE_TYPE_3D || image_create_info.imageType == VK_IMAGE_TYPE_2D) { |
1725 | ERR_FAIL_COND_V_MSG(p_format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures" ); |
1726 | image_create_info.extent.height = p_format.height; |
1727 | } else { |
1728 | image_create_info.extent.height = 1; |
1729 | } |
1730 | |
1731 | if (image_create_info.imageType == VK_IMAGE_TYPE_3D) { |
1732 | ERR_FAIL_COND_V_MSG(p_format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures" ); |
1733 | image_create_info.extent.depth = p_format.depth; |
1734 | } else { |
1735 | image_create_info.extent.depth = 1; |
1736 | } |
1737 | |
1738 | ERR_FAIL_COND_V(p_format.mipmaps < 1, RID()); |
1739 | |
1740 | image_create_info.mipLevels = p_format.mipmaps; |
1741 | |
1742 | if (p_format.texture_type == TEXTURE_TYPE_1D_ARRAY || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) { |
1743 | ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(), |
1744 | "Amount of layers must be equal or greater than 1 for arrays and cubemaps." ); |
1745 | ERR_FAIL_COND_V_MSG((p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), |
1746 | "Cubemap and cubemap array textures must provide a layer number that is multiple of 6" ); |
1747 | image_create_info.arrayLayers = p_format.array_layers; |
1748 | } else { |
1749 | image_create_info.arrayLayers = 1; |
1750 | } |
1751 | |
1752 | ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID()); |
1753 | |
1754 | image_create_info.samples = _ensure_supported_sample_count(p_format.samples); |
1755 | image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; |
1756 | |
1757 | // Usage. |
1758 | image_create_info.usage = 0; |
1759 | |
1760 | if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { |
1761 | image_create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; |
1762 | } |
1763 | |
1764 | if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) { |
1765 | image_create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT; |
1766 | } |
1767 | |
1768 | if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
1769 | image_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
1770 | } |
1771 | |
1772 | if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
1773 | image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
1774 | } |
1775 | |
1776 | if (p_format.usage_bits & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) { |
1777 | image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; |
1778 | } |
1779 | |
1780 | if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { |
1781 | image_create_info.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; |
1782 | } |
1783 | |
1784 | if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { |
1785 | image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
1786 | } |
1787 | if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT) { |
1788 | image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
1789 | } |
1790 | |
1791 | if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) { |
1792 | image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
1793 | } |
1794 | |
1795 | image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
1796 | image_create_info.queueFamilyIndexCount = 0; |
1797 | image_create_info.pQueueFamilyIndices = nullptr; |
1798 | image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
1799 | |
1800 | uint32_t required_mipmaps = get_image_required_mipmaps(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth); |
1801 | |
1802 | ERR_FAIL_COND_V_MSG(required_mipmaps < image_create_info.mipLevels, RID(), |
1803 | "Too many mipmaps requested for texture format and dimensions (" + itos(image_create_info.mipLevels) + "), maximum allowed: (" + itos(required_mipmaps) + ")." ); |
1804 | |
1805 | if (p_data.size()) { |
1806 | ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), |
1807 | "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later" ); |
1808 | |
1809 | int expected_images = image_create_info.arrayLayers; |
1810 | ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(), |
1811 | "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ")." ); |
1812 | |
1813 | for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { |
1814 | uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, image_create_info.mipLevels); |
1815 | ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(), |
1816 | "Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ")." ); |
1817 | } |
1818 | } |
1819 | |
1820 | { |
1821 | // Validate that this image is supported for the intended use. |
1822 | VkFormatProperties properties; |
1823 | vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), image_create_info.format, &properties); |
1824 | VkFormatFeatureFlags flags; |
1825 | |
1826 | String format_text = "'" + String(named_formats[p_format.format]) + "'" ; |
1827 | |
1828 | if (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) { |
1829 | flags = properties.linearTilingFeatures; |
1830 | format_text += " (with CPU read bit)" ; |
1831 | } else { |
1832 | flags = properties.optimalTilingFeatures; |
1833 | } |
1834 | |
1835 | if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { |
1836 | ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture." ); |
1837 | } |
1838 | |
1839 | if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { |
1840 | ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment." ); |
1841 | } |
1842 | |
1843 | if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
1844 | ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment." ); |
1845 | } |
1846 | |
1847 | if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { |
1848 | ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image." ); |
1849 | } |
1850 | |
1851 | if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { |
1852 | ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image." ); |
1853 | } |
1854 | |
1855 | // Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported. |
1856 | if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && p_format.format != DATA_FORMAT_R8_UINT) { |
1857 | ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as VRS attachment." ); |
1858 | } |
1859 | } |
1860 | |
1861 | // Some view validation. |
1862 | |
1863 | if (p_view.format_override != DATA_FORMAT_MAX) { |
1864 | ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); |
1865 | } |
1866 | ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID()); |
1867 | ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID()); |
1868 | ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID()); |
1869 | ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID()); |
1870 | |
1871 | // Allocate memory. |
1872 | |
1873 | uint32_t width, height; |
1874 | uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height); |
1875 | |
1876 | VmaAllocationCreateInfo allocInfo; |
1877 | allocInfo.flags = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT : 0; |
1878 | allocInfo.pool = nullptr; |
1879 | allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; |
1880 | allocInfo.requiredFlags = 0; |
1881 | allocInfo.preferredFlags = 0; |
1882 | allocInfo.memoryTypeBits = 0; |
1883 | allocInfo.pUserData = nullptr; |
1884 | if (image_size <= SMALL_ALLOCATION_MAX_SIZE) { |
1885 | uint32_t mem_type_index = 0; |
1886 | vmaFindMemoryTypeIndexForImageInfo(allocator, &image_create_info, &allocInfo, &mem_type_index); |
1887 | allocInfo.pool = _find_or_create_small_allocs_pool(mem_type_index); |
1888 | } |
1889 | |
1890 | Texture texture; |
1891 | |
1892 | VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); |
1893 | ERR_FAIL_COND_V_MSG(err, RID(), "vmaCreateImage failed with error " + itos(err) + "." ); |
1894 | image_memory += texture.allocation_info.size; |
1895 | texture.type = p_format.texture_type; |
1896 | texture.format = p_format.format; |
1897 | texture.width = image_create_info.extent.width; |
1898 | texture.height = image_create_info.extent.height; |
1899 | texture.depth = image_create_info.extent.depth; |
1900 | texture.layers = image_create_info.arrayLayers; |
1901 | texture.mipmaps = image_create_info.mipLevels; |
1902 | texture.base_mipmap = 0; |
1903 | texture.base_layer = 0; |
1904 | texture.is_resolve_buffer = p_format.is_resolve_buffer; |
1905 | texture.usage_flags = p_format.usage_bits; |
1906 | texture.samples = p_format.samples; |
1907 | texture.allowed_shared_formats = p_format.shareable_formats; |
1908 | |
1909 | // Set base layout based on usage priority. |
1910 | |
1911 | if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { |
1912 | // First priority, readable. |
1913 | texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
1914 | |
1915 | } else if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) { |
1916 | // Second priority, storage. |
1917 | |
1918 | texture.layout = VK_IMAGE_LAYOUT_GENERAL; |
1919 | |
1920 | } else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
1921 | // Third priority, color or depth. |
1922 | |
1923 | texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
1924 | |
1925 | } else if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
1926 | texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
1927 | |
1928 | } else { |
1929 | texture.layout = VK_IMAGE_LAYOUT_GENERAL; |
1930 | } |
1931 | |
1932 | if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
1933 | texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; |
1934 | texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; |
1935 | |
1936 | if (format_has_stencil(p_format.format)) { |
1937 | texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; |
1938 | } |
1939 | } else { |
1940 | texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; |
1941 | texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; |
1942 | } |
1943 | |
1944 | texture.bound = false; |
1945 | |
1946 | // Create view. |
1947 | |
1948 | VkImageViewCreateInfo image_view_create_info; |
1949 | image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
1950 | image_view_create_info.pNext = nullptr; |
1951 | image_view_create_info.flags = 0; |
1952 | image_view_create_info.image = texture.image; |
1953 | |
1954 | static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { |
1955 | VK_IMAGE_VIEW_TYPE_1D, |
1956 | VK_IMAGE_VIEW_TYPE_2D, |
1957 | VK_IMAGE_VIEW_TYPE_3D, |
1958 | VK_IMAGE_VIEW_TYPE_CUBE, |
1959 | VK_IMAGE_VIEW_TYPE_1D_ARRAY, |
1960 | VK_IMAGE_VIEW_TYPE_2D_ARRAY, |
1961 | VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, |
1962 | }; |
1963 | |
1964 | image_view_create_info.viewType = view_types[p_format.texture_type]; |
1965 | if (p_view.format_override == DATA_FORMAT_MAX) { |
1966 | image_view_create_info.format = image_create_info.format; |
1967 | } else { |
1968 | image_view_create_info.format = vulkan_formats[p_view.format_override]; |
1969 | } |
1970 | |
1971 | static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { |
1972 | VK_COMPONENT_SWIZZLE_IDENTITY, |
1973 | VK_COMPONENT_SWIZZLE_ZERO, |
1974 | VK_COMPONENT_SWIZZLE_ONE, |
1975 | VK_COMPONENT_SWIZZLE_R, |
1976 | VK_COMPONENT_SWIZZLE_G, |
1977 | VK_COMPONENT_SWIZZLE_B, |
1978 | VK_COMPONENT_SWIZZLE_A |
1979 | }; |
1980 | |
1981 | image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; |
1982 | image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; |
1983 | image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; |
1984 | image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; |
1985 | |
1986 | image_view_create_info.subresourceRange.baseMipLevel = 0; |
1987 | image_view_create_info.subresourceRange.levelCount = image_create_info.mipLevels; |
1988 | image_view_create_info.subresourceRange.baseArrayLayer = 0; |
1989 | image_view_create_info.subresourceRange.layerCount = image_create_info.arrayLayers; |
1990 | if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
1991 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
1992 | } else { |
1993 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
1994 | } |
1995 | |
1996 | err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view); |
1997 | |
1998 | if (err) { |
1999 | vmaDestroyImage(allocator, texture.image, texture.allocation); |
2000 | ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + "." ); |
2001 | } |
2002 | |
2003 | // Barrier to set layout. |
2004 | { |
2005 | VkImageMemoryBarrier image_memory_barrier; |
2006 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2007 | image_memory_barrier.pNext = nullptr; |
2008 | image_memory_barrier.srcAccessMask = 0; |
2009 | image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
2010 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
2011 | image_memory_barrier.newLayout = texture.layout; |
2012 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2013 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2014 | image_memory_barrier.image = texture.image; |
2015 | image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask; |
2016 | image_memory_barrier.subresourceRange.baseMipLevel = 0; |
2017 | image_memory_barrier.subresourceRange.levelCount = image_create_info.mipLevels; |
2018 | image_memory_barrier.subresourceRange.baseArrayLayer = 0; |
2019 | image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers; |
2020 | |
2021 | vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
2022 | } |
2023 | |
2024 | RID id = texture_owner.make_rid(texture); |
2025 | #ifdef DEV_ENABLED |
2026 | set_resource_name(id, "RID:" + itos(id.get_id())); |
2027 | #endif |
2028 | |
2029 | if (p_data.size()) { |
2030 | for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { |
2031 | _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL_BARRIERS, true); |
2032 | } |
2033 | } |
2034 | return id; |
2035 | } |
2036 | |
2037 | RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID p_with_texture) { |
2038 | _THREAD_SAFE_METHOD_ |
2039 | |
2040 | Texture *src_texture = texture_owner.get_or_null(p_with_texture); |
2041 | ERR_FAIL_NULL_V(src_texture, RID()); |
2042 | |
2043 | if (src_texture->owner.is_valid()) { // Ahh this is a share. |
2044 | p_with_texture = src_texture->owner; |
2045 | src_texture = texture_owner.get_or_null(src_texture->owner); |
2046 | ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug. |
2047 | } |
2048 | |
2049 | // Create view. |
2050 | |
2051 | Texture texture = *src_texture; |
2052 | |
2053 | VkImageViewCreateInfo image_view_create_info; |
2054 | image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
2055 | image_view_create_info.pNext = nullptr; |
2056 | image_view_create_info.flags = 0; |
2057 | image_view_create_info.image = texture.image; |
2058 | |
2059 | static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { |
2060 | VK_IMAGE_VIEW_TYPE_1D, |
2061 | VK_IMAGE_VIEW_TYPE_2D, |
2062 | VK_IMAGE_VIEW_TYPE_3D, |
2063 | VK_IMAGE_VIEW_TYPE_CUBE, |
2064 | VK_IMAGE_VIEW_TYPE_1D_ARRAY, |
2065 | VK_IMAGE_VIEW_TYPE_2D_ARRAY, |
2066 | VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, |
2067 | }; |
2068 | |
2069 | image_view_create_info.viewType = view_types[texture.type]; |
2070 | if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { |
2071 | image_view_create_info.format = vulkan_formats[texture.format]; |
2072 | } else { |
2073 | ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); |
2074 | |
2075 | ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(), |
2076 | "Format override is not in the list of allowed shareable formats for original texture." ); |
2077 | image_view_create_info.format = vulkan_formats[p_view.format_override]; |
2078 | } |
2079 | |
2080 | static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { |
2081 | VK_COMPONENT_SWIZZLE_IDENTITY, |
2082 | VK_COMPONENT_SWIZZLE_ZERO, |
2083 | VK_COMPONENT_SWIZZLE_ONE, |
2084 | VK_COMPONENT_SWIZZLE_R, |
2085 | VK_COMPONENT_SWIZZLE_G, |
2086 | VK_COMPONENT_SWIZZLE_B, |
2087 | VK_COMPONENT_SWIZZLE_A |
2088 | }; |
2089 | |
2090 | image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; |
2091 | image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; |
2092 | image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; |
2093 | image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; |
2094 | |
2095 | image_view_create_info.subresourceRange.baseMipLevel = 0; |
2096 | image_view_create_info.subresourceRange.levelCount = texture.mipmaps; |
2097 | image_view_create_info.subresourceRange.layerCount = texture.layers; |
2098 | image_view_create_info.subresourceRange.baseArrayLayer = 0; |
2099 | |
2100 | if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
2101 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
2102 | } else { |
2103 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
2104 | } |
2105 | |
2106 | VkImageViewUsageCreateInfo usage_info; |
2107 | if (context->is_device_extension_enabled(VK_KHR_MAINTENANCE_2_EXTENSION_NAME)) { |
2108 | // May need to make VK_KHR_maintenance2 manditory and thus has Vulkan 1.1 be our minimum supported version |
2109 | // if we require setting this information. Vulkan 1.0 may simply not care.. |
2110 | |
2111 | usage_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; |
2112 | usage_info.pNext = nullptr; |
2113 | if (p_view.format_override != DATA_FORMAT_MAX) { |
2114 | // Need to validate usage with vulkan. |
2115 | |
2116 | usage_info.usage = 0; |
2117 | |
2118 | if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { |
2119 | usage_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; |
2120 | } |
2121 | |
2122 | if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) { |
2123 | if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_STORAGE_BIT)) { |
2124 | usage_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT; |
2125 | } |
2126 | } |
2127 | |
2128 | if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
2129 | if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { |
2130 | usage_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
2131 | } |
2132 | } |
2133 | |
2134 | if (texture.usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) { |
2135 | usage_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; |
2136 | } |
2137 | |
2138 | if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
2139 | usage_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
2140 | } |
2141 | |
2142 | if (texture.usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT) { |
2143 | usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
2144 | } |
2145 | if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT) { |
2146 | usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
2147 | } |
2148 | |
2149 | if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT) { |
2150 | usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
2151 | } |
2152 | |
2153 | image_view_create_info.pNext = &usage_info; |
2154 | } |
2155 | } |
2156 | |
2157 | VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view); |
2158 | ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateImageView failed with error " + itos(err) + "." ); |
2159 | |
2160 | texture.owner = p_with_texture; |
2161 | RID id = texture_owner.make_rid(texture); |
2162 | #ifdef DEV_ENABLED |
2163 | set_resource_name(id, "RID:" + itos(id.get_id())); |
2164 | #endif |
2165 | _add_dependency(id, p_with_texture); |
2166 | |
2167 | return id; |
2168 | } |
2169 | |
2170 | RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) { |
2171 | _THREAD_SAFE_METHOD_ |
2172 | // This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this). |
2173 | VkImage image = (VkImage)p_image; |
2174 | |
2175 | Texture texture; |
2176 | texture.image = image; |
2177 | // If we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image? |
2178 | // Also leave texture.allocation_info alone. |
2179 | // We'll set texture.view later on. |
2180 | texture.type = p_type; |
2181 | texture.format = p_format; |
2182 | texture.samples = p_samples; |
2183 | texture.width = p_width; |
2184 | texture.height = p_height; |
2185 | texture.depth = p_depth; |
2186 | texture.layers = p_layers; |
2187 | texture.mipmaps = 1; |
2188 | texture.usage_flags = p_flags; |
2189 | texture.base_mipmap = 0; |
2190 | texture.base_layer = 0; |
2191 | texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); |
2192 | texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); |
2193 | |
2194 | // Set base layout based on usage priority. |
2195 | |
2196 | if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { |
2197 | // First priority, readable. |
2198 | texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
2199 | |
2200 | } else if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) { |
2201 | // Second priority, storage. |
2202 | |
2203 | texture.layout = VK_IMAGE_LAYOUT_GENERAL; |
2204 | |
2205 | } else if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
2206 | // Third priority, color or depth. |
2207 | |
2208 | texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
2209 | |
2210 | } else if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
2211 | texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
2212 | |
2213 | } else { |
2214 | texture.layout = VK_IMAGE_LAYOUT_GENERAL; |
2215 | } |
2216 | |
2217 | if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
2218 | texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; |
2219 | texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; |
2220 | |
2221 | // if (format_has_stencil(p_format.format)) { |
2222 | // texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; |
2223 | // } |
2224 | } else { |
2225 | texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; |
2226 | texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; |
2227 | } |
2228 | |
2229 | // Create a view for us to use. |
2230 | |
2231 | VkImageViewCreateInfo image_view_create_info; |
2232 | image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
2233 | image_view_create_info.pNext = nullptr; |
2234 | image_view_create_info.flags = 0; |
2235 | image_view_create_info.image = texture.image; |
2236 | |
2237 | static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { |
2238 | VK_IMAGE_VIEW_TYPE_1D, |
2239 | VK_IMAGE_VIEW_TYPE_2D, |
2240 | VK_IMAGE_VIEW_TYPE_3D, |
2241 | VK_IMAGE_VIEW_TYPE_CUBE, |
2242 | VK_IMAGE_VIEW_TYPE_1D_ARRAY, |
2243 | VK_IMAGE_VIEW_TYPE_2D_ARRAY, |
2244 | VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, |
2245 | }; |
2246 | |
2247 | image_view_create_info.viewType = view_types[texture.type]; |
2248 | image_view_create_info.format = vulkan_formats[texture.format]; |
2249 | |
2250 | static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { |
2251 | VK_COMPONENT_SWIZZLE_IDENTITY, |
2252 | VK_COMPONENT_SWIZZLE_ZERO, |
2253 | VK_COMPONENT_SWIZZLE_ONE, |
2254 | VK_COMPONENT_SWIZZLE_R, |
2255 | VK_COMPONENT_SWIZZLE_G, |
2256 | VK_COMPONENT_SWIZZLE_B, |
2257 | VK_COMPONENT_SWIZZLE_A |
2258 | }; |
2259 | |
2260 | // Hardcode for now, maybe make this settable from outside. |
2261 | image_view_create_info.components.r = component_swizzles[TEXTURE_SWIZZLE_R]; |
2262 | image_view_create_info.components.g = component_swizzles[TEXTURE_SWIZZLE_G]; |
2263 | image_view_create_info.components.b = component_swizzles[TEXTURE_SWIZZLE_B]; |
2264 | image_view_create_info.components.a = component_swizzles[TEXTURE_SWIZZLE_A]; |
2265 | |
2266 | image_view_create_info.subresourceRange.baseMipLevel = 0; |
2267 | image_view_create_info.subresourceRange.levelCount = texture.mipmaps; |
2268 | image_view_create_info.subresourceRange.baseArrayLayer = 0; |
2269 | image_view_create_info.subresourceRange.layerCount = texture.layers; |
2270 | if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
2271 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
2272 | } else { |
2273 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
2274 | } |
2275 | |
2276 | VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view); |
2277 | |
2278 | if (err) { |
2279 | // vmaDestroyImage(allocator, texture.image, texture.allocation); |
2280 | ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + "." ); |
2281 | } |
2282 | |
2283 | // Barrier to set layout. |
2284 | { |
2285 | VkImageMemoryBarrier image_memory_barrier; |
2286 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2287 | image_memory_barrier.pNext = nullptr; |
2288 | image_memory_barrier.srcAccessMask = 0; |
2289 | image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
2290 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
2291 | image_memory_barrier.newLayout = texture.layout; |
2292 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2293 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2294 | image_memory_barrier.image = texture.image; |
2295 | image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask; |
2296 | image_memory_barrier.subresourceRange.baseMipLevel = 0; |
2297 | image_memory_barrier.subresourceRange.levelCount = texture.mipmaps; |
2298 | image_memory_barrier.subresourceRange.baseArrayLayer = 0; |
2299 | image_memory_barrier.subresourceRange.layerCount = texture.layers; |
2300 | |
2301 | vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
2302 | } |
2303 | |
2304 | RID id = texture_owner.make_rid(texture); |
2305 | #ifdef DEV_ENABLED |
2306 | set_resource_name(id, "RID:" + itos(id.get_id())); |
2307 | #endif |
2308 | |
2309 | return id; |
2310 | } |
2311 | |
2312 | RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type, uint32_t p_layers) { |
2313 | _THREAD_SAFE_METHOD_ |
2314 | |
2315 | Texture *src_texture = texture_owner.get_or_null(p_with_texture); |
2316 | ERR_FAIL_NULL_V(src_texture, RID()); |
2317 | |
2318 | if (src_texture->owner.is_valid()) { // Ahh this is a share. |
2319 | p_with_texture = src_texture->owner; |
2320 | src_texture = texture_owner.get_or_null(src_texture->owner); |
2321 | ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug. |
2322 | } |
2323 | |
2324 | ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(), |
2325 | "Can only create a cubemap slice from a cubemap or cubemap array mipmap" ); |
2326 | |
2327 | ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(), |
2328 | "Can only create a 3D slice from a 3D texture" ); |
2329 | |
2330 | ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(), |
2331 | "Can only create an array slice from a 2D array mipmap" ); |
2332 | |
2333 | // Create view. |
2334 | |
2335 | ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); |
2336 | ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID()); |
2337 | ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID()); |
2338 | |
2339 | int slice_layers = 1; |
2340 | if (p_layers != 0) { |
2341 | ERR_FAIL_COND_V_MSG(p_layers > 1 && p_slice_type != TEXTURE_SLICE_2D_ARRAY, RID(), "layer slicing only supported for 2D arrays" ); |
2342 | ERR_FAIL_COND_V_MSG(p_layer + p_layers > src_texture->layers, RID(), "layer slice is out of bounds" ); |
2343 | slice_layers = p_layers; |
2344 | } else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) { |
2345 | ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice" ); |
2346 | slice_layers = src_texture->layers; |
2347 | } else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { |
2348 | slice_layers = 6; |
2349 | } |
2350 | |
2351 | Texture texture = *src_texture; |
2352 | get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); |
2353 | texture.mipmaps = p_mipmaps; |
2354 | texture.layers = slice_layers; |
2355 | texture.base_mipmap = p_mipmap; |
2356 | texture.base_layer = p_layer; |
2357 | |
2358 | VkImageViewCreateInfo image_view_create_info; |
2359 | image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
2360 | image_view_create_info.pNext = nullptr; |
2361 | image_view_create_info.flags = 0; |
2362 | image_view_create_info.image = texture.image; |
2363 | |
2364 | static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { |
2365 | VK_IMAGE_VIEW_TYPE_1D, |
2366 | VK_IMAGE_VIEW_TYPE_2D, |
2367 | VK_IMAGE_VIEW_TYPE_2D, |
2368 | VK_IMAGE_VIEW_TYPE_2D, |
2369 | VK_IMAGE_VIEW_TYPE_1D, |
2370 | VK_IMAGE_VIEW_TYPE_2D, |
2371 | VK_IMAGE_VIEW_TYPE_2D, |
2372 | }; |
2373 | |
2374 | image_view_create_info.viewType = view_types[texture.type]; |
2375 | |
2376 | if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { |
2377 | image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE; |
2378 | } else if (p_slice_type == TEXTURE_SLICE_3D) { |
2379 | image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D; |
2380 | } else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) { |
2381 | image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; |
2382 | } |
2383 | |
2384 | if (p_slice_type == TEXTURE_SLICE_2D) { |
2385 | texture.type = TEXTURE_TYPE_2D; |
2386 | } else if (p_slice_type == TEXTURE_SLICE_3D) { |
2387 | texture.type = TEXTURE_TYPE_3D; |
2388 | } |
2389 | |
2390 | if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { |
2391 | image_view_create_info.format = vulkan_formats[texture.format]; |
2392 | } else { |
2393 | ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); |
2394 | |
2395 | ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(), |
2396 | "Format override is not in the list of allowed shareable formats for original texture." ); |
2397 | image_view_create_info.format = vulkan_formats[p_view.format_override]; |
2398 | } |
2399 | |
2400 | static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { |
2401 | VK_COMPONENT_SWIZZLE_IDENTITY, |
2402 | VK_COMPONENT_SWIZZLE_ZERO, |
2403 | VK_COMPONENT_SWIZZLE_ONE, |
2404 | VK_COMPONENT_SWIZZLE_R, |
2405 | VK_COMPONENT_SWIZZLE_G, |
2406 | VK_COMPONENT_SWIZZLE_B, |
2407 | VK_COMPONENT_SWIZZLE_A |
2408 | }; |
2409 | |
2410 | image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; |
2411 | image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; |
2412 | image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; |
2413 | image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; |
2414 | |
2415 | if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { |
2416 | ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(), |
2417 | "Specified layer is invalid for cubemap" ); |
2418 | ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(), |
2419 | "Specified layer must be a multiple of 6." ); |
2420 | } |
2421 | image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; |
2422 | image_view_create_info.subresourceRange.levelCount = p_mipmaps; |
2423 | image_view_create_info.subresourceRange.layerCount = slice_layers; |
2424 | image_view_create_info.subresourceRange.baseArrayLayer = p_layer; |
2425 | |
2426 | if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
2427 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
2428 | } else { |
2429 | image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
2430 | } |
2431 | |
2432 | VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view); |
2433 | ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateImageView failed with error " + itos(err) + "." ); |
2434 | |
2435 | texture.owner = p_with_texture; |
2436 | RID id = texture_owner.make_rid(texture); |
2437 | #ifdef DEV_ENABLED |
2438 | set_resource_name(id, "RID:" + itos(id.get_id())); |
2439 | #endif |
2440 | _add_dependency(id, p_with_texture); |
2441 | |
2442 | return id; |
2443 | } |
2444 | |
2445 | Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { |
2446 | return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false); |
2447 | } |
2448 | |
2449 | static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_unit_size) { |
2450 | uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size; |
2451 | uint32_t dst_offset = 0; |
2452 | for (uint32_t y = p_src_h; y > 0; y--) { |
2453 | uint8_t const *__restrict src = p_src + src_offset; |
2454 | uint8_t *__restrict dst = p_dst + dst_offset; |
2455 | for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) { |
2456 | *dst = *src; |
2457 | src++; |
2458 | dst++; |
2459 | } |
2460 | src_offset += p_src_full_w * p_unit_size; |
2461 | dst_offset += p_src_w * p_unit_size; |
2462 | } |
2463 | } |
2464 | |
2465 | Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue) { |
2466 | _THREAD_SAFE_METHOD_ |
2467 | |
2468 | ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER, |
2469 | "Updating textures is forbidden during creation of a draw or compute list" ); |
2470 | |
2471 | Texture *texture = texture_owner.get_or_null(p_texture); |
2472 | ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER); |
2473 | |
2474 | if (texture->owner != RID()) { |
2475 | p_texture = texture->owner; |
2476 | texture = texture_owner.get_or_null(texture->owner); |
2477 | ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug. |
2478 | } |
2479 | |
2480 | ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE, |
2481 | "Texture can't be updated while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to update this texture." ); |
2482 | |
2483 | ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, |
2484 | "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable." ); |
2485 | |
2486 | uint32_t layer_count = texture->layers; |
2487 | if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) { |
2488 | layer_count *= 6; |
2489 | } |
2490 | ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER); |
2491 | |
2492 | uint32_t width, height; |
2493 | uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height); |
2494 | uint32_t required_size = image_size; |
2495 | uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format); |
2496 | if (required_align == 1) { |
2497 | required_align = get_image_format_pixel_size(texture->format); |
2498 | } |
2499 | if ((required_align % 4) != 0) { // Alignment rules are really strange. |
2500 | required_align *= 4; |
2501 | } |
2502 | |
2503 | ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER, |
2504 | "Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ")." ); |
2505 | |
2506 | uint32_t region_size = texture_upload_region_size_px; |
2507 | |
2508 | const uint8_t *r = p_data.ptr(); |
2509 | |
2510 | VkCommandBuffer command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer; |
2511 | |
2512 | // Barrier to transfer. |
2513 | { |
2514 | VkImageMemoryBarrier image_memory_barrier; |
2515 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2516 | image_memory_barrier.pNext = nullptr; |
2517 | image_memory_barrier.srcAccessMask = 0; |
2518 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
2519 | image_memory_barrier.oldLayout = texture->layout; |
2520 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
2521 | |
2522 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2523 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2524 | image_memory_barrier.image = texture->image; |
2525 | image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask; |
2526 | image_memory_barrier.subresourceRange.baseMipLevel = 0; |
2527 | image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; |
2528 | image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; |
2529 | image_memory_barrier.subresourceRange.layerCount = 1; |
2530 | |
2531 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
2532 | } |
2533 | |
2534 | uint32_t mipmap_offset = 0; |
2535 | |
2536 | uint32_t logic_width = texture->width; |
2537 | uint32_t logic_height = texture->height; |
2538 | |
2539 | for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) { |
2540 | uint32_t depth; |
2541 | uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth); |
2542 | |
2543 | const uint8_t *read_ptr_mipmap = r + mipmap_offset; |
2544 | image_size = image_total - mipmap_offset; |
2545 | |
2546 | for (uint32_t z = 0; z < depth; z++) { // For 3D textures, depth may be > 0. |
2547 | |
2548 | const uint8_t *read_ptr = read_ptr_mipmap + (image_size / depth) * z; |
2549 | |
2550 | for (uint32_t y = 0; y < height; y += region_size) { |
2551 | for (uint32_t x = 0; x < width; x += region_size) { |
2552 | uint32_t region_w = MIN(region_size, width - x); |
2553 | uint32_t region_h = MIN(region_size, height - y); |
2554 | |
2555 | uint32_t region_logic_w = MIN(region_size, logic_width - x); |
2556 | uint32_t region_logic_h = MIN(region_size, logic_height - y); |
2557 | |
2558 | uint32_t pixel_size = get_image_format_pixel_size(texture->format); |
2559 | uint32_t to_allocate = region_w * region_h * pixel_size; |
2560 | to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); |
2561 | |
2562 | uint32_t alloc_offset, alloc_size; |
2563 | Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false); |
2564 | ERR_FAIL_COND_V(err, ERR_CANT_CREATE); |
2565 | |
2566 | uint8_t *write_ptr; |
2567 | |
2568 | { // Map. |
2569 | void *data_ptr = nullptr; |
2570 | VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); |
2571 | ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + "." ); |
2572 | write_ptr = (uint8_t *)data_ptr; |
2573 | write_ptr += alloc_offset; |
2574 | } |
2575 | |
2576 | uint32_t block_w, block_h; |
2577 | get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); |
2578 | |
2579 | ERR_FAIL_COND_V(region_w % block_w, ERR_BUG); |
2580 | ERR_FAIL_COND_V(region_h % block_h, ERR_BUG); |
2581 | |
2582 | if (block_w != 1 || block_h != 1) { |
2583 | // Compressed image (blocks). |
2584 | // Must copy a block region. |
2585 | |
2586 | uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); |
2587 | // Re-create current variables in blocky format. |
2588 | uint32_t xb = x / block_w; |
2589 | uint32_t yb = y / block_h; |
2590 | uint32_t wb = width / block_w; |
2591 | //uint32_t hb = height / block_h; |
2592 | uint32_t region_wb = region_w / block_w; |
2593 | uint32_t region_hb = region_h / block_h; |
2594 | _copy_region(read_ptr, write_ptr, xb, yb, region_wb, region_hb, wb, block_size); |
2595 | } else { |
2596 | // Regular image (pixels). |
2597 | // Must copy a pixel region. |
2598 | _copy_region(read_ptr, write_ptr, x, y, region_w, region_h, width, pixel_size); |
2599 | } |
2600 | |
2601 | { // Unmap. |
2602 | vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); |
2603 | } |
2604 | |
2605 | VkBufferImageCopy buffer_image_copy; |
2606 | buffer_image_copy.bufferOffset = alloc_offset; |
2607 | buffer_image_copy.bufferRowLength = 0; // Tightly packed. |
2608 | buffer_image_copy.bufferImageHeight = 0; // Tightly packed. |
2609 | |
2610 | buffer_image_copy.imageSubresource.aspectMask = texture->read_aspect_mask; |
2611 | buffer_image_copy.imageSubresource.mipLevel = mm_i; |
2612 | buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; |
2613 | buffer_image_copy.imageSubresource.layerCount = 1; |
2614 | |
2615 | buffer_image_copy.imageOffset.x = x; |
2616 | buffer_image_copy.imageOffset.y = y; |
2617 | buffer_image_copy.imageOffset.z = z; |
2618 | |
2619 | buffer_image_copy.imageExtent.width = region_logic_w; |
2620 | buffer_image_copy.imageExtent.height = region_logic_h; |
2621 | buffer_image_copy.imageExtent.depth = 1; |
2622 | |
2623 | vkCmdCopyBufferToImage(command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy); |
2624 | |
2625 | staging_buffer_blocks.write[staging_buffer_current].fill_amount = alloc_offset + alloc_size; |
2626 | } |
2627 | } |
2628 | } |
2629 | |
2630 | mipmap_offset = image_total; |
2631 | logic_width = MAX(1u, logic_width >> 1); |
2632 | logic_height = MAX(1u, logic_height >> 1); |
2633 | } |
2634 | |
2635 | // Barrier to restore layout. |
2636 | { |
2637 | uint32_t barrier_flags = 0; |
2638 | uint32_t access_flags = 0; |
2639 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
2640 | barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
2641 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
2642 | } |
2643 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
2644 | barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
2645 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
2646 | } |
2647 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
2648 | barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
2649 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
2650 | } |
2651 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
2652 | barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
2653 | access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; |
2654 | } |
2655 | |
2656 | if (barrier_flags == 0) { |
2657 | barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
2658 | } |
2659 | |
2660 | VkImageMemoryBarrier image_memory_barrier; |
2661 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2662 | image_memory_barrier.pNext = nullptr; |
2663 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
2664 | image_memory_barrier.dstAccessMask = access_flags; |
2665 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
2666 | image_memory_barrier.newLayout = texture->layout; |
2667 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2668 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2669 | image_memory_barrier.image = texture->image; |
2670 | image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask; |
2671 | image_memory_barrier.subresourceRange.baseMipLevel = 0; |
2672 | image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; |
2673 | image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; |
2674 | image_memory_barrier.subresourceRange.layerCount = 1; |
2675 | |
2676 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
2677 | } |
2678 | |
2679 | if (texture->used_in_frame != frames_drawn) { |
2680 | texture->used_in_raster = false; |
2681 | texture->used_in_compute = false; |
2682 | texture->used_in_frame = frames_drawn; |
2683 | } |
2684 | texture->used_in_transfer = true; |
2685 | |
2686 | return OK; |
2687 | } |
2688 | |
2689 | Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d) { |
2690 | uint32_t width, height, depth; |
2691 | uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth); |
2692 | |
2693 | Vector<uint8_t> image_data; |
2694 | image_data.resize(image_size); |
2695 | |
2696 | void *img_mem; |
2697 | vmaMapMemory(allocator, p_allocation, &img_mem); |
2698 | |
2699 | uint32_t blockw, blockh; |
2700 | get_compressed_image_format_block_dimensions(tex->format, blockw, blockh); |
2701 | uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format); |
2702 | uint32_t pixel_size = get_image_format_pixel_size(tex->format); |
2703 | |
2704 | { |
2705 | uint8_t *w = image_data.ptrw(); |
2706 | |
2707 | uint32_t mipmap_offset = 0; |
2708 | for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) { |
2709 | uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, mm_i + 1, &width, &height, &depth); |
2710 | |
2711 | uint8_t *write_ptr_mipmap = w + mipmap_offset; |
2712 | image_size = image_total - mipmap_offset; |
2713 | |
2714 | VkImageSubresource image_sub_resorce; |
2715 | image_sub_resorce.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
2716 | image_sub_resorce.arrayLayer = p_layer; |
2717 | image_sub_resorce.mipLevel = mm_i; |
2718 | VkSubresourceLayout layout; |
2719 | vkGetImageSubresourceLayout(device, p_image, &image_sub_resorce, &layout); |
2720 | |
2721 | for (uint32_t z = 0; z < depth; z++) { |
2722 | uint8_t *write_ptr = write_ptr_mipmap + z * image_size / depth; |
2723 | const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch; |
2724 | |
2725 | if (block_size > 1) { |
2726 | // Compressed. |
2727 | uint32_t line_width = (block_size * (width / blockw)); |
2728 | for (uint32_t y = 0; y < height / blockh; y++) { |
2729 | const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch; |
2730 | uint8_t *wptr = write_ptr + y * line_width; |
2731 | |
2732 | memcpy(wptr, rptr, line_width); |
2733 | } |
2734 | |
2735 | } else { |
2736 | // Uncompressed. |
2737 | for (uint32_t y = 0; y < height; y++) { |
2738 | const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch; |
2739 | uint8_t *wptr = write_ptr + y * pixel_size * width; |
2740 | memcpy(wptr, rptr, (uint64_t)pixel_size * width); |
2741 | } |
2742 | } |
2743 | } |
2744 | |
2745 | mipmap_offset = image_total; |
2746 | } |
2747 | } |
2748 | |
2749 | vmaUnmapMemory(allocator, p_allocation); |
2750 | |
2751 | return image_data; |
2752 | } |
2753 | |
2754 | Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) { |
2755 | _THREAD_SAFE_METHOD_ |
2756 | |
2757 | Texture *tex = texture_owner.get_or_null(p_texture); |
2758 | ERR_FAIL_NULL_V(tex, Vector<uint8_t>()); |
2759 | |
2760 | ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(), |
2761 | "Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture." ); |
2762 | ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(), |
2763 | "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved." ); |
2764 | |
2765 | uint32_t layer_count = tex->layers; |
2766 | if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) { |
2767 | layer_count *= 6; |
2768 | } |
2769 | ERR_FAIL_COND_V(p_layer >= layer_count, Vector<uint8_t>()); |
2770 | |
2771 | if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) { |
2772 | // Does not need anything fancy, map and read. |
2773 | return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer); |
2774 | } else { |
2775 | // Compute total image size. |
2776 | uint32_t width, height, depth; |
2777 | uint32_t buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth); |
2778 | |
2779 | // Allocate buffer. |
2780 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; // Makes more sense to retrieve. |
2781 | Buffer tmp_buffer; |
2782 | _buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT); |
2783 | |
2784 | { // Source image barrier. |
2785 | VkImageMemoryBarrier image_memory_barrier; |
2786 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2787 | image_memory_barrier.pNext = nullptr; |
2788 | image_memory_barrier.srcAccessMask = 0; |
2789 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
2790 | image_memory_barrier.oldLayout = tex->layout; |
2791 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
2792 | |
2793 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2794 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2795 | image_memory_barrier.image = tex->image; |
2796 | image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask; |
2797 | image_memory_barrier.subresourceRange.baseMipLevel = 0; |
2798 | image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; |
2799 | image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; |
2800 | image_memory_barrier.subresourceRange.layerCount = 1; |
2801 | |
2802 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
2803 | } |
2804 | |
2805 | uint32_t computed_w = tex->width; |
2806 | uint32_t computed_h = tex->height; |
2807 | uint32_t computed_d = tex->depth; |
2808 | |
2809 | uint32_t prev_size = 0; |
2810 | uint32_t offset = 0; |
2811 | for (uint32_t i = 0; i < tex->mipmaps; i++) { |
2812 | VkBufferImageCopy buffer_image_copy; |
2813 | |
2814 | uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1); |
2815 | uint32_t size = image_size - prev_size; |
2816 | prev_size = image_size; |
2817 | |
2818 | buffer_image_copy.bufferOffset = offset; |
2819 | buffer_image_copy.bufferImageHeight = 0; |
2820 | buffer_image_copy.bufferRowLength = 0; |
2821 | buffer_image_copy.imageSubresource.aspectMask = tex->read_aspect_mask; |
2822 | buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; |
2823 | buffer_image_copy.imageSubresource.layerCount = 1; |
2824 | buffer_image_copy.imageSubresource.mipLevel = i; |
2825 | buffer_image_copy.imageOffset.x = 0; |
2826 | buffer_image_copy.imageOffset.y = 0; |
2827 | buffer_image_copy.imageOffset.z = 0; |
2828 | buffer_image_copy.imageExtent.width = computed_w; |
2829 | buffer_image_copy.imageExtent.height = computed_h; |
2830 | buffer_image_copy.imageExtent.depth = computed_d; |
2831 | |
2832 | vkCmdCopyImageToBuffer(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer.buffer, 1, &buffer_image_copy); |
2833 | |
2834 | computed_w = MAX(1u, computed_w >> 1); |
2835 | computed_h = MAX(1u, computed_h >> 1); |
2836 | computed_d = MAX(1u, computed_d >> 1); |
2837 | offset += size; |
2838 | } |
2839 | |
2840 | { // Restore src. |
2841 | VkImageMemoryBarrier image_memory_barrier; |
2842 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2843 | image_memory_barrier.pNext = nullptr; |
2844 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
2845 | image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
2846 | if (tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { |
2847 | image_memory_barrier.dstAccessMask |= VK_ACCESS_SHADER_WRITE_BIT; |
2848 | } |
2849 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
2850 | image_memory_barrier.newLayout = tex->layout; |
2851 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2852 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2853 | image_memory_barrier.image = tex->image; |
2854 | image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask; |
2855 | image_memory_barrier.subresourceRange.baseMipLevel = 0; |
2856 | image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; |
2857 | image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; |
2858 | image_memory_barrier.subresourceRange.layerCount = 1; |
2859 | |
2860 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
2861 | } |
2862 | |
2863 | _flush(true); |
2864 | |
2865 | void *buffer_mem; |
2866 | VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); |
2867 | ERR_FAIL_COND_V_MSG(vkerr, Vector<uint8_t>(), "vmaMapMemory failed with error " + itos(vkerr) + "." ); |
2868 | |
2869 | Vector<uint8_t> buffer_data; |
2870 | { |
2871 | buffer_data.resize(buffer_size); |
2872 | uint8_t *w = buffer_data.ptrw(); |
2873 | memcpy(w, buffer_mem, buffer_size); |
2874 | } |
2875 | |
2876 | vmaUnmapMemory(allocator, tmp_buffer.allocation); |
2877 | |
2878 | _buffer_free(&tmp_buffer); |
2879 | |
2880 | return buffer_data; |
2881 | } |
2882 | } |
2883 | |
2884 | bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { |
2885 | _THREAD_SAFE_METHOD_ |
2886 | |
2887 | Texture *tex = texture_owner.get_or_null(p_texture); |
2888 | ERR_FAIL_NULL_V(tex, false); |
2889 | return tex->owner.is_valid(); |
2890 | } |
2891 | |
2892 | bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { |
2893 | return texture_owner.owns(p_texture); |
2894 | } |
2895 | |
2896 | RD::TextureFormat RenderingDeviceVulkan::texture_get_format(RID p_texture) { |
2897 | _THREAD_SAFE_METHOD_ |
2898 | |
2899 | Texture *tex = texture_owner.get_or_null(p_texture); |
2900 | ERR_FAIL_NULL_V(tex, TextureFormat()); |
2901 | |
2902 | TextureFormat tf; |
2903 | |
2904 | tf.format = tex->format; |
2905 | tf.width = tex->width; |
2906 | tf.height = tex->height; |
2907 | tf.depth = tex->depth; |
2908 | tf.array_layers = tex->layers; |
2909 | tf.mipmaps = tex->mipmaps; |
2910 | tf.texture_type = tex->type; |
2911 | tf.samples = tex->samples; |
2912 | tf.usage_bits = tex->usage_flags; |
2913 | tf.shareable_formats = tex->allowed_shared_formats; |
2914 | tf.is_resolve_buffer = tex->is_resolve_buffer; |
2915 | |
2916 | return tf; |
2917 | } |
2918 | |
2919 | Size2i RenderingDeviceVulkan::texture_size(RID p_texture) { |
2920 | _THREAD_SAFE_METHOD_ |
2921 | |
2922 | Texture *tex = texture_owner.get_or_null(p_texture); |
2923 | ERR_FAIL_NULL_V(tex, Size2i()); |
2924 | return Size2i(tex->width, tex->height); |
2925 | } |
2926 | |
2927 | uint64_t RenderingDeviceVulkan::texture_get_native_handle(RID p_texture) { |
2928 | _THREAD_SAFE_METHOD_ |
2929 | |
2930 | Texture *tex = texture_owner.get_or_null(p_texture); |
2931 | ERR_FAIL_NULL_V(tex, 0); |
2932 | |
2933 | return (uint64_t)tex->image; |
2934 | } |
2935 | |
2936 | Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) { |
2937 | _THREAD_SAFE_METHOD_ |
2938 | |
2939 | Texture *src_tex = texture_owner.get_or_null(p_from_texture); |
2940 | ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER); |
2941 | |
2942 | ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER, |
2943 | "Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture." ); |
2944 | ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, |
2945 | "Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved." ); |
2946 | |
2947 | uint32_t src_layer_count = src_tex->layers; |
2948 | uint32_t src_width, src_height, src_depth; |
2949 | get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth); |
2950 | if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { |
2951 | src_layer_count *= 6; |
2952 | } |
2953 | |
2954 | ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER); |
2955 | ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER); |
2956 | ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER); |
2957 | ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER); |
2958 | ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER); |
2959 | |
2960 | Texture *dst_tex = texture_owner.get_or_null(p_to_texture); |
2961 | ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER); |
2962 | |
2963 | ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER, |
2964 | "Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture." ); |
2965 | ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, |
2966 | "Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved." ); |
2967 | |
2968 | uint32_t dst_layer_count = dst_tex->layers; |
2969 | uint32_t dst_width, dst_height, dst_depth; |
2970 | get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth); |
2971 | if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { |
2972 | dst_layer_count *= 6; |
2973 | } |
2974 | |
2975 | ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER); |
2976 | ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER); |
2977 | ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER); |
2978 | ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER); |
2979 | ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER); |
2980 | |
2981 | ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, |
2982 | "Source and destination texture must be of the same type (color or depth)." ); |
2983 | |
2984 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; |
2985 | |
2986 | { |
2987 | // PRE Copy the image. |
2988 | |
2989 | { // Source. |
2990 | VkImageMemoryBarrier image_memory_barrier; |
2991 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
2992 | image_memory_barrier.pNext = nullptr; |
2993 | image_memory_barrier.srcAccessMask = 0; |
2994 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
2995 | image_memory_barrier.oldLayout = src_tex->layout; |
2996 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
2997 | |
2998 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
2999 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3000 | image_memory_barrier.image = src_tex->image; |
3001 | image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; |
3002 | image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; |
3003 | image_memory_barrier.subresourceRange.levelCount = 1; |
3004 | image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; |
3005 | image_memory_barrier.subresourceRange.layerCount = 1; |
3006 | |
3007 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3008 | } |
3009 | { // Dest. |
3010 | VkImageMemoryBarrier image_memory_barrier; |
3011 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3012 | image_memory_barrier.pNext = nullptr; |
3013 | image_memory_barrier.srcAccessMask = 0; |
3014 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
3015 | image_memory_barrier.oldLayout = dst_tex->layout; |
3016 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
3017 | |
3018 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3019 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3020 | image_memory_barrier.image = dst_tex->image; |
3021 | image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask; |
3022 | image_memory_barrier.subresourceRange.baseMipLevel = p_dst_mipmap; |
3023 | image_memory_barrier.subresourceRange.levelCount = 1; |
3024 | image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer; |
3025 | image_memory_barrier.subresourceRange.layerCount = 1; |
3026 | |
3027 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3028 | } |
3029 | |
3030 | // COPY. |
3031 | |
3032 | { |
3033 | VkImageCopy image_copy_region; |
3034 | image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; |
3035 | image_copy_region.srcSubresource.baseArrayLayer = p_src_layer; |
3036 | image_copy_region.srcSubresource.layerCount = 1; |
3037 | image_copy_region.srcSubresource.mipLevel = p_src_mipmap; |
3038 | image_copy_region.srcOffset.x = p_from.x; |
3039 | image_copy_region.srcOffset.y = p_from.y; |
3040 | image_copy_region.srcOffset.z = p_from.z; |
3041 | |
3042 | image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask; |
3043 | image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; |
3044 | image_copy_region.dstSubresource.layerCount = 1; |
3045 | image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; |
3046 | image_copy_region.dstOffset.x = p_to.x; |
3047 | image_copy_region.dstOffset.y = p_to.y; |
3048 | image_copy_region.dstOffset.z = p_to.z; |
3049 | |
3050 | image_copy_region.extent.width = p_size.x; |
3051 | image_copy_region.extent.height = p_size.y; |
3052 | image_copy_region.extent.depth = p_size.z; |
3053 | |
3054 | vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); |
3055 | } |
3056 | |
3057 | // RESTORE LAYOUT for SRC and DST. |
3058 | |
3059 | uint32_t barrier_flags = 0; |
3060 | uint32_t access_flags = 0; |
3061 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
3062 | barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
3063 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3064 | } |
3065 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
3066 | barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
3067 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3068 | } |
3069 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
3070 | barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
3071 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3072 | } |
3073 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
3074 | barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
3075 | access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; |
3076 | } |
3077 | |
3078 | if (barrier_flags == 0) { |
3079 | barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
3080 | } |
3081 | |
3082 | { // Restore src. |
3083 | VkImageMemoryBarrier image_memory_barrier; |
3084 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3085 | image_memory_barrier.pNext = nullptr; |
3086 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
3087 | image_memory_barrier.dstAccessMask = access_flags; |
3088 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
3089 | image_memory_barrier.newLayout = src_tex->layout; |
3090 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3091 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3092 | image_memory_barrier.image = src_tex->image; |
3093 | image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; |
3094 | image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; |
3095 | image_memory_barrier.subresourceRange.levelCount = src_tex->mipmaps; |
3096 | image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; |
3097 | image_memory_barrier.subresourceRange.layerCount = 1; |
3098 | |
3099 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3100 | } |
3101 | |
3102 | { // Make dst readable. |
3103 | |
3104 | VkImageMemoryBarrier image_memory_barrier; |
3105 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3106 | image_memory_barrier.pNext = nullptr; |
3107 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
3108 | image_memory_barrier.dstAccessMask = access_flags; |
3109 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
3110 | image_memory_barrier.newLayout = dst_tex->layout; |
3111 | |
3112 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3113 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3114 | image_memory_barrier.image = dst_tex->image; |
3115 | image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
3116 | image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; |
3117 | image_memory_barrier.subresourceRange.levelCount = 1; |
3118 | image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; |
3119 | image_memory_barrier.subresourceRange.layerCount = 1; |
3120 | |
3121 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3122 | } |
3123 | } |
3124 | |
3125 | if (dst_tex->used_in_frame != frames_drawn) { |
3126 | dst_tex->used_in_raster = false; |
3127 | dst_tex->used_in_compute = false; |
3128 | dst_tex->used_in_frame = frames_drawn; |
3129 | } |
3130 | dst_tex->used_in_transfer = true; |
3131 | |
3132 | return OK; |
3133 | } |
3134 | |
3135 | Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) { |
3136 | _THREAD_SAFE_METHOD_ |
3137 | |
3138 | Texture *src_tex = texture_owner.get_or_null(p_from_texture); |
3139 | ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER); |
3140 | |
3141 | ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER, |
3142 | "Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture." ); |
3143 | ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, |
3144 | "Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved." ); |
3145 | |
3146 | ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)" ); |
3147 | ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled." ); |
3148 | |
3149 | Texture *dst_tex = texture_owner.get_or_null(p_to_texture); |
3150 | ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER); |
3151 | |
3152 | ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER, |
3153 | "Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture." ); |
3154 | ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, |
3155 | "Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved." ); |
3156 | |
3157 | ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture)." ); |
3158 | ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled." ); |
3159 | |
3160 | ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destination textures must be the same format." ); |
3161 | ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destination textures must have the same dimensions." ); |
3162 | |
3163 | ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, |
3164 | "Source and destination texture must be of the same type (color or depth)." ); |
3165 | |
3166 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; |
3167 | |
3168 | { |
3169 | // PRE Copy the image. |
3170 | |
3171 | { // Source. |
3172 | VkImageMemoryBarrier image_memory_barrier; |
3173 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3174 | image_memory_barrier.pNext = nullptr; |
3175 | image_memory_barrier.srcAccessMask = 0; |
3176 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
3177 | image_memory_barrier.oldLayout = src_tex->layout; |
3178 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
3179 | |
3180 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3181 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3182 | image_memory_barrier.image = src_tex->image; |
3183 | image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; |
3184 | image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap; |
3185 | image_memory_barrier.subresourceRange.levelCount = 1; |
3186 | image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer; |
3187 | image_memory_barrier.subresourceRange.layerCount = 1; |
3188 | |
3189 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3190 | } |
3191 | { // Dest. |
3192 | VkImageMemoryBarrier image_memory_barrier; |
3193 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3194 | image_memory_barrier.pNext = nullptr; |
3195 | image_memory_barrier.srcAccessMask = 0; |
3196 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
3197 | image_memory_barrier.oldLayout = dst_tex->layout; |
3198 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
3199 | |
3200 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3201 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3202 | image_memory_barrier.image = dst_tex->image; |
3203 | image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask; |
3204 | image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap; |
3205 | image_memory_barrier.subresourceRange.levelCount = 1; |
3206 | image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer; |
3207 | image_memory_barrier.subresourceRange.layerCount = 1; |
3208 | |
3209 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3210 | } |
3211 | |
3212 | // COPY. |
3213 | |
3214 | { |
3215 | VkImageResolve image_copy_region; |
3216 | image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; |
3217 | image_copy_region.srcSubresource.baseArrayLayer = src_tex->base_layer; |
3218 | image_copy_region.srcSubresource.layerCount = 1; |
3219 | image_copy_region.srcSubresource.mipLevel = src_tex->base_mipmap; |
3220 | image_copy_region.srcOffset.x = 0; |
3221 | image_copy_region.srcOffset.y = 0; |
3222 | image_copy_region.srcOffset.z = 0; |
3223 | |
3224 | image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask; |
3225 | image_copy_region.dstSubresource.baseArrayLayer = dst_tex->base_layer; |
3226 | image_copy_region.dstSubresource.layerCount = 1; |
3227 | image_copy_region.dstSubresource.mipLevel = dst_tex->base_mipmap; |
3228 | image_copy_region.dstOffset.x = 0; |
3229 | image_copy_region.dstOffset.y = 0; |
3230 | image_copy_region.dstOffset.z = 0; |
3231 | |
3232 | image_copy_region.extent.width = src_tex->width; |
3233 | image_copy_region.extent.height = src_tex->height; |
3234 | image_copy_region.extent.depth = src_tex->depth; |
3235 | |
3236 | vkCmdResolveImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); |
3237 | } |
3238 | |
3239 | // RESTORE LAYOUT for SRC and DST. |
3240 | |
3241 | uint32_t barrier_flags = 0; |
3242 | uint32_t access_flags = 0; |
3243 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
3244 | barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
3245 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3246 | } |
3247 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
3248 | barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
3249 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3250 | } |
3251 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
3252 | barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
3253 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3254 | } |
3255 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
3256 | barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
3257 | access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; |
3258 | } |
3259 | |
3260 | if (barrier_flags == 0) { |
3261 | barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
3262 | } |
3263 | |
3264 | { // Restore src. |
3265 | VkImageMemoryBarrier image_memory_barrier; |
3266 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3267 | image_memory_barrier.pNext = nullptr; |
3268 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
3269 | image_memory_barrier.dstAccessMask = access_flags; |
3270 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
3271 | image_memory_barrier.newLayout = src_tex->layout; |
3272 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3273 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3274 | image_memory_barrier.image = src_tex->image; |
3275 | image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; |
3276 | image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap; |
3277 | image_memory_barrier.subresourceRange.levelCount = 1; |
3278 | image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer; |
3279 | image_memory_barrier.subresourceRange.layerCount = 1; |
3280 | |
3281 | vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3282 | } |
3283 | |
3284 | { // Make dst readable. |
3285 | |
3286 | VkImageMemoryBarrier image_memory_barrier; |
3287 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3288 | image_memory_barrier.pNext = nullptr; |
3289 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
3290 | image_memory_barrier.dstAccessMask = access_flags; |
3291 | image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
3292 | image_memory_barrier.newLayout = dst_tex->layout; |
3293 | |
3294 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3295 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3296 | image_memory_barrier.image = dst_tex->image; |
3297 | image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
3298 | image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap; |
3299 | image_memory_barrier.subresourceRange.levelCount = 1; |
3300 | image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer; |
3301 | image_memory_barrier.subresourceRange.layerCount = 1; |
3302 | |
3303 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3304 | } |
3305 | } |
3306 | |
3307 | return OK; |
3308 | } |
3309 | |
3310 | Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) { |
3311 | _THREAD_SAFE_METHOD_ |
3312 | |
3313 | Texture *src_tex = texture_owner.get_or_null(p_texture); |
3314 | ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER); |
3315 | |
3316 | ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER, |
3317 | "Source texture can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to clear this texture." ); |
3318 | |
3319 | ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER); |
3320 | ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER); |
3321 | |
3322 | ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, |
3323 | "Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be cleared." ); |
3324 | |
3325 | uint32_t src_layer_count = src_tex->layers; |
3326 | if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { |
3327 | src_layer_count *= 6; |
3328 | } |
3329 | |
3330 | ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); |
3331 | ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER); |
3332 | |
3333 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; |
3334 | |
3335 | VkImageLayout clear_layout = (src_tex->layout == VK_IMAGE_LAYOUT_GENERAL) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
3336 | |
3337 | // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner.) |
3338 | const VkPipelineStageFlags valid_texture_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
3339 | constexpr VkAccessFlags read_access = VK_ACCESS_SHADER_READ_BIT; |
3340 | constexpr VkAccessFlags read_write_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3341 | const VkAccessFlags valid_texture_access = (src_tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) ? read_write_access : read_access; |
3342 | |
3343 | { // Barrier from previous access with optional layout change (see clear_layout logic above). |
3344 | VkImageMemoryBarrier image_memory_barrier; |
3345 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3346 | image_memory_barrier.pNext = nullptr; |
3347 | image_memory_barrier.srcAccessMask = valid_texture_access; |
3348 | image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
3349 | image_memory_barrier.oldLayout = src_tex->layout; |
3350 | image_memory_barrier.newLayout = clear_layout; |
3351 | |
3352 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3353 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3354 | image_memory_barrier.image = src_tex->image; |
3355 | image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; |
3356 | image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap; |
3357 | image_memory_barrier.subresourceRange.levelCount = p_mipmaps; |
3358 | image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer; |
3359 | image_memory_barrier.subresourceRange.layerCount = p_layers; |
3360 | |
3361 | vkCmdPipelineBarrier(command_buffer, valid_texture_stages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3362 | } |
3363 | |
3364 | VkClearColorValue clear_color; |
3365 | clear_color.float32[0] = p_color.r; |
3366 | clear_color.float32[1] = p_color.g; |
3367 | clear_color.float32[2] = p_color.b; |
3368 | clear_color.float32[3] = p_color.a; |
3369 | |
3370 | VkImageSubresourceRange range; |
3371 | range.aspectMask = src_tex->read_aspect_mask; |
3372 | range.baseArrayLayer = src_tex->base_layer + p_base_layer; |
3373 | range.layerCount = p_layers; |
3374 | range.baseMipLevel = src_tex->base_mipmap + p_base_mipmap; |
3375 | range.levelCount = p_mipmaps; |
3376 | |
3377 | vkCmdClearColorImage(command_buffer, src_tex->image, clear_layout, &clear_color, 1, &range); |
3378 | |
3379 | { // Barrier to post clear accesses (changing back the layout if needed). |
3380 | |
3381 | uint32_t barrier_flags = 0; |
3382 | uint32_t access_flags = 0; |
3383 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
3384 | barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
3385 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3386 | } |
3387 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
3388 | barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
3389 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3390 | } |
3391 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
3392 | barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
3393 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
3394 | } |
3395 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
3396 | barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
3397 | access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; |
3398 | } |
3399 | |
3400 | if (barrier_flags == 0) { |
3401 | barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
3402 | } |
3403 | |
3404 | VkImageMemoryBarrier image_memory_barrier; |
3405 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
3406 | image_memory_barrier.pNext = nullptr; |
3407 | image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
3408 | image_memory_barrier.dstAccessMask = access_flags; |
3409 | image_memory_barrier.oldLayout = clear_layout; |
3410 | image_memory_barrier.newLayout = src_tex->layout; |
3411 | |
3412 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3413 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
3414 | image_memory_barrier.image = src_tex->image; |
3415 | image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; |
3416 | image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap; |
3417 | image_memory_barrier.subresourceRange.levelCount = p_mipmaps; |
3418 | image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer; |
3419 | image_memory_barrier.subresourceRange.layerCount = p_layers; |
3420 | |
3421 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
3422 | } |
3423 | |
3424 | if (src_tex->used_in_frame != frames_drawn) { |
3425 | src_tex->used_in_raster = false; |
3426 | src_tex->used_in_compute = false; |
3427 | src_tex->used_in_frame = frames_drawn; |
3428 | } |
3429 | src_tex->used_in_transfer = true; |
3430 | |
3431 | return OK; |
3432 | } |
3433 | |
3434 | bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const { |
3435 | ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); |
3436 | |
3437 | _THREAD_SAFE_METHOD_ |
3438 | |
3439 | // Validate that this image is supported for the intended use. |
3440 | VkFormatProperties properties; |
3441 | vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties); |
3442 | VkFormatFeatureFlags flags; |
3443 | |
3444 | if (p_usage.has_flag(TEXTURE_USAGE_CPU_READ_BIT)) { |
3445 | flags = properties.linearTilingFeatures; |
3446 | } else { |
3447 | flags = properties.optimalTilingFeatures; |
3448 | } |
3449 | |
3450 | if (p_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT) && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { |
3451 | return false; |
3452 | } |
3453 | |
3454 | if (p_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { |
3455 | return false; |
3456 | } |
3457 | |
3458 | if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
3459 | return false; |
3460 | } |
3461 | |
3462 | if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT) && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { |
3463 | return false; |
3464 | } |
3465 | |
3466 | if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { |
3467 | return false; |
3468 | } |
3469 | |
3470 | // Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported. |
3471 | if (p_usage.has_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && p_format != DATA_FORMAT_R8_UINT) { |
3472 | return false; |
3473 | } |
3474 | |
3475 | return true; |
3476 | } |
3477 | |
3478 | /********************/ |
3479 | /**** ATTACHMENT ****/ |
3480 | /********************/ |
3481 | |
3482 | VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) { |
3483 | // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them. |
3484 | const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
3485 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
3486 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
3487 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
3488 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148. |
3489 | VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; |
3490 | |
3491 | VkPipelineStageFlags reading_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; |
3492 | VkSubpassDependency2KHR dependencies[2] = { |
3493 | { VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0, 0 }, |
3494 | { VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0, 0 } |
3495 | }; |
3496 | VkSubpassDependency2KHR &dependency_from_external = dependencies[0]; |
3497 | VkSubpassDependency2KHR &dependency_to_external = dependencies[1]; |
3498 | LocalVector<int32_t> attachment_last_pass; |
3499 | attachment_last_pass.resize(p_attachments.size()); |
3500 | |
3501 | if (p_view_count > 1) { |
3502 | const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities(); |
3503 | |
3504 | // This only works with multiview! |
3505 | ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported" ); |
3506 | |
3507 | // Make sure we limit this to the number of views we support. |
3508 | ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass" ); |
3509 | } |
3510 | |
3511 | // These are only used if we use multiview but we need to define them in scope. |
3512 | const uint32_t view_mask = (1 << p_view_count) - 1; |
3513 | const uint32_t correlation_mask = (1 << p_view_count) - 1; |
3514 | |
3515 | Vector<VkAttachmentDescription2KHR> attachments; |
3516 | Vector<int> attachment_remap; |
3517 | |
3518 | for (int i = 0; i < p_attachments.size(); i++) { |
3519 | if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) { |
3520 | attachment_remap.push_back(VK_ATTACHMENT_UNUSED); |
3521 | continue; |
3522 | } |
3523 | |
3524 | ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); |
3525 | ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); |
3526 | ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)), |
3527 | VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set." ); |
3528 | |
3529 | VkAttachmentDescription2KHR description = {}; |
3530 | description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; |
3531 | description.pNext = nullptr; |
3532 | description.flags = 0; |
3533 | description.format = vulkan_formats[p_attachments[i].format]; |
3534 | description.samples = _ensure_supported_sample_count(p_attachments[i].samples); |
3535 | |
3536 | bool is_sampled = p_attachments[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT; |
3537 | bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT; |
3538 | bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
3539 | |
3540 | // We can setup a framebuffer where we write to our VRS texture to set it up. |
3541 | // We make the assumption here that if our texture is actually used as our VRS attachment. |
3542 | // It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses. |
3543 | bool is_vrs = p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment; |
3544 | |
3545 | if (is_vrs) { |
3546 | // For VRS we only read, there is no writing to this texture. |
3547 | description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3548 | description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
3549 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3550 | } else { |
3551 | // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write. |
3552 | // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs |
3553 | // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that |
3554 | // stage. |
3555 | |
3556 | switch (is_depth ? p_initial_depth_action : p_initial_action) { |
3557 | case INITIAL_ACTION_CLEAR_REGION: |
3558 | case INITIAL_ACTION_CLEAR: { |
3559 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3560 | description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
3561 | description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
3562 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3563 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3564 | description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
3565 | description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); |
3566 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
3567 | dependency_from_external.srcStageMask |= reading_stages; |
3568 | } else { |
3569 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3570 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3571 | description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3572 | dependency_from_external.srcStageMask |= reading_stages; |
3573 | } |
3574 | } break; |
3575 | case INITIAL_ACTION_KEEP: { |
3576 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3577 | description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3578 | description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
3579 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3580 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3581 | description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3582 | description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); |
3583 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3584 | dependency_from_external.srcStageMask |= reading_stages; |
3585 | } else { |
3586 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3587 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3588 | description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3589 | dependency_from_external.srcStageMask |= reading_stages; |
3590 | } |
3591 | } break; |
3592 | case INITIAL_ACTION_DROP: { |
3593 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3594 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3595 | description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
3596 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3597 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3598 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3599 | description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3600 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3601 | dependency_from_external.srcStageMask |= reading_stages; |
3602 | } else { |
3603 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3604 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3605 | description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3606 | dependency_from_external.srcStageMask |= reading_stages; |
3607 | } |
3608 | } break; |
3609 | case INITIAL_ACTION_CLEAR_REGION_CONTINUE: |
3610 | case INITIAL_ACTION_CONTINUE: { |
3611 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3612 | description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3613 | description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
3614 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3615 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3616 | description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3617 | description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
3618 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
3619 | } else { |
3620 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3621 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3622 | description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3623 | dependency_from_external.srcStageMask |= reading_stages; |
3624 | } |
3625 | } break; |
3626 | default: { |
3627 | ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here. |
3628 | } |
3629 | } |
3630 | } |
3631 | |
3632 | bool used_last = false; |
3633 | |
3634 | { |
3635 | int last_pass = p_passes.size() - 1; |
3636 | |
3637 | if (is_depth) { |
3638 | // Likely missing depth resolve? |
3639 | if (p_passes[last_pass].depth_attachment == i) { |
3640 | used_last = true; |
3641 | } |
3642 | } else if (is_vrs) { |
3643 | if (p_passes[last_pass].vrs_attachment == i) { |
3644 | used_last = true; |
3645 | } |
3646 | } else { |
3647 | if (p_passes[last_pass].resolve_attachments.size()) { |
3648 | // If using resolve attachments, check resolve attachments. |
3649 | for (int j = 0; j < p_passes[last_pass].resolve_attachments.size(); j++) { |
3650 | if (p_passes[last_pass].resolve_attachments[j] == i) { |
3651 | used_last = true; |
3652 | break; |
3653 | } |
3654 | } |
3655 | } |
3656 | if (!used_last) { |
3657 | for (int j = 0; j < p_passes[last_pass].color_attachments.size(); j++) { |
3658 | if (p_passes[last_pass].color_attachments[j] == i) { |
3659 | used_last = true; |
3660 | break; |
3661 | } |
3662 | } |
3663 | } |
3664 | } |
3665 | |
3666 | if (!used_last) { |
3667 | for (int j = 0; j < p_passes[last_pass].preserve_attachments.size(); j++) { |
3668 | if (p_passes[last_pass].preserve_attachments[j] == i) { |
3669 | used_last = true; |
3670 | break; |
3671 | } |
3672 | } |
3673 | } |
3674 | } |
3675 | |
3676 | FinalAction final_action = p_final_action; |
3677 | FinalAction final_depth_action = p_final_depth_action; |
3678 | |
3679 | if (!used_last) { |
3680 | if (is_depth) { |
3681 | final_depth_action = FINAL_ACTION_DISCARD; |
3682 | |
3683 | } else { |
3684 | final_action = FINAL_ACTION_DISCARD; |
3685 | } |
3686 | } |
3687 | |
3688 | if (is_vrs) { |
3689 | // We don't change our VRS texture during this process. |
3690 | |
3691 | description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3692 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3693 | description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
3694 | |
3695 | // TODO: Do we need to update our external dependency? |
3696 | // update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); |
3697 | } else { |
3698 | switch (is_depth ? final_depth_action : final_action) { |
3699 | case FINAL_ACTION_READ: { |
3700 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3701 | description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
3702 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3703 | description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
3704 | update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); |
3705 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3706 | description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
3707 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; |
3708 | description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); |
3709 | update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true); |
3710 | } else { |
3711 | description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3712 | description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
3713 | description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3714 | // TODO: What does this mean about the next usage (and thus appropriate dependency masks. |
3715 | } |
3716 | } break; |
3717 | case FINAL_ACTION_DISCARD: { |
3718 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3719 | description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3720 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3721 | description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
3722 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3723 | description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3724 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3725 | description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); |
3726 | } else { |
3727 | description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3728 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3729 | description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3730 | } |
3731 | } break; |
3732 | case FINAL_ACTION_CONTINUE: { |
3733 | if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
3734 | description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
3735 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3736 | description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
3737 | } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
3738 | description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
3739 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; |
3740 | description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
3741 | } else { |
3742 | description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3743 | description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
3744 | description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there. |
3745 | } |
3746 | |
3747 | } break; |
3748 | default: { |
3749 | ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here. |
3750 | } |
3751 | } |
3752 | } |
3753 | |
3754 | attachment_last_pass[i] = -1; |
3755 | attachment_remap.push_back(attachments.size()); |
3756 | attachments.push_back(description); |
3757 | } |
3758 | |
3759 | LocalVector<VkSubpassDescription2KHR> subpasses; |
3760 | LocalVector<LocalVector<VkAttachmentReference2KHR>> color_reference_array; |
3761 | LocalVector<LocalVector<VkAttachmentReference2KHR>> input_reference_array; |
3762 | LocalVector<LocalVector<VkAttachmentReference2KHR>> resolve_reference_array; |
3763 | LocalVector<LocalVector<uint32_t>> preserve_reference_array; |
3764 | LocalVector<VkAttachmentReference2KHR> depth_reference_array; |
3765 | LocalVector<VkAttachmentReference2KHR> vrs_reference_array; |
3766 | LocalVector<VkFragmentShadingRateAttachmentInfoKHR> vrs_attachment_info_array; |
3767 | |
3768 | subpasses.resize(p_passes.size()); |
3769 | color_reference_array.resize(p_passes.size()); |
3770 | input_reference_array.resize(p_passes.size()); |
3771 | resolve_reference_array.resize(p_passes.size()); |
3772 | preserve_reference_array.resize(p_passes.size()); |
3773 | depth_reference_array.resize(p_passes.size()); |
3774 | vrs_reference_array.resize(p_passes.size()); |
3775 | vrs_attachment_info_array.resize(p_passes.size()); |
3776 | |
3777 | LocalVector<VkSubpassDependency2KHR> subpass_dependencies; |
3778 | |
3779 | for (int i = 0; i < p_passes.size(); i++) { |
3780 | const FramebufferPass *pass = &p_passes[i]; |
3781 | |
3782 | LocalVector<VkAttachmentReference2KHR> &color_references = color_reference_array[i]; |
3783 | |
3784 | TextureSamples texture_samples = TEXTURE_SAMPLES_1; |
3785 | bool is_multisample_first = true; |
3786 | void *subpass_nextptr = nullptr; |
3787 | |
3788 | for (int j = 0; j < pass->color_attachments.size(); j++) { |
3789 | int32_t attachment = pass->color_attachments[j]; |
3790 | VkAttachmentReference2KHR reference; |
3791 | reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; |
3792 | reference.pNext = nullptr; |
3793 | if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { |
3794 | reference.attachment = VK_ATTACHMENT_UNUSED; |
3795 | reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; |
3796 | } else { |
3797 | ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), color attachment (" + itos(j) + ")." ); |
3798 | ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as color attachment." ); |
3799 | ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass." ); |
3800 | |
3801 | if (is_multisample_first) { |
3802 | texture_samples = p_attachments[attachment].samples; |
3803 | is_multisample_first = false; |
3804 | } else { |
3805 | ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples." ); |
3806 | } |
3807 | reference.attachment = attachment_remap[attachment]; |
3808 | reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
3809 | attachment_last_pass[attachment] = i; |
3810 | } |
3811 | reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
3812 | color_references.push_back(reference); |
3813 | } |
3814 | |
3815 | LocalVector<VkAttachmentReference2KHR> &input_references = input_reference_array[i]; |
3816 | |
3817 | for (int j = 0; j < pass->input_attachments.size(); j++) { |
3818 | int32_t attachment = pass->input_attachments[j]; |
3819 | VkAttachmentReference2KHR reference; |
3820 | reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; |
3821 | reference.pNext = nullptr; |
3822 | if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { |
3823 | reference.attachment = VK_ATTACHMENT_UNUSED; |
3824 | reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; |
3825 | } else { |
3826 | ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ")." ); |
3827 | ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture." ); |
3828 | ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass." ); |
3829 | reference.attachment = attachment_remap[attachment]; |
3830 | reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
3831 | attachment_last_pass[attachment] = i; |
3832 | } |
3833 | reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
3834 | input_references.push_back(reference); |
3835 | } |
3836 | |
3837 | LocalVector<VkAttachmentReference2KHR> &resolve_references = resolve_reference_array[i]; |
3838 | |
3839 | if (pass->resolve_attachments.size() > 0) { |
3840 | ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), VK_NULL_HANDLE, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ")." ); |
3841 | ERR_FAIL_COND_V_MSG(texture_samples == TEXTURE_SAMPLES_1, VK_NULL_HANDLE, "Resolve attachments specified, but color attachments are not multisample." ); |
3842 | } |
3843 | for (int j = 0; j < pass->resolve_attachments.size(); j++) { |
3844 | int32_t attachment = pass->resolve_attachments[j]; |
3845 | VkAttachmentReference2KHR reference; |
3846 | reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; |
3847 | reference.pNext = nullptr; |
3848 | if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { |
3849 | reference.attachment = VK_ATTACHMENT_UNUSED; |
3850 | reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; |
3851 | } else { |
3852 | ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ")." ); |
3853 | ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused." ); |
3854 | ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment, it isn't marked as a color texture." ); |
3855 | ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass." ); |
3856 | bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1; |
3857 | ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample." ); |
3858 | reference.attachment = attachment_remap[attachment]; |
3859 | reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL |
3860 | attachment_last_pass[attachment] = i; |
3861 | } |
3862 | reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
3863 | resolve_references.push_back(reference); |
3864 | } |
3865 | |
3866 | VkAttachmentReference2KHR &depth_stencil_reference = depth_reference_array[i]; |
3867 | depth_stencil_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; |
3868 | depth_stencil_reference.pNext = nullptr; |
3869 | |
3870 | if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) { |
3871 | int32_t attachment = pass->depth_attachment; |
3872 | ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment." ); |
3873 | ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment." ); |
3874 | ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass." ); |
3875 | depth_stencil_reference.attachment = attachment_remap[attachment]; |
3876 | depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
3877 | depth_stencil_reference.aspectMask = VK_IMAGE_ASPECT_NONE; |
3878 | attachment_last_pass[attachment] = i; |
3879 | |
3880 | if (is_multisample_first) { |
3881 | texture_samples = p_attachments[attachment].samples; |
3882 | is_multisample_first = false; |
3883 | } else { |
3884 | ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples including the depth." ); |
3885 | } |
3886 | |
3887 | } else { |
3888 | depth_stencil_reference.attachment = VK_ATTACHMENT_UNUSED; |
3889 | depth_stencil_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; |
3890 | } |
3891 | |
3892 | if (context->get_vrs_capabilities().attachment_vrs_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) { |
3893 | int32_t attachment = pass->vrs_attachment; |
3894 | ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment." ); |
3895 | ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as VRS, but it's not a VRS attachment." ); |
3896 | ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass." ); |
3897 | |
3898 | VkAttachmentReference2KHR &vrs_reference = vrs_reference_array[i]; |
3899 | vrs_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; |
3900 | vrs_reference.pNext = nullptr; |
3901 | vrs_reference.attachment = attachment_remap[attachment]; |
3902 | vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; |
3903 | vrs_reference.aspectMask = VK_IMAGE_ASPECT_NONE; |
3904 | |
3905 | Size2i texel_size = context->get_vrs_capabilities().texel_size; |
3906 | |
3907 | VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i]; |
3908 | vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; |
3909 | vrs_attachment_info.pNext = nullptr; |
3910 | vrs_attachment_info.pFragmentShadingRateAttachment = &vrs_reference; |
3911 | vrs_attachment_info.shadingRateAttachmentTexelSize = { uint32_t(texel_size.x), uint32_t(texel_size.y) }; |
3912 | |
3913 | attachment_last_pass[attachment] = i; |
3914 | |
3915 | subpass_nextptr = &vrs_attachment_info; |
3916 | } |
3917 | |
3918 | LocalVector<uint32_t> &preserve_references = preserve_reference_array[i]; |
3919 | |
3920 | for (int j = 0; j < pass->preserve_attachments.size(); j++) { |
3921 | int32_t attachment = pass->preserve_attachments[j]; |
3922 | |
3923 | ERR_FAIL_COND_V_MSG(attachment == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + "). Preserve attachments can't be unused." ); |
3924 | |
3925 | ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ")." ); |
3926 | |
3927 | if (attachment_last_pass[attachment] != i) { |
3928 | // Preserve can still be used to keep depth or color from being discarded after use. |
3929 | attachment_last_pass[attachment] = i; |
3930 | preserve_references.push_back(attachment); |
3931 | } |
3932 | } |
3933 | |
3934 | VkSubpassDescription2KHR &subpass = subpasses[i]; |
3935 | subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR; |
3936 | subpass.pNext = subpass_nextptr; |
3937 | subpass.flags = 0; |
3938 | subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
3939 | if (p_view_count == 1) { |
3940 | // VUID-VkSubpassDescription2-multiview-06558: If the multiview feature is not enabled, viewMask must be 0. |
3941 | subpass.viewMask = 0; |
3942 | } else { |
3943 | subpass.viewMask = view_mask; |
3944 | } |
3945 | subpass.inputAttachmentCount = input_references.size(); |
3946 | if (input_references.size()) { |
3947 | subpass.pInputAttachments = input_references.ptr(); |
3948 | } else { |
3949 | subpass.pInputAttachments = nullptr; |
3950 | } |
3951 | subpass.colorAttachmentCount = color_references.size(); |
3952 | if (color_references.size()) { |
3953 | subpass.pColorAttachments = color_references.ptr(); |
3954 | } else { |
3955 | subpass.pColorAttachments = nullptr; |
3956 | } |
3957 | if (depth_stencil_reference.attachment != VK_ATTACHMENT_UNUSED) { |
3958 | subpass.pDepthStencilAttachment = &depth_stencil_reference; |
3959 | } else { |
3960 | subpass.pDepthStencilAttachment = nullptr; |
3961 | } |
3962 | |
3963 | if (resolve_references.size()) { |
3964 | subpass.pResolveAttachments = resolve_references.ptr(); |
3965 | } else { |
3966 | subpass.pResolveAttachments = nullptr; |
3967 | } |
3968 | |
3969 | subpass.preserveAttachmentCount = preserve_references.size(); |
3970 | if (preserve_references.size()) { |
3971 | subpass.pPreserveAttachments = preserve_references.ptr(); |
3972 | } else { |
3973 | subpass.pPreserveAttachments = nullptr; |
3974 | } |
3975 | |
3976 | if (r_samples) { |
3977 | r_samples->push_back(texture_samples); |
3978 | } |
3979 | |
3980 | if (i > 0) { |
3981 | VkSubpassDependency2KHR dependency; |
3982 | dependency.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR; |
3983 | dependency.pNext = nullptr; |
3984 | dependency.srcSubpass = i - 1; |
3985 | dependency.dstSubpass = i; |
3986 | dependency.srcStageMask = 0; |
3987 | dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; |
3988 | dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
3989 | |
3990 | dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; |
3991 | dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; |
3992 | dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; |
3993 | dependency.viewOffset = 0; |
3994 | subpass_dependencies.push_back(dependency); |
3995 | } |
3996 | /* |
3997 | // NOTE: Big Mallet Approach -- any layout transition causes a full barrier. |
3998 | if (reference.layout != description.initialLayout) { |
3999 | // NOTE: This should be smarter based on the texture's knowledge of its previous role. |
4000 | dependency_from_external.srcStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; |
4001 | dependency_from_external.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; |
4002 | } |
4003 | if (reference.layout != description.finalLayout) { |
4004 | // NOTE: This should be smarter based on the texture's knowledge of its subsequent role. |
4005 | dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; |
4006 | dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; |
4007 | } |
4008 | */ |
4009 | } |
4010 | |
4011 | VkRenderPassCreateInfo2KHR render_pass_create_info; |
4012 | render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; |
4013 | render_pass_create_info.pNext = nullptr; |
4014 | render_pass_create_info.flags = 0; |
4015 | |
4016 | render_pass_create_info.attachmentCount = attachments.size(); |
4017 | render_pass_create_info.pAttachments = attachments.ptr(); |
4018 | render_pass_create_info.subpassCount = subpasses.size(); |
4019 | render_pass_create_info.pSubpasses = subpasses.ptr(); |
4020 | // Commenting this because it seems it just avoids raster and compute to work at the same time. |
4021 | // Other barriers seem to be protecting the render pass fine. |
4022 | // render_pass_create_info.dependencyCount = 2; |
4023 | // render_pass_create_info.pDependencies = dependencies; |
4024 | |
4025 | render_pass_create_info.dependencyCount = subpass_dependencies.size(); |
4026 | if (subpass_dependencies.size()) { |
4027 | render_pass_create_info.pDependencies = subpass_dependencies.ptr(); |
4028 | } else { |
4029 | render_pass_create_info.pDependencies = nullptr; |
4030 | } |
4031 | |
4032 | if (p_view_count == 1) { |
4033 | // VUID-VkRenderPassCreateInfo2-viewMask-03057: If the VkSubpassDescription2::viewMask member of all elements of pSubpasses is 0, correlatedViewMaskCount must be 0. |
4034 | render_pass_create_info.correlatedViewMaskCount = 0; |
4035 | render_pass_create_info.pCorrelatedViewMasks = nullptr; |
4036 | } else { |
4037 | render_pass_create_info.correlatedViewMaskCount = 1; |
4038 | render_pass_create_info.pCorrelatedViewMasks = &correlation_mask; |
4039 | } |
4040 | |
4041 | Vector<uint32_t> view_masks; |
4042 | VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info; |
4043 | |
4044 | if ((p_view_count > 1) && !context->supports_renderpass2()) { |
4045 | // This is only required when using vkCreateRenderPass, we add it if vkCreateRenderPass2KHR is not supported |
4046 | // resulting this in being passed to our vkCreateRenderPass fallback. |
4047 | |
4048 | // Set view masks for each subpass. |
4049 | for (uint32_t i = 0; i < subpasses.size(); i++) { |
4050 | view_masks.push_back(view_mask); |
4051 | } |
4052 | |
4053 | render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; |
4054 | render_pass_multiview_create_info.pNext = nullptr; |
4055 | render_pass_multiview_create_info.subpassCount = subpasses.size(); |
4056 | render_pass_multiview_create_info.pViewMasks = view_masks.ptr(); |
4057 | render_pass_multiview_create_info.dependencyCount = 0; |
4058 | render_pass_multiview_create_info.pViewOffsets = nullptr; |
4059 | render_pass_multiview_create_info.correlationMaskCount = 1; |
4060 | render_pass_multiview_create_info.pCorrelationMasks = &correlation_mask; |
4061 | |
4062 | render_pass_create_info.pNext = &render_pass_multiview_create_info; |
4063 | } |
4064 | |
4065 | VkRenderPass render_pass; |
4066 | VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass); |
4067 | ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass2KHR failed with error " + itos(res) + "." ); |
4068 | |
4069 | return render_pass; |
4070 | } |
4071 | |
4072 | RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count) { |
4073 | FramebufferPass pass; |
4074 | for (int i = 0; i < p_format.size(); i++) { |
4075 | if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
4076 | pass.depth_attachment = i; |
4077 | } else { |
4078 | pass.color_attachments.push_back(i); |
4079 | } |
4080 | } |
4081 | |
4082 | Vector<FramebufferPass> passes; |
4083 | passes.push_back(pass); |
4084 | return framebuffer_format_create_multipass(p_format, passes, p_view_count); |
4085 | } |
4086 | RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count) { |
4087 | _THREAD_SAFE_METHOD_ |
4088 | |
4089 | FramebufferFormatKey key; |
4090 | key.attachments = p_attachments; |
4091 | key.passes = p_passes; |
4092 | key.view_count = p_view_count; |
4093 | |
4094 | const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key); |
4095 | if (E) { |
4096 | // Exists, return. |
4097 | return E->get(); |
4098 | } |
4099 | |
4100 | Vector<TextureSamples> samples; |
4101 | VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); // Actions don't matter for this use case. |
4102 | |
4103 | if (render_pass == VK_NULL_HANDLE) { // Was likely invalid. |
4104 | return INVALID_ID; |
4105 | } |
4106 | FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT)); |
4107 | |
4108 | E = framebuffer_format_cache.insert(key, id); |
4109 | FramebufferFormat fb_format; |
4110 | fb_format.E = E; |
4111 | fb_format.render_pass = render_pass; |
4112 | fb_format.pass_samples = samples; |
4113 | fb_format.view_count = p_view_count; |
4114 | framebuffer_formats[id] = fb_format; |
4115 | return id; |
4116 | } |
4117 | |
4118 | RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_empty(TextureSamples p_samples) { |
4119 | FramebufferFormatKey key; |
4120 | key.passes.push_back(FramebufferPass()); |
4121 | |
4122 | const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key); |
4123 | if (E) { |
4124 | // Exists, return. |
4125 | return E->get(); |
4126 | } |
4127 | |
4128 | VkSubpassDescription2KHR subpass; |
4129 | subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR; |
4130 | subpass.pNext = nullptr; |
4131 | subpass.flags = 0; |
4132 | subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
4133 | subpass.viewMask = 0; |
4134 | subpass.inputAttachmentCount = 0; // Unsupported for now. |
4135 | subpass.pInputAttachments = nullptr; |
4136 | subpass.colorAttachmentCount = 0; |
4137 | subpass.pColorAttachments = nullptr; |
4138 | subpass.pDepthStencilAttachment = nullptr; |
4139 | subpass.pResolveAttachments = nullptr; |
4140 | subpass.preserveAttachmentCount = 0; |
4141 | subpass.pPreserveAttachments = nullptr; |
4142 | |
4143 | VkRenderPassCreateInfo2KHR render_pass_create_info; |
4144 | render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; |
4145 | render_pass_create_info.pNext = nullptr; |
4146 | render_pass_create_info.flags = 0; |
4147 | render_pass_create_info.attachmentCount = 0; |
4148 | render_pass_create_info.pAttachments = nullptr; |
4149 | render_pass_create_info.subpassCount = 1; |
4150 | render_pass_create_info.pSubpasses = &subpass; |
4151 | render_pass_create_info.dependencyCount = 0; |
4152 | render_pass_create_info.pDependencies = nullptr; |
4153 | render_pass_create_info.correlatedViewMaskCount = 0; |
4154 | render_pass_create_info.pCorrelatedViewMasks = nullptr; |
4155 | |
4156 | VkRenderPass render_pass; |
4157 | VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass); |
4158 | |
4159 | ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass2KHR for empty fb failed with error " + itos(res) + "." ); |
4160 | |
4161 | if (render_pass == VK_NULL_HANDLE) { // Was likely invalid. |
4162 | return INVALID_ID; |
4163 | } |
4164 | |
4165 | FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT)); |
4166 | |
4167 | E = framebuffer_format_cache.insert(key, id); |
4168 | |
4169 | FramebufferFormat fb_format; |
4170 | fb_format.E = E; |
4171 | fb_format.render_pass = render_pass; |
4172 | fb_format.pass_samples.push_back(p_samples); |
4173 | framebuffer_formats[id] = fb_format; |
4174 | return id; |
4175 | } |
4176 | |
4177 | RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) { |
4178 | HashMap<FramebufferFormatID, FramebufferFormat>::Iterator E = framebuffer_formats.find(p_format); |
4179 | ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1); |
4180 | ERR_FAIL_COND_V(p_pass >= uint32_t(E->value.pass_samples.size()), TEXTURE_SAMPLES_1); |
4181 | |
4182 | return E->value.pass_samples[p_pass]; |
4183 | } |
4184 | |
4185 | /***********************/ |
4186 | /**** RENDER TARGET ****/ |
4187 | /***********************/ |
4188 | |
4189 | RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples, FramebufferFormatID p_format_check) { |
4190 | _THREAD_SAFE_METHOD_ |
4191 | Framebuffer framebuffer; |
4192 | framebuffer.format_id = framebuffer_format_create_empty(p_samples); |
4193 | ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID()); |
4194 | framebuffer.size = p_size; |
4195 | framebuffer.view_count = 1; |
4196 | |
4197 | RID id = framebuffer_owner.make_rid(framebuffer); |
4198 | #ifdef DEV_ENABLED |
4199 | set_resource_name(id, "RID:" + itos(id.get_id())); |
4200 | #endif |
4201 | return id; |
4202 | } |
4203 | |
4204 | RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) { |
4205 | _THREAD_SAFE_METHOD_ |
4206 | |
4207 | FramebufferPass pass; |
4208 | |
4209 | for (int i = 0; i < p_texture_attachments.size(); i++) { |
4210 | Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]); |
4211 | |
4212 | ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer" ); |
4213 | |
4214 | if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
4215 | pass.depth_attachment = i; |
4216 | } else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { |
4217 | pass.vrs_attachment = i; |
4218 | } else { |
4219 | if (texture && texture->is_resolve_buffer) { |
4220 | pass.resolve_attachments.push_back(i); |
4221 | } else { |
4222 | pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED); |
4223 | } |
4224 | } |
4225 | } |
4226 | |
4227 | Vector<FramebufferPass> passes; |
4228 | passes.push_back(pass); |
4229 | |
4230 | return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count); |
4231 | } |
4232 | |
4233 | RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { |
4234 | _THREAD_SAFE_METHOD_ |
4235 | |
4236 | Vector<AttachmentFormat> attachments; |
4237 | attachments.resize(p_texture_attachments.size()); |
4238 | Size2i size; |
4239 | bool size_set = false; |
4240 | for (int i = 0; i < p_texture_attachments.size(); i++) { |
4241 | AttachmentFormat af; |
4242 | Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]); |
4243 | if (!texture) { |
4244 | af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT; |
4245 | } else { |
4246 | ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer" ); |
4247 | |
4248 | if (!size_set) { |
4249 | size.width = texture->width; |
4250 | size.height = texture->height; |
4251 | size_set = true; |
4252 | } else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { |
4253 | // If this is not the first attachment we assume this is used as the VRS attachment. |
4254 | // In this case this texture will be 1/16th the size of the color attachment. |
4255 | // So we skip the size check. |
4256 | } else { |
4257 | ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(), |
4258 | "All textures in a framebuffer should be the same size." ); |
4259 | } |
4260 | |
4261 | af.format = texture->format; |
4262 | af.samples = texture->samples; |
4263 | af.usage_flags = texture->usage_flags; |
4264 | } |
4265 | attachments.write[i] = af; |
4266 | } |
4267 | |
4268 | ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused." ); |
4269 | |
4270 | FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count); |
4271 | if (format_id == INVALID_ID) { |
4272 | return RID(); |
4273 | } |
4274 | |
4275 | ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(), |
4276 | "The format used to check this framebuffer differs from the intended framebuffer format." ); |
4277 | |
4278 | Framebuffer framebuffer; |
4279 | framebuffer.format_id = format_id; |
4280 | framebuffer.texture_ids = p_texture_attachments; |
4281 | framebuffer.size = size; |
4282 | framebuffer.view_count = p_view_count; |
4283 | |
4284 | RID id = framebuffer_owner.make_rid(framebuffer); |
4285 | #ifdef DEV_ENABLED |
4286 | set_resource_name(id, "RID:" + itos(id.get_id())); |
4287 | #endif |
4288 | |
4289 | for (int i = 0; i < p_texture_attachments.size(); i++) { |
4290 | if (p_texture_attachments[i].is_valid()) { |
4291 | _add_dependency(id, p_texture_attachments[i]); |
4292 | } |
4293 | } |
4294 | |
4295 | return id; |
4296 | } |
4297 | |
4298 | RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_format(RID p_framebuffer) { |
4299 | _THREAD_SAFE_METHOD_ |
4300 | |
4301 | Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); |
4302 | ERR_FAIL_NULL_V(framebuffer, INVALID_ID); |
4303 | |
4304 | return framebuffer->format_id; |
4305 | } |
4306 | |
4307 | bool RenderingDeviceVulkan::framebuffer_is_valid(RID p_framebuffer) const { |
4308 | _THREAD_SAFE_METHOD_ |
4309 | |
4310 | return framebuffer_owner.owns(p_framebuffer); |
4311 | } |
4312 | |
4313 | void RenderingDeviceVulkan::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) { |
4314 | _THREAD_SAFE_METHOD_ |
4315 | |
4316 | Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); |
4317 | ERR_FAIL_NULL(framebuffer); |
4318 | |
4319 | framebuffer->invalidated_callback = p_callback; |
4320 | framebuffer->invalidated_callback_userdata = p_userdata; |
4321 | } |
4322 | |
4323 | /*****************/ |
4324 | /**** SAMPLER ****/ |
4325 | /*****************/ |
4326 | |
4327 | RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { |
4328 | _THREAD_SAFE_METHOD_ |
4329 | |
4330 | VkSamplerCreateInfo sampler_create_info; |
4331 | sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; |
4332 | sampler_create_info.pNext = nullptr; |
4333 | sampler_create_info.flags = 0; |
4334 | sampler_create_info.magFilter = p_state.mag_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; |
4335 | sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; |
4336 | sampler_create_info.mipmapMode = p_state.mip_filter == SAMPLER_FILTER_LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; |
4337 | |
4338 | ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID()); |
4339 | sampler_create_info.addressModeU = address_modes[p_state.repeat_u]; |
4340 | ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID()); |
4341 | sampler_create_info.addressModeV = address_modes[p_state.repeat_v]; |
4342 | ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID()); |
4343 | sampler_create_info.addressModeW = address_modes[p_state.repeat_w]; |
4344 | |
4345 | sampler_create_info.mipLodBias = p_state.lod_bias; |
4346 | sampler_create_info.anisotropyEnable = p_state.use_anisotropy && context->get_physical_device_features().samplerAnisotropy; |
4347 | sampler_create_info.maxAnisotropy = p_state.anisotropy_max; |
4348 | sampler_create_info.compareEnable = p_state.enable_compare; |
4349 | |
4350 | ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID()); |
4351 | sampler_create_info.compareOp = compare_operators[p_state.compare_op]; |
4352 | |
4353 | sampler_create_info.minLod = p_state.min_lod; |
4354 | sampler_create_info.maxLod = p_state.max_lod; |
4355 | |
4356 | ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID()); |
4357 | sampler_create_info.borderColor = sampler_border_colors[p_state.border_color]; |
4358 | |
4359 | sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw; |
4360 | |
4361 | VkSampler sampler; |
4362 | VkResult res = vkCreateSampler(device, &sampler_create_info, nullptr, &sampler); |
4363 | ERR_FAIL_COND_V_MSG(res, RID(), "vkCreateSampler failed with error " + itos(res) + "." ); |
4364 | |
4365 | RID id = sampler_owner.make_rid(sampler); |
4366 | #ifdef DEV_ENABLED |
4367 | set_resource_name(id, "RID:" + itos(id.get_id())); |
4368 | #endif |
4369 | return id; |
4370 | } |
4371 | |
4372 | bool RenderingDeviceVulkan::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const { |
4373 | ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); |
4374 | |
4375 | _THREAD_SAFE_METHOD_ |
4376 | |
4377 | // Validate that this image is supported for the intended filtering. |
4378 | VkFormatProperties properties; |
4379 | vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties); |
4380 | |
4381 | return p_sampler_filter == RD::SAMPLER_FILTER_NEAREST || (p_sampler_filter == RD::SAMPLER_FILTER_LINEAR && (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)); |
4382 | } |
4383 | |
4384 | /**********************/ |
4385 | /**** VERTEX ARRAY ****/ |
4386 | /**********************/ |
4387 | |
4388 | RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, bool p_use_as_storage) { |
4389 | _THREAD_SAFE_METHOD_ |
4390 | |
4391 | ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); |
4392 | |
4393 | uint32_t usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
4394 | if (p_use_as_storage) { |
4395 | usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
4396 | } |
4397 | Buffer buffer; |
4398 | _buffer_allocate(&buffer, p_size_bytes, usage, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
4399 | if (p_data.size()) { |
4400 | uint64_t data_size = p_data.size(); |
4401 | const uint8_t *r = p_data.ptr(); |
4402 | _buffer_update(&buffer, 0, r, data_size); |
4403 | _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); |
4404 | } |
4405 | |
4406 | RID id = vertex_buffer_owner.make_rid(buffer); |
4407 | #ifdef DEV_ENABLED |
4408 | set_resource_name(id, "RID:" + itos(id.get_id())); |
4409 | #endif |
4410 | return id; |
4411 | } |
4412 | |
4413 | // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated. |
4414 | RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) { |
4415 | _THREAD_SAFE_METHOD_ |
4416 | |
4417 | VertexDescriptionKey key; |
4418 | key.vertex_formats = p_vertex_formats; |
4419 | |
4420 | VertexFormatID *idptr = vertex_format_cache.getptr(key); |
4421 | if (idptr) { |
4422 | return *idptr; |
4423 | } |
4424 | |
4425 | // Does not exist, create one and cache it. |
4426 | VertexDescriptionCache vdcache; |
4427 | vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size()); |
4428 | vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size()); |
4429 | |
4430 | HashSet<int> used_locations; |
4431 | for (int i = 0; i < p_vertex_formats.size(); i++) { |
4432 | ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX); |
4433 | ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID); |
4434 | |
4435 | ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID, |
4436 | "Data format for attachment (" + itos(i) + "), '" + named_formats[p_vertex_formats[i].format] + "', is not valid for a vertex array." ); |
4437 | |
4438 | vdcache.bindings[i].binding = i; |
4439 | vdcache.bindings[i].stride = p_vertex_formats[i].stride; |
4440 | vdcache.bindings[i].inputRate = p_vertex_formats[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; |
4441 | vdcache.attributes[i].binding = i; |
4442 | vdcache.attributes[i].location = p_vertex_formats[i].location; |
4443 | vdcache.attributes[i].format = vulkan_formats[p_vertex_formats[i].format]; |
4444 | vdcache.attributes[i].offset = p_vertex_formats[i].offset; |
4445 | used_locations.insert(p_vertex_formats[i].location); |
4446 | } |
4447 | |
4448 | vdcache.create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; |
4449 | vdcache.create_info.pNext = nullptr; |
4450 | vdcache.create_info.flags = 0; |
4451 | |
4452 | vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_formats.size(); |
4453 | vdcache.create_info.pVertexAttributeDescriptions = vdcache.attributes; |
4454 | |
4455 | vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size(); |
4456 | vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings; |
4457 | vdcache.vertex_formats = p_vertex_formats; |
4458 | |
4459 | VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT); |
4460 | vertex_format_cache[key] = id; |
4461 | vertex_formats[id] = vdcache; |
4462 | return id; |
4463 | } |
4464 | |
4465 | RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets) { |
4466 | _THREAD_SAFE_METHOD_ |
4467 | |
4468 | ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); |
4469 | const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; |
4470 | |
4471 | ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID()); |
4472 | |
4473 | for (int i = 0; i < p_src_buffers.size(); i++) { |
4474 | ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID()); |
4475 | } |
4476 | |
4477 | VertexArray vertex_array; |
4478 | |
4479 | if (p_offsets.is_empty()) { |
4480 | vertex_array.offsets.resize_zeroed(p_src_buffers.size()); |
4481 | } else { |
4482 | ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID()); |
4483 | vertex_array.offsets = p_offsets; |
4484 | } |
4485 | |
4486 | vertex_array.vertex_count = p_vertex_count; |
4487 | vertex_array.description = p_vertex_format; |
4488 | vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want. |
4489 | for (int i = 0; i < p_src_buffers.size(); i++) { |
4490 | Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]); |
4491 | |
4492 | // Validate with buffer. |
4493 | { |
4494 | const VertexAttribute &atf = vd.vertex_formats[i]; |
4495 | |
4496 | uint32_t element_size = get_format_vertex_size(atf.format); |
4497 | ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated. |
4498 | |
4499 | if (atf.frequency == VERTEX_FREQUENCY_VERTEX) { |
4500 | // Validate size for regular drawing. |
4501 | uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size; |
4502 | ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(), |
4503 | "Attachment (" + itos(i) + ") will read past the end of the buffer." ); |
4504 | |
4505 | } else { |
4506 | // Validate size for instances drawing. |
4507 | uint64_t available = buffer->size - atf.offset; |
4508 | ERR_FAIL_COND_V_MSG(available < element_size, RID(), |
4509 | "Attachment (" + itos(i) + ") uses instancing, but it's just too small." ); |
4510 | |
4511 | uint32_t instances_allowed = available / atf.stride; |
4512 | vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed); |
4513 | } |
4514 | } |
4515 | |
4516 | vertex_array.buffers.push_back(buffer->buffer); |
4517 | } |
4518 | |
4519 | RID id = vertex_array_owner.make_rid(vertex_array); |
4520 | for (int i = 0; i < p_src_buffers.size(); i++) { |
4521 | _add_dependency(id, p_src_buffers[i]); |
4522 | } |
4523 | |
4524 | return id; |
4525 | } |
4526 | |
4527 | RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const Vector<uint8_t> &p_data, bool p_use_restart_indices) { |
4528 | _THREAD_SAFE_METHOD_ |
4529 | |
4530 | ERR_FAIL_COND_V(p_index_count == 0, RID()); |
4531 | |
4532 | IndexBuffer index_buffer; |
4533 | index_buffer.index_type = (p_format == INDEX_BUFFER_FORMAT_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; |
4534 | index_buffer.supports_restart_indices = p_use_restart_indices; |
4535 | index_buffer.index_count = p_index_count; |
4536 | uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4); |
4537 | #ifdef DEBUG_ENABLED |
4538 | if (p_data.size()) { |
4539 | index_buffer.max_index = 0; |
4540 | ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(), |
4541 | "Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ")." ); |
4542 | const uint8_t *r = p_data.ptr(); |
4543 | if (p_format == INDEX_BUFFER_FORMAT_UINT16) { |
4544 | const uint16_t *index16 = (const uint16_t *)r; |
4545 | for (uint32_t i = 0; i < p_index_count; i++) { |
4546 | if (p_use_restart_indices && index16[i] == 0xFFFF) { |
4547 | continue; // Restart index, ignore. |
4548 | } |
4549 | index_buffer.max_index = MAX(index16[i], index_buffer.max_index); |
4550 | } |
4551 | } else { |
4552 | const uint32_t *index32 = (const uint32_t *)r; |
4553 | for (uint32_t i = 0; i < p_index_count; i++) { |
4554 | if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) { |
4555 | continue; // Restart index, ignore. |
4556 | } |
4557 | index_buffer.max_index = MAX(index32[i], index_buffer.max_index); |
4558 | } |
4559 | } |
4560 | } else { |
4561 | index_buffer.max_index = 0xFFFFFFFF; |
4562 | } |
4563 | #else |
4564 | index_buffer.max_index = 0xFFFFFFFF; |
4565 | #endif |
4566 | _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
4567 | if (p_data.size()) { |
4568 | uint64_t data_size = p_data.size(); |
4569 | const uint8_t *r = p_data.ptr(); |
4570 | _buffer_update(&index_buffer, 0, r, data_size); |
4571 | _buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); |
4572 | } |
4573 | RID id = index_buffer_owner.make_rid(index_buffer); |
4574 | #ifdef DEV_ENABLED |
4575 | set_resource_name(id, "RID:" + itos(id.get_id())); |
4576 | #endif |
4577 | return id; |
4578 | } |
4579 | |
4580 | RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { |
4581 | _THREAD_SAFE_METHOD_ |
4582 | |
4583 | ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID()); |
4584 | |
4585 | IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_index_buffer); |
4586 | |
4587 | ERR_FAIL_COND_V(p_index_count == 0, RID()); |
4588 | ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID()); |
4589 | |
4590 | IndexArray index_array; |
4591 | index_array.max_index = index_buffer->max_index; |
4592 | index_array.buffer = index_buffer->buffer; |
4593 | index_array.offset = p_index_offset; |
4594 | index_array.indices = p_index_count; |
4595 | index_array.index_type = index_buffer->index_type; |
4596 | index_array.supports_restart_indices = index_buffer->supports_restart_indices; |
4597 | |
4598 | RID id = index_array_owner.make_rid(index_array); |
4599 | _add_dependency(id, p_index_buffer); |
4600 | return id; |
4601 | } |
4602 | |
4603 | /****************/ |
4604 | /**** SHADER ****/ |
4605 | /****************/ |
4606 | |
4607 | static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX] = { |
4608 | "Sampler" , "CombinedSampler" , "Texture" , "Image" , "TextureBuffer" , "SamplerTextureBuffer" , "ImageBuffer" , "UniformBuffer" , "StorageBuffer" , "InputAttachment" |
4609 | }; |
4610 | |
4611 | static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MAX] = { |
4612 | VK_SHADER_STAGE_VERTEX_BIT, |
4613 | VK_SHADER_STAGE_FRAGMENT_BIT, |
4614 | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
4615 | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, |
4616 | VK_SHADER_STAGE_COMPUTE_BIT, |
4617 | }; |
4618 | |
4619 | String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { |
4620 | String ret; |
4621 | const Shader *shader = shader_owner.get_or_null(p_shader); |
4622 | ERR_FAIL_NULL_V(shader, String()); |
4623 | for (int i = 0; i < shader->sets.size(); i++) { |
4624 | if (p_set >= 0 && i != p_set) { |
4625 | continue; |
4626 | } |
4627 | for (int j = 0; j < shader->sets[i].uniform_info.size(); j++) { |
4628 | const UniformInfo &ui = shader->sets[i].uniform_info[j]; |
4629 | if (!ret.is_empty()) { |
4630 | ret += "\n" ; |
4631 | } |
4632 | ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Writable: " + (ui.writable ? "Y" : "N" ) + " Length: " + itos(ui.length); |
4633 | } |
4634 | } |
4635 | return ret; |
4636 | } |
4637 | |
4638 | // Version 1: initial. |
4639 | // Version 2: Added shader name. |
4640 | // Version 3: Added writable. |
4641 | |
4642 | #define SHADER_BINARY_VERSION 3 |
4643 | |
4644 | String RenderingDeviceVulkan::shader_get_binary_cache_key() const { |
4645 | return "Vulkan-SV" + itos(SHADER_BINARY_VERSION); |
4646 | } |
4647 | |
4648 | struct RenderingDeviceVulkanShaderBinaryDataBinding { |
4649 | uint32_t type; |
4650 | uint32_t binding; |
4651 | uint32_t stages; |
4652 | uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements). |
4653 | uint32_t writable; |
4654 | }; |
4655 | |
4656 | struct RenderingDeviceVulkanShaderBinarySpecializationConstant { |
4657 | uint32_t type; |
4658 | uint32_t constant_id; |
4659 | union { |
4660 | uint32_t int_value; |
4661 | float float_value; |
4662 | bool bool_value; |
4663 | }; |
4664 | uint32_t stage_flags; |
4665 | }; |
4666 | |
4667 | struct RenderingDeviceVulkanShaderBinaryData { |
4668 | uint32_t vertex_input_mask; |
4669 | uint32_t fragment_output_mask; |
4670 | uint32_t specialization_constants_count; |
4671 | uint32_t is_compute; |
4672 | uint32_t compute_local_size[3]; |
4673 | uint32_t set_count; |
4674 | uint32_t push_constant_size; |
4675 | uint32_t push_constant_vk_stages_mask; |
4676 | uint32_t stage_count; |
4677 | uint32_t shader_name_len; |
4678 | }; |
4679 | |
4680 | Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) { |
4681 | SpirvReflectionData spirv_data; |
4682 | if (_reflect_spirv(p_spirv, spirv_data) != OK) { |
4683 | return Vector<uint8_t>(); |
4684 | } |
4685 | |
4686 | ERR_FAIL_COND_V_MSG((uint32_t)spirv_data.uniforms.size() > limits.maxBoundDescriptorSets, Vector<uint8_t>(), |
4687 | "Number of uniform sets is larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")." ); |
4688 | |
4689 | // Collect reflection data into binary data. |
4690 | RenderingDeviceVulkanShaderBinaryData binary_data{}; |
4691 | Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings. |
4692 | Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants; |
4693 | { |
4694 | binary_data.vertex_input_mask = spirv_data.vertex_input_mask; |
4695 | binary_data.fragment_output_mask = spirv_data.fragment_output_mask; |
4696 | binary_data.specialization_constants_count = spirv_data.specialization_constants.size(); |
4697 | binary_data.is_compute = spirv_data.is_compute; |
4698 | binary_data.compute_local_size[0] = spirv_data.compute_local_size[0]; |
4699 | binary_data.compute_local_size[1] = spirv_data.compute_local_size[1]; |
4700 | binary_data.compute_local_size[2] = spirv_data.compute_local_size[2]; |
4701 | binary_data.set_count = spirv_data.uniforms.size(); |
4702 | binary_data.push_constant_size = spirv_data.push_constant_size; |
4703 | for (uint32_t i = 0; i < SHADER_STAGE_MAX; i++) { |
4704 | if (spirv_data.push_constant_stages_mask.has_flag((ShaderStage)(1 << i))) { |
4705 | binary_data.push_constant_vk_stages_mask |= shader_stage_masks[i]; |
4706 | } |
4707 | } |
4708 | |
4709 | for (const Vector<SpirvReflectionData::Uniform> &spirv_set : spirv_data.uniforms) { |
4710 | Vector<RenderingDeviceVulkanShaderBinaryDataBinding> set_bindings; |
4711 | for (const SpirvReflectionData::Uniform &spirv_uniform : spirv_set) { |
4712 | RenderingDeviceVulkanShaderBinaryDataBinding binding{}; |
4713 | binding.type = (uint32_t)spirv_uniform.type; |
4714 | binding.binding = spirv_uniform.binding; |
4715 | binding.stages = (uint32_t)spirv_uniform.stages_mask; |
4716 | binding.length = spirv_uniform.length; |
4717 | binding.writable = (uint32_t)spirv_uniform.writable; |
4718 | set_bindings.push_back(binding); |
4719 | } |
4720 | uniform_info.push_back(set_bindings); |
4721 | } |
4722 | |
4723 | for (const SpirvReflectionData::SpecializationConstant &spirv_sc : spirv_data.specialization_constants) { |
4724 | RenderingDeviceVulkanShaderBinarySpecializationConstant spec_constant{}; |
4725 | spec_constant.type = (uint32_t)spirv_sc.type; |
4726 | spec_constant.constant_id = spirv_sc.constant_id; |
4727 | spec_constant.int_value = spirv_sc.int_value; |
4728 | spec_constant.stage_flags = (uint32_t)spirv_sc.stages_mask; |
4729 | specialization_constants.push_back(spec_constant); |
4730 | } |
4731 | } |
4732 | |
4733 | Vector<Vector<uint8_t>> compressed_stages; |
4734 | Vector<uint32_t> smolv_size; |
4735 | Vector<uint32_t> zstd_size; // If 0, zstd not used. |
4736 | |
4737 | uint32_t stages_binary_size = 0; |
4738 | |
4739 | bool strip_debug = false; |
4740 | |
4741 | for (int i = 0; i < p_spirv.size(); i++) { |
4742 | smolv::ByteArray smolv; |
4743 | if (!smolv::Encode(p_spirv[i].spir_v.ptr(), p_spirv[i].spir_v.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) { |
4744 | ERR_FAIL_V_MSG(Vector<uint8_t>(), "Error compressing shader stage :" + String(shader_stage_names[p_spirv[i].shader_stage])); |
4745 | } else { |
4746 | smolv_size.push_back(smolv.size()); |
4747 | { // zstd. |
4748 | Vector<uint8_t> zstd; |
4749 | zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD)); |
4750 | int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD); |
4751 | |
4752 | if (dst_size > 0 && (uint32_t)dst_size < smolv.size()) { |
4753 | zstd_size.push_back(dst_size); |
4754 | zstd.resize(dst_size); |
4755 | compressed_stages.push_back(zstd); |
4756 | } else { |
4757 | Vector<uint8_t> smv; |
4758 | smv.resize(smolv.size()); |
4759 | memcpy(smv.ptrw(), &smolv[0], smolv.size()); |
4760 | zstd_size.push_back(0); // Not using zstd. |
4761 | compressed_stages.push_back(smv); |
4762 | } |
4763 | } |
4764 | } |
4765 | uint32_t s = compressed_stages[i].size(); |
4766 | if (s % 4 != 0) { |
4767 | s += 4 - (s % 4); |
4768 | } |
4769 | stages_binary_size += s; |
4770 | } |
4771 | |
4772 | binary_data.specialization_constants_count = specialization_constants.size(); |
4773 | binary_data.set_count = uniform_info.size(); |
4774 | binary_data.stage_count = p_spirv.size(); |
4775 | |
4776 | CharString shader_name_utf = p_shader_name.utf8(); |
4777 | |
4778 | binary_data.shader_name_len = shader_name_utf.length(); |
4779 | |
4780 | uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;. |
4781 | total_size += sizeof(RenderingDeviceVulkanShaderBinaryData); |
4782 | |
4783 | total_size += binary_data.shader_name_len; |
4784 | |
4785 | if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange. |
4786 | total_size += 4 - (binary_data.shader_name_len % 4); |
4787 | } |
4788 | |
4789 | for (int i = 0; i < uniform_info.size(); i++) { |
4790 | total_size += sizeof(uint32_t); |
4791 | total_size += uniform_info[i].size() * sizeof(RenderingDeviceVulkanShaderBinaryDataBinding); |
4792 | } |
4793 | |
4794 | total_size += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size(); |
4795 | |
4796 | total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes. |
4797 | total_size += stages_binary_size; |
4798 | |
4799 | Vector<uint8_t> ret; |
4800 | ret.resize(total_size); |
4801 | { |
4802 | uint32_t offset = 0; |
4803 | uint8_t *binptr = ret.ptrw(); |
4804 | binptr[0] = 'G'; |
4805 | binptr[1] = 'S'; |
4806 | binptr[2] = 'B'; |
4807 | binptr[3] = 'D'; // Godot Shader Binary Data. |
4808 | offset += 4; |
4809 | encode_uint32(SHADER_BINARY_VERSION, binptr + offset); |
4810 | offset += sizeof(uint32_t); |
4811 | encode_uint32(sizeof(RenderingDeviceVulkanShaderBinaryData), binptr + offset); |
4812 | offset += sizeof(uint32_t); |
4813 | memcpy(binptr + offset, &binary_data, sizeof(RenderingDeviceVulkanShaderBinaryData)); |
4814 | offset += sizeof(RenderingDeviceVulkanShaderBinaryData); |
4815 | |
4816 | if (binary_data.shader_name_len > 0) { |
4817 | memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len); |
4818 | offset += binary_data.shader_name_len; |
4819 | |
4820 | if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange. |
4821 | offset += 4 - (binary_data.shader_name_len % 4); |
4822 | } |
4823 | } |
4824 | |
4825 | for (int i = 0; i < uniform_info.size(); i++) { |
4826 | int count = uniform_info[i].size(); |
4827 | encode_uint32(count, binptr + offset); |
4828 | offset += sizeof(uint32_t); |
4829 | if (count > 0) { |
4830 | memcpy(binptr + offset, uniform_info[i].ptr(), sizeof(RenderingDeviceVulkanShaderBinaryDataBinding) * count); |
4831 | offset += sizeof(RenderingDeviceVulkanShaderBinaryDataBinding) * count; |
4832 | } |
4833 | } |
4834 | |
4835 | if (specialization_constants.size()) { |
4836 | memcpy(binptr + offset, specialization_constants.ptr(), sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size()); |
4837 | offset += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size(); |
4838 | } |
4839 | |
4840 | for (int i = 0; i < compressed_stages.size(); i++) { |
4841 | encode_uint32(p_spirv[i].shader_stage, binptr + offset); |
4842 | offset += sizeof(uint32_t); |
4843 | encode_uint32(smolv_size[i], binptr + offset); |
4844 | offset += sizeof(uint32_t); |
4845 | encode_uint32(zstd_size[i], binptr + offset); |
4846 | offset += sizeof(uint32_t); |
4847 | memcpy(binptr + offset, compressed_stages[i].ptr(), compressed_stages[i].size()); |
4848 | |
4849 | uint32_t s = compressed_stages[i].size(); |
4850 | |
4851 | if (s % 4 != 0) { |
4852 | s += 4 - (s % 4); |
4853 | } |
4854 | |
4855 | offset += s; |
4856 | } |
4857 | |
4858 | ERR_FAIL_COND_V(offset != (uint32_t)ret.size(), Vector<uint8_t>()); |
4859 | } |
4860 | |
4861 | return ret; |
4862 | } |
4863 | |
4864 | RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder) { |
4865 | const uint8_t *binptr = p_shader_binary.ptr(); |
4866 | uint32_t binsize = p_shader_binary.size(); |
4867 | |
4868 | uint32_t read_offset = 0; |
4869 | // Consistency check. |
4870 | ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(RenderingDeviceVulkanShaderBinaryData), RID()); |
4871 | ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || binptr[2] != 'B' || binptr[3] != 'D', RID()); |
4872 | |
4873 | uint32_t bin_version = decode_uint32(binptr + 4); |
4874 | ERR_FAIL_COND_V(bin_version != SHADER_BINARY_VERSION, RID()); |
4875 | |
4876 | uint32_t bin_data_size = decode_uint32(binptr + 8); |
4877 | |
4878 | const RenderingDeviceVulkanShaderBinaryData &binary_data = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinaryData *>(binptr + 12)); |
4879 | |
4880 | Shader::PushConstant push_constant; |
4881 | push_constant.size = binary_data.push_constant_size; |
4882 | push_constant.vk_stages_mask = binary_data.push_constant_vk_stages_mask; |
4883 | |
4884 | uint32_t vertex_input_mask = binary_data.vertex_input_mask; |
4885 | |
4886 | uint32_t fragment_output_mask = binary_data.fragment_output_mask; |
4887 | |
4888 | bool is_compute = binary_data.is_compute; |
4889 | |
4890 | const uint32_t compute_local_size[3] = { binary_data.compute_local_size[0], binary_data.compute_local_size[1], binary_data.compute_local_size[2] }; |
4891 | |
4892 | read_offset += sizeof(uint32_t) * 3 + bin_data_size; |
4893 | |
4894 | String name; |
4895 | |
4896 | if (binary_data.shader_name_len) { |
4897 | name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len); |
4898 | read_offset += binary_data.shader_name_len; |
4899 | if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange. |
4900 | read_offset += 4 - (binary_data.shader_name_len % 4); |
4901 | } |
4902 | } |
4903 | |
4904 | Vector<Vector<VkDescriptorSetLayoutBinding>> set_bindings; |
4905 | Vector<Vector<UniformInfo>> uniform_info; |
4906 | |
4907 | set_bindings.resize(binary_data.set_count); |
4908 | uniform_info.resize(binary_data.set_count); |
4909 | |
4910 | for (uint32_t i = 0; i < binary_data.set_count; i++) { |
4911 | ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) >= binsize, RID()); |
4912 | uint32_t set_count = decode_uint32(binptr + read_offset); |
4913 | read_offset += sizeof(uint32_t); |
4914 | const RenderingDeviceVulkanShaderBinaryDataBinding *set_ptr = reinterpret_cast<const RenderingDeviceVulkanShaderBinaryDataBinding *>(binptr + read_offset); |
4915 | uint32_t set_size = set_count * sizeof(RenderingDeviceVulkanShaderBinaryDataBinding); |
4916 | ERR_FAIL_COND_V(read_offset + set_size >= binsize, RID()); |
4917 | |
4918 | for (uint32_t j = 0; j < set_count; j++) { |
4919 | UniformInfo info; |
4920 | info.type = UniformType(set_ptr[j].type); |
4921 | info.writable = set_ptr[j].writable; |
4922 | info.length = set_ptr[j].length; |
4923 | info.binding = set_ptr[j].binding; |
4924 | info.stages = set_ptr[j].stages; |
4925 | |
4926 | VkDescriptorSetLayoutBinding layout_binding; |
4927 | layout_binding.pImmutableSamplers = nullptr; |
4928 | layout_binding.binding = set_ptr[j].binding; |
4929 | layout_binding.descriptorCount = 1; |
4930 | layout_binding.stageFlags = 0; |
4931 | for (uint32_t k = 0; k < SHADER_STAGE_MAX; k++) { |
4932 | if (set_ptr[j].stages & (1 << k)) { |
4933 | layout_binding.stageFlags |= shader_stage_masks[k]; |
4934 | } |
4935 | } |
4936 | |
4937 | switch (info.type) { |
4938 | case UNIFORM_TYPE_SAMPLER: { |
4939 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; |
4940 | layout_binding.descriptorCount = set_ptr[j].length; |
4941 | } break; |
4942 | case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: { |
4943 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
4944 | layout_binding.descriptorCount = set_ptr[j].length; |
4945 | } break; |
4946 | case UNIFORM_TYPE_TEXTURE: { |
4947 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; |
4948 | layout_binding.descriptorCount = set_ptr[j].length; |
4949 | } break; |
4950 | case UNIFORM_TYPE_IMAGE: { |
4951 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
4952 | layout_binding.descriptorCount = set_ptr[j].length; |
4953 | } break; |
4954 | case UNIFORM_TYPE_TEXTURE_BUFFER: { |
4955 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; |
4956 | layout_binding.descriptorCount = set_ptr[j].length; |
4957 | } break; |
4958 | case UNIFORM_TYPE_IMAGE_BUFFER: { |
4959 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; |
4960 | } break; |
4961 | case UNIFORM_TYPE_UNIFORM_BUFFER: { |
4962 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
4963 | } break; |
4964 | case UNIFORM_TYPE_STORAGE_BUFFER: { |
4965 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
4966 | } break; |
4967 | case UNIFORM_TYPE_INPUT_ATTACHMENT: { |
4968 | layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; |
4969 | } break; |
4970 | default: { |
4971 | ERR_FAIL_V(RID()); |
4972 | } |
4973 | } |
4974 | |
4975 | set_bindings.write[i].push_back(layout_binding); |
4976 | uniform_info.write[i].push_back(info); |
4977 | } |
4978 | |
4979 | read_offset += set_size; |
4980 | } |
4981 | |
4982 | ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) >= binsize, RID()); |
4983 | |
4984 | Vector<Shader::SpecializationConstant> specialization_constants; |
4985 | |
4986 | for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) { |
4987 | const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinarySpecializationConstant *>(binptr + read_offset)); |
4988 | Shader::SpecializationConstant sc; |
4989 | sc.constant.int_value = src_sc.int_value; |
4990 | sc.constant.type = PipelineSpecializationConstantType(src_sc.type); |
4991 | sc.constant.constant_id = src_sc.constant_id; |
4992 | sc.stage_flags = src_sc.stage_flags; |
4993 | specialization_constants.push_back(sc); |
4994 | |
4995 | read_offset += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant); |
4996 | } |
4997 | |
4998 | Vector<Vector<uint8_t>> stage_spirv_data; |
4999 | Vector<ShaderStage> stage_type; |
5000 | |
5001 | for (uint32_t i = 0; i < binary_data.stage_count; i++) { |
5002 | ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) * 3 >= binsize, RID()); |
5003 | uint32_t stage = decode_uint32(binptr + read_offset); |
5004 | read_offset += sizeof(uint32_t); |
5005 | uint32_t smolv_size = decode_uint32(binptr + read_offset); |
5006 | read_offset += sizeof(uint32_t); |
5007 | uint32_t zstd_size = decode_uint32(binptr + read_offset); |
5008 | read_offset += sizeof(uint32_t); |
5009 | |
5010 | uint32_t buf_size = (zstd_size > 0) ? zstd_size : smolv_size; |
5011 | |
5012 | Vector<uint8_t> smolv; |
5013 | const uint8_t *src_smolv = nullptr; |
5014 | |
5015 | if (zstd_size > 0) { |
5016 | // Decompress to smolv. |
5017 | smolv.resize(smolv_size); |
5018 | int dec_smolv_size = Compression::decompress(smolv.ptrw(), smolv.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD); |
5019 | ERR_FAIL_COND_V(dec_smolv_size != (int32_t)smolv_size, RID()); |
5020 | src_smolv = smolv.ptr(); |
5021 | } else { |
5022 | src_smolv = binptr + read_offset; |
5023 | } |
5024 | |
5025 | Vector<uint8_t> spirv; |
5026 | uint32_t spirv_size = smolv::GetDecodedBufferSize(src_smolv, smolv_size); |
5027 | spirv.resize(spirv_size); |
5028 | if (!smolv::Decode(src_smolv, smolv_size, spirv.ptrw(), spirv_size)) { |
5029 | ERR_FAIL_V_MSG(RID(), "Malformed smolv input uncompressing shader stage:" + String(shader_stage_names[stage])); |
5030 | } |
5031 | stage_spirv_data.push_back(spirv); |
5032 | stage_type.push_back(ShaderStage(stage)); |
5033 | |
5034 | if (buf_size % 4 != 0) { |
5035 | buf_size += 4 - (buf_size % 4); |
5036 | } |
5037 | |
5038 | ERR_FAIL_COND_V(read_offset + buf_size > binsize, RID()); |
5039 | |
5040 | read_offset += buf_size; |
5041 | } |
5042 | |
5043 | ERR_FAIL_COND_V(read_offset != binsize, RID()); |
5044 | |
5045 | // All good, let's create modules. |
5046 | |
5047 | _THREAD_SAFE_METHOD_ |
5048 | |
5049 | RID id; |
5050 | if (p_placeholder.is_null()) { |
5051 | id = shader_owner.make_rid(); |
5052 | } else { |
5053 | id = p_placeholder; |
5054 | } |
5055 | |
5056 | Shader *shader = shader_owner.get_or_null(id); |
5057 | |
5058 | shader->vertex_input_mask = vertex_input_mask; |
5059 | shader->fragment_output_mask = fragment_output_mask; |
5060 | shader->push_constant = push_constant; |
5061 | shader->is_compute = is_compute; |
5062 | shader->compute_local_size[0] = compute_local_size[0]; |
5063 | shader->compute_local_size[1] = compute_local_size[1]; |
5064 | shader->compute_local_size[2] = compute_local_size[2]; |
5065 | shader->specialization_constants = specialization_constants; |
5066 | shader->name = name; |
5067 | |
5068 | String error_text; |
5069 | |
5070 | bool success = true; |
5071 | for (int i = 0; i < stage_spirv_data.size(); i++) { |
5072 | VkShaderModuleCreateInfo shader_module_create_info; |
5073 | shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; |
5074 | shader_module_create_info.pNext = nullptr; |
5075 | shader_module_create_info.flags = 0; |
5076 | shader_module_create_info.codeSize = stage_spirv_data[i].size(); |
5077 | const uint8_t *r = stage_spirv_data[i].ptr(); |
5078 | |
5079 | shader_module_create_info.pCode = (const uint32_t *)r; |
5080 | |
5081 | VkShaderModule module; |
5082 | VkResult res = vkCreateShaderModule(device, &shader_module_create_info, nullptr, &module); |
5083 | if (res) { |
5084 | success = false; |
5085 | error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(shader_stage_names[stage_type[i]]); |
5086 | break; |
5087 | } |
5088 | |
5089 | VkPipelineShaderStageCreateInfo shader_stage; |
5090 | shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
5091 | shader_stage.pNext = nullptr; |
5092 | shader_stage.flags = 0; |
5093 | shader_stage.stage = shader_stage_masks[stage_type[i]]; |
5094 | shader_stage.module = module; |
5095 | shader_stage.pName = "main" ; |
5096 | shader_stage.pSpecializationInfo = nullptr; |
5097 | |
5098 | shader->pipeline_stages.push_back(shader_stage); |
5099 | } |
5100 | // Proceed to create descriptor sets. |
5101 | |
5102 | if (success) { |
5103 | for (int i = 0; i < set_bindings.size(); i++) { |
5104 | // Empty ones are fine if they were not used according to spec (binding count will be 0). |
5105 | VkDescriptorSetLayoutCreateInfo layout_create_info; |
5106 | layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; |
5107 | layout_create_info.pNext = nullptr; |
5108 | layout_create_info.flags = 0; |
5109 | layout_create_info.bindingCount = set_bindings[i].size(); |
5110 | layout_create_info.pBindings = set_bindings[i].ptr(); |
5111 | |
5112 | VkDescriptorSetLayout layout; |
5113 | VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, nullptr, &layout); |
5114 | if (res) { |
5115 | error_text = "Error (" + itos(res) + ") creating descriptor set layout for set " + itos(i); |
5116 | success = false; |
5117 | break; |
5118 | } |
5119 | |
5120 | Shader::Set set; |
5121 | set.descriptor_set_layout = layout; |
5122 | set.uniform_info = uniform_info[i]; |
5123 | // Sort and hash. |
5124 | set.uniform_info.sort(); |
5125 | |
5126 | uint32_t format = 0; // No format, default. |
5127 | |
5128 | if (set.uniform_info.size()) { |
5129 | // Has data, needs an actual format. |
5130 | UniformSetFormat usformat; |
5131 | usformat.uniform_info = set.uniform_info; |
5132 | RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat); |
5133 | if (E) { |
5134 | format = E->get(); |
5135 | } else { |
5136 | format = uniform_set_format_cache.size() + 1; |
5137 | uniform_set_format_cache.insert(usformat, format); |
5138 | } |
5139 | } |
5140 | |
5141 | shader->sets.push_back(set); |
5142 | shader->set_formats.push_back(format); |
5143 | } |
5144 | } |
5145 | |
5146 | if (success) { |
5147 | // Create pipeline layout. |
5148 | VkPipelineLayoutCreateInfo pipeline_layout_create_info; |
5149 | pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
5150 | pipeline_layout_create_info.pNext = nullptr; |
5151 | pipeline_layout_create_info.flags = 0; |
5152 | pipeline_layout_create_info.setLayoutCount = shader->sets.size(); |
5153 | |
5154 | Vector<VkDescriptorSetLayout> layouts; |
5155 | layouts.resize(shader->sets.size()); |
5156 | |
5157 | for (int i = 0; i < layouts.size(); i++) { |
5158 | layouts.write[i] = shader->sets[i].descriptor_set_layout; |
5159 | } |
5160 | |
5161 | pipeline_layout_create_info.pSetLayouts = layouts.ptr(); |
5162 | // Needs to be declared in this outer scope, otherwise it may not outlive its assignment |
5163 | // to pipeline_layout_create_info. |
5164 | VkPushConstantRange push_constant_range; |
5165 | if (push_constant.size) { |
5166 | push_constant_range.stageFlags = push_constant.vk_stages_mask; |
5167 | push_constant_range.offset = 0; |
5168 | push_constant_range.size = push_constant.size; |
5169 | |
5170 | pipeline_layout_create_info.pushConstantRangeCount = 1; |
5171 | pipeline_layout_create_info.pPushConstantRanges = &push_constant_range; |
5172 | } else { |
5173 | pipeline_layout_create_info.pushConstantRangeCount = 0; |
5174 | pipeline_layout_create_info.pPushConstantRanges = nullptr; |
5175 | } |
5176 | |
5177 | VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &shader->pipeline_layout); |
5178 | |
5179 | if (err) { |
5180 | error_text = "Error (" + itos(err) + ") creating pipeline layout." ; |
5181 | success = false; |
5182 | } |
5183 | } |
5184 | |
5185 | if (!success) { |
5186 | // Clean up if failed. |
5187 | for (int i = 0; i < shader->pipeline_stages.size(); i++) { |
5188 | vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr); |
5189 | } |
5190 | |
5191 | for (int i = 0; i < shader->sets.size(); i++) { |
5192 | vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr); |
5193 | } |
5194 | |
5195 | shader_owner.free(id); |
5196 | |
5197 | ERR_FAIL_V_MSG(RID(), error_text); |
5198 | } |
5199 | |
5200 | #ifdef DEV_ENABLED |
5201 | set_resource_name(id, "RID:" + itos(id.get_id())); |
5202 | #endif |
5203 | return id; |
5204 | } |
5205 | |
5206 | RID RenderingDeviceVulkan::shader_create_placeholder() { |
5207 | Shader shader; |
5208 | return shader_owner.make_rid(shader); |
5209 | } |
5210 | |
5211 | uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { |
5212 | _THREAD_SAFE_METHOD_ |
5213 | |
5214 | const Shader *shader = shader_owner.get_or_null(p_shader); |
5215 | ERR_FAIL_NULL_V(shader, 0); |
5216 | return shader->vertex_input_mask; |
5217 | } |
5218 | |
5219 | /******************/ |
5220 | /**** UNIFORMS ****/ |
5221 | /******************/ |
5222 | |
5223 | RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) { |
5224 | _THREAD_SAFE_METHOD_ |
5225 | |
5226 | ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); |
5227 | |
5228 | Buffer buffer; |
5229 | Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
5230 | ERR_FAIL_COND_V(err != OK, RID()); |
5231 | if (p_data.size()) { |
5232 | uint64_t data_size = p_data.size(); |
5233 | const uint8_t *r = p_data.ptr(); |
5234 | _buffer_update(&buffer, 0, r, data_size); |
5235 | _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); |
5236 | } |
5237 | RID id = uniform_buffer_owner.make_rid(buffer); |
5238 | #ifdef DEV_ENABLED |
5239 | set_resource_name(id, "RID:" + itos(id.get_id())); |
5240 | #endif |
5241 | return id; |
5242 | } |
5243 | |
5244 | RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, BitField<StorageBufferUsage> p_usage) { |
5245 | _THREAD_SAFE_METHOD_ |
5246 | |
5247 | ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); |
5248 | |
5249 | Buffer buffer; |
5250 | uint32_t flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
5251 | if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) { |
5252 | flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
5253 | } |
5254 | Error err = _buffer_allocate(&buffer, p_size_bytes, flags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
5255 | ERR_FAIL_COND_V(err != OK, RID()); |
5256 | |
5257 | if (p_data.size()) { |
5258 | uint64_t data_size = p_data.size(); |
5259 | const uint8_t *r = p_data.ptr(); |
5260 | _buffer_update(&buffer, 0, r, data_size); |
5261 | _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); |
5262 | } |
5263 | return storage_buffer_owner.make_rid(buffer); |
5264 | } |
5265 | |
5266 | RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) { |
5267 | _THREAD_SAFE_METHOD_ |
5268 | |
5269 | uint32_t element_size = get_format_vertex_size(p_format); |
5270 | ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers" ); |
5271 | uint64_t size_bytes = uint64_t(element_size) * p_size_elements; |
5272 | |
5273 | ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID()); |
5274 | |
5275 | TextureBuffer texture_buffer; |
5276 | Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); |
5277 | ERR_FAIL_COND_V(err != OK, RID()); |
5278 | |
5279 | if (p_data.size()) { |
5280 | uint64_t data_size = p_data.size(); |
5281 | const uint8_t *r = p_data.ptr(); |
5282 | _buffer_update(&texture_buffer.buffer, 0, r, data_size); |
5283 | _buffer_memory_barrier(texture_buffer.buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); |
5284 | } |
5285 | |
5286 | VkBufferViewCreateInfo view_create_info; |
5287 | view_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; |
5288 | view_create_info.pNext = nullptr; |
5289 | view_create_info.flags = 0; |
5290 | view_create_info.buffer = texture_buffer.buffer.buffer; |
5291 | view_create_info.format = vulkan_formats[p_format]; |
5292 | view_create_info.offset = 0; |
5293 | view_create_info.range = size_bytes; |
5294 | |
5295 | texture_buffer.view = VK_NULL_HANDLE; |
5296 | |
5297 | VkResult res = vkCreateBufferView(device, &view_create_info, nullptr, &texture_buffer.view); |
5298 | if (res) { |
5299 | _buffer_free(&texture_buffer.buffer); |
5300 | ERR_FAIL_V_MSG(RID(), "Unable to create buffer view, error " + itos(res) + "." ); |
5301 | } |
5302 | |
5303 | // Allocate the view. |
5304 | RID id = texture_buffer_owner.make_rid(texture_buffer); |
5305 | #ifdef DEV_ENABLED |
5306 | set_resource_name(id, "RID:" + itos(id.get_id())); |
5307 | #endif |
5308 | return id; |
5309 | } |
5310 | |
5311 | RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) { |
5312 | if (!descriptor_pools.has(p_key)) { |
5313 | descriptor_pools[p_key] = HashSet<DescriptorPool *>(); |
5314 | } |
5315 | |
5316 | DescriptorPool *pool = nullptr; |
5317 | |
5318 | for (DescriptorPool *E : descriptor_pools[p_key]) { |
5319 | if (E->usage < max_descriptors_per_pool) { |
5320 | pool = E; |
5321 | break; |
5322 | } |
5323 | } |
5324 | |
5325 | if (!pool) { |
5326 | // Create a new one. |
5327 | pool = memnew(DescriptorPool); |
5328 | pool->usage = 0; |
5329 | |
5330 | VkDescriptorPoolCreateInfo descriptor_pool_create_info; |
5331 | descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; |
5332 | descriptor_pool_create_info.pNext = nullptr; |
5333 | descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // Can't think how somebody may NOT need this flag. |
5334 | descriptor_pool_create_info.maxSets = max_descriptors_per_pool; |
5335 | Vector<VkDescriptorPoolSize> sizes; |
5336 | // Here comes more vulkan API strangeness. |
5337 | |
5338 | if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) { |
5339 | VkDescriptorPoolSize s; |
5340 | s.type = VK_DESCRIPTOR_TYPE_SAMPLER; |
5341 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER] * max_descriptors_per_pool; |
5342 | sizes.push_back(s); |
5343 | } |
5344 | if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE]) { |
5345 | VkDescriptorPoolSize s; |
5346 | s.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
5347 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE] * max_descriptors_per_pool; |
5348 | sizes.push_back(s); |
5349 | } |
5350 | if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE]) { |
5351 | VkDescriptorPoolSize s; |
5352 | s.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; |
5353 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_TEXTURE] * max_descriptors_per_pool; |
5354 | sizes.push_back(s); |
5355 | } |
5356 | if (p_key.uniform_type[UNIFORM_TYPE_IMAGE]) { |
5357 | VkDescriptorPoolSize s; |
5358 | s.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
5359 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE] * max_descriptors_per_pool; |
5360 | sizes.push_back(s); |
5361 | } |
5362 | if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] || p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) { |
5363 | VkDescriptorPoolSize s; |
5364 | s.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; |
5365 | s.descriptorCount = (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] + p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) * max_descriptors_per_pool; |
5366 | sizes.push_back(s); |
5367 | } |
5368 | if (p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER]) { |
5369 | VkDescriptorPoolSize s; |
5370 | s.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; |
5371 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER] * max_descriptors_per_pool; |
5372 | sizes.push_back(s); |
5373 | } |
5374 | if (p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER]) { |
5375 | VkDescriptorPoolSize s; |
5376 | s.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
5377 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER] * max_descriptors_per_pool; |
5378 | sizes.push_back(s); |
5379 | } |
5380 | |
5381 | if (p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER]) { |
5382 | VkDescriptorPoolSize s; |
5383 | s.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
5384 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER] * max_descriptors_per_pool; |
5385 | sizes.push_back(s); |
5386 | } |
5387 | |
5388 | if (p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT]) { |
5389 | VkDescriptorPoolSize s; |
5390 | s.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; |
5391 | s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT] * max_descriptors_per_pool; |
5392 | sizes.push_back(s); |
5393 | } |
5394 | |
5395 | descriptor_pool_create_info.poolSizeCount = sizes.size(); |
5396 | descriptor_pool_create_info.pPoolSizes = sizes.ptr(); |
5397 | VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &pool->pool); |
5398 | if (res) { |
5399 | memdelete(pool); |
5400 | ERR_FAIL_COND_V_MSG(res, nullptr, "vkCreateDescriptorPool failed with error " + itos(res) + "." ); |
5401 | } |
5402 | descriptor_pools[p_key].insert(pool); |
5403 | } |
5404 | |
5405 | pool->usage++; |
5406 | |
5407 | return pool; |
5408 | } |
5409 | |
5410 | void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool) { |
5411 | #ifdef DEBUG_ENABLED |
5412 | ERR_FAIL_COND(!descriptor_pools[p_key].has(p_pool)); |
5413 | #endif |
5414 | ERR_FAIL_COND(p_pool->usage == 0); |
5415 | p_pool->usage--; |
5416 | if (p_pool->usage == 0) { |
5417 | vkDestroyDescriptorPool(device, p_pool->pool, nullptr); |
5418 | descriptor_pools[p_key].erase(p_pool); |
5419 | memdelete(p_pool); |
5420 | if (descriptor_pools[p_key].is_empty()) { |
5421 | descriptor_pools.erase(p_key); |
5422 | } |
5423 | } |
5424 | } |
5425 | |
5426 | RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) { |
5427 | _THREAD_SAFE_METHOD_ |
5428 | |
5429 | ERR_FAIL_COND_V(p_uniforms.size() == 0, RID()); |
5430 | |
5431 | Shader *shader = shader_owner.get_or_null(p_shader); |
5432 | ERR_FAIL_NULL_V(shader, RID()); |
5433 | |
5434 | ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(), |
5435 | "Desired set (" + itos(p_shader_set) + ") not used by shader." ); |
5436 | // See that all sets in shader are satisfied. |
5437 | |
5438 | const Shader::Set &set = shader->sets[p_shader_set]; |
5439 | |
5440 | uint32_t uniform_count = p_uniforms.size(); |
5441 | const Uniform *uniforms = p_uniforms.ptr(); |
5442 | |
5443 | uint32_t set_uniform_count = set.uniform_info.size(); |
5444 | const UniformInfo *set_uniforms = set.uniform_info.ptr(); |
5445 | |
5446 | Vector<VkWriteDescriptorSet> writes; |
5447 | DescriptorPoolKey pool_key; |
5448 | |
5449 | // To keep them alive until update call. |
5450 | List<Vector<VkDescriptorBufferInfo>> buffer_infos; |
5451 | List<Vector<VkBufferView>> buffer_views; |
5452 | List<Vector<VkDescriptorImageInfo>> image_infos; |
5453 | // Used for verification to make sure a uniform set does not use a framebuffer bound texture. |
5454 | LocalVector<UniformSet::AttachableTexture> attachable_textures; |
5455 | Vector<Texture *> mutable_sampled_textures; |
5456 | Vector<Texture *> mutable_storage_textures; |
5457 | |
5458 | for (uint32_t i = 0; i < set_uniform_count; i++) { |
5459 | const UniformInfo &set_uniform = set_uniforms[i]; |
5460 | int uniform_idx = -1; |
5461 | for (int j = 0; j < (int)uniform_count; j++) { |
5462 | if (uniforms[j].binding == set_uniform.binding) { |
5463 | uniform_idx = j; |
5464 | } |
5465 | } |
5466 | ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(), |
5467 | "All the shader bindings for the given set must be covered by the uniforms provided. Binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + ") was not provided." ); |
5468 | |
5469 | const Uniform &uniform = uniforms[uniform_idx]; |
5470 | |
5471 | ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(), |
5472 | "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.uniform_type] + "'." ); |
5473 | |
5474 | VkWriteDescriptorSet write; // Common header. |
5475 | write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; |
5476 | write.pNext = nullptr; |
5477 | write.dstSet = VK_NULL_HANDLE; // Will assign afterwards when everything is valid. |
5478 | write.dstBinding = set_uniform.binding; |
5479 | write.dstArrayElement = 0; |
5480 | write.descriptorCount = 0; |
5481 | write.descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; // Invalid value. |
5482 | write.pImageInfo = nullptr; |
5483 | write.pBufferInfo = nullptr; |
5484 | write.pTexelBufferView = nullptr; |
5485 | uint32_t type_size = 1; |
5486 | |
5487 | switch (uniform.uniform_type) { |
5488 | case UNIFORM_TYPE_SAMPLER: { |
5489 | if (uniform.get_id_count() != (uint32_t)set_uniform.length) { |
5490 | if (set_uniform.length > 1) { |
5491 | ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5492 | } else { |
5493 | ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5494 | } |
5495 | } |
5496 | |
5497 | Vector<VkDescriptorImageInfo> image_info; |
5498 | |
5499 | for (uint32_t j = 0; j < uniform.get_id_count(); j++) { |
5500 | VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j)); |
5501 | ERR_FAIL_NULL_V_MSG(sampler, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler." ); |
5502 | |
5503 | VkDescriptorImageInfo img_info; |
5504 | img_info.sampler = *sampler; |
5505 | img_info.imageView = VK_NULL_HANDLE; |
5506 | img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
5507 | |
5508 | image_info.push_back(img_info); |
5509 | } |
5510 | |
5511 | write.dstArrayElement = 0; |
5512 | write.descriptorCount = uniform.get_id_count(); |
5513 | write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; |
5514 | write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); |
5515 | write.pBufferInfo = nullptr; |
5516 | write.pTexelBufferView = nullptr; |
5517 | |
5518 | type_size = uniform.get_id_count(); |
5519 | |
5520 | } break; |
5521 | case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: { |
5522 | if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) { |
5523 | if (set_uniform.length > 1) { |
5524 | ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5525 | } else { |
5526 | ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5527 | } |
5528 | } |
5529 | |
5530 | Vector<VkDescriptorImageInfo> image_info; |
5531 | |
5532 | for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) { |
5533 | VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0)); |
5534 | ERR_FAIL_NULL_V_MSG(sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler." ); |
5535 | |
5536 | Texture *texture = texture_owner.get_or_null(uniform.get_id(j + 1)); |
5537 | ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture." ); |
5538 | |
5539 | ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), |
5540 | "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform." ); |
5541 | |
5542 | VkDescriptorImageInfo img_info; |
5543 | img_info.sampler = *sampler; |
5544 | img_info.imageView = texture->view; |
5545 | |
5546 | if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) { |
5547 | UniformSet::AttachableTexture attachable_texture; |
5548 | attachable_texture.bind = set_uniform.binding; |
5549 | attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1); |
5550 | attachable_textures.push_back(attachable_texture); |
5551 | } |
5552 | |
5553 | if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { |
5554 | // Can also be used as storage, add to mutable sampled. |
5555 | mutable_sampled_textures.push_back(texture); |
5556 | } |
5557 | |
5558 | DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); |
5559 | |
5560 | img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
5561 | |
5562 | image_info.push_back(img_info); |
5563 | } |
5564 | |
5565 | write.dstArrayElement = 0; |
5566 | write.descriptorCount = uniform.get_id_count() / 2; |
5567 | write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
5568 | write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); |
5569 | write.pBufferInfo = nullptr; |
5570 | write.pTexelBufferView = nullptr; |
5571 | |
5572 | type_size = uniform.get_id_count() / 2; |
5573 | |
5574 | } break; |
5575 | case UNIFORM_TYPE_TEXTURE: { |
5576 | if (uniform.get_id_count() != (uint32_t)set_uniform.length) { |
5577 | if (set_uniform.length > 1) { |
5578 | ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5579 | } else { |
5580 | ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5581 | } |
5582 | } |
5583 | |
5584 | Vector<VkDescriptorImageInfo> image_info; |
5585 | |
5586 | for (uint32_t j = 0; j < uniform.get_id_count(); j++) { |
5587 | Texture *texture = texture_owner.get_or_null(uniform.get_id(j)); |
5588 | ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture." ); |
5589 | |
5590 | ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), |
5591 | "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform." ); |
5592 | |
5593 | VkDescriptorImageInfo img_info; |
5594 | img_info.sampler = VK_NULL_HANDLE; |
5595 | img_info.imageView = texture->view; |
5596 | |
5597 | if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) { |
5598 | UniformSet::AttachableTexture attachable_texture; |
5599 | attachable_texture.bind = set_uniform.binding; |
5600 | attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j); |
5601 | attachable_textures.push_back(attachable_texture); |
5602 | } |
5603 | |
5604 | if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { |
5605 | // Can also be used as storage, add to mutable sampled. |
5606 | mutable_sampled_textures.push_back(texture); |
5607 | } |
5608 | |
5609 | DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); |
5610 | |
5611 | img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
5612 | |
5613 | image_info.push_back(img_info); |
5614 | } |
5615 | |
5616 | write.dstArrayElement = 0; |
5617 | write.descriptorCount = uniform.get_id_count(); |
5618 | write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; |
5619 | write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); |
5620 | write.pBufferInfo = nullptr; |
5621 | write.pTexelBufferView = nullptr; |
5622 | |
5623 | type_size = uniform.get_id_count(); |
5624 | } break; |
5625 | case UNIFORM_TYPE_IMAGE: { |
5626 | if (uniform.get_id_count() != (uint32_t)set_uniform.length) { |
5627 | if (set_uniform.length > 1) { |
5628 | ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5629 | } else { |
5630 | ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5631 | } |
5632 | } |
5633 | |
5634 | Vector<VkDescriptorImageInfo> image_info; |
5635 | |
5636 | for (uint32_t j = 0; j < uniform.get_id_count(); j++) { |
5637 | Texture *texture = texture_owner.get_or_null(uniform.get_id(j)); |
5638 | |
5639 | ERR_FAIL_NULL_V_MSG(texture, RID(), |
5640 | "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture." ); |
5641 | |
5642 | ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(), |
5643 | "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform." ); |
5644 | |
5645 | VkDescriptorImageInfo img_info; |
5646 | img_info.sampler = VK_NULL_HANDLE; |
5647 | img_info.imageView = texture->view; |
5648 | |
5649 | if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { |
5650 | // Can also be used as storage, add to mutable sampled. |
5651 | mutable_storage_textures.push_back(texture); |
5652 | } |
5653 | |
5654 | DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); |
5655 | |
5656 | img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; |
5657 | |
5658 | image_info.push_back(img_info); |
5659 | } |
5660 | |
5661 | write.dstArrayElement = 0; |
5662 | write.descriptorCount = uniform.get_id_count(); |
5663 | write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; |
5664 | write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); |
5665 | write.pBufferInfo = nullptr; |
5666 | write.pTexelBufferView = nullptr; |
5667 | |
5668 | type_size = uniform.get_id_count(); |
5669 | |
5670 | } break; |
5671 | case UNIFORM_TYPE_TEXTURE_BUFFER: { |
5672 | if (uniform.get_id_count() != (uint32_t)set_uniform.length) { |
5673 | if (set_uniform.length > 1) { |
5674 | ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5675 | } else { |
5676 | ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5677 | } |
5678 | } |
5679 | |
5680 | Vector<VkDescriptorBufferInfo> buffer_info; |
5681 | Vector<VkBufferView> buffer_view; |
5682 | |
5683 | for (uint32_t j = 0; j < uniform.get_id_count(); j++) { |
5684 | TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j)); |
5685 | ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer." ); |
5686 | |
5687 | buffer_info.push_back(buffer->buffer.buffer_info); |
5688 | buffer_view.push_back(buffer->view); |
5689 | } |
5690 | |
5691 | write.dstArrayElement = 0; |
5692 | write.descriptorCount = uniform.get_id_count(); |
5693 | write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; |
5694 | write.pImageInfo = nullptr; |
5695 | write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr(); |
5696 | write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr(); |
5697 | |
5698 | type_size = uniform.get_id_count(); |
5699 | |
5700 | } break; |
5701 | case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: { |
5702 | if (uniform.get_id_count() != (uint32_t)set_uniform.length * 2) { |
5703 | if (set_uniform.length > 1) { |
5704 | ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5705 | } else { |
5706 | ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5707 | } |
5708 | } |
5709 | |
5710 | Vector<VkDescriptorImageInfo> image_info; |
5711 | Vector<VkDescriptorBufferInfo> buffer_info; |
5712 | Vector<VkBufferView> buffer_view; |
5713 | |
5714 | for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) { |
5715 | VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0)); |
5716 | ERR_FAIL_NULL_V_MSG(sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler." ); |
5717 | |
5718 | TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1)); |
5719 | |
5720 | VkDescriptorImageInfo img_info; |
5721 | img_info.sampler = *sampler; |
5722 | img_info.imageView = VK_NULL_HANDLE; |
5723 | img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
5724 | |
5725 | image_info.push_back(img_info); |
5726 | |
5727 | ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer." ); |
5728 | |
5729 | buffer_info.push_back(buffer->buffer.buffer_info); |
5730 | buffer_view.push_back(buffer->view); |
5731 | } |
5732 | |
5733 | write.dstArrayElement = 0; |
5734 | write.descriptorCount = uniform.get_id_count() / 2; |
5735 | write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; |
5736 | write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); |
5737 | write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr(); |
5738 | write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr(); |
5739 | |
5740 | type_size = uniform.get_id_count() / 2; |
5741 | } break; |
5742 | case UNIFORM_TYPE_IMAGE_BUFFER: { |
5743 | // Todo. |
5744 | |
5745 | } break; |
5746 | case UNIFORM_TYPE_UNIFORM_BUFFER: { |
5747 | ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(), |
5748 | "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided)." ); |
5749 | |
5750 | Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.get_id(0)); |
5751 | ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid." ); |
5752 | |
5753 | ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), |
5754 | "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")." ); |
5755 | |
5756 | write.dstArrayElement = 0; |
5757 | write.descriptorCount = 1; |
5758 | write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
5759 | write.pImageInfo = nullptr; |
5760 | write.pBufferInfo = &buffer->buffer_info; |
5761 | write.pTexelBufferView = nullptr; |
5762 | |
5763 | } break; |
5764 | case UNIFORM_TYPE_STORAGE_BUFFER: { |
5765 | ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(), |
5766 | "Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided)." ); |
5767 | |
5768 | Buffer *buffer = nullptr; |
5769 | |
5770 | if (storage_buffer_owner.owns(uniform.get_id(0))) { |
5771 | buffer = storage_buffer_owner.get_or_null(uniform.get_id(0)); |
5772 | } else if (vertex_buffer_owner.owns(uniform.get_id(0))) { |
5773 | buffer = vertex_buffer_owner.get_or_null(uniform.get_id(0)); |
5774 | |
5775 | ERR_FAIL_COND_V_MSG(!(buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag." ); |
5776 | } |
5777 | ERR_FAIL_NULL_V_MSG(buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid." ); |
5778 | |
5779 | // If 0, then it's sized on link time. |
5780 | ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(), |
5781 | "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")." ); |
5782 | |
5783 | write.dstArrayElement = 0; |
5784 | write.descriptorCount = 1; |
5785 | write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
5786 | write.pImageInfo = nullptr; |
5787 | write.pBufferInfo = &buffer->buffer_info; |
5788 | write.pTexelBufferView = nullptr; |
5789 | } break; |
5790 | case UNIFORM_TYPE_INPUT_ATTACHMENT: { |
5791 | ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed)." ); |
5792 | |
5793 | if (uniform.get_id_count() != (uint32_t)set_uniform.length) { |
5794 | if (set_uniform.length > 1) { |
5795 | ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5796 | } else { |
5797 | ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ")." ); |
5798 | } |
5799 | } |
5800 | |
5801 | Vector<VkDescriptorImageInfo> image_info; |
5802 | |
5803 | for (uint32_t j = 0; j < uniform.get_id_count(); j++) { |
5804 | Texture *texture = texture_owner.get_or_null(uniform.get_id(j)); |
5805 | |
5806 | ERR_FAIL_NULL_V_MSG(texture, RID(), |
5807 | "InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture." ); |
5808 | |
5809 | ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), |
5810 | "InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform." ); |
5811 | |
5812 | VkDescriptorImageInfo img_info; |
5813 | img_info.sampler = VK_NULL_HANDLE; |
5814 | img_info.imageView = texture->view; |
5815 | |
5816 | DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); |
5817 | |
5818 | img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
5819 | |
5820 | image_info.push_back(img_info); |
5821 | } |
5822 | |
5823 | write.dstArrayElement = 0; |
5824 | write.descriptorCount = uniform.get_id_count(); |
5825 | write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; |
5826 | write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); |
5827 | write.pBufferInfo = nullptr; |
5828 | write.pTexelBufferView = nullptr; |
5829 | |
5830 | type_size = uniform.get_id_count(); |
5831 | } break; |
5832 | default: { |
5833 | } |
5834 | } |
5835 | |
5836 | writes.push_back(write); |
5837 | |
5838 | ERR_FAIL_COND_V_MSG(pool_key.uniform_type[set_uniform.type] == MAX_DESCRIPTOR_POOL_ELEMENT, RID(), |
5839 | "Uniform set reached the limit of bindings for the same type (" + itos(MAX_DESCRIPTOR_POOL_ELEMENT) + ")." ); |
5840 | pool_key.uniform_type[set_uniform.type] += type_size; |
5841 | } |
5842 | |
5843 | // Need a descriptor pool. |
5844 | DescriptorPool *pool = _descriptor_pool_allocate(pool_key); |
5845 | |
5846 | ERR_FAIL_NULL_V(pool, RID()); |
5847 | |
5848 | VkDescriptorSetAllocateInfo descriptor_set_allocate_info; |
5849 | |
5850 | descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; |
5851 | descriptor_set_allocate_info.pNext = nullptr; |
5852 | descriptor_set_allocate_info.descriptorPool = pool->pool; |
5853 | descriptor_set_allocate_info.descriptorSetCount = 1; |
5854 | descriptor_set_allocate_info.pSetLayouts = &shader->sets[p_shader_set].descriptor_set_layout; |
5855 | |
5856 | VkDescriptorSet descriptor_set; |
5857 | |
5858 | VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &descriptor_set); |
5859 | if (res) { |
5860 | _descriptor_pool_free(pool_key, pool); // Meh. |
5861 | ERR_FAIL_V_MSG(RID(), "Cannot allocate descriptor sets, error " + itos(res) + "." ); |
5862 | } |
5863 | |
5864 | UniformSet uniform_set; |
5865 | uniform_set.pool = pool; |
5866 | uniform_set.pool_key = pool_key; |
5867 | uniform_set.descriptor_set = descriptor_set; |
5868 | uniform_set.format = shader->set_formats[p_shader_set]; |
5869 | uniform_set.attachable_textures = attachable_textures; |
5870 | uniform_set.mutable_sampled_textures = mutable_sampled_textures; |
5871 | uniform_set.mutable_storage_textures = mutable_storage_textures; |
5872 | uniform_set.shader_set = p_shader_set; |
5873 | uniform_set.shader_id = p_shader; |
5874 | |
5875 | RID id = uniform_set_owner.make_rid(uniform_set); |
5876 | #ifdef DEV_ENABLED |
5877 | set_resource_name(id, "RID:" + itos(id.get_id())); |
5878 | #endif |
5879 | // Add dependencies. |
5880 | _add_dependency(id, p_shader); |
5881 | for (uint32_t i = 0; i < uniform_count; i++) { |
5882 | const Uniform &uniform = uniforms[i]; |
5883 | int id_count = uniform.get_id_count(); |
5884 | for (int j = 0; j < id_count; j++) { |
5885 | _add_dependency(id, uniform.get_id(j)); |
5886 | } |
5887 | } |
5888 | |
5889 | // Write the contents. |
5890 | if (writes.size()) { |
5891 | for (int i = 0; i < writes.size(); i++) { |
5892 | writes.write[i].dstSet = descriptor_set; |
5893 | } |
5894 | vkUpdateDescriptorSets(device, writes.size(), writes.ptr(), 0, nullptr); |
5895 | } |
5896 | |
5897 | return id; |
5898 | } |
5899 | |
5900 | bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { |
5901 | return uniform_set_owner.owns(p_uniform_set); |
5902 | } |
5903 | |
5904 | void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) { |
5905 | UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set); |
5906 | ERR_FAIL_NULL(us); |
5907 | us->invalidated_callback = p_callback; |
5908 | us->invalidated_callback_userdata = p_userdata; |
5909 | } |
5910 | |
5911 | Error RenderingDeviceVulkan::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) { |
5912 | _THREAD_SAFE_METHOD_ |
5913 | |
5914 | ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER, |
5915 | "Copying buffers is forbidden during creation of a draw list" ); |
5916 | ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER, |
5917 | "Copying buffers is forbidden during creation of a compute list" ); |
5918 | |
5919 | // This method assumes the barriers have been pushed prior to being called, therefore no barriers are pushed |
5920 | // for the source or destination buffers before performing the copy. These masks are effectively ignored. |
5921 | VkPipelineShaderStageCreateFlags src_stage_mask = 0; |
5922 | VkAccessFlags src_access_mask = 0; |
5923 | Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_NO_BARRIER); |
5924 | if (!src_buffer) { |
5925 | ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Source buffer argument is not a valid buffer of any type." ); |
5926 | } |
5927 | |
5928 | VkPipelineStageFlags dst_stage_mask = 0; |
5929 | VkAccessFlags dst_access = 0; |
5930 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
5931 | // If the post barrier mask defines it, we indicate the destination buffer will require a barrier with these flags set |
5932 | // after the copy command is queued. |
5933 | dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; |
5934 | dst_access = VK_ACCESS_TRANSFER_WRITE_BIT; |
5935 | } |
5936 | |
5937 | Buffer *dst_buffer = _get_buffer_from_owner(p_dst_buffer, dst_stage_mask, dst_access, p_post_barrier); |
5938 | if (!dst_buffer) { |
5939 | ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Destination buffer argument is not a valid buffer of any type." ); |
5940 | } |
5941 | |
5942 | // Validate the copy's dimensions for both buffers. |
5943 | ERR_FAIL_COND_V_MSG((p_size + p_src_offset) > src_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the source buffer." ); |
5944 | ERR_FAIL_COND_V_MSG((p_size + p_dst_offset) > dst_buffer->size, ERR_INVALID_PARAMETER, "Size is larger than the destination buffer." ); |
5945 | |
5946 | // Perform the copy. |
5947 | VkBufferCopy region; |
5948 | region.srcOffset = p_src_offset; |
5949 | region.dstOffset = p_dst_offset; |
5950 | region.size = p_size; |
5951 | vkCmdCopyBuffer(frames[frame].draw_command_buffer, src_buffer->buffer, dst_buffer->buffer, 1, ®ion); |
5952 | |
5953 | #ifdef FORCE_FULL_BARRIER |
5954 | _full_barrier(true); |
5955 | #else |
5956 | if (dst_stage_mask == 0) { |
5957 | dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
5958 | } |
5959 | |
5960 | // As indicated by the post barrier mask, push a new barrier. |
5961 | if (p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) { |
5962 | _buffer_memory_barrier(dst_buffer->buffer, p_dst_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true); |
5963 | } |
5964 | #endif |
5965 | |
5966 | return OK; |
5967 | } |
5968 | |
5969 | Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) { |
5970 | _THREAD_SAFE_METHOD_ |
5971 | |
5972 | ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER, |
5973 | "Updating buffers is forbidden during creation of a draw list" ); |
5974 | ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER, |
5975 | "Updating buffers is forbidden during creation of a compute list" ); |
5976 | |
5977 | VkPipelineStageFlags dst_stage_mask = 0; |
5978 | VkAccessFlags dst_access = 0; |
5979 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
5980 | // Protect subsequent updates. |
5981 | dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; |
5982 | dst_access = VK_ACCESS_TRANSFER_WRITE_BIT; |
5983 | } |
5984 | Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stage_mask, dst_access, p_post_barrier); |
5985 | if (!buffer) { |
5986 | ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type." ); |
5987 | } |
5988 | |
5989 | ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, |
5990 | "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end." ); |
5991 | |
5992 | // No barrier should be needed here. |
5993 | // _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, true); |
5994 | |
5995 | Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_post_barrier); |
5996 | if (err) { |
5997 | return err; |
5998 | } |
5999 | |
6000 | #ifdef FORCE_FULL_BARRIER |
6001 | _full_barrier(true); |
6002 | #else |
6003 | if (dst_stage_mask == 0) { |
6004 | dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
6005 | } |
6006 | |
6007 | if (p_post_barrier != RD::BARRIER_MASK_NO_BARRIER) { |
6008 | _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true); |
6009 | } |
6010 | |
6011 | #endif |
6012 | return err; |
6013 | } |
6014 | |
6015 | Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) { |
6016 | _THREAD_SAFE_METHOD_ |
6017 | |
6018 | ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER, |
6019 | "Size must be a multiple of four" ); |
6020 | ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER, |
6021 | "Updating buffers in is forbidden during creation of a draw list" ); |
6022 | ERR_FAIL_COND_V_MSG(compute_list, ERR_INVALID_PARAMETER, |
6023 | "Updating buffers is forbidden during creation of a compute list" ); |
6024 | |
6025 | VkPipelineStageFlags dst_stage_mask = 0; |
6026 | VkAccessFlags dst_access = 0; |
6027 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
6028 | // Protect subsequent updates. |
6029 | dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; |
6030 | dst_access = VK_ACCESS_TRANSFER_WRITE_BIT; |
6031 | } |
6032 | |
6033 | Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stage_mask, dst_access, p_post_barrier); |
6034 | if (!buffer) { |
6035 | ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type." ); |
6036 | } |
6037 | |
6038 | ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, |
6039 | "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end." ); |
6040 | |
6041 | // Should not be needed. |
6042 | // _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, p_post_barrier); |
6043 | |
6044 | vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size, 0); |
6045 | |
6046 | #ifdef FORCE_FULL_BARRIER |
6047 | _full_barrier(true); |
6048 | #else |
6049 | if (dst_stage_mask == 0) { |
6050 | dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
6051 | } |
6052 | |
6053 | _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, dst_stage_mask); |
6054 | |
6055 | #endif |
6056 | return OK; |
6057 | } |
6058 | |
6059 | Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer, uint32_t p_offset, uint32_t p_size) { |
6060 | _THREAD_SAFE_METHOD_ |
6061 | |
6062 | // It could be this buffer was just created. |
6063 | VkPipelineShaderStageCreateFlags src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; |
6064 | VkAccessFlags src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT; |
6065 | // Get the vulkan buffer and the potential stage/access possible. |
6066 | Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL_BARRIERS); |
6067 | if (!buffer) { |
6068 | ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving." ); |
6069 | } |
6070 | |
6071 | // Make sure no one is using the buffer -- the "true" gets us to the same command buffer as below. |
6072 | _buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, src_access_mask, VK_ACCESS_TRANSFER_READ_BIT, true); |
6073 | |
6074 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; |
6075 | |
6076 | // Size of buffer to retrieve. |
6077 | if (!p_size) { |
6078 | p_size = buffer->size; |
6079 | } else { |
6080 | ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector<uint8_t>(), |
6081 | "Size is larger than the buffer." ); |
6082 | } |
6083 | |
6084 | Buffer tmp_buffer; |
6085 | _buffer_allocate(&tmp_buffer, p_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT); |
6086 | VkBufferCopy region; |
6087 | region.srcOffset = p_offset; |
6088 | region.dstOffset = 0; |
6089 | region.size = p_size; |
6090 | vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, ®ion); // Dst buffer is in CPU, but I wonder if src buffer needs a barrier for this. |
6091 | // Flush everything so memory can be safely mapped. |
6092 | _flush(true); |
6093 | |
6094 | void *buffer_mem; |
6095 | VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); |
6096 | ERR_FAIL_COND_V_MSG(vkerr, Vector<uint8_t>(), "vmaMapMemory failed with error " + itos(vkerr) + "." ); |
6097 | |
6098 | Vector<uint8_t> buffer_data; |
6099 | { |
6100 | buffer_data.resize(p_size); |
6101 | uint8_t *w = buffer_data.ptrw(); |
6102 | memcpy(w, buffer_mem, p_size); |
6103 | } |
6104 | |
6105 | vmaUnmapMemory(allocator, tmp_buffer.allocation); |
6106 | |
6107 | _buffer_free(&tmp_buffer); |
6108 | |
6109 | return buffer_data; |
6110 | } |
6111 | |
6112 | /*************************/ |
6113 | /**** RENDER PIPELINE ****/ |
6114 | /*************************/ |
6115 | |
6116 | RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { |
6117 | _THREAD_SAFE_METHOD_ |
6118 | |
6119 | // Needs a shader. |
6120 | Shader *shader = shader_owner.get_or_null(p_shader); |
6121 | ERR_FAIL_NULL_V(shader, RID()); |
6122 | |
6123 | ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), |
6124 | "Compute shaders can't be used in render pipelines" ); |
6125 | |
6126 | if (p_framebuffer_format == INVALID_ID) { |
6127 | // If nothing provided, use an empty one (no attachments). |
6128 | p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>()); |
6129 | } |
6130 | ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID()); |
6131 | const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format]; |
6132 | |
6133 | { // Validate shader vs framebuffer. |
6134 | |
6135 | ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.E->key().passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds" ); |
6136 | const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass]; |
6137 | uint32_t output_mask = 0; |
6138 | for (int i = 0; i < pass.color_attachments.size(); i++) { |
6139 | if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) { |
6140 | output_mask |= 1 << i; |
6141 | } |
6142 | } |
6143 | ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(), |
6144 | "Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline." ); |
6145 | } |
6146 | // Vertex. |
6147 | VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info; |
6148 | |
6149 | if (p_vertex_format != INVALID_ID) { |
6150 | // Uses vertices, else it does not. |
6151 | ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); |
6152 | const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; |
6153 | |
6154 | pipeline_vertex_input_state_create_info = vd.create_info; |
6155 | |
6156 | // Validate with inputs. |
6157 | for (uint32_t i = 0; i < 32; i++) { |
6158 | if (!(shader->vertex_input_mask & (1UL << i))) { |
6159 | continue; |
6160 | } |
6161 | bool found = false; |
6162 | for (int j = 0; j < vd.vertex_formats.size(); j++) { |
6163 | if (vd.vertex_formats[j].location == i) { |
6164 | found = true; |
6165 | } |
6166 | } |
6167 | |
6168 | ERR_FAIL_COND_V_MSG(!found, RID(), |
6169 | "Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation." ); |
6170 | } |
6171 | |
6172 | } else { |
6173 | // Does not use vertices. |
6174 | pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; |
6175 | pipeline_vertex_input_state_create_info.pNext = nullptr; |
6176 | pipeline_vertex_input_state_create_info.flags = 0; |
6177 | pipeline_vertex_input_state_create_info.vertexBindingDescriptionCount = 0; |
6178 | pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = nullptr; |
6179 | pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0; |
6180 | pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = nullptr; |
6181 | |
6182 | ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(), |
6183 | "Shader contains vertex inputs, but no vertex input description was provided for pipeline creation." ); |
6184 | } |
6185 | // Input assembly. |
6186 | |
6187 | ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID()); |
6188 | |
6189 | VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info; |
6190 | input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; |
6191 | input_assembly_create_info.pNext = nullptr; |
6192 | input_assembly_create_info.flags = 0; |
6193 | |
6194 | static const VkPrimitiveTopology topology_list[RENDER_PRIMITIVE_MAX] = { |
6195 | VK_PRIMITIVE_TOPOLOGY_POINT_LIST, |
6196 | VK_PRIMITIVE_TOPOLOGY_LINE_LIST, |
6197 | VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, |
6198 | VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, |
6199 | VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, |
6200 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, |
6201 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, |
6202 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, |
6203 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, |
6204 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, |
6205 | VK_PRIMITIVE_TOPOLOGY_PATCH_LIST |
6206 | }; |
6207 | |
6208 | input_assembly_create_info.topology = topology_list[p_render_primitive]; |
6209 | input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX); |
6210 | |
6211 | // Tessellation. |
6212 | VkPipelineTessellationStateCreateInfo tessellation_create_info; |
6213 | tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; |
6214 | tessellation_create_info.pNext = nullptr; |
6215 | tessellation_create_info.flags = 0; |
6216 | ERR_FAIL_COND_V(limits.maxTessellationPatchSize > 0 && (p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize), RID()); |
6217 | tessellation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; |
6218 | |
6219 | VkPipelineViewportStateCreateInfo viewport_state_create_info; |
6220 | viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; |
6221 | viewport_state_create_info.pNext = nullptr; |
6222 | viewport_state_create_info.flags = 0; |
6223 | viewport_state_create_info.viewportCount = 1; // If VR extensions are supported at some point, this will have to be customizable in the framebuffer format. |
6224 | viewport_state_create_info.pViewports = nullptr; |
6225 | viewport_state_create_info.scissorCount = 1; |
6226 | viewport_state_create_info.pScissors = nullptr; |
6227 | |
6228 | // Rasterization. |
6229 | VkPipelineRasterizationStateCreateInfo rasterization_state_create_info; |
6230 | rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; |
6231 | rasterization_state_create_info.pNext = nullptr; |
6232 | rasterization_state_create_info.flags = 0; |
6233 | rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp; |
6234 | rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives; |
6235 | rasterization_state_create_info.polygonMode = (p_rasterization_state.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL); |
6236 | static const VkCullModeFlags cull_mode[3] = { |
6237 | VK_CULL_MODE_NONE, |
6238 | VK_CULL_MODE_FRONT_BIT, |
6239 | VK_CULL_MODE_BACK_BIT |
6240 | }; |
6241 | |
6242 | ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID()); |
6243 | rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode]; |
6244 | rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); |
6245 | rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enabled; |
6246 | rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor; |
6247 | rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp; |
6248 | rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor; |
6249 | rasterization_state_create_info.lineWidth = p_rasterization_state.line_width; |
6250 | |
6251 | // Multisample. |
6252 | VkPipelineMultisampleStateCreateInfo multisample_state_create_info; |
6253 | multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; |
6254 | multisample_state_create_info.pNext = nullptr; |
6255 | multisample_state_create_info.flags = 0; |
6256 | |
6257 | multisample_state_create_info.rasterizationSamples = _ensure_supported_sample_count(p_multisample_state.sample_count); |
6258 | multisample_state_create_info.sampleShadingEnable = p_multisample_state.enable_sample_shading; |
6259 | multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading; |
6260 | Vector<VkSampleMask> sample_mask; |
6261 | if (p_multisample_state.sample_mask.size()) { |
6262 | // Use sample mask. |
6263 | const int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = { |
6264 | 1, 2, 4, 8, 16, 32, 64 |
6265 | }; |
6266 | ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID()); |
6267 | sample_mask.resize(p_multisample_state.sample_mask.size()); |
6268 | for (int i = 0; i < p_multisample_state.sample_mask.size(); i++) { |
6269 | VkSampleMask mask = p_multisample_state.sample_mask[i]; |
6270 | sample_mask.push_back(mask); |
6271 | } |
6272 | multisample_state_create_info.pSampleMask = sample_mask.ptr(); |
6273 | } else { |
6274 | multisample_state_create_info.pSampleMask = nullptr; |
6275 | } |
6276 | |
6277 | multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage; |
6278 | multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one; |
6279 | |
6280 | // Depth stencil. |
6281 | |
6282 | VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info; |
6283 | depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; |
6284 | depth_stencil_state_create_info.pNext = nullptr; |
6285 | depth_stencil_state_create_info.flags = 0; |
6286 | depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test; |
6287 | depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write; |
6288 | ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID()); |
6289 | depth_stencil_state_create_info.depthCompareOp = compare_operators[p_depth_stencil_state.depth_compare_operator]; |
6290 | depth_stencil_state_create_info.depthBoundsTestEnable = p_depth_stencil_state.enable_depth_range; |
6291 | depth_stencil_state_create_info.stencilTestEnable = p_depth_stencil_state.enable_stencil; |
6292 | |
6293 | ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.fail, STENCIL_OP_MAX, RID()); |
6294 | depth_stencil_state_create_info.front.failOp = stencil_operations[p_depth_stencil_state.front_op.fail]; |
6295 | ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.pass, STENCIL_OP_MAX, RID()); |
6296 | depth_stencil_state_create_info.front.passOp = stencil_operations[p_depth_stencil_state.front_op.pass]; |
6297 | ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.depth_fail, STENCIL_OP_MAX, RID()); |
6298 | depth_stencil_state_create_info.front.depthFailOp = stencil_operations[p_depth_stencil_state.front_op.depth_fail]; |
6299 | ERR_FAIL_INDEX_V(p_depth_stencil_state.front_op.compare, COMPARE_OP_MAX, RID()); |
6300 | depth_stencil_state_create_info.front.compareOp = compare_operators[p_depth_stencil_state.front_op.compare]; |
6301 | depth_stencil_state_create_info.front.compareMask = p_depth_stencil_state.front_op.compare_mask; |
6302 | depth_stencil_state_create_info.front.writeMask = p_depth_stencil_state.front_op.write_mask; |
6303 | depth_stencil_state_create_info.front.reference = p_depth_stencil_state.front_op.reference; |
6304 | |
6305 | ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.fail, STENCIL_OP_MAX, RID()); |
6306 | depth_stencil_state_create_info.back.failOp = stencil_operations[p_depth_stencil_state.back_op.fail]; |
6307 | ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.pass, STENCIL_OP_MAX, RID()); |
6308 | depth_stencil_state_create_info.back.passOp = stencil_operations[p_depth_stencil_state.back_op.pass]; |
6309 | ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.depth_fail, STENCIL_OP_MAX, RID()); |
6310 | depth_stencil_state_create_info.back.depthFailOp = stencil_operations[p_depth_stencil_state.back_op.depth_fail]; |
6311 | ERR_FAIL_INDEX_V(p_depth_stencil_state.back_op.compare, COMPARE_OP_MAX, RID()); |
6312 | depth_stencil_state_create_info.back.compareOp = compare_operators[p_depth_stencil_state.back_op.compare]; |
6313 | depth_stencil_state_create_info.back.compareMask = p_depth_stencil_state.back_op.compare_mask; |
6314 | depth_stencil_state_create_info.back.writeMask = p_depth_stencil_state.back_op.write_mask; |
6315 | depth_stencil_state_create_info.back.reference = p_depth_stencil_state.back_op.reference; |
6316 | |
6317 | depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min; |
6318 | depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max; |
6319 | |
6320 | // Blend state. |
6321 | VkPipelineColorBlendStateCreateInfo color_blend_state_create_info; |
6322 | color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; |
6323 | color_blend_state_create_info.pNext = nullptr; |
6324 | color_blend_state_create_info.flags = 0; |
6325 | color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op; |
6326 | ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID()); |
6327 | color_blend_state_create_info.logicOp = logic_operations[p_blend_state.logic_op]; |
6328 | |
6329 | Vector<VkPipelineColorBlendAttachmentState> attachment_states; |
6330 | { |
6331 | const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass]; |
6332 | attachment_states.resize(pass.color_attachments.size()); |
6333 | ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID()); |
6334 | for (int i = 0; i < pass.color_attachments.size(); i++) { |
6335 | VkPipelineColorBlendAttachmentState state; |
6336 | if (pass.color_attachments[i] == FramebufferPass::ATTACHMENT_UNUSED) { |
6337 | state.blendEnable = false; |
6338 | |
6339 | state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; |
6340 | state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; |
6341 | state.colorBlendOp = VK_BLEND_OP_ADD; |
6342 | |
6343 | state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; |
6344 | state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; |
6345 | state.alphaBlendOp = VK_BLEND_OP_ADD; |
6346 | |
6347 | state.colorWriteMask = 0; |
6348 | } else { |
6349 | state.blendEnable = p_blend_state.attachments[i].enable_blend; |
6350 | |
6351 | ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID()); |
6352 | state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor]; |
6353 | ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID()); |
6354 | state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor]; |
6355 | ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID()); |
6356 | state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op]; |
6357 | |
6358 | ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); |
6359 | state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor]; |
6360 | ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); |
6361 | state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor]; |
6362 | ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID()); |
6363 | state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op]; |
6364 | |
6365 | state.colorWriteMask = 0; |
6366 | if (p_blend_state.attachments[i].write_r) { |
6367 | state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; |
6368 | } |
6369 | if (p_blend_state.attachments[i].write_g) { |
6370 | state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; |
6371 | } |
6372 | if (p_blend_state.attachments[i].write_b) { |
6373 | state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; |
6374 | } |
6375 | if (p_blend_state.attachments[i].write_a) { |
6376 | state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; |
6377 | } |
6378 | } |
6379 | attachment_states.write[i] = state; |
6380 | } |
6381 | } |
6382 | |
6383 | color_blend_state_create_info.attachmentCount = attachment_states.size(); |
6384 | color_blend_state_create_info.pAttachments = attachment_states.ptr(); |
6385 | |
6386 | color_blend_state_create_info.blendConstants[0] = p_blend_state.blend_constant.r; |
6387 | color_blend_state_create_info.blendConstants[1] = p_blend_state.blend_constant.g; |
6388 | color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b; |
6389 | color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a; |
6390 | |
6391 | // Dynamic state. |
6392 | |
6393 | VkPipelineDynamicStateCreateInfo dynamic_state_create_info; |
6394 | dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; |
6395 | dynamic_state_create_info.pNext = nullptr; |
6396 | dynamic_state_create_info.flags = 0; |
6397 | Vector<VkDynamicState> dynamic_states; // Vulkan is weird. |
6398 | |
6399 | dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); // Viewport and scissor are always dynamic. |
6400 | dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); |
6401 | |
6402 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_LINE_WIDTH)) { |
6403 | dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH); |
6404 | } |
6405 | |
6406 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_DEPTH_BIAS)) { |
6407 | dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS); |
6408 | } |
6409 | |
6410 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_BLEND_CONSTANTS)) { |
6411 | dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS); |
6412 | } |
6413 | |
6414 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_DEPTH_BOUNDS)) { |
6415 | dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); |
6416 | } |
6417 | |
6418 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_COMPARE_MASK)) { |
6419 | dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); |
6420 | } |
6421 | |
6422 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_WRITE_MASK)) { |
6423 | dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); |
6424 | } |
6425 | |
6426 | if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_REFERENCE)) { |
6427 | dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE); |
6428 | } |
6429 | |
6430 | dynamic_state_create_info.dynamicStateCount = dynamic_states.size(); |
6431 | dynamic_state_create_info.pDynamicStates = dynamic_states.ptr(); |
6432 | |
6433 | void *graphics_pipeline_nextptr = nullptr; |
6434 | |
6435 | VkPipelineFragmentShadingRateStateCreateInfoKHR vrs_create_info; |
6436 | if (context->get_vrs_capabilities().attachment_vrs_supported) { |
6437 | // If VRS is used, this defines how the different VRS types are combined. |
6438 | // combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS. |
6439 | // combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS. |
6440 | |
6441 | vrs_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; |
6442 | vrs_create_info.pNext = nullptr; |
6443 | vrs_create_info.fragmentSize = { 4, 4 }; |
6444 | vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter. |
6445 | vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // Always use the outcome of attachment VRS if enabled. |
6446 | |
6447 | graphics_pipeline_nextptr = &vrs_create_info; |
6448 | } |
6449 | |
6450 | // Finally, pipeline create info. |
6451 | VkGraphicsPipelineCreateInfo graphics_pipeline_create_info; |
6452 | |
6453 | graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; |
6454 | graphics_pipeline_create_info.pNext = graphics_pipeline_nextptr; |
6455 | graphics_pipeline_create_info.flags = 0; |
6456 | |
6457 | Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages; |
6458 | Vector<VkSpecializationInfo> specialization_info; |
6459 | Vector<Vector<VkSpecializationMapEntry>> specialization_map_entries; |
6460 | Vector<uint32_t> specialization_constant_data; |
6461 | |
6462 | if (shader->specialization_constants.size()) { |
6463 | specialization_constant_data.resize(shader->specialization_constants.size()); |
6464 | uint32_t *data_ptr = specialization_constant_data.ptrw(); |
6465 | specialization_info.resize(pipeline_stages.size()); |
6466 | specialization_map_entries.resize(pipeline_stages.size()); |
6467 | for (int i = 0; i < shader->specialization_constants.size(); i++) { |
6468 | // See if overridden. |
6469 | const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; |
6470 | data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits. |
6471 | |
6472 | for (int j = 0; j < p_specialization_constants.size(); j++) { |
6473 | const PipelineSpecializationConstant &psc = p_specialization_constants[j]; |
6474 | if (psc.constant_id == sc.constant.constant_id) { |
6475 | ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type." ); |
6476 | data_ptr[i] = psc.int_value; |
6477 | break; |
6478 | } |
6479 | } |
6480 | |
6481 | VkSpecializationMapEntry entry; |
6482 | |
6483 | entry.constantID = sc.constant.constant_id; |
6484 | entry.offset = i * sizeof(uint32_t); |
6485 | entry.size = sizeof(uint32_t); |
6486 | |
6487 | for (int j = 0; j < SHADER_STAGE_MAX; j++) { |
6488 | if (sc.stage_flags & (1 << j)) { |
6489 | VkShaderStageFlagBits stage = shader_stage_masks[j]; |
6490 | for (int k = 0; k < pipeline_stages.size(); k++) { |
6491 | if (pipeline_stages[k].stage == stage) { |
6492 | specialization_map_entries.write[k].push_back(entry); |
6493 | } |
6494 | } |
6495 | } |
6496 | } |
6497 | } |
6498 | |
6499 | for (int i = 0; i < pipeline_stages.size(); i++) { |
6500 | if (specialization_map_entries[i].size()) { |
6501 | specialization_info.write[i].dataSize = specialization_constant_data.size() * sizeof(uint32_t); |
6502 | specialization_info.write[i].pData = data_ptr; |
6503 | specialization_info.write[i].mapEntryCount = specialization_map_entries[i].size(); |
6504 | specialization_info.write[i].pMapEntries = specialization_map_entries[i].ptr(); |
6505 | pipeline_stages.write[i].pSpecializationInfo = specialization_info.ptr() + i; |
6506 | } |
6507 | } |
6508 | } |
6509 | |
6510 | graphics_pipeline_create_info.stageCount = pipeline_stages.size(); |
6511 | graphics_pipeline_create_info.pStages = pipeline_stages.ptr(); |
6512 | |
6513 | graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; |
6514 | graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; |
6515 | graphics_pipeline_create_info.pTessellationState = &tessellation_create_info; |
6516 | graphics_pipeline_create_info.pViewportState = &viewport_state_create_info; |
6517 | graphics_pipeline_create_info.pRasterizationState = &rasterization_state_create_info; |
6518 | graphics_pipeline_create_info.pMultisampleState = &multisample_state_create_info; |
6519 | graphics_pipeline_create_info.pDepthStencilState = &depth_stencil_state_create_info; |
6520 | graphics_pipeline_create_info.pColorBlendState = &color_blend_state_create_info; |
6521 | graphics_pipeline_create_info.pDynamicState = &dynamic_state_create_info; |
6522 | graphics_pipeline_create_info.layout = shader->pipeline_layout; |
6523 | graphics_pipeline_create_info.renderPass = fb_format.render_pass; |
6524 | |
6525 | graphics_pipeline_create_info.subpass = p_for_render_pass; |
6526 | graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; |
6527 | graphics_pipeline_create_info.basePipelineIndex = 0; |
6528 | |
6529 | RenderPipeline pipeline; |
6530 | VkResult err = vkCreateGraphicsPipelines(device, pipelines_cache.cache_object, 1, &graphics_pipeline_create_info, nullptr, &pipeline.pipeline); |
6531 | ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateGraphicsPipelines failed with error " + itos(err) + " for shader '" + shader->name + "'." ); |
6532 | |
6533 | if (pipelines_cache.cache_object != VK_NULL_HANDLE) { |
6534 | _update_pipeline_cache(); |
6535 | } |
6536 | |
6537 | pipeline.set_formats = shader->set_formats; |
6538 | pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask; |
6539 | pipeline.pipeline_layout = shader->pipeline_layout; |
6540 | pipeline.shader = p_shader; |
6541 | pipeline.push_constant_size = shader->push_constant.size; |
6542 | |
6543 | #ifdef DEBUG_ENABLED |
6544 | pipeline.validation.dynamic_state = p_dynamic_state_flags; |
6545 | pipeline.validation.framebuffer_format = p_framebuffer_format; |
6546 | pipeline.validation.render_pass = p_for_render_pass; |
6547 | pipeline.validation.vertex_format = p_vertex_format; |
6548 | pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; |
6549 | |
6550 | static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { |
6551 | 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 |
6552 | }; |
6553 | pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive]; |
6554 | static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = { |
6555 | 1, |
6556 | 2, |
6557 | 2, |
6558 | 2, |
6559 | 2, |
6560 | 3, |
6561 | 3, |
6562 | 3, |
6563 | 3, |
6564 | 3, |
6565 | 1, |
6566 | }; |
6567 | pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive]; |
6568 | #endif |
6569 | // Create ID to associate with this pipeline. |
6570 | RID id = render_pipeline_owner.make_rid(pipeline); |
6571 | #ifdef DEV_ENABLED |
6572 | set_resource_name(id, "RID:" + itos(id.get_id())); |
6573 | #endif |
6574 | // Now add all the dependencies. |
6575 | _add_dependency(id, p_shader); |
6576 | return id; |
6577 | } |
6578 | |
6579 | bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { |
6580 | _THREAD_SAFE_METHOD_ |
6581 | return render_pipeline_owner.owns(p_pipeline); |
6582 | } |
6583 | |
6584 | /**************************/ |
6585 | /**** COMPUTE PIPELINE ****/ |
6586 | /**************************/ |
6587 | |
6588 | RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { |
6589 | _THREAD_SAFE_METHOD_ |
6590 | |
6591 | // Needs a shader. |
6592 | Shader *shader = shader_owner.get_or_null(p_shader); |
6593 | ERR_FAIL_NULL_V(shader, RID()); |
6594 | |
6595 | ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(), |
6596 | "Non-compute shaders can't be used in compute pipelines" ); |
6597 | |
6598 | // Finally, pipeline create info. |
6599 | VkComputePipelineCreateInfo compute_pipeline_create_info; |
6600 | |
6601 | compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; |
6602 | compute_pipeline_create_info.pNext = nullptr; |
6603 | compute_pipeline_create_info.flags = 0; |
6604 | |
6605 | compute_pipeline_create_info.stage = shader->pipeline_stages[0]; |
6606 | compute_pipeline_create_info.layout = shader->pipeline_layout; |
6607 | compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; |
6608 | compute_pipeline_create_info.basePipelineIndex = 0; |
6609 | |
6610 | VkSpecializationInfo specialization_info; |
6611 | Vector<VkSpecializationMapEntry> specialization_map_entries; |
6612 | Vector<uint32_t> specialization_constant_data; |
6613 | |
6614 | if (shader->specialization_constants.size()) { |
6615 | specialization_constant_data.resize(shader->specialization_constants.size()); |
6616 | uint32_t *data_ptr = specialization_constant_data.ptrw(); |
6617 | for (int i = 0; i < shader->specialization_constants.size(); i++) { |
6618 | // See if overridden. |
6619 | const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; |
6620 | data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits. |
6621 | |
6622 | for (int j = 0; j < p_specialization_constants.size(); j++) { |
6623 | const PipelineSpecializationConstant &psc = p_specialization_constants[j]; |
6624 | if (psc.constant_id == sc.constant.constant_id) { |
6625 | ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type." ); |
6626 | data_ptr[i] = psc.int_value; |
6627 | break; |
6628 | } |
6629 | } |
6630 | |
6631 | VkSpecializationMapEntry entry; |
6632 | |
6633 | entry.constantID = sc.constant.constant_id; |
6634 | entry.offset = i * sizeof(uint32_t); |
6635 | entry.size = sizeof(uint32_t); |
6636 | |
6637 | specialization_map_entries.push_back(entry); |
6638 | } |
6639 | |
6640 | specialization_info.dataSize = specialization_constant_data.size() * sizeof(uint32_t); |
6641 | specialization_info.pData = data_ptr; |
6642 | specialization_info.mapEntryCount = specialization_map_entries.size(); |
6643 | specialization_info.pMapEntries = specialization_map_entries.ptr(); |
6644 | |
6645 | compute_pipeline_create_info.stage.pSpecializationInfo = &specialization_info; |
6646 | } |
6647 | |
6648 | ComputePipeline pipeline; |
6649 | VkResult err = vkCreateComputePipelines(device, pipelines_cache.cache_object, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline); |
6650 | ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + "." ); |
6651 | |
6652 | if (pipelines_cache.cache_object != VK_NULL_HANDLE) { |
6653 | _update_pipeline_cache(); |
6654 | } |
6655 | |
6656 | pipeline.set_formats = shader->set_formats; |
6657 | pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask; |
6658 | pipeline.pipeline_layout = shader->pipeline_layout; |
6659 | pipeline.shader = p_shader; |
6660 | pipeline.push_constant_size = shader->push_constant.size; |
6661 | pipeline.local_group_size[0] = shader->compute_local_size[0]; |
6662 | pipeline.local_group_size[1] = shader->compute_local_size[1]; |
6663 | pipeline.local_group_size[2] = shader->compute_local_size[2]; |
6664 | |
6665 | // Create ID to associate with this pipeline. |
6666 | RID id = compute_pipeline_owner.make_rid(pipeline); |
6667 | #ifdef DEV_ENABLED |
6668 | set_resource_name(id, "RID:" + itos(id.get_id())); |
6669 | #endif |
6670 | // Now add all the dependencies. |
6671 | _add_dependency(id, p_shader); |
6672 | return id; |
6673 | } |
6674 | |
6675 | bool RenderingDeviceVulkan::compute_pipeline_is_valid(RID p_pipeline) { |
6676 | return compute_pipeline_owner.owns(p_pipeline); |
6677 | } |
6678 | |
6679 | /****************/ |
6680 | /**** SCREEN ****/ |
6681 | /****************/ |
6682 | |
6683 | int RenderingDeviceVulkan::screen_get_width(DisplayServer::WindowID p_screen) const { |
6684 | _THREAD_SAFE_METHOD_ |
6685 | ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen" ); |
6686 | return context->window_get_width(p_screen); |
6687 | } |
6688 | |
6689 | int RenderingDeviceVulkan::screen_get_height(DisplayServer::WindowID p_screen) const { |
6690 | _THREAD_SAFE_METHOD_ |
6691 | ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen" ); |
6692 | |
6693 | return context->window_get_height(p_screen); |
6694 | } |
6695 | |
6696 | RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { |
6697 | _THREAD_SAFE_METHOD_ |
6698 | ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen" ); |
6699 | |
6700 | // Very hacky, but not used often per frame so I guess ok. |
6701 | VkFormat vkformat = context->get_screen_format(); |
6702 | DataFormat format = DATA_FORMAT_MAX; |
6703 | for (int i = 0; i < DATA_FORMAT_MAX; i++) { |
6704 | if (vkformat == vulkan_formats[i]) { |
6705 | format = DataFormat(i); |
6706 | break; |
6707 | } |
6708 | } |
6709 | |
6710 | ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID); |
6711 | |
6712 | AttachmentFormat attachment; |
6713 | attachment.format = format; |
6714 | attachment.samples = TEXTURE_SAMPLES_1; |
6715 | attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; |
6716 | Vector<AttachmentFormat> screen_attachment; |
6717 | screen_attachment.push_back(attachment); |
6718 | return const_cast<RenderingDeviceVulkan *>(this)->framebuffer_format_create(screen_attachment); |
6719 | } |
6720 | |
6721 | /*******************/ |
6722 | /**** DRAW LIST ****/ |
6723 | /*******************/ |
6724 | |
6725 | RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) { |
6726 | _THREAD_SAFE_METHOD_ |
6727 | ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen" ); |
6728 | |
6729 | ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time." ); |
6730 | ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time." ); |
6731 | |
6732 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; |
6733 | |
6734 | if (!context->window_is_valid_swapchain(p_screen)) { |
6735 | return INVALID_ID; |
6736 | } |
6737 | |
6738 | Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen)); |
6739 | |
6740 | _draw_list_allocate(Rect2i(Vector2i(), size), 0, 0); |
6741 | #ifdef DEBUG_ENABLED |
6742 | draw_list_framebuffer_format = screen_get_framebuffer_format(); |
6743 | #endif |
6744 | draw_list_subpass_count = 1; |
6745 | |
6746 | VkRenderPassBeginInfo render_pass_begin; |
6747 | render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; |
6748 | render_pass_begin.pNext = nullptr; |
6749 | render_pass_begin.renderPass = context->window_get_render_pass(p_screen); |
6750 | render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen); |
6751 | |
6752 | render_pass_begin.renderArea.extent.width = size.width; |
6753 | render_pass_begin.renderArea.extent.height = size.height; |
6754 | render_pass_begin.renderArea.offset.x = 0; |
6755 | render_pass_begin.renderArea.offset.y = 0; |
6756 | |
6757 | render_pass_begin.clearValueCount = 1; |
6758 | |
6759 | VkClearValue clear_value; |
6760 | clear_value.color.float32[0] = p_clear_color.r; |
6761 | clear_value.color.float32[1] = p_clear_color.g; |
6762 | clear_value.color.float32[2] = p_clear_color.b; |
6763 | clear_value.color.float32[3] = p_clear_color.a; |
6764 | |
6765 | render_pass_begin.pClearValues = &clear_value; |
6766 | |
6767 | vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); |
6768 | |
6769 | uint32_t size_x = screen_get_width(p_screen); |
6770 | uint32_t size_y = screen_get_height(p_screen); |
6771 | |
6772 | VkViewport viewport; |
6773 | viewport.x = 0; |
6774 | viewport.y = 0; |
6775 | viewport.width = size_x; |
6776 | viewport.height = size_y; |
6777 | viewport.minDepth = 0; |
6778 | viewport.maxDepth = 1.0; |
6779 | |
6780 | vkCmdSetViewport(command_buffer, 0, 1, &viewport); |
6781 | |
6782 | VkRect2D scissor; |
6783 | scissor.offset.x = 0; |
6784 | scissor.offset.y = 0; |
6785 | scissor.extent.width = size_x; |
6786 | scissor.extent.height = size_y; |
6787 | |
6788 | vkCmdSetScissor(command_buffer, 0, 1, &scissor); |
6789 | |
6790 | return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; |
6791 | } |
6792 | |
6793 | Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count) { |
6794 | Framebuffer::VersionKey vk; |
6795 | vk.initial_color_action = p_initial_color_action; |
6796 | vk.final_color_action = p_final_color_action; |
6797 | vk.initial_depth_action = p_initial_depth_action; |
6798 | vk.final_depth_action = p_final_depth_action; |
6799 | vk.view_count = p_framebuffer->view_count; |
6800 | |
6801 | if (!p_framebuffer->framebuffers.has(vk)) { |
6802 | // Need to create this version. |
6803 | Framebuffer::Version version; |
6804 | |
6805 | version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, framebuffer_formats[p_framebuffer->format_id].E->key().passes, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_framebuffer->view_count); |
6806 | |
6807 | VkFramebufferCreateInfo framebuffer_create_info; |
6808 | framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; |
6809 | framebuffer_create_info.pNext = nullptr; |
6810 | framebuffer_create_info.flags = 0; |
6811 | framebuffer_create_info.renderPass = version.render_pass; |
6812 | Vector<VkImageView> attachments; |
6813 | for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) { |
6814 | Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]); |
6815 | if (texture) { |
6816 | attachments.push_back(texture->view); |
6817 | if (!(texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) { // VRS attachment will be a different size. |
6818 | ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG); |
6819 | ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG); |
6820 | } |
6821 | } |
6822 | } |
6823 | framebuffer_create_info.attachmentCount = attachments.size(); |
6824 | framebuffer_create_info.pAttachments = attachments.ptr(); |
6825 | framebuffer_create_info.width = p_framebuffer->size.width; |
6826 | framebuffer_create_info.height = p_framebuffer->size.height; |
6827 | framebuffer_create_info.layers = 1; |
6828 | |
6829 | VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr, &version.framebuffer); |
6830 | ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkCreateFramebuffer failed with error " + itos(err) + "." ); |
6831 | |
6832 | version.subpass_count = framebuffer_formats[p_framebuffer->format_id].E->key().passes.size(); |
6833 | |
6834 | p_framebuffer->framebuffers.insert(vk, version); |
6835 | } |
6836 | const Framebuffer::Version &version = p_framebuffer->framebuffers[vk]; |
6837 | *r_framebuffer = version.framebuffer; |
6838 | *r_render_pass = version.render_pass; |
6839 | *r_subpass_count = version.subpass_count; |
6840 | |
6841 | return OK; |
6842 | } |
6843 | |
6844 | Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures) { |
6845 | VkRenderPassBeginInfo render_pass_begin; |
6846 | render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; |
6847 | render_pass_begin.pNext = nullptr; |
6848 | render_pass_begin.renderPass = render_pass; |
6849 | render_pass_begin.framebuffer = vkframebuffer; |
6850 | /* |
6851 | * Given how API works, it makes sense to always fully operate on the whole framebuffer. |
6852 | * This allows better continue operations for operations like shadowmapping. |
6853 | render_pass_begin.renderArea.extent.width = viewport_size.width; |
6854 | render_pass_begin.renderArea.extent.height = viewport_size.height; |
6855 | render_pass_begin.renderArea.offset.x = viewport_offset.x; |
6856 | render_pass_begin.renderArea.offset.y = viewport_offset.y; |
6857 | */ |
6858 | render_pass_begin.renderArea.extent.width = framebuffer->size.width; |
6859 | render_pass_begin.renderArea.extent.height = framebuffer->size.height; |
6860 | render_pass_begin.renderArea.offset.x = 0; |
6861 | render_pass_begin.renderArea.offset.y = 0; |
6862 | |
6863 | Vector<VkClearValue> clear_values; |
6864 | clear_values.resize(framebuffer->texture_ids.size()); |
6865 | int clear_values_count = 0; |
6866 | { |
6867 | int color_index = 0; |
6868 | for (int i = 0; i < framebuffer->texture_ids.size(); i++) { |
6869 | VkClearValue clear_value; |
6870 | |
6871 | Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); |
6872 | if (!texture) { |
6873 | color_index++; |
6874 | continue; |
6875 | } |
6876 | |
6877 | if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
6878 | ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug. |
6879 | Color clear_color = p_clear_colors[color_index]; |
6880 | clear_value.color.float32[0] = clear_color.r; |
6881 | clear_value.color.float32[1] = clear_color.g; |
6882 | clear_value.color.float32[2] = clear_color.b; |
6883 | clear_value.color.float32[3] = clear_color.a; |
6884 | color_index++; |
6885 | } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
6886 | clear_value.depthStencil.depth = p_clear_depth; |
6887 | clear_value.depthStencil.stencil = p_clear_stencil; |
6888 | } else { |
6889 | clear_value.color.float32[0] = 0; |
6890 | clear_value.color.float32[1] = 0; |
6891 | clear_value.color.float32[2] = 0; |
6892 | clear_value.color.float32[3] = 0; |
6893 | } |
6894 | clear_values.write[clear_values_count++] = clear_value; |
6895 | } |
6896 | } |
6897 | |
6898 | render_pass_begin.clearValueCount = clear_values_count; |
6899 | render_pass_begin.pClearValues = clear_values.ptr(); |
6900 | |
6901 | for (int i = 0; i < p_storage_textures.size(); i++) { |
6902 | Texture *texture = texture_owner.get_or_null(p_storage_textures[i]); |
6903 | if (!texture) { |
6904 | continue; |
6905 | } |
6906 | ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage." ); |
6907 | |
6908 | if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { |
6909 | // Must change layout to general. |
6910 | VkImageMemoryBarrier image_memory_barrier; |
6911 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
6912 | image_memory_barrier.pNext = nullptr; |
6913 | image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
6914 | image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
6915 | image_memory_barrier.oldLayout = texture->layout; |
6916 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
6917 | |
6918 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
6919 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
6920 | image_memory_barrier.image = texture->image; |
6921 | image_memory_barrier.subresourceRange.aspectMask = texture->read_aspect_mask; |
6922 | image_memory_barrier.subresourceRange.baseMipLevel = texture->base_mipmap; |
6923 | image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; |
6924 | image_memory_barrier.subresourceRange.baseArrayLayer = texture->base_layer; |
6925 | image_memory_barrier.subresourceRange.layerCount = texture->layers; |
6926 | |
6927 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); |
6928 | |
6929 | texture->layout = VK_IMAGE_LAYOUT_GENERAL; |
6930 | |
6931 | draw_list_storage_textures.push_back(p_storage_textures[i]); |
6932 | } |
6933 | } |
6934 | |
6935 | vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents); |
6936 | |
6937 | // Mark textures as bound. |
6938 | draw_list_bound_textures.clear(); |
6939 | draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE; |
6940 | draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE; |
6941 | |
6942 | for (int i = 0; i < framebuffer->texture_ids.size(); i++) { |
6943 | Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); |
6944 | if (!texture) { |
6945 | continue; |
6946 | } |
6947 | texture->bound = true; |
6948 | draw_list_bound_textures.push_back(framebuffer->texture_ids[i]); |
6949 | } |
6950 | |
6951 | return OK; |
6952 | } |
6953 | |
6954 | void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { |
6955 | Vector<VkClearAttachment> clear_attachments; |
6956 | int color_index = 0; |
6957 | int texture_index = 0; |
6958 | for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) { |
6959 | Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]); |
6960 | |
6961 | if (!texture) { |
6962 | texture_index++; |
6963 | continue; |
6964 | } |
6965 | |
6966 | VkClearAttachment clear_at = {}; |
6967 | if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { |
6968 | Color clear_color = p_clear_colors[texture_index++]; |
6969 | clear_at.clearValue.color.float32[0] = clear_color.r; |
6970 | clear_at.clearValue.color.float32[1] = clear_color.g; |
6971 | clear_at.clearValue.color.float32[2] = clear_color.b; |
6972 | clear_at.clearValue.color.float32[3] = clear_color.a; |
6973 | clear_at.colorAttachment = color_index++; |
6974 | clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
6975 | } else if (p_clear_depth && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
6976 | clear_at.clearValue.depthStencil.depth = p_depth; |
6977 | clear_at.clearValue.depthStencil.stencil = p_stencil; |
6978 | clear_at.colorAttachment = 0; |
6979 | clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
6980 | if (format_has_stencil(texture->format)) { |
6981 | clear_at.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; |
6982 | } |
6983 | } else { |
6984 | ERR_CONTINUE(true); |
6985 | } |
6986 | clear_attachments.push_back(clear_at); |
6987 | } |
6988 | |
6989 | VkClearRect cr; |
6990 | cr.baseArrayLayer = 0; |
6991 | cr.layerCount = 1; |
6992 | cr.rect.offset.x = p_viewport_offset.x; |
6993 | cr.rect.offset.y = p_viewport_offset.y; |
6994 | cr.rect.extent.width = p_viewport_size.width; |
6995 | cr.rect.extent.height = p_viewport_size.height; |
6996 | |
6997 | vkCmdClearAttachments(p_draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr); |
6998 | } |
6999 | |
7000 | RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { |
7001 | _THREAD_SAFE_METHOD_ |
7002 | |
7003 | ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time." ); |
7004 | ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, INVALID_ID, "Only one draw/compute list can be active at the same time." ); |
7005 | |
7006 | Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); |
7007 | ERR_FAIL_NULL_V(framebuffer, INVALID_ID); |
7008 | |
7009 | Point2i viewport_offset; |
7010 | Point2i viewport_size = framebuffer->size; |
7011 | bool needs_clear_color = false; |
7012 | bool needs_clear_depth = false; |
7013 | |
7014 | if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region. |
7015 | Rect2i viewport(viewport_offset, viewport_size); |
7016 | Rect2i regioni = p_region; |
7017 | if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && |
7018 | ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && |
7019 | ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { |
7020 | ERR_FAIL_V_MSG(INVALID_ID, "When supplying a custom region, it must be contained within the framebuffer rectangle" ); |
7021 | } |
7022 | |
7023 | viewport_offset = regioni.position; |
7024 | viewport_size = regioni.size; |
7025 | if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) { |
7026 | needs_clear_color = true; |
7027 | p_initial_color_action = INITIAL_ACTION_CONTINUE; |
7028 | } |
7029 | if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) { |
7030 | needs_clear_depth = true; |
7031 | p_initial_depth_action = INITIAL_ACTION_CONTINUE; |
7032 | } |
7033 | if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) { |
7034 | needs_clear_color = true; |
7035 | p_initial_color_action = INITIAL_ACTION_KEEP; |
7036 | } |
7037 | if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) { |
7038 | needs_clear_depth = true; |
7039 | p_initial_depth_action = INITIAL_ACTION_KEEP; |
7040 | } |
7041 | } |
7042 | |
7043 | if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values. |
7044 | int color_count = 0; |
7045 | for (int i = 0; i < framebuffer->texture_ids.size(); i++) { |
7046 | Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); |
7047 | // We only check for our VRS usage bit if this is not the first texture id. |
7048 | // If it is the first we're likely populating our VRS texture. |
7049 | // Bit dirty but... |
7050 | if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) { |
7051 | if (!texture || !texture->is_resolve_buffer) { |
7052 | color_count++; |
7053 | } |
7054 | } |
7055 | } |
7056 | ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID, "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ")." ); |
7057 | } |
7058 | |
7059 | VkFramebuffer vkframebuffer; |
7060 | VkRenderPass render_pass; |
7061 | |
7062 | Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass, &draw_list_subpass_count); |
7063 | ERR_FAIL_COND_V(err != OK, INVALID_ID); |
7064 | |
7065 | VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; |
7066 | err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE, p_storage_textures); |
7067 | |
7068 | if (err != OK) { |
7069 | return INVALID_ID; |
7070 | } |
7071 | |
7072 | draw_list_render_pass = render_pass; |
7073 | draw_list_vkframebuffer = vkframebuffer; |
7074 | |
7075 | _draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0, 0); |
7076 | #ifdef DEBUG_ENABLED |
7077 | draw_list_framebuffer_format = framebuffer->format_id; |
7078 | #endif |
7079 | draw_list_current_subpass = 0; |
7080 | |
7081 | if (needs_clear_color || needs_clear_depth) { |
7082 | _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); |
7083 | } |
7084 | |
7085 | VkViewport viewport; |
7086 | viewport.x = viewport_offset.x; |
7087 | viewport.y = viewport_offset.y; |
7088 | viewport.width = viewport_size.width; |
7089 | viewport.height = viewport_size.height; |
7090 | viewport.minDepth = 0; |
7091 | viewport.maxDepth = 1.0; |
7092 | |
7093 | vkCmdSetViewport(command_buffer, 0, 1, &viewport); |
7094 | |
7095 | VkRect2D scissor; |
7096 | scissor.offset.x = viewport_offset.x; |
7097 | scissor.offset.y = viewport_offset.y; |
7098 | scissor.extent.width = viewport_size.width; |
7099 | scissor.extent.height = viewport_size.height; |
7100 | |
7101 | vkCmdSetScissor(command_buffer, 0, 1, &scissor); |
7102 | |
7103 | return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; |
7104 | } |
7105 | |
7106 | Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { |
7107 | _THREAD_SAFE_METHOD_ |
7108 | |
7109 | ERR_FAIL_COND_V_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time." ); |
7110 | ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time." ); |
7111 | |
7112 | ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION); |
7113 | |
7114 | Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); |
7115 | ERR_FAIL_NULL_V(framebuffer, ERR_INVALID_DECLARATION); |
7116 | |
7117 | Point2i viewport_offset; |
7118 | Point2i viewport_size = framebuffer->size; |
7119 | |
7120 | bool needs_clear_color = false; |
7121 | bool needs_clear_depth = false; |
7122 | |
7123 | if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region. |
7124 | Rect2i viewport(viewport_offset, viewport_size); |
7125 | Rect2i regioni = p_region; |
7126 | if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && |
7127 | ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && |
7128 | ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { |
7129 | ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle" ); |
7130 | } |
7131 | |
7132 | viewport_offset = regioni.position; |
7133 | viewport_size = regioni.size; |
7134 | |
7135 | if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) { |
7136 | needs_clear_color = true; |
7137 | p_initial_color_action = INITIAL_ACTION_KEEP; |
7138 | } |
7139 | if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) { |
7140 | needs_clear_depth = true; |
7141 | p_initial_depth_action = INITIAL_ACTION_KEEP; |
7142 | } |
7143 | } |
7144 | |
7145 | if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values. |
7146 | |
7147 | int color_count = 0; |
7148 | for (int i = 0; i < framebuffer->texture_ids.size(); i++) { |
7149 | Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); |
7150 | |
7151 | if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
7152 | color_count++; |
7153 | } |
7154 | } |
7155 | |
7156 | ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, ERR_INVALID_PARAMETER, |
7157 | "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_count) + ")." ); |
7158 | } |
7159 | |
7160 | VkFramebuffer vkframebuffer; |
7161 | VkRenderPass render_pass; |
7162 | |
7163 | Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass, &draw_list_subpass_count); |
7164 | ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); |
7165 | |
7166 | VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer; |
7167 | err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, p_storage_textures); |
7168 | |
7169 | if (err != OK) { |
7170 | return ERR_CANT_CREATE; |
7171 | } |
7172 | |
7173 | draw_list_current_subpass = 0; |
7174 | |
7175 | #ifdef DEBUG_ENABLED |
7176 | draw_list_framebuffer_format = framebuffer->format_id; |
7177 | #endif |
7178 | draw_list_render_pass = render_pass; |
7179 | draw_list_vkframebuffer = vkframebuffer; |
7180 | |
7181 | err = _draw_list_allocate(Rect2i(viewport_offset, viewport_size), p_splits, 0); |
7182 | if (err != OK) { |
7183 | return err; |
7184 | } |
7185 | |
7186 | if (needs_clear_color || needs_clear_depth) { |
7187 | _draw_list_insert_clear_region(&draw_list[0], framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); |
7188 | } |
7189 | |
7190 | for (uint32_t i = 0; i < p_splits; i++) { |
7191 | VkViewport viewport; |
7192 | viewport.x = viewport_offset.x; |
7193 | viewport.y = viewport_offset.y; |
7194 | viewport.width = viewport_size.width; |
7195 | viewport.height = viewport_size.height; |
7196 | viewport.minDepth = 0; |
7197 | viewport.maxDepth = 1.0; |
7198 | |
7199 | vkCmdSetViewport(draw_list[i].command_buffer, 0, 1, &viewport); |
7200 | |
7201 | VkRect2D scissor; |
7202 | scissor.offset.x = viewport_offset.x; |
7203 | scissor.offset.y = viewport_offset.y; |
7204 | scissor.extent.width = viewport_size.width; |
7205 | scissor.extent.height = viewport_size.height; |
7206 | |
7207 | vkCmdSetScissor(draw_list[i].command_buffer, 0, 1, &scissor); |
7208 | r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; |
7209 | } |
7210 | |
7211 | return OK; |
7212 | } |
7213 | |
7214 | RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) { |
7215 | if (p_id < 0) { |
7216 | return nullptr; |
7217 | } |
7218 | |
7219 | if (!draw_list) { |
7220 | return nullptr; |
7221 | } else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) { |
7222 | if (draw_list_split) { |
7223 | return nullptr; |
7224 | } |
7225 | return draw_list; |
7226 | } else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) { |
7227 | if (!draw_list_split) { |
7228 | return nullptr; |
7229 | } |
7230 | |
7231 | uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask. |
7232 | |
7233 | if (index >= draw_list_count) { |
7234 | return nullptr; |
7235 | } |
7236 | |
7237 | return &draw_list[index]; |
7238 | } else { |
7239 | return nullptr; |
7240 | } |
7241 | } |
7242 | |
7243 | void RenderingDeviceVulkan::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) { |
7244 | DrawList *dl = _get_draw_list_ptr(p_list); |
7245 | ERR_FAIL_NULL(dl); |
7246 | #ifdef DEBUG_ENABLED |
7247 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7248 | #endif |
7249 | |
7250 | vkCmdSetBlendConstants(dl->command_buffer, p_color.components); |
7251 | } |
7252 | |
7253 | void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) { |
7254 | DrawList *dl = _get_draw_list_ptr(p_list); |
7255 | ERR_FAIL_NULL(dl); |
7256 | #ifdef DEBUG_ENABLED |
7257 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7258 | #endif |
7259 | |
7260 | const RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_render_pipeline); |
7261 | ERR_FAIL_NULL(pipeline); |
7262 | #ifdef DEBUG_ENABLED |
7263 | ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer_format && pipeline->validation.render_pass != draw_list_current_subpass); |
7264 | #endif |
7265 | |
7266 | if (p_render_pipeline == dl->state.pipeline) { |
7267 | return; // Redundant state, return. |
7268 | } |
7269 | |
7270 | dl->state.pipeline = p_render_pipeline; |
7271 | dl->state.pipeline_layout = pipeline->pipeline_layout; |
7272 | |
7273 | vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); |
7274 | |
7275 | if (dl->state.pipeline_shader != pipeline->shader) { |
7276 | // Shader changed, so descriptor sets may become incompatible. |
7277 | |
7278 | // Go through ALL sets, and unbind them (and all those above) if the format is different. |
7279 | |
7280 | uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline. |
7281 | dl->state.set_count = MAX(dl->state.set_count, pcount); |
7282 | const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats. |
7283 | |
7284 | bool sets_valid = true; // Once invalid, all above become invalid. |
7285 | for (uint32_t i = 0; i < pcount; i++) { |
7286 | // If a part of the format is different, invalidate it (and the rest). |
7287 | if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) { |
7288 | dl->state.sets[i].bound = false; |
7289 | dl->state.sets[i].pipeline_expected_format = pformats[i]; |
7290 | sets_valid = false; |
7291 | } |
7292 | } |
7293 | |
7294 | for (uint32_t i = pcount; i < dl->state.set_count; i++) { |
7295 | // Unbind the ones above (not used) if exist. |
7296 | dl->state.sets[i].bound = false; |
7297 | } |
7298 | |
7299 | dl->state.set_count = pcount; // Update set count. |
7300 | |
7301 | if (pipeline->push_constant_size) { |
7302 | dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask; |
7303 | #ifdef DEBUG_ENABLED |
7304 | dl->validation.pipeline_push_constant_supplied = false; |
7305 | #endif |
7306 | } |
7307 | |
7308 | dl->state.pipeline_shader = pipeline->shader; |
7309 | } |
7310 | |
7311 | #ifdef DEBUG_ENABLED |
7312 | // Update render pass pipeline info. |
7313 | dl->validation.pipeline_active = true; |
7314 | dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state; |
7315 | dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format; |
7316 | dl->validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices; |
7317 | dl->validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor; |
7318 | dl->validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum; |
7319 | dl->validation.pipeline_push_constant_size = pipeline->push_constant_size; |
7320 | #endif |
7321 | } |
7322 | |
7323 | void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { |
7324 | #ifdef DEBUG_ENABLED |
7325 | ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS, |
7326 | "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")." ); |
7327 | #endif |
7328 | DrawList *dl = _get_draw_list_ptr(p_list); |
7329 | ERR_FAIL_NULL(dl); |
7330 | |
7331 | #ifdef DEBUG_ENABLED |
7332 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7333 | #endif |
7334 | |
7335 | const UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set); |
7336 | ERR_FAIL_NULL(uniform_set); |
7337 | |
7338 | if (p_index > dl->state.set_count) { |
7339 | dl->state.set_count = p_index; |
7340 | } |
7341 | |
7342 | dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer. |
7343 | dl->state.sets[p_index].bound = false; // Needs rebind. |
7344 | dl->state.sets[p_index].uniform_set_format = uniform_set->format; |
7345 | dl->state.sets[p_index].uniform_set = p_uniform_set; |
7346 | |
7347 | uint32_t mst_count = uniform_set->mutable_storage_textures.size(); |
7348 | if (mst_count) { |
7349 | Texture **mst_textures = const_cast<UniformSet *>(uniform_set)->mutable_storage_textures.ptrw(); |
7350 | for (uint32_t i = 0; i < mst_count; i++) { |
7351 | if (mst_textures[i]->used_in_frame != frames_drawn) { |
7352 | mst_textures[i]->used_in_frame = frames_drawn; |
7353 | mst_textures[i]->used_in_transfer = false; |
7354 | mst_textures[i]->used_in_compute = false; |
7355 | } |
7356 | mst_textures[i]->used_in_raster = true; |
7357 | } |
7358 | } |
7359 | |
7360 | #ifdef DEBUG_ENABLED |
7361 | { // Validate that textures bound are not attached as framebuffer bindings. |
7362 | uint32_t attachable_count = uniform_set->attachable_textures.size(); |
7363 | const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr(); |
7364 | uint32_t bound_count = draw_list_bound_textures.size(); |
7365 | const RID *bound_ptr = draw_list_bound_textures.ptr(); |
7366 | for (uint32_t i = 0; i < attachable_count; i++) { |
7367 | for (uint32_t j = 0; j < bound_count; j++) { |
7368 | ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j], |
7369 | "Attempted to use the same texture in framebuffer attachment and a uniform (set: " + itos(p_index) + ", binding: " + itos(attachable_ptr[i].bind) + "), this is not allowed." ); |
7370 | } |
7371 | } |
7372 | } |
7373 | #endif |
7374 | } |
7375 | |
7376 | void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) { |
7377 | DrawList *dl = _get_draw_list_ptr(p_list); |
7378 | ERR_FAIL_NULL(dl); |
7379 | #ifdef DEBUG_ENABLED |
7380 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7381 | #endif |
7382 | |
7383 | const VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array); |
7384 | ERR_FAIL_NULL(vertex_array); |
7385 | |
7386 | if (dl->state.vertex_array == p_vertex_array) { |
7387 | return; // Already set. |
7388 | } |
7389 | |
7390 | dl->state.vertex_array = p_vertex_array; |
7391 | |
7392 | #ifdef DEBUG_ENABLED |
7393 | dl->validation.vertex_format = vertex_array->description; |
7394 | dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; |
7395 | #endif |
7396 | dl->validation.vertex_array_size = vertex_array->vertex_count; |
7397 | vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); |
7398 | } |
7399 | |
7400 | void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { |
7401 | DrawList *dl = _get_draw_list_ptr(p_list); |
7402 | ERR_FAIL_NULL(dl); |
7403 | #ifdef DEBUG_ENABLED |
7404 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7405 | #endif |
7406 | |
7407 | const IndexArray *index_array = index_array_owner.get_or_null(p_index_array); |
7408 | ERR_FAIL_NULL(index_array); |
7409 | |
7410 | if (dl->state.index_array == p_index_array) { |
7411 | return; // Already set. |
7412 | } |
7413 | |
7414 | dl->state.index_array = p_index_array; |
7415 | #ifdef DEBUG_ENABLED |
7416 | dl->validation.index_array_max_index = index_array->max_index; |
7417 | #endif |
7418 | dl->validation.index_array_size = index_array->indices; |
7419 | dl->validation.index_array_offset = index_array->offset; |
7420 | |
7421 | vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, 0, index_array->index_type); |
7422 | } |
7423 | |
7424 | void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) { |
7425 | DrawList *dl = _get_draw_list_ptr(p_list); |
7426 | ERR_FAIL_NULL(dl); |
7427 | #ifdef DEBUG_ENABLED |
7428 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7429 | #endif |
7430 | |
7431 | vkCmdSetLineWidth(dl->command_buffer, p_width); |
7432 | } |
7433 | |
7434 | void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) { |
7435 | DrawList *dl = _get_draw_list_ptr(p_list); |
7436 | ERR_FAIL_NULL(dl); |
7437 | |
7438 | #ifdef DEBUG_ENABLED |
7439 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7440 | #endif |
7441 | |
7442 | #ifdef DEBUG_ENABLED |
7443 | ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size, |
7444 | "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")" ); |
7445 | #endif |
7446 | vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); |
7447 | #ifdef DEBUG_ENABLED |
7448 | dl->validation.pipeline_push_constant_supplied = true; |
7449 | #endif |
7450 | } |
7451 | |
7452 | void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) { |
7453 | DrawList *dl = _get_draw_list_ptr(p_list); |
7454 | ERR_FAIL_NULL(dl); |
7455 | #ifdef DEBUG_ENABLED |
7456 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7457 | #endif |
7458 | |
7459 | #ifdef DEBUG_ENABLED |
7460 | ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, |
7461 | "No render pipeline was set before attempting to draw." ); |
7462 | if (dl->validation.pipeline_vertex_format != INVALID_ID) { |
7463 | // Pipeline uses vertices, validate format. |
7464 | ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID, |
7465 | "No vertex array was bound, and render pipeline expects vertices." ); |
7466 | // Make sure format is right. |
7467 | ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format, |
7468 | "The vertex format used to create the pipeline does not match the vertex format bound." ); |
7469 | // Make sure number of instances is valid. |
7470 | ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed, |
7471 | "Number of instances requested (" + itos(p_instances) + " is larger than the maximum number supported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ")." ); |
7472 | } |
7473 | |
7474 | if (dl->validation.pipeline_push_constant_size > 0) { |
7475 | // Using push constants, check that they were supplied. |
7476 | ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied, |
7477 | "The shader in this pipeline requires a push constant to be set before drawing, but it's not present." ); |
7478 | } |
7479 | |
7480 | #endif |
7481 | |
7482 | // Bind descriptor sets. |
7483 | |
7484 | for (uint32_t i = 0; i < dl->state.set_count; i++) { |
7485 | if (dl->state.sets[i].pipeline_expected_format == 0) { |
7486 | continue; // Nothing expected by this pipeline. |
7487 | } |
7488 | #ifdef DEBUG_ENABLED |
7489 | if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { |
7490 | if (dl->state.sets[i].uniform_set_format == 0) { |
7491 | ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline" ); |
7492 | } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { |
7493 | UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set); |
7494 | ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); |
7495 | } else { |
7496 | ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); |
7497 | } |
7498 | } |
7499 | #endif |
7500 | if (!dl->state.sets[i].bound) { |
7501 | // All good, see if this requires re-binding. |
7502 | vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, nullptr); |
7503 | dl->state.sets[i].bound = true; |
7504 | } |
7505 | } |
7506 | |
7507 | if (p_use_indices) { |
7508 | #ifdef DEBUG_ENABLED |
7509 | ERR_FAIL_COND_MSG(p_procedural_vertices > 0, |
7510 | "Procedural vertices can't be used together with indices." ); |
7511 | |
7512 | ERR_FAIL_COND_MSG(!dl->validation.index_array_size, |
7513 | "Draw command requested indices, but no index buffer was set." ); |
7514 | |
7515 | ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, |
7516 | "The usage of restart indices in index buffer does not match the render primitive in the pipeline." ); |
7517 | #endif |
7518 | uint32_t to_draw = dl->validation.index_array_size; |
7519 | |
7520 | #ifdef DEBUG_ENABLED |
7521 | ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, |
7522 | "Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")." ); |
7523 | |
7524 | ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, |
7525 | "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")." ); |
7526 | #endif |
7527 | vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); |
7528 | } else { |
7529 | uint32_t to_draw; |
7530 | |
7531 | if (p_procedural_vertices > 0) { |
7532 | #ifdef DEBUG_ENABLED |
7533 | ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != INVALID_ID, |
7534 | "Procedural vertices requested, but pipeline expects a vertex array." ); |
7535 | #endif |
7536 | to_draw = p_procedural_vertices; |
7537 | } else { |
7538 | #ifdef DEBUG_ENABLED |
7539 | ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, |
7540 | "Draw command lacks indices, but pipeline format does not use vertices." ); |
7541 | #endif |
7542 | to_draw = dl->validation.vertex_array_size; |
7543 | } |
7544 | |
7545 | #ifdef DEBUG_ENABLED |
7546 | ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, |
7547 | "Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")." ); |
7548 | |
7549 | ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, |
7550 | "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")." ); |
7551 | #endif |
7552 | |
7553 | vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); |
7554 | } |
7555 | } |
7556 | |
7557 | void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { |
7558 | DrawList *dl = _get_draw_list_ptr(p_list); |
7559 | |
7560 | ERR_FAIL_NULL(dl); |
7561 | #ifdef DEBUG_ENABLED |
7562 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7563 | #endif |
7564 | Rect2i rect = p_rect; |
7565 | rect.position += dl->viewport.position; |
7566 | |
7567 | rect = dl->viewport.intersection(rect); |
7568 | |
7569 | if (rect.get_area() == 0) { |
7570 | return; |
7571 | } |
7572 | VkRect2D scissor; |
7573 | scissor.offset.x = rect.position.x; |
7574 | scissor.offset.y = rect.position.y; |
7575 | scissor.extent.width = rect.size.width; |
7576 | scissor.extent.height = rect.size.height; |
7577 | |
7578 | vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); |
7579 | } |
7580 | |
7581 | void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { |
7582 | DrawList *dl = _get_draw_list_ptr(p_list); |
7583 | ERR_FAIL_NULL(dl); |
7584 | #ifdef DEBUG_ENABLED |
7585 | ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified." ); |
7586 | #endif |
7587 | |
7588 | VkRect2D scissor; |
7589 | scissor.offset.x = dl->viewport.position.x; |
7590 | scissor.offset.y = dl->viewport.position.y; |
7591 | scissor.extent.width = dl->viewport.size.width; |
7592 | scissor.extent.height = dl->viewport.size.height; |
7593 | vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); |
7594 | } |
7595 | |
7596 | uint32_t RenderingDeviceVulkan::draw_list_get_current_pass() { |
7597 | return draw_list_current_subpass; |
7598 | } |
7599 | |
7600 | RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass() { |
7601 | _THREAD_SAFE_METHOD_ |
7602 | ERR_FAIL_NULL_V(draw_list, INVALID_ID); |
7603 | ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID); |
7604 | |
7605 | draw_list_current_subpass++; |
7606 | |
7607 | Rect2i viewport; |
7608 | _draw_list_free(&viewport); |
7609 | |
7610 | vkCmdNextSubpass(frames[frame].draw_command_buffer, VK_SUBPASS_CONTENTS_INLINE); |
7611 | |
7612 | _draw_list_allocate(viewport, 0, draw_list_current_subpass); |
7613 | |
7614 | return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; |
7615 | } |
7616 | Error RenderingDeviceVulkan::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) { |
7617 | _THREAD_SAFE_METHOD_ |
7618 | ERR_FAIL_NULL_V(draw_list, ERR_INVALID_PARAMETER); |
7619 | ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER); |
7620 | |
7621 | draw_list_current_subpass++; |
7622 | |
7623 | Rect2i viewport; |
7624 | _draw_list_free(&viewport); |
7625 | |
7626 | vkCmdNextSubpass(frames[frame].draw_command_buffer, VK_SUBPASS_CONTENTS_INLINE); |
7627 | |
7628 | _draw_list_allocate(viewport, p_splits, draw_list_current_subpass); |
7629 | |
7630 | for (uint32_t i = 0; i < p_splits; i++) { |
7631 | r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; |
7632 | } |
7633 | |
7634 | return OK; |
7635 | } |
7636 | |
7637 | Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) { |
7638 | // Lock while draw_list is active. |
7639 | _THREAD_SAFE_LOCK_ |
7640 | |
7641 | if (p_splits == 0) { |
7642 | draw_list = memnew(DrawList); |
7643 | draw_list->command_buffer = frames[frame].draw_command_buffer; |
7644 | draw_list->viewport = p_viewport; |
7645 | draw_list_count = 0; |
7646 | draw_list_split = false; |
7647 | } else { |
7648 | if (p_splits > (uint32_t)split_draw_list_allocators.size()) { |
7649 | uint32_t from = split_draw_list_allocators.size(); |
7650 | split_draw_list_allocators.resize(p_splits); |
7651 | for (uint32_t i = from; i < p_splits; i++) { |
7652 | VkCommandPoolCreateInfo cmd_pool_info; |
7653 | cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
7654 | cmd_pool_info.pNext = nullptr; |
7655 | cmd_pool_info.queueFamilyIndex = context->get_graphics_queue_family_index(); |
7656 | cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
7657 | |
7658 | VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &split_draw_list_allocators.write[i].command_pool); |
7659 | ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "vkCreateCommandPool failed with error " + itos(res) + "." ); |
7660 | |
7661 | for (int j = 0; j < frame_count; j++) { |
7662 | VkCommandBuffer command_buffer; |
7663 | |
7664 | VkCommandBufferAllocateInfo cmdbuf; |
7665 | // No command buffer exists, create it. |
7666 | cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
7667 | cmdbuf.pNext = nullptr; |
7668 | cmdbuf.commandPool = split_draw_list_allocators[i].command_pool; |
7669 | cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; |
7670 | cmdbuf.commandBufferCount = 1; |
7671 | |
7672 | VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &command_buffer); |
7673 | ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkAllocateCommandBuffers failed with error " + itos(err) + "." ); |
7674 | |
7675 | split_draw_list_allocators.write[i].command_buffers.push_back(command_buffer); |
7676 | } |
7677 | } |
7678 | } |
7679 | draw_list = memnew_arr(DrawList, p_splits); |
7680 | draw_list_count = p_splits; |
7681 | draw_list_split = true; |
7682 | |
7683 | for (uint32_t i = 0; i < p_splits; i++) { |
7684 | // Take a command buffer and initialize it. |
7685 | VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame]; |
7686 | |
7687 | VkCommandBufferInheritanceInfo inheritance_info; |
7688 | inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; |
7689 | inheritance_info.pNext = nullptr; |
7690 | inheritance_info.renderPass = draw_list_render_pass; |
7691 | inheritance_info.subpass = p_subpass; |
7692 | inheritance_info.framebuffer = draw_list_vkframebuffer; |
7693 | inheritance_info.occlusionQueryEnable = false; |
7694 | inheritance_info.queryFlags = 0; // ? |
7695 | inheritance_info.pipelineStatistics = 0; |
7696 | |
7697 | VkCommandBufferBeginInfo cmdbuf_begin; |
7698 | cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
7699 | cmdbuf_begin.pNext = nullptr; |
7700 | cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; |
7701 | cmdbuf_begin.pInheritanceInfo = &inheritance_info; |
7702 | |
7703 | VkResult res = vkResetCommandBuffer(command_buffer, 0); |
7704 | if (res) { |
7705 | memdelete_arr(draw_list); |
7706 | draw_list = nullptr; |
7707 | ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkResetCommandBuffer failed with error " + itos(res) + "." ); |
7708 | } |
7709 | |
7710 | res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin); |
7711 | if (res) { |
7712 | memdelete_arr(draw_list); |
7713 | draw_list = nullptr; |
7714 | ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkBeginCommandBuffer failed with error " + itos(res) + "." ); |
7715 | } |
7716 | |
7717 | draw_list[i].command_buffer = command_buffer; |
7718 | draw_list[i].viewport = p_viewport; |
7719 | } |
7720 | } |
7721 | |
7722 | return OK; |
7723 | } |
7724 | |
7725 | void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) { |
7726 | if (draw_list_split) { |
7727 | // Send all command buffers. |
7728 | VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count); |
7729 | for (uint32_t i = 0; i < draw_list_count; i++) { |
7730 | vkEndCommandBuffer(draw_list[i].command_buffer); |
7731 | command_buffers[i] = draw_list[i].command_buffer; |
7732 | if (r_last_viewport) { |
7733 | if (i == 0 || draw_list[i].viewport_set) { |
7734 | *r_last_viewport = draw_list[i].viewport; |
7735 | } |
7736 | } |
7737 | } |
7738 | |
7739 | vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers); |
7740 | memdelete_arr(draw_list); |
7741 | draw_list = nullptr; |
7742 | |
7743 | } else { |
7744 | if (r_last_viewport) { |
7745 | *r_last_viewport = draw_list->viewport; |
7746 | } |
7747 | // Just end the list. |
7748 | memdelete(draw_list); |
7749 | draw_list = nullptr; |
7750 | } |
7751 | |
7752 | // Draw_list is no longer active. |
7753 | _THREAD_SAFE_UNLOCK_ |
7754 | } |
7755 | |
7756 | void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier) { |
7757 | _THREAD_SAFE_METHOD_ |
7758 | |
7759 | ERR_FAIL_NULL_MSG(draw_list, "Immediate draw list is already inactive." ); |
7760 | |
7761 | _draw_list_free(); |
7762 | |
7763 | vkCmdEndRenderPass(frames[frame].draw_command_buffer); |
7764 | |
7765 | for (int i = 0; i < draw_list_bound_textures.size(); i++) { |
7766 | Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]); |
7767 | ERR_CONTINUE(!texture); // Wtf. |
7768 | if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { |
7769 | texture->bound = false; |
7770 | } |
7771 | if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
7772 | texture->bound = false; |
7773 | } |
7774 | } |
7775 | |
7776 | uint32_t barrier_flags = 0; |
7777 | uint32_t access_flags = 0; |
7778 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
7779 | barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
7780 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
7781 | } |
7782 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
7783 | barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/; |
7784 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/; |
7785 | } |
7786 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
7787 | barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/; |
7788 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/; |
7789 | } |
7790 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
7791 | barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
7792 | access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; |
7793 | } |
7794 | |
7795 | if (barrier_flags == 0) { |
7796 | barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
7797 | } |
7798 | |
7799 | draw_list_bound_textures.clear(); |
7800 | |
7801 | VkImageMemoryBarrier *image_barriers = nullptr; |
7802 | |
7803 | uint32_t image_barrier_count = draw_list_storage_textures.size(); |
7804 | |
7805 | if (image_barrier_count) { |
7806 | image_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * draw_list_storage_textures.size()); |
7807 | } |
7808 | |
7809 | uint32_t src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | |
7810 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; |
7811 | uint32_t src_access = |
7812 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
7813 | |
7814 | if (image_barrier_count) { |
7815 | src_stage |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
7816 | src_access |= VK_ACCESS_SHADER_WRITE_BIT; |
7817 | } |
7818 | |
7819 | for (uint32_t i = 0; i < image_barrier_count; i++) { |
7820 | Texture *texture = texture_owner.get_or_null(draw_list_storage_textures[i]); |
7821 | |
7822 | VkImageMemoryBarrier &image_memory_barrier = image_barriers[i]; |
7823 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
7824 | image_memory_barrier.pNext = nullptr; |
7825 | image_memory_barrier.srcAccessMask = src_access; |
7826 | image_memory_barrier.dstAccessMask = access_flags; |
7827 | image_memory_barrier.oldLayout = texture->layout; |
7828 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
7829 | |
7830 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
7831 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
7832 | image_memory_barrier.image = texture->image; |
7833 | image_memory_barrier.subresourceRange.aspectMask = texture->read_aspect_mask; |
7834 | image_memory_barrier.subresourceRange.baseMipLevel = texture->base_mipmap; |
7835 | image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; |
7836 | image_memory_barrier.subresourceRange.baseArrayLayer = texture->base_layer; |
7837 | image_memory_barrier.subresourceRange.layerCount = texture->layers; |
7838 | |
7839 | texture->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
7840 | } |
7841 | |
7842 | draw_list_storage_textures.clear(); |
7843 | |
7844 | // To ensure proper synchronization, we must make sure rendering is done before: |
7845 | // * Some buffer is copied. |
7846 | // * Another render pass happens (since we may be done). |
7847 | |
7848 | VkMemoryBarrier mem_barrier; |
7849 | mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; |
7850 | mem_barrier.pNext = nullptr; |
7851 | mem_barrier.srcAccessMask = src_access; |
7852 | mem_barrier.dstAccessMask = access_flags; |
7853 | |
7854 | if (image_barrier_count > 0 || p_post_barrier != BARRIER_MASK_NO_BARRIER) { |
7855 | vkCmdPipelineBarrier(frames[frame].draw_command_buffer, src_stage, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers); |
7856 | } |
7857 | |
7858 | #ifdef FORCE_FULL_BARRIER |
7859 | _full_barrier(true); |
7860 | #endif |
7861 | } |
7862 | |
7863 | /***********************/ |
7864 | /**** COMPUTE LISTS ****/ |
7865 | /***********************/ |
7866 | |
7867 | RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin(bool p_allow_draw_overlap) { |
7868 | _THREAD_SAFE_METHOD_ |
7869 | |
7870 | ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time." ); |
7871 | ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time." ); |
7872 | |
7873 | // Lock while compute_list is active. |
7874 | _THREAD_SAFE_LOCK_ |
7875 | |
7876 | compute_list = memnew(ComputeList); |
7877 | compute_list->command_buffer = frames[frame].draw_command_buffer; |
7878 | compute_list->state.allow_draw_overlap = p_allow_draw_overlap; |
7879 | |
7880 | return ID_TYPE_COMPUTE_LIST; |
7881 | } |
7882 | |
7883 | void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) { |
7884 | // Must be called within a compute list, the class mutex is locked during that time |
7885 | |
7886 | ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); |
7887 | ERR_FAIL_NULL(compute_list); |
7888 | |
7889 | ComputeList *cl = compute_list; |
7890 | |
7891 | const ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_compute_pipeline); |
7892 | ERR_FAIL_NULL(pipeline); |
7893 | |
7894 | if (p_compute_pipeline == cl->state.pipeline) { |
7895 | return; // Redundant state, return. |
7896 | } |
7897 | |
7898 | cl->state.pipeline = p_compute_pipeline; |
7899 | cl->state.pipeline_layout = pipeline->pipeline_layout; |
7900 | |
7901 | vkCmdBindPipeline(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline); |
7902 | |
7903 | if (cl->state.pipeline_shader != pipeline->shader) { |
7904 | // Shader changed, so descriptor sets may become incompatible. |
7905 | |
7906 | // Go through ALL sets, and unbind them (and all those above) if the format is different. |
7907 | |
7908 | uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline. |
7909 | cl->state.set_count = MAX(cl->state.set_count, pcount); |
7910 | const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats. |
7911 | |
7912 | bool sets_valid = true; // Once invalid, all above become invalid. |
7913 | for (uint32_t i = 0; i < pcount; i++) { |
7914 | // If a part of the format is different, invalidate it (and the rest). |
7915 | if (!sets_valid || cl->state.sets[i].pipeline_expected_format != pformats[i]) { |
7916 | cl->state.sets[i].bound = false; |
7917 | cl->state.sets[i].pipeline_expected_format = pformats[i]; |
7918 | sets_valid = false; |
7919 | } |
7920 | } |
7921 | |
7922 | for (uint32_t i = pcount; i < cl->state.set_count; i++) { |
7923 | // Unbind the ones above (not used) if exist. |
7924 | cl->state.sets[i].bound = false; |
7925 | } |
7926 | |
7927 | cl->state.set_count = pcount; // Update set count. |
7928 | |
7929 | if (pipeline->push_constant_size) { |
7930 | cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask; |
7931 | #ifdef DEBUG_ENABLED |
7932 | cl->validation.pipeline_push_constant_supplied = false; |
7933 | #endif |
7934 | } |
7935 | |
7936 | cl->state.pipeline_shader = pipeline->shader; |
7937 | cl->state.local_group_size[0] = pipeline->local_group_size[0]; |
7938 | cl->state.local_group_size[1] = pipeline->local_group_size[1]; |
7939 | cl->state.local_group_size[2] = pipeline->local_group_size[2]; |
7940 | } |
7941 | |
7942 | #ifdef DEBUG_ENABLED |
7943 | // Update compute pass pipeline info. |
7944 | cl->validation.pipeline_active = true; |
7945 | cl->validation.pipeline_push_constant_size = pipeline->push_constant_size; |
7946 | #endif |
7947 | } |
7948 | |
7949 | void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) { |
7950 | // Must be called within a compute list, the class mutex is locked during that time |
7951 | |
7952 | ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); |
7953 | ERR_FAIL_NULL(compute_list); |
7954 | |
7955 | ComputeList *cl = compute_list; |
7956 | |
7957 | #ifdef DEBUG_ENABLED |
7958 | ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS, |
7959 | "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")." ); |
7960 | #endif |
7961 | |
7962 | #ifdef DEBUG_ENABLED |
7963 | ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified." ); |
7964 | #endif |
7965 | |
7966 | UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set); |
7967 | ERR_FAIL_NULL(uniform_set); |
7968 | |
7969 | if (p_index > cl->state.set_count) { |
7970 | cl->state.set_count = p_index; |
7971 | } |
7972 | |
7973 | cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer. |
7974 | cl->state.sets[p_index].bound = false; // Needs rebind. |
7975 | cl->state.sets[p_index].uniform_set_format = uniform_set->format; |
7976 | cl->state.sets[p_index].uniform_set = p_uniform_set; |
7977 | |
7978 | uint32_t textures_to_sampled_count = uniform_set->mutable_sampled_textures.size(); |
7979 | uint32_t textures_to_storage_count = uniform_set->mutable_storage_textures.size(); |
7980 | |
7981 | Texture **textures_to_sampled = uniform_set->mutable_sampled_textures.ptrw(); |
7982 | |
7983 | VkImageMemoryBarrier *texture_barriers = nullptr; |
7984 | |
7985 | if (textures_to_sampled_count + textures_to_storage_count) { |
7986 | texture_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * (textures_to_sampled_count + textures_to_storage_count)); |
7987 | } |
7988 | uint32_t texture_barrier_count = 0; |
7989 | |
7990 | uint32_t src_stage_flags = 0; |
7991 | |
7992 | for (uint32_t i = 0; i < textures_to_sampled_count; i++) { |
7993 | if (textures_to_sampled[i]->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { |
7994 | src_stage_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
7995 | |
7996 | VkImageMemoryBarrier &image_memory_barrier = texture_barriers[texture_barrier_count++]; |
7997 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
7998 | image_memory_barrier.pNext = nullptr; |
7999 | image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8000 | image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8001 | image_memory_barrier.oldLayout = textures_to_sampled[i]->layout; |
8002 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
8003 | |
8004 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
8005 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
8006 | image_memory_barrier.image = textures_to_sampled[i]->image; |
8007 | image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask; |
8008 | image_memory_barrier.subresourceRange.baseMipLevel = textures_to_sampled[i]->base_mipmap; |
8009 | image_memory_barrier.subresourceRange.levelCount = textures_to_sampled[i]->mipmaps; |
8010 | image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_sampled[i]->base_layer; |
8011 | image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers; |
8012 | |
8013 | textures_to_sampled[i]->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
8014 | |
8015 | cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]); |
8016 | } |
8017 | |
8018 | if (textures_to_sampled[i]->used_in_frame != frames_drawn) { |
8019 | textures_to_sampled[i]->used_in_frame = frames_drawn; |
8020 | textures_to_sampled[i]->used_in_transfer = false; |
8021 | textures_to_sampled[i]->used_in_raster = false; |
8022 | } |
8023 | textures_to_sampled[i]->used_in_compute = true; |
8024 | } |
8025 | |
8026 | Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw(); |
8027 | |
8028 | for (uint32_t i = 0; i < textures_to_storage_count; i++) { |
8029 | if (textures_to_storage[i]->layout != VK_IMAGE_LAYOUT_GENERAL) { |
8030 | uint32_t src_access_flags = 0; |
8031 | |
8032 | if (textures_to_storage[i]->used_in_frame == frames_drawn) { |
8033 | if (textures_to_storage[i]->used_in_compute) { |
8034 | src_stage_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
8035 | src_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8036 | } |
8037 | if (textures_to_storage[i]->used_in_raster) { |
8038 | src_stage_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; |
8039 | src_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8040 | } |
8041 | if (textures_to_storage[i]->used_in_transfer) { |
8042 | src_stage_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
8043 | src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; |
8044 | } |
8045 | |
8046 | textures_to_storage[i]->used_in_compute = false; |
8047 | textures_to_storage[i]->used_in_raster = false; |
8048 | textures_to_storage[i]->used_in_transfer = false; |
8049 | |
8050 | } else { |
8051 | src_access_flags = 0; |
8052 | textures_to_storage[i]->used_in_compute = false; |
8053 | textures_to_storage[i]->used_in_raster = false; |
8054 | textures_to_storage[i]->used_in_transfer = false; |
8055 | textures_to_storage[i]->used_in_frame = frames_drawn; |
8056 | } |
8057 | |
8058 | VkImageMemoryBarrier &image_memory_barrier = texture_barriers[texture_barrier_count++]; |
8059 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
8060 | image_memory_barrier.pNext = nullptr; |
8061 | image_memory_barrier.srcAccessMask = src_access_flags; |
8062 | image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8063 | image_memory_barrier.oldLayout = textures_to_storage[i]->layout; |
8064 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
8065 | |
8066 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
8067 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
8068 | image_memory_barrier.image = textures_to_storage[i]->image; |
8069 | image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask; |
8070 | image_memory_barrier.subresourceRange.baseMipLevel = textures_to_storage[i]->base_mipmap; |
8071 | image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps; |
8072 | image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_storage[i]->base_layer; |
8073 | image_memory_barrier.subresourceRange.layerCount = textures_to_storage[i]->layers; |
8074 | |
8075 | textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL; |
8076 | |
8077 | cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards. |
8078 | } |
8079 | } |
8080 | |
8081 | if (texture_barrier_count) { |
8082 | if (src_stage_flags == 0) { |
8083 | src_stage_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; |
8084 | } |
8085 | |
8086 | vkCmdPipelineBarrier(cl->command_buffer, src_stage_flags, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, texture_barrier_count, texture_barriers); |
8087 | } |
8088 | |
8089 | #if 0 |
8090 | { // Validate that textures bound are not attached as framebuffer bindings. |
8091 | uint32_t attachable_count = uniform_set->attachable_textures.size(); |
8092 | const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); |
8093 | uint32_t bound_count = draw_list_bound_textures.size(); |
8094 | const RID *bound_ptr = draw_list_bound_textures.ptr(); |
8095 | for (uint32_t i = 0; i < attachable_count; i++) { |
8096 | for (uint32_t j = 0; j < bound_count; j++) { |
8097 | ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], |
8098 | "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed." ); |
8099 | } |
8100 | } |
8101 | } |
8102 | #endif |
8103 | } |
8104 | |
8105 | void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) { |
8106 | ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); |
8107 | ERR_FAIL_NULL(compute_list); |
8108 | |
8109 | ComputeList *cl = compute_list; |
8110 | |
8111 | #ifdef DEBUG_ENABLED |
8112 | ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified." ); |
8113 | #endif |
8114 | |
8115 | #ifdef DEBUG_ENABLED |
8116 | ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_push_constant_size, |
8117 | "This compute pipeline requires (" + itos(cl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")" ); |
8118 | #endif |
8119 | vkCmdPushConstants(cl->command_buffer, cl->state.pipeline_layout, cl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); |
8120 | #ifdef DEBUG_ENABLED |
8121 | cl->validation.pipeline_push_constant_supplied = true; |
8122 | #endif |
8123 | } |
8124 | |
8125 | void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) { |
8126 | // Must be called within a compute list, the class mutex is locked during that time |
8127 | |
8128 | ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); |
8129 | ERR_FAIL_NULL(compute_list); |
8130 | |
8131 | ComputeList *cl = compute_list; |
8132 | |
8133 | #ifdef DEBUG_ENABLED |
8134 | ERR_FAIL_COND_MSG(p_x_groups == 0, "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is zero." ); |
8135 | ERR_FAIL_COND_MSG(p_z_groups == 0, "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is zero." ); |
8136 | ERR_FAIL_COND_MSG(p_y_groups == 0, "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is zero." ); |
8137 | ERR_FAIL_COND_MSG(p_x_groups > limits.maxComputeWorkGroupCount[0], |
8138 | "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")" ); |
8139 | ERR_FAIL_COND_MSG(p_y_groups > limits.maxComputeWorkGroupCount[1], |
8140 | "Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[1]) + ")" ); |
8141 | ERR_FAIL_COND_MSG(p_z_groups > limits.maxComputeWorkGroupCount[2], |
8142 | "Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[2]) + ")" ); |
8143 | |
8144 | ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified." ); |
8145 | #endif |
8146 | |
8147 | #ifdef DEBUG_ENABLED |
8148 | |
8149 | ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw." ); |
8150 | |
8151 | if (cl->validation.pipeline_push_constant_size > 0) { |
8152 | // Using push constants, check that they were supplied. |
8153 | ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied, |
8154 | "The shader in this pipeline requires a push constant to be set before drawing, but it's not present." ); |
8155 | } |
8156 | |
8157 | #endif |
8158 | |
8159 | // Bind descriptor sets. |
8160 | |
8161 | for (uint32_t i = 0; i < cl->state.set_count; i++) { |
8162 | if (cl->state.sets[i].pipeline_expected_format == 0) { |
8163 | continue; // Nothing expected by this pipeline. |
8164 | } |
8165 | #ifdef DEBUG_ENABLED |
8166 | if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { |
8167 | if (cl->state.sets[i].uniform_set_format == 0) { |
8168 | ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline" ); |
8169 | } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { |
8170 | UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); |
8171 | ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); |
8172 | } else { |
8173 | ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); |
8174 | } |
8175 | } |
8176 | #endif |
8177 | if (!cl->state.sets[i].bound) { |
8178 | // All good, see if this requires re-binding. |
8179 | vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr); |
8180 | cl->state.sets[i].bound = true; |
8181 | } |
8182 | } |
8183 | |
8184 | vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups); |
8185 | } |
8186 | |
8187 | void RenderingDeviceVulkan::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) { |
8188 | ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); |
8189 | ERR_FAIL_NULL(compute_list); |
8190 | |
8191 | #ifdef DEBUG_ENABLED |
8192 | ERR_FAIL_COND_MSG(p_x_threads == 0, "Dispatch amount of X compute threads (" + itos(p_x_threads) + ") is zero." ); |
8193 | ERR_FAIL_COND_MSG(p_y_threads == 0, "Dispatch amount of Y compute threads (" + itos(p_y_threads) + ") is zero." ); |
8194 | ERR_FAIL_COND_MSG(p_z_threads == 0, "Dispatch amount of Z compute threads (" + itos(p_z_threads) + ") is zero." ); |
8195 | #endif |
8196 | |
8197 | ComputeList *cl = compute_list; |
8198 | |
8199 | #ifdef DEBUG_ENABLED |
8200 | |
8201 | ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw." ); |
8202 | |
8203 | if (cl->validation.pipeline_push_constant_size > 0) { |
8204 | // Using push constants, check that they were supplied. |
8205 | ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied, |
8206 | "The shader in this pipeline requires a push constant to be set before drawing, but it's not present." ); |
8207 | } |
8208 | |
8209 | #endif |
8210 | |
8211 | compute_list_dispatch(p_list, (p_x_threads - 1) / cl->state.local_group_size[0] + 1, (p_y_threads - 1) / cl->state.local_group_size[1] + 1, (p_z_threads - 1) / cl->state.local_group_size[2] + 1); |
8212 | } |
8213 | |
8214 | void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) { |
8215 | ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); |
8216 | ERR_FAIL_NULL(compute_list); |
8217 | |
8218 | ComputeList *cl = compute_list; |
8219 | Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer); |
8220 | ERR_FAIL_NULL(buffer); |
8221 | |
8222 | ERR_FAIL_COND_MSG(!(buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), "Buffer provided was not created to do indirect dispatch." ); |
8223 | |
8224 | ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer." ); |
8225 | |
8226 | #ifdef DEBUG_ENABLED |
8227 | ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified." ); |
8228 | #endif |
8229 | |
8230 | #ifdef DEBUG_ENABLED |
8231 | |
8232 | ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw." ); |
8233 | |
8234 | if (cl->validation.pipeline_push_constant_size > 0) { |
8235 | // Using push constants, check that they were supplied. |
8236 | ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied, |
8237 | "The shader in this pipeline requires a push constant to be set before drawing, but it's not present." ); |
8238 | } |
8239 | |
8240 | #endif |
8241 | |
8242 | // Bind descriptor sets. |
8243 | |
8244 | for (uint32_t i = 0; i < cl->state.set_count; i++) { |
8245 | if (cl->state.sets[i].pipeline_expected_format == 0) { |
8246 | continue; // Nothing expected by this pipeline. |
8247 | } |
8248 | #ifdef DEBUG_ENABLED |
8249 | if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { |
8250 | if (cl->state.sets[i].uniform_set_format == 0) { |
8251 | ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline" ); |
8252 | } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { |
8253 | UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set); |
8254 | ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); |
8255 | } else { |
8256 | ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); |
8257 | } |
8258 | } |
8259 | #endif |
8260 | if (!cl->state.sets[i].bound) { |
8261 | // All good, see if this requires re-binding. |
8262 | vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr); |
8263 | cl->state.sets[i].bound = true; |
8264 | } |
8265 | } |
8266 | |
8267 | vkCmdDispatchIndirect(cl->command_buffer, buffer->buffer, p_offset); |
8268 | } |
8269 | |
8270 | void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { |
8271 | // Must be called within a compute list, the class mutex is locked during that time |
8272 | |
8273 | uint32_t barrier_flags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
8274 | uint32_t access_flags = VK_ACCESS_SHADER_READ_BIT; |
8275 | _compute_list_add_barrier(BARRIER_MASK_COMPUTE, barrier_flags, access_flags); |
8276 | } |
8277 | |
8278 | void RenderingDeviceVulkan::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, uint32_t p_barrier_flags, uint32_t p_access_flags) { |
8279 | ERR_FAIL_NULL(compute_list); |
8280 | |
8281 | VkImageMemoryBarrier *image_barriers = nullptr; |
8282 | |
8283 | uint32_t image_barrier_count = compute_list->state.textures_to_sampled_layout.size(); |
8284 | |
8285 | if (image_barrier_count) { |
8286 | image_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * image_barrier_count); |
8287 | } |
8288 | |
8289 | image_barrier_count = 0; // We'll count how many we end up issuing. |
8290 | |
8291 | for (Texture *E : compute_list->state.textures_to_sampled_layout) { |
8292 | if (E->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { |
8293 | VkImageMemoryBarrier &image_memory_barrier = image_barriers[image_barrier_count++]; |
8294 | image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
8295 | image_memory_barrier.pNext = nullptr; |
8296 | image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8297 | image_memory_barrier.dstAccessMask = p_access_flags; |
8298 | image_memory_barrier.oldLayout = E->layout; |
8299 | image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
8300 | |
8301 | image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
8302 | image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
8303 | image_memory_barrier.image = E->image; |
8304 | image_memory_barrier.subresourceRange.aspectMask = E->read_aspect_mask; |
8305 | image_memory_barrier.subresourceRange.baseMipLevel = E->base_mipmap; |
8306 | image_memory_barrier.subresourceRange.levelCount = E->mipmaps; |
8307 | image_memory_barrier.subresourceRange.baseArrayLayer = E->base_layer; |
8308 | image_memory_barrier.subresourceRange.layerCount = E->layers; |
8309 | |
8310 | E->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
8311 | } |
8312 | |
8313 | if (E->used_in_frame != frames_drawn) { |
8314 | E->used_in_transfer = false; |
8315 | E->used_in_raster = false; |
8316 | E->used_in_compute = false; |
8317 | E->used_in_frame = frames_drawn; |
8318 | } |
8319 | } |
8320 | |
8321 | if (p_barrier_flags) { |
8322 | VkMemoryBarrier mem_barrier; |
8323 | mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; |
8324 | mem_barrier.pNext = nullptr; |
8325 | mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; |
8326 | mem_barrier.dstAccessMask = p_access_flags; |
8327 | vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, p_barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers); |
8328 | } else if (image_barrier_count) { |
8329 | vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, image_barrier_count, image_barriers); |
8330 | } |
8331 | |
8332 | #ifdef FORCE_FULL_BARRIER |
8333 | _full_barrier(true); |
8334 | #endif |
8335 | } |
8336 | |
8337 | void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrier) { |
8338 | ERR_FAIL_NULL(compute_list); |
8339 | |
8340 | uint32_t barrier_flags = 0; |
8341 | uint32_t access_flags = 0; |
8342 | if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { |
8343 | barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
8344 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8345 | } |
8346 | if (p_post_barrier.has_flag(BARRIER_MASK_VERTEX)) { |
8347 | barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; |
8348 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; |
8349 | } |
8350 | if (p_post_barrier.has_flag(BARRIER_MASK_FRAGMENT)) { |
8351 | barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; |
8352 | access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; |
8353 | } |
8354 | if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { |
8355 | barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
8356 | access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; |
8357 | } |
8358 | _compute_list_add_barrier(p_post_barrier, barrier_flags, access_flags); |
8359 | |
8360 | memdelete(compute_list); |
8361 | compute_list = nullptr; |
8362 | |
8363 | // Compute_list is no longer active. |
8364 | _THREAD_SAFE_UNLOCK_ |
8365 | } |
8366 | |
8367 | void RenderingDeviceVulkan::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) { |
8368 | uint32_t src_barrier_flags = 0; |
8369 | uint32_t src_access_flags = 0; |
8370 | |
8371 | if (p_from == 0) { |
8372 | src_barrier_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; |
8373 | } else { |
8374 | if (p_from.has_flag(BARRIER_MASK_COMPUTE)) { |
8375 | src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
8376 | src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT; |
8377 | } |
8378 | if (p_from.has_flag(BARRIER_MASK_FRAGMENT)) { |
8379 | src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | |
8380 | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | |
8381 | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; |
8382 | src_access_flags |= |
8383 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
8384 | } |
8385 | if (p_from.has_flag(BARRIER_MASK_TRANSFER)) { |
8386 | src_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
8387 | src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; |
8388 | } |
8389 | } |
8390 | |
8391 | uint32_t dst_barrier_flags = 0; |
8392 | uint32_t dst_access_flags = 0; |
8393 | |
8394 | if (p_to == 0) { |
8395 | dst_barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; |
8396 | } else { |
8397 | if (p_to.has_flag(BARRIER_MASK_COMPUTE)) { |
8398 | dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
8399 | dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; |
8400 | } |
8401 | if (p_to.has_flag(BARRIER_MASK_VERTEX)) { |
8402 | dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; |
8403 | dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; |
8404 | } |
8405 | if (p_to.has_flag(BARRIER_MASK_FRAGMENT)) { |
8406 | dst_barrier_flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; |
8407 | dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; |
8408 | } |
8409 | if (p_to.has_flag(BARRIER_MASK_TRANSFER)) { |
8410 | dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; |
8411 | dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; |
8412 | } |
8413 | } |
8414 | |
8415 | _memory_barrier(src_barrier_flags, dst_barrier_flags, src_access_flags, dst_access_flags, true); |
8416 | } |
8417 | |
8418 | void RenderingDeviceVulkan::full_barrier() { |
8419 | #ifndef DEBUG_ENABLED |
8420 | ERR_PRINT("Full barrier is debug-only, should not be used in production" ); |
8421 | #endif |
8422 | _full_barrier(true); |
8423 | } |
8424 | |
8425 | #if 0 |
8426 | void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Variant> &p_clear_colors) { |
8427 | VkCommandBuffer frame_cmdbuf = frames[frame].frame_buffer; |
8428 | ERR_FAIL_NULL(frame_cmdbuf); |
8429 | |
8430 | VkRenderPassBeginInfo render_pass_begin; |
8431 | render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; |
8432 | render_pass_begin.pNext = nullptr; |
8433 | render_pass_begin.renderPass = context->get_render_pass(); |
8434 | render_pass_begin.framebuffer = context->get_frame_framebuffer(frame); |
8435 | |
8436 | render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen); |
8437 | render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen); |
8438 | render_pass_begin.renderArea.offset.x = 0; |
8439 | render_pass_begin.renderArea.offset.y = 0; |
8440 | |
8441 | render_pass_begin.clearValueCount = 1; |
8442 | |
8443 | VkClearValue clear_value; |
8444 | clear_value.color.float32[0] = p_clear_color.r; |
8445 | clear_value.color.float32[1] = p_clear_color.g; |
8446 | clear_value.color.float32[2] = p_clear_color.b; |
8447 | clear_value.color.float32[3] = p_clear_color.a; |
8448 | |
8449 | render_pass_begin.pClearValues = &clear_value; |
8450 | |
8451 | vkCmdBeginRenderPass(frame_cmdbuf, &render_pass_begin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); |
8452 | |
8453 | ID screen_format = screen_get_framebuffer_format(); |
8454 | { |
8455 | VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * p_draw_list_count); |
8456 | uint32_t command_buffer_count = 0; |
8457 | |
8458 | for (uint32_t i = 0; i < p_draw_list_count; i++) { |
8459 | DrawList *dl = _get_draw_list_ptr(p_draw_lists[i]); |
8460 | ERR_CONTINUE_MSG(!dl, "Draw list index (" + itos(i) + ") is not a valid draw list ID." ); |
8461 | ERR_CONTINUE_MSG(dl->validation.framebuffer_format != p_format_check, |
8462 | "Draw list index (" + itos(i) + ") is created with a framebuffer format incompatible with this render pass." ); |
8463 | |
8464 | if (dl->validation.active) { |
8465 | // Needs to be closed, so close it. |
8466 | vkEndCommandBuffer(dl->command_buffer); |
8467 | dl->validation.active = false; |
8468 | } |
8469 | |
8470 | command_buffers[command_buffer_count++] = dl->command_buffer; |
8471 | } |
8472 | |
8473 | print_line("to draw: " + itos(command_buffer_count)); |
8474 | vkCmdExecuteCommands(p_primary, command_buffer_count, command_buffers); |
8475 | } |
8476 | |
8477 | vkCmdEndRenderPass(frame_cmdbuf); |
8478 | } |
8479 | #endif |
8480 | |
8481 | void RenderingDeviceVulkan::_free_internal(RID p_id) { |
8482 | #ifdef DEV_ENABLED |
8483 | String resource_name; |
8484 | if (resource_names.has(p_id)) { |
8485 | resource_name = resource_names[p_id]; |
8486 | resource_names.erase(p_id); |
8487 | } |
8488 | #endif |
8489 | |
8490 | // Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it). |
8491 | if (texture_owner.owns(p_id)) { |
8492 | Texture *texture = texture_owner.get_or_null(p_id); |
8493 | frames[frame].textures_to_dispose_of.push_back(*texture); |
8494 | texture_owner.free(p_id); |
8495 | } else if (framebuffer_owner.owns(p_id)) { |
8496 | Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id); |
8497 | frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer); |
8498 | |
8499 | if (framebuffer->invalidated_callback != nullptr) { |
8500 | framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata); |
8501 | } |
8502 | |
8503 | framebuffer_owner.free(p_id); |
8504 | } else if (sampler_owner.owns(p_id)) { |
8505 | VkSampler *sampler = sampler_owner.get_or_null(p_id); |
8506 | frames[frame].samplers_to_dispose_of.push_back(*sampler); |
8507 | sampler_owner.free(p_id); |
8508 | } else if (vertex_buffer_owner.owns(p_id)) { |
8509 | Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id); |
8510 | frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer); |
8511 | vertex_buffer_owner.free(p_id); |
8512 | } else if (vertex_array_owner.owns(p_id)) { |
8513 | vertex_array_owner.free(p_id); |
8514 | } else if (index_buffer_owner.owns(p_id)) { |
8515 | IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id); |
8516 | Buffer b; |
8517 | b.allocation = index_buffer->allocation; |
8518 | b.buffer = index_buffer->buffer; |
8519 | b.size = index_buffer->size; |
8520 | b.buffer_info = {}; |
8521 | frames[frame].buffers_to_dispose_of.push_back(b); |
8522 | index_buffer_owner.free(p_id); |
8523 | } else if (index_array_owner.owns(p_id)) { |
8524 | index_array_owner.free(p_id); |
8525 | } else if (shader_owner.owns(p_id)) { |
8526 | Shader *shader = shader_owner.get_or_null(p_id); |
8527 | frames[frame].shaders_to_dispose_of.push_back(*shader); |
8528 | shader_owner.free(p_id); |
8529 | } else if (uniform_buffer_owner.owns(p_id)) { |
8530 | Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id); |
8531 | frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer); |
8532 | uniform_buffer_owner.free(p_id); |
8533 | } else if (texture_buffer_owner.owns(p_id)) { |
8534 | TextureBuffer *texture_buffer = texture_buffer_owner.get_or_null(p_id); |
8535 | frames[frame].buffers_to_dispose_of.push_back(texture_buffer->buffer); |
8536 | frames[frame].buffer_views_to_dispose_of.push_back(texture_buffer->view); |
8537 | texture_buffer_owner.free(p_id); |
8538 | } else if (storage_buffer_owner.owns(p_id)) { |
8539 | Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id); |
8540 | frames[frame].buffers_to_dispose_of.push_back(*storage_buffer); |
8541 | storage_buffer_owner.free(p_id); |
8542 | } else if (uniform_set_owner.owns(p_id)) { |
8543 | UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id); |
8544 | frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); |
8545 | uniform_set_owner.free(p_id); |
8546 | |
8547 | if (uniform_set->invalidated_callback != nullptr) { |
8548 | uniform_set->invalidated_callback(uniform_set->invalidated_callback_userdata); |
8549 | } |
8550 | } else if (render_pipeline_owner.owns(p_id)) { |
8551 | RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id); |
8552 | frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline); |
8553 | render_pipeline_owner.free(p_id); |
8554 | } else if (compute_pipeline_owner.owns(p_id)) { |
8555 | ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id); |
8556 | frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline); |
8557 | compute_pipeline_owner.free(p_id); |
8558 | } else { |
8559 | #ifdef DEV_ENABLED |
8560 | ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name); |
8561 | #else |
8562 | ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id())); |
8563 | #endif |
8564 | } |
8565 | } |
8566 | |
8567 | void RenderingDeviceVulkan::free(RID p_id) { |
8568 | _THREAD_SAFE_METHOD_ |
8569 | |
8570 | _free_dependencies(p_id); // Recursively erase dependencies first, to avoid potential API problems. |
8571 | _free_internal(p_id); |
8572 | } |
8573 | |
8574 | // The full list of resources that can be named is in the VkObjectType enum. |
8575 | // We just expose the resources that are owned and can be accessed easily. |
8576 | void RenderingDeviceVulkan::set_resource_name(RID p_id, const String p_name) { |
8577 | if (texture_owner.owns(p_id)) { |
8578 | Texture *texture = texture_owner.get_or_null(p_id); |
8579 | if (texture->owner.is_null()) { |
8580 | // Don't set the source texture's name when calling on a texture view. |
8581 | context->set_object_name(VK_OBJECT_TYPE_IMAGE, uint64_t(texture->image), p_name); |
8582 | } |
8583 | context->set_object_name(VK_OBJECT_TYPE_IMAGE_VIEW, uint64_t(texture->view), p_name + " View" ); |
8584 | } else if (framebuffer_owner.owns(p_id)) { |
8585 | //Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id); |
8586 | // Not implemented for now as the relationship between Framebuffer and RenderPass is very complex. |
8587 | } else if (sampler_owner.owns(p_id)) { |
8588 | VkSampler *sampler = sampler_owner.get_or_null(p_id); |
8589 | context->set_object_name(VK_OBJECT_TYPE_SAMPLER, uint64_t(*sampler), p_name); |
8590 | } else if (vertex_buffer_owner.owns(p_id)) { |
8591 | Buffer *vertex_buffer = vertex_buffer_owner.get_or_null(p_id); |
8592 | context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(vertex_buffer->buffer), p_name); |
8593 | } else if (index_buffer_owner.owns(p_id)) { |
8594 | IndexBuffer *index_buffer = index_buffer_owner.get_or_null(p_id); |
8595 | context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(index_buffer->buffer), p_name); |
8596 | } else if (shader_owner.owns(p_id)) { |
8597 | Shader *shader = shader_owner.get_or_null(p_id); |
8598 | context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(shader->pipeline_layout), p_name + " Pipeline Layout" ); |
8599 | for (int i = 0; i < shader->sets.size(); i++) { |
8600 | context->set_object_name(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, uint64_t(shader->sets[i].descriptor_set_layout), p_name); |
8601 | } |
8602 | } else if (uniform_buffer_owner.owns(p_id)) { |
8603 | Buffer *uniform_buffer = uniform_buffer_owner.get_or_null(p_id); |
8604 | context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(uniform_buffer->buffer), p_name); |
8605 | } else if (texture_buffer_owner.owns(p_id)) { |
8606 | TextureBuffer *texture_buffer = texture_buffer_owner.get_or_null(p_id); |
8607 | context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(texture_buffer->buffer.buffer), p_name); |
8608 | context->set_object_name(VK_OBJECT_TYPE_BUFFER_VIEW, uint64_t(texture_buffer->view), p_name + " View" ); |
8609 | } else if (storage_buffer_owner.owns(p_id)) { |
8610 | Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id); |
8611 | context->set_object_name(VK_OBJECT_TYPE_BUFFER, uint64_t(storage_buffer->buffer), p_name); |
8612 | } else if (uniform_set_owner.owns(p_id)) { |
8613 | UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id); |
8614 | context->set_object_name(VK_OBJECT_TYPE_DESCRIPTOR_SET, uint64_t(uniform_set->descriptor_set), p_name); |
8615 | } else if (render_pipeline_owner.owns(p_id)) { |
8616 | RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id); |
8617 | context->set_object_name(VK_OBJECT_TYPE_PIPELINE, uint64_t(pipeline->pipeline), p_name); |
8618 | context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(pipeline->pipeline_layout), p_name + " Layout" ); |
8619 | } else if (compute_pipeline_owner.owns(p_id)) { |
8620 | ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id); |
8621 | context->set_object_name(VK_OBJECT_TYPE_PIPELINE, uint64_t(pipeline->pipeline), p_name); |
8622 | context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(pipeline->pipeline_layout), p_name + " Layout" ); |
8623 | } else { |
8624 | ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id())); |
8625 | return; |
8626 | } |
8627 | #ifdef DEV_ENABLED |
8628 | resource_names[p_id] = p_name; |
8629 | #endif |
8630 | } |
8631 | |
8632 | void RenderingDeviceVulkan::draw_command_begin_label(String p_label_name, const Color p_color) { |
8633 | _THREAD_SAFE_METHOD_ |
8634 | context->command_begin_label(frames[frame].draw_command_buffer, p_label_name, p_color); |
8635 | } |
8636 | |
8637 | void RenderingDeviceVulkan::draw_command_insert_label(String p_label_name, const Color p_color) { |
8638 | _THREAD_SAFE_METHOD_ |
8639 | context->command_insert_label(frames[frame].draw_command_buffer, p_label_name, p_color); |
8640 | } |
8641 | |
8642 | void RenderingDeviceVulkan::draw_command_end_label() { |
8643 | _THREAD_SAFE_METHOD_ |
8644 | context->command_end_label(frames[frame].draw_command_buffer); |
8645 | } |
8646 | |
8647 | String RenderingDeviceVulkan::get_device_vendor_name() const { |
8648 | return context->get_device_vendor_name(); |
8649 | } |
8650 | |
8651 | String RenderingDeviceVulkan::get_device_name() const { |
8652 | return context->get_device_name(); |
8653 | } |
8654 | |
8655 | RenderingDevice::DeviceType RenderingDeviceVulkan::get_device_type() const { |
8656 | return context->get_device_type(); |
8657 | } |
8658 | |
8659 | String RenderingDeviceVulkan::get_device_api_version() const { |
8660 | return context->get_device_api_version(); |
8661 | } |
8662 | |
8663 | String RenderingDeviceVulkan::get_device_pipeline_cache_uuid() const { |
8664 | return context->get_device_pipeline_cache_uuid(); |
8665 | } |
8666 | |
8667 | void RenderingDeviceVulkan::_finalize_command_bufers() { |
8668 | if (draw_list) { |
8669 | ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)." ); |
8670 | } |
8671 | |
8672 | if (compute_list) { |
8673 | ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)." ); |
8674 | } |
8675 | |
8676 | { // Complete the setup buffer (that needs to be processed before anything else). |
8677 | vkEndCommandBuffer(frames[frame].setup_command_buffer); |
8678 | vkEndCommandBuffer(frames[frame].draw_command_buffer); |
8679 | } |
8680 | } |
8681 | |
8682 | void RenderingDeviceVulkan::_begin_frame() { |
8683 | // Erase pending resources. |
8684 | _free_pending_resources(frame); |
8685 | |
8686 | // Create setup command buffer and set as the setup buffer. |
8687 | |
8688 | { |
8689 | VkCommandBufferBeginInfo cmdbuf_begin; |
8690 | cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
8691 | cmdbuf_begin.pNext = nullptr; |
8692 | cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
8693 | cmdbuf_begin.pInheritanceInfo = nullptr; |
8694 | |
8695 | VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0); |
8696 | ERR_FAIL_COND_MSG(err, "vkResetCommandBuffer failed with error " + itos(err) + "." ); |
8697 | |
8698 | err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); |
8699 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
8700 | err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); |
8701 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
8702 | |
8703 | if (local_device.is_null()) { |
8704 | context->append_command_buffer(frames[frame].draw_command_buffer); |
8705 | context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else. |
8706 | } |
8707 | } |
8708 | |
8709 | // Advance current frame. |
8710 | frames_drawn++; |
8711 | // Advance staging buffer if used. |
8712 | if (staging_buffer_used) { |
8713 | staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); |
8714 | staging_buffer_used = false; |
8715 | } |
8716 | |
8717 | if (frames[frame].timestamp_count) { |
8718 | vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values.ptr(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); |
8719 | vkCmdResetQueryPool(frames[frame].setup_command_buffer, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count); |
8720 | SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); |
8721 | SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); |
8722 | } |
8723 | |
8724 | frames[frame].timestamp_result_count = frames[frame].timestamp_count; |
8725 | frames[frame].timestamp_count = 0; |
8726 | frames[frame].index = Engine::get_singleton()->get_frames_drawn(); |
8727 | } |
8728 | |
8729 | VkSampleCountFlagBits RenderingDeviceVulkan::_ensure_supported_sample_count(TextureSamples p_requested_sample_count) const { |
8730 | VkSampleCountFlags sample_count_flags = limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts; |
8731 | |
8732 | if (sample_count_flags & rasterization_sample_count[p_requested_sample_count]) { |
8733 | // The requested sample count is supported. |
8734 | return rasterization_sample_count[p_requested_sample_count]; |
8735 | } else { |
8736 | // Find the closest lower supported sample count. |
8737 | VkSampleCountFlagBits sample_count = rasterization_sample_count[p_requested_sample_count]; |
8738 | while (sample_count > VK_SAMPLE_COUNT_1_BIT) { |
8739 | if (sample_count_flags & sample_count) { |
8740 | return sample_count; |
8741 | } |
8742 | sample_count = (VkSampleCountFlagBits)(sample_count >> 1); |
8743 | } |
8744 | } |
8745 | return VK_SAMPLE_COUNT_1_BIT; |
8746 | } |
8747 | |
8748 | void RenderingDeviceVulkan::swap_buffers() { |
8749 | ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers." ); |
8750 | _THREAD_SAFE_METHOD_ |
8751 | |
8752 | _finalize_command_bufers(); |
8753 | |
8754 | screen_prepared = false; |
8755 | // Swap buffers. |
8756 | context->swap_buffers(); |
8757 | |
8758 | frame = (frame + 1) % frame_count; |
8759 | |
8760 | _begin_frame(); |
8761 | } |
8762 | |
8763 | void RenderingDeviceVulkan::submit() { |
8764 | _THREAD_SAFE_METHOD_ |
8765 | |
8766 | ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync." ); |
8767 | ERR_FAIL_COND_MSG(local_device_processing, "device already submitted, call sync to wait until done." ); |
8768 | |
8769 | _finalize_command_bufers(); |
8770 | |
8771 | VkCommandBuffer command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer }; |
8772 | context->local_device_push_command_buffers(local_device, command_buffers, 2); |
8773 | local_device_processing = true; |
8774 | } |
8775 | |
8776 | void RenderingDeviceVulkan::sync() { |
8777 | _THREAD_SAFE_METHOD_ |
8778 | |
8779 | ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync." ); |
8780 | ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit" ); |
8781 | |
8782 | context->local_device_sync(local_device); |
8783 | _begin_frame(); |
8784 | local_device_processing = false; |
8785 | } |
8786 | |
8787 | VmaPool RenderingDeviceVulkan::_find_or_create_small_allocs_pool(uint32_t p_mem_type_index) { |
8788 | if (small_allocs_pools.has(p_mem_type_index)) { |
8789 | return small_allocs_pools[p_mem_type_index]; |
8790 | } |
8791 | |
8792 | print_verbose("Creating VMA small objects pool for memory type index " + itos(p_mem_type_index)); |
8793 | |
8794 | VmaPoolCreateInfo pci; |
8795 | pci.memoryTypeIndex = p_mem_type_index; |
8796 | pci.flags = 0; |
8797 | pci.blockSize = 0; |
8798 | pci.minBlockCount = 0; |
8799 | pci.maxBlockCount = SIZE_MAX; |
8800 | pci.priority = 0.5f; |
8801 | pci.minAllocationAlignment = 0; |
8802 | pci.pMemoryAllocateNext = nullptr; |
8803 | VmaPool pool = VK_NULL_HANDLE; |
8804 | VkResult res = vmaCreatePool(allocator, &pci, &pool); |
8805 | small_allocs_pools[p_mem_type_index] = pool; // Don't try to create it again if failed the first time. |
8806 | ERR_FAIL_COND_V_MSG(res, pool, "vmaCreatePool failed with error " + itos(res) + "." ); |
8807 | |
8808 | return pool; |
8809 | } |
8810 | |
8811 | void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { |
8812 | // Free in dependency usage order, so nothing weird happens. |
8813 | // Pipelines. |
8814 | while (frames[p_frame].render_pipelines_to_dispose_of.front()) { |
8815 | RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get(); |
8816 | |
8817 | vkDestroyPipeline(device, pipeline->pipeline, nullptr); |
8818 | |
8819 | frames[p_frame].render_pipelines_to_dispose_of.pop_front(); |
8820 | } |
8821 | |
8822 | while (frames[p_frame].compute_pipelines_to_dispose_of.front()) { |
8823 | ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get(); |
8824 | |
8825 | vkDestroyPipeline(device, pipeline->pipeline, nullptr); |
8826 | |
8827 | frames[p_frame].compute_pipelines_to_dispose_of.pop_front(); |
8828 | } |
8829 | |
8830 | // Uniform sets. |
8831 | while (frames[p_frame].uniform_sets_to_dispose_of.front()) { |
8832 | UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get(); |
8833 | |
8834 | vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set); |
8835 | _descriptor_pool_free(uniform_set->pool_key, uniform_set->pool); |
8836 | |
8837 | frames[p_frame].uniform_sets_to_dispose_of.pop_front(); |
8838 | } |
8839 | |
8840 | // Buffer views. |
8841 | while (frames[p_frame].buffer_views_to_dispose_of.front()) { |
8842 | VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get(); |
8843 | |
8844 | vkDestroyBufferView(device, buffer_view, nullptr); |
8845 | |
8846 | frames[p_frame].buffer_views_to_dispose_of.pop_front(); |
8847 | } |
8848 | |
8849 | // Shaders. |
8850 | while (frames[p_frame].shaders_to_dispose_of.front()) { |
8851 | Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get(); |
8852 | |
8853 | // Descriptor set layout for each set. |
8854 | for (int i = 0; i < shader->sets.size(); i++) { |
8855 | vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr); |
8856 | } |
8857 | |
8858 | // Pipeline layout. |
8859 | vkDestroyPipelineLayout(device, shader->pipeline_layout, nullptr); |
8860 | |
8861 | // Shaders themselves. |
8862 | for (int i = 0; i < shader->pipeline_stages.size(); i++) { |
8863 | vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr); |
8864 | } |
8865 | |
8866 | frames[p_frame].shaders_to_dispose_of.pop_front(); |
8867 | } |
8868 | |
8869 | // Samplers. |
8870 | while (frames[p_frame].samplers_to_dispose_of.front()) { |
8871 | VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get(); |
8872 | |
8873 | vkDestroySampler(device, sampler, nullptr); |
8874 | |
8875 | frames[p_frame].samplers_to_dispose_of.pop_front(); |
8876 | } |
8877 | |
8878 | // Framebuffers. |
8879 | while (frames[p_frame].framebuffers_to_dispose_of.front()) { |
8880 | Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get(); |
8881 | |
8882 | for (const KeyValue<Framebuffer::VersionKey, Framebuffer::Version> &E : framebuffer->framebuffers) { |
8883 | // First framebuffer, then render pass because it depends on it. |
8884 | vkDestroyFramebuffer(device, E.value.framebuffer, nullptr); |
8885 | vkDestroyRenderPass(device, E.value.render_pass, nullptr); |
8886 | } |
8887 | |
8888 | frames[p_frame].framebuffers_to_dispose_of.pop_front(); |
8889 | } |
8890 | |
8891 | // Textures. |
8892 | while (frames[p_frame].textures_to_dispose_of.front()) { |
8893 | Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get(); |
8894 | |
8895 | if (texture->bound) { |
8896 | WARN_PRINT("Deleted a texture while it was bound." ); |
8897 | } |
8898 | vkDestroyImageView(device, texture->view, nullptr); |
8899 | if (texture->owner.is_null()) { |
8900 | // Actually owns the image and the allocation too. |
8901 | image_memory -= texture->allocation_info.size; |
8902 | vmaDestroyImage(allocator, texture->image, texture->allocation); |
8903 | } |
8904 | frames[p_frame].textures_to_dispose_of.pop_front(); |
8905 | } |
8906 | |
8907 | // Buffers. |
8908 | while (frames[p_frame].buffers_to_dispose_of.front()) { |
8909 | _buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get()); |
8910 | |
8911 | frames[p_frame].buffers_to_dispose_of.pop_front(); |
8912 | } |
8913 | } |
8914 | |
8915 | void RenderingDeviceVulkan::prepare_screen_for_drawing() { |
8916 | _THREAD_SAFE_METHOD_ |
8917 | context->prepare_buffers(); |
8918 | screen_prepared = true; |
8919 | } |
8920 | |
8921 | uint32_t RenderingDeviceVulkan::get_frame_delay() const { |
8922 | return frame_count; |
8923 | } |
8924 | |
8925 | uint64_t RenderingDeviceVulkan::get_memory_usage(MemoryType p_type) const { |
8926 | if (p_type == MEMORY_BUFFERS) { |
8927 | return buffer_memory; |
8928 | } else if (p_type == MEMORY_TEXTURES) { |
8929 | return image_memory; |
8930 | } else { |
8931 | VmaTotalStatistics stats; |
8932 | vmaCalculateStatistics(allocator, &stats); |
8933 | return stats.total.statistics.allocationBytes; |
8934 | } |
8935 | } |
8936 | |
8937 | void RenderingDeviceVulkan::_flush(bool p_current_frame) { |
8938 | if (local_device.is_valid() && !p_current_frame) { |
8939 | return; // Flushing previous frames has no effect with local device. |
8940 | } |
8941 | // Not doing this crashes RADV (undefined behavior). |
8942 | if (p_current_frame) { |
8943 | vkEndCommandBuffer(frames[frame].setup_command_buffer); |
8944 | vkEndCommandBuffer(frames[frame].draw_command_buffer); |
8945 | } |
8946 | |
8947 | if (local_device.is_valid()) { |
8948 | VkCommandBuffer command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer }; |
8949 | context->local_device_push_command_buffers(local_device, command_buffers, 2); |
8950 | context->local_device_sync(local_device); |
8951 | |
8952 | VkCommandBufferBeginInfo cmdbuf_begin; |
8953 | cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
8954 | cmdbuf_begin.pNext = nullptr; |
8955 | cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
8956 | cmdbuf_begin.pInheritanceInfo = nullptr; |
8957 | |
8958 | VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); |
8959 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
8960 | err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); |
8961 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
8962 | |
8963 | } else { |
8964 | context->flush(p_current_frame, p_current_frame); |
8965 | // Re-create the setup command. |
8966 | if (p_current_frame) { |
8967 | VkCommandBufferBeginInfo cmdbuf_begin; |
8968 | cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
8969 | cmdbuf_begin.pNext = nullptr; |
8970 | cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
8971 | cmdbuf_begin.pInheritanceInfo = nullptr; |
8972 | |
8973 | VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); |
8974 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
8975 | context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else. |
8976 | } |
8977 | |
8978 | if (p_current_frame) { |
8979 | VkCommandBufferBeginInfo cmdbuf_begin; |
8980 | cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
8981 | cmdbuf_begin.pNext = nullptr; |
8982 | cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
8983 | cmdbuf_begin.pInheritanceInfo = nullptr; |
8984 | |
8985 | VkResult err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); |
8986 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
8987 | context->append_command_buffer(frames[frame].draw_command_buffer); |
8988 | } |
8989 | } |
8990 | } |
8991 | |
8992 | void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) { |
8993 | // Get our device capabilities. |
8994 | { |
8995 | device_capabilities.version_major = p_context->get_vulkan_major(); |
8996 | device_capabilities.version_minor = p_context->get_vulkan_minor(); |
8997 | } |
8998 | |
8999 | context = p_context; |
9000 | device = p_context->get_device(); |
9001 | if (p_local_device) { |
9002 | frame_count = 1; |
9003 | local_device = p_context->local_device_create(); |
9004 | device = p_context->local_device_get_vk_device(local_device); |
9005 | } else { |
9006 | frame_count = p_context->get_swapchain_image_count() + 1; // Always need one extra to ensure it's unused at any time, without having to use a fence for this. |
9007 | } |
9008 | limits = p_context->get_device_limits(); |
9009 | max_timestamp_query_elements = 256; |
9010 | |
9011 | { // Initialize allocator. |
9012 | |
9013 | VmaAllocatorCreateInfo allocatorInfo; |
9014 | memset(&allocatorInfo, 0, sizeof(VmaAllocatorCreateInfo)); |
9015 | allocatorInfo.physicalDevice = p_context->get_physical_device(); |
9016 | allocatorInfo.device = device; |
9017 | allocatorInfo.instance = p_context->get_instance(); |
9018 | vmaCreateAllocator(&allocatorInfo, &allocator); |
9019 | } |
9020 | |
9021 | frames.resize(frame_count); |
9022 | frame = 0; |
9023 | // Create setup and frame buffers. |
9024 | for (int i = 0; i < frame_count; i++) { |
9025 | frames[i].index = 0; |
9026 | |
9027 | { // Create command pool, one per frame is recommended. |
9028 | VkCommandPoolCreateInfo cmd_pool_info; |
9029 | cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
9030 | cmd_pool_info.pNext = nullptr; |
9031 | cmd_pool_info.queueFamilyIndex = p_context->get_graphics_queue_family_index(); |
9032 | cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
9033 | |
9034 | VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &frames[i].command_pool); |
9035 | ERR_FAIL_COND_MSG(res, "vkCreateCommandPool failed with error " + itos(res) + "." ); |
9036 | } |
9037 | |
9038 | { // Create command buffers. |
9039 | |
9040 | VkCommandBufferAllocateInfo cmdbuf; |
9041 | // No command buffer exists, create it. |
9042 | cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
9043 | cmdbuf.pNext = nullptr; |
9044 | cmdbuf.commandPool = frames[i].command_pool; |
9045 | cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
9046 | cmdbuf.commandBufferCount = 1; |
9047 | |
9048 | VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].setup_command_buffer); |
9049 | ERR_CONTINUE_MSG(err, "vkAllocateCommandBuffers failed with error " + itos(err) + "." ); |
9050 | |
9051 | err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].draw_command_buffer); |
9052 | ERR_CONTINUE_MSG(err, "vkAllocateCommandBuffers failed with error " + itos(err) + "." ); |
9053 | } |
9054 | |
9055 | { |
9056 | // Create query pool. |
9057 | VkQueryPoolCreateInfo query_pool_create_info; |
9058 | query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; |
9059 | query_pool_create_info.flags = 0; |
9060 | query_pool_create_info.pNext = nullptr; |
9061 | query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; |
9062 | query_pool_create_info.queryCount = max_timestamp_query_elements; |
9063 | query_pool_create_info.pipelineStatistics = 0; |
9064 | |
9065 | vkCreateQueryPool(device, &query_pool_create_info, nullptr, &frames[i].timestamp_pool); |
9066 | |
9067 | frames[i].timestamp_names.resize(max_timestamp_query_elements); |
9068 | frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements); |
9069 | frames[i].timestamp_count = 0; |
9070 | frames[i].timestamp_result_names.resize(max_timestamp_query_elements); |
9071 | frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements); |
9072 | frames[i].timestamp_result_values.resize(max_timestamp_query_elements); |
9073 | frames[i].timestamp_result_count = 0; |
9074 | } |
9075 | } |
9076 | |
9077 | { |
9078 | // Begin the first command buffer for the first frame, so |
9079 | // setting up things can be done in the meantime until swap_buffers(), which is called before advance. |
9080 | VkCommandBufferBeginInfo cmdbuf_begin; |
9081 | cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
9082 | cmdbuf_begin.pNext = nullptr; |
9083 | cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
9084 | cmdbuf_begin.pInheritanceInfo = nullptr; |
9085 | |
9086 | VkResult err = vkBeginCommandBuffer(frames[0].setup_command_buffer, &cmdbuf_begin); |
9087 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
9088 | |
9089 | err = vkBeginCommandBuffer(frames[0].draw_command_buffer, &cmdbuf_begin); |
9090 | ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + "." ); |
9091 | if (local_device.is_null()) { |
9092 | context->set_setup_buffer(frames[0].setup_command_buffer); // Append now so it's added before everything else. |
9093 | context->append_command_buffer(frames[0].draw_command_buffer); |
9094 | } |
9095 | } |
9096 | |
9097 | for (int i = 0; i < frame_count; i++) { |
9098 | //Reset all queries in a query pool before doing any operations with them. |
9099 | vkCmdResetQueryPool(frames[0].setup_command_buffer, frames[i].timestamp_pool, 0, max_timestamp_query_elements); |
9100 | } |
9101 | |
9102 | staging_buffer_block_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb" ); |
9103 | staging_buffer_block_size = MAX(4u, staging_buffer_block_size); |
9104 | staging_buffer_block_size *= 1024; // Kb -> bytes. |
9105 | staging_buffer_max_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb" ); |
9106 | staging_buffer_max_size = MAX(1u, staging_buffer_max_size); |
9107 | staging_buffer_max_size *= 1024 * 1024; |
9108 | |
9109 | if (staging_buffer_max_size < staging_buffer_block_size * 4) { |
9110 | // Validate enough blocks. |
9111 | staging_buffer_max_size = staging_buffer_block_size * 4; |
9112 | } |
9113 | texture_upload_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px" ); |
9114 | texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px); |
9115 | |
9116 | frames_drawn = frame_count; // Start from frame count, so everything else is immediately old. |
9117 | |
9118 | // Ensure current staging block is valid and at least one per frame exists. |
9119 | staging_buffer_current = 0; |
9120 | staging_buffer_used = false; |
9121 | |
9122 | for (int i = 0; i < frame_count; i++) { |
9123 | // Staging was never used, create a block. |
9124 | Error err = _insert_staging_block(); |
9125 | ERR_CONTINUE(err != OK); |
9126 | } |
9127 | |
9128 | max_descriptors_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool" ); |
9129 | |
9130 | // Check to make sure DescriptorPoolKey is good. |
9131 | static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t)); |
9132 | |
9133 | draw_list = nullptr; |
9134 | draw_list_count = 0; |
9135 | draw_list_split = false; |
9136 | |
9137 | compute_list = nullptr; |
9138 | |
9139 | pipelines_cache.file_path = "user://vulkan/pipelines" ; |
9140 | pipelines_cache.file_path += "." + context->get_device_name().validate_filename().replace(" " , "_" ).to_lower(); |
9141 | if (Engine::get_singleton()->is_editor_hint()) { |
9142 | pipelines_cache.file_path += ".editor" ; |
9143 | } |
9144 | pipelines_cache.file_path += ".cache" ; |
9145 | |
9146 | // Prepare most fields now. |
9147 | VkPhysicalDeviceProperties props; |
9148 | vkGetPhysicalDeviceProperties(context->get_physical_device(), &props); |
9149 | pipelines_cache.header.magic = 868 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE; |
9150 | pipelines_cache.header.device_id = props.deviceID; |
9151 | pipelines_cache.header.vendor_id = props.vendorID; |
9152 | pipelines_cache.header.driver_version = props.driverVersion; |
9153 | memcpy(pipelines_cache.header.uuid, props.pipelineCacheUUID, VK_UUID_SIZE); |
9154 | pipelines_cache.header.driver_abi = sizeof(void *); |
9155 | |
9156 | _load_pipeline_cache(); |
9157 | print_verbose(vformat("Startup PSO cache (%.1f MiB)" , pipelines_cache.buffer.size() / (1024.0f * 1024.0f))); |
9158 | VkPipelineCacheCreateInfo cache_info = {}; |
9159 | cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; |
9160 | cache_info.pNext = nullptr; |
9161 | if (context->is_device_extension_enabled(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) { |
9162 | cache_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; |
9163 | } |
9164 | cache_info.initialDataSize = pipelines_cache.buffer.size(); |
9165 | cache_info.pInitialData = pipelines_cache.buffer.ptr(); |
9166 | VkResult err = vkCreatePipelineCache(device, &cache_info, nullptr, &pipelines_cache.cache_object); |
9167 | |
9168 | if (err != VK_SUCCESS) { |
9169 | WARN_PRINT("vkCreatePipelinecache failed with error " + itos(err) + "." ); |
9170 | } |
9171 | } |
9172 | |
9173 | void RenderingDeviceVulkan::_load_pipeline_cache() { |
9174 | DirAccess::make_dir_recursive_absolute(pipelines_cache.file_path.get_base_dir()); |
9175 | |
9176 | if (FileAccess::exists(pipelines_cache.file_path)) { |
9177 | Error file_error; |
9178 | Vector<uint8_t> file_data = FileAccess::get_file_as_bytes(pipelines_cache.file_path, &file_error); |
9179 | if (file_error != OK || file_data.size() <= (int)sizeof(PipelineCacheHeader)) { |
9180 | WARN_PRINT("Invalid/corrupt pipelines cache." ); |
9181 | return; |
9182 | } |
9183 | const PipelineCacheHeader * = reinterpret_cast<const PipelineCacheHeader *>(file_data.ptr()); |
9184 | if (header->magic != 868 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE) { |
9185 | WARN_PRINT("Invalid pipelines cache magic number." ); |
9186 | return; |
9187 | } |
9188 | const uint8_t *loaded_buffer_start = file_data.ptr() + sizeof(PipelineCacheHeader); |
9189 | uint32_t loaded_buffer_size = file_data.size() - sizeof(PipelineCacheHeader); |
9190 | if (header->data_hash != hash_murmur3_buffer(loaded_buffer_start, loaded_buffer_size) || |
9191 | header->data_size != loaded_buffer_size || |
9192 | header->vendor_id != pipelines_cache.header.vendor_id || |
9193 | header->device_id != pipelines_cache.header.device_id || |
9194 | header->driver_version != pipelines_cache.header.driver_version || |
9195 | memcmp(header->uuid, pipelines_cache.header.uuid, VK_UUID_SIZE) != 0 || |
9196 | header->driver_abi != pipelines_cache.header.driver_abi) { |
9197 | WARN_PRINT("Invalid pipelines cache header." ); |
9198 | pipelines_cache.current_size = 0; |
9199 | pipelines_cache.buffer.clear(); |
9200 | } else { |
9201 | pipelines_cache.current_size = loaded_buffer_size; |
9202 | pipelines_cache.buffer.resize(loaded_buffer_size); |
9203 | memcpy(pipelines_cache.buffer.ptr(), loaded_buffer_start, pipelines_cache.buffer.size()); |
9204 | } |
9205 | } |
9206 | } |
9207 | |
9208 | void RenderingDeviceVulkan::_update_pipeline_cache(bool p_closing) { |
9209 | { |
9210 | bool still_saving = pipelines_cache_save_task != WorkerThreadPool::INVALID_TASK_ID && !WorkerThreadPool::get_singleton()->is_task_completed(pipelines_cache_save_task); |
9211 | if (still_saving) { |
9212 | if (p_closing) { |
9213 | WorkerThreadPool::get_singleton()->wait_for_task_completion(pipelines_cache_save_task); |
9214 | pipelines_cache_save_task = WorkerThreadPool::INVALID_TASK_ID; |
9215 | } else { |
9216 | // We can't save until the currently running save is done. We'll retry next time; worst case, we'll save when exiting. |
9217 | return; |
9218 | } |
9219 | } |
9220 | } |
9221 | |
9222 | { |
9223 | // FIXME: |
9224 | // We're letting the cache grow unboundedly. We may want to set at limit and see if implementations use LRU or the like. |
9225 | // If we do, we won't be able to assume any longer that the cache is dirty if, and only if, it has grown. |
9226 | size_t pso_blob_size = 0; |
9227 | VkResult vr = vkGetPipelineCacheData(device, pipelines_cache.cache_object, &pso_blob_size, nullptr); |
9228 | ERR_FAIL_COND(vr); |
9229 | size_t difference = pso_blob_size - pipelines_cache.current_size; |
9230 | |
9231 | bool must_save = false; |
9232 | |
9233 | if (p_closing) { |
9234 | must_save = difference > 0; |
9235 | } else { |
9236 | float save_interval = GLOBAL_GET("rendering/rendering_device/pipeline_cache/save_chunk_size_mb" ); |
9237 | must_save = difference > 0 && difference / (1024.0f * 1024.0f) >= save_interval; |
9238 | } |
9239 | |
9240 | if (must_save) { |
9241 | pipelines_cache.current_size = pso_blob_size; |
9242 | } else { |
9243 | return; |
9244 | } |
9245 | } |
9246 | |
9247 | if (p_closing) { |
9248 | _save_pipeline_cache(this); |
9249 | } else { |
9250 | pipelines_cache_save_task = WorkerThreadPool::get_singleton()->add_native_task(&_save_pipeline_cache, this, false, "PipelineCacheSave" ); |
9251 | } |
9252 | } |
9253 | |
9254 | void RenderingDeviceVulkan::_save_pipeline_cache(void *p_data) { |
9255 | RenderingDeviceVulkan *self = static_cast<RenderingDeviceVulkan *>(p_data); |
9256 | |
9257 | self->pipelines_cache.buffer.resize(self->pipelines_cache.current_size); |
9258 | |
9259 | self->_thread_safe_.lock(); |
9260 | VkResult vr = vkGetPipelineCacheData(self->device, self->pipelines_cache.cache_object, &self->pipelines_cache.current_size, self->pipelines_cache.buffer.ptr()); |
9261 | self->_thread_safe_.unlock(); |
9262 | ERR_FAIL_COND(vr != VK_SUCCESS && vr != VK_INCOMPLETE); // Incomplete is OK because the cache may have grown since the size was queried (unless when exiting). |
9263 | print_verbose(vformat("Updated PSO cache (%.1f MiB)" , self->pipelines_cache.current_size / (1024.0f * 1024.0f))); |
9264 | |
9265 | // The real buffer size may now be bigger than the updated current_size. |
9266 | // We take into account the new size but keep the buffer resized in a worst-case fashion. |
9267 | |
9268 | self->pipelines_cache.header.data_size = self->pipelines_cache.current_size; |
9269 | self->pipelines_cache.header.data_hash = hash_murmur3_buffer(self->pipelines_cache.buffer.ptr(), self->pipelines_cache.current_size); |
9270 | Ref<FileAccess> f = FileAccess::open(self->pipelines_cache.file_path, FileAccess::WRITE, nullptr); |
9271 | if (f.is_valid()) { |
9272 | f->store_buffer((const uint8_t *)&self->pipelines_cache.header, sizeof(PipelineCacheHeader)); |
9273 | f->store_buffer(self->pipelines_cache.buffer.ptr(), self->pipelines_cache.current_size); |
9274 | } |
9275 | } |
9276 | |
9277 | template <class T> |
9278 | void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { |
9279 | List<RID> owned; |
9280 | p_owner.get_owned_list(&owned); |
9281 | if (owned.size()) { |
9282 | if (owned.size() == 1) { |
9283 | WARN_PRINT(vformat("1 RID of type \"%s\" was leaked." , p_type)); |
9284 | } else { |
9285 | WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked." , owned.size(), p_type)); |
9286 | } |
9287 | for (const RID &E : owned) { |
9288 | #ifdef DEV_ENABLED |
9289 | if (resource_names.has(E)) { |
9290 | print_line(String(" - " ) + resource_names[E]); |
9291 | } |
9292 | #endif |
9293 | free(E); |
9294 | } |
9295 | } |
9296 | } |
9297 | |
9298 | void RenderingDeviceVulkan::capture_timestamp(const String &p_name) { |
9299 | ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name); |
9300 | ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements); |
9301 | |
9302 | // This should be optional for profiling, else it will slow things down. |
9303 | { |
9304 | VkMemoryBarrier memoryBarrier; |
9305 | |
9306 | memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; |
9307 | memoryBarrier.pNext = nullptr; |
9308 | memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | |
9309 | VK_ACCESS_INDEX_READ_BIT | |
9310 | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | |
9311 | VK_ACCESS_UNIFORM_READ_BIT | |
9312 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
9313 | VK_ACCESS_SHADER_READ_BIT | |
9314 | VK_ACCESS_SHADER_WRITE_BIT | |
9315 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
9316 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
9317 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
9318 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
9319 | VK_ACCESS_TRANSFER_READ_BIT | |
9320 | VK_ACCESS_TRANSFER_WRITE_BIT | |
9321 | VK_ACCESS_HOST_READ_BIT | |
9322 | VK_ACCESS_HOST_WRITE_BIT; |
9323 | memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | |
9324 | VK_ACCESS_INDEX_READ_BIT | |
9325 | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | |
9326 | VK_ACCESS_UNIFORM_READ_BIT | |
9327 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
9328 | VK_ACCESS_SHADER_READ_BIT | |
9329 | VK_ACCESS_SHADER_WRITE_BIT | |
9330 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
9331 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
9332 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
9333 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
9334 | VK_ACCESS_TRANSFER_READ_BIT | |
9335 | VK_ACCESS_TRANSFER_WRITE_BIT | |
9336 | VK_ACCESS_HOST_READ_BIT | |
9337 | VK_ACCESS_HOST_WRITE_BIT; |
9338 | |
9339 | vkCmdPipelineBarrier(frames[frame].draw_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr); |
9340 | } |
9341 | |
9342 | vkCmdWriteTimestamp(frames[frame].draw_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frames[frame].timestamp_pool, frames[frame].timestamp_count); |
9343 | frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name; |
9344 | frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec(); |
9345 | frames[frame].timestamp_count++; |
9346 | } |
9347 | |
9348 | uint64_t RenderingDeviceVulkan::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) { |
9349 | _THREAD_SAFE_METHOD_ |
9350 | |
9351 | switch (p_resource) { |
9352 | case DRIVER_RESOURCE_VULKAN_DEVICE: { |
9353 | return (uint64_t)context->get_device(); |
9354 | } break; |
9355 | case DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE: { |
9356 | return (uint64_t)context->get_physical_device(); |
9357 | } break; |
9358 | case DRIVER_RESOURCE_VULKAN_INSTANCE: { |
9359 | return (uint64_t)context->get_instance(); |
9360 | } break; |
9361 | case DRIVER_RESOURCE_VULKAN_QUEUE: { |
9362 | return (uint64_t)context->get_graphics_queue(); |
9363 | } break; |
9364 | case DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX: { |
9365 | return context->get_graphics_queue_family_index(); |
9366 | } break; |
9367 | case DRIVER_RESOURCE_VULKAN_IMAGE: { |
9368 | Texture *tex = texture_owner.get_or_null(p_rid); |
9369 | ERR_FAIL_NULL_V(tex, 0); |
9370 | |
9371 | return (uint64_t)tex->image; |
9372 | } break; |
9373 | case DRIVER_RESOURCE_VULKAN_IMAGE_VIEW: { |
9374 | Texture *tex = texture_owner.get_or_null(p_rid); |
9375 | ERR_FAIL_NULL_V(tex, 0); |
9376 | |
9377 | return (uint64_t)tex->view; |
9378 | } break; |
9379 | case DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT: { |
9380 | Texture *tex = texture_owner.get_or_null(p_rid); |
9381 | ERR_FAIL_NULL_V(tex, 0); |
9382 | |
9383 | return vulkan_formats[tex->format]; |
9384 | } break; |
9385 | case DRIVER_RESOURCE_VULKAN_SAMPLER: { |
9386 | VkSampler *sampler = sampler_owner.get_or_null(p_rid); |
9387 | ERR_FAIL_NULL_V(sampler, 0); |
9388 | |
9389 | return uint64_t(*sampler); |
9390 | } break; |
9391 | case DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET: { |
9392 | UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid); |
9393 | ERR_FAIL_NULL_V(uniform_set, 0); |
9394 | |
9395 | return uint64_t(uniform_set->descriptor_set); |
9396 | } break; |
9397 | case DRIVER_RESOURCE_VULKAN_BUFFER: { |
9398 | Buffer *buffer = nullptr; |
9399 | if (vertex_buffer_owner.owns(p_rid)) { |
9400 | buffer = vertex_buffer_owner.get_or_null(p_rid); |
9401 | } else if (index_buffer_owner.owns(p_rid)) { |
9402 | buffer = index_buffer_owner.get_or_null(p_rid); |
9403 | } else if (uniform_buffer_owner.owns(p_rid)) { |
9404 | buffer = uniform_buffer_owner.get_or_null(p_rid); |
9405 | } else if (texture_buffer_owner.owns(p_rid)) { |
9406 | buffer = &texture_buffer_owner.get_or_null(p_rid)->buffer; |
9407 | } else if (storage_buffer_owner.owns(p_rid)) { |
9408 | buffer = storage_buffer_owner.get_or_null(p_rid); |
9409 | } |
9410 | |
9411 | ERR_FAIL_NULL_V(buffer, 0); |
9412 | |
9413 | return uint64_t(buffer->buffer); |
9414 | } break; |
9415 | case DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE: { |
9416 | ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid); |
9417 | ERR_FAIL_NULL_V(compute_pipeline, 0); |
9418 | |
9419 | return uint64_t(compute_pipeline->pipeline); |
9420 | } break; |
9421 | case DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE: { |
9422 | RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid); |
9423 | ERR_FAIL_NULL_V(render_pipeline, 0); |
9424 | |
9425 | return uint64_t(render_pipeline->pipeline); |
9426 | } break; |
9427 | default: { |
9428 | // Not supported for this driver. |
9429 | return 0; |
9430 | } break; |
9431 | } |
9432 | } |
9433 | |
9434 | uint32_t RenderingDeviceVulkan::get_captured_timestamps_count() const { |
9435 | return frames[frame].timestamp_result_count; |
9436 | } |
9437 | |
9438 | uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const { |
9439 | return frames[frame].index; |
9440 | } |
9441 | |
9442 | static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) { |
9443 | uint64_t u1 = (u & 0xffffffff); |
9444 | uint64_t v1 = (v & 0xffffffff); |
9445 | uint64_t t = (u1 * v1); |
9446 | uint64_t w3 = (t & 0xffffffff); |
9447 | uint64_t k = (t >> 32); |
9448 | |
9449 | u >>= 32; |
9450 | t = (u * v1) + k; |
9451 | k = (t & 0xffffffff); |
9452 | uint64_t w1 = (t >> 32); |
9453 | |
9454 | v >>= 32; |
9455 | t = (u1 * v) + k; |
9456 | k = (t >> 32); |
9457 | |
9458 | h = (u * v) + w1 + k; |
9459 | l = (t << 32) + w3; |
9460 | } |
9461 | |
9462 | uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const { |
9463 | ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); |
9464 | |
9465 | // This sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs. |
9466 | // So, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible. |
9467 | // Need to do 128 bits fixed point multiplication to get the right value. |
9468 | |
9469 | uint64_t shift_bits = 16; |
9470 | |
9471 | uint64_t h, l; |
9472 | |
9473 | mult64to128(frames[frame].timestamp_result_values[p_index], uint64_t(double(limits.timestampPeriod) * double(1 << shift_bits)), h, l); |
9474 | l >>= shift_bits; |
9475 | l |= h << (64 - shift_bits); |
9476 | |
9477 | return l; |
9478 | } |
9479 | |
9480 | uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const { |
9481 | ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); |
9482 | return frames[frame].timestamp_cpu_result_values[p_index]; |
9483 | } |
9484 | |
9485 | String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) const { |
9486 | ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String()); |
9487 | return frames[frame].timestamp_result_names[p_index]; |
9488 | } |
9489 | |
9490 | uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const { |
9491 | switch (p_limit) { |
9492 | case LIMIT_MAX_BOUND_UNIFORM_SETS: |
9493 | return limits.maxBoundDescriptorSets; |
9494 | case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS: |
9495 | return limits.maxColorAttachments; |
9496 | case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET: |
9497 | return limits.maxDescriptorSetSampledImages; |
9498 | case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET: |
9499 | return limits.maxDescriptorSetSamplers; |
9500 | case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET: |
9501 | return limits.maxDescriptorSetStorageBuffers; |
9502 | case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET: |
9503 | return limits.maxDescriptorSetStorageImages; |
9504 | case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET: |
9505 | return limits.maxDescriptorSetUniformBuffers; |
9506 | case LIMIT_MAX_DRAW_INDEXED_INDEX: |
9507 | return limits.maxDrawIndexedIndexValue; |
9508 | case LIMIT_MAX_FRAMEBUFFER_HEIGHT: |
9509 | return limits.maxFramebufferHeight; |
9510 | case LIMIT_MAX_FRAMEBUFFER_WIDTH: |
9511 | return limits.maxFramebufferWidth; |
9512 | case LIMIT_MAX_TEXTURE_ARRAY_LAYERS: |
9513 | return limits.maxImageArrayLayers; |
9514 | case LIMIT_MAX_TEXTURE_SIZE_1D: |
9515 | return limits.maxImageDimension1D; |
9516 | case LIMIT_MAX_TEXTURE_SIZE_2D: |
9517 | return limits.maxImageDimension2D; |
9518 | case LIMIT_MAX_TEXTURE_SIZE_3D: |
9519 | return limits.maxImageDimension3D; |
9520 | case LIMIT_MAX_TEXTURE_SIZE_CUBE: |
9521 | return limits.maxImageDimensionCube; |
9522 | case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE: |
9523 | return limits.maxPerStageDescriptorSampledImages; |
9524 | case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE: |
9525 | return limits.maxPerStageDescriptorSamplers; |
9526 | case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE: |
9527 | return limits.maxPerStageDescriptorStorageBuffers; |
9528 | case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE: |
9529 | return limits.maxPerStageDescriptorStorageImages; |
9530 | case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE: |
9531 | return limits.maxPerStageDescriptorUniformBuffers; |
9532 | case LIMIT_MAX_PUSH_CONSTANT_SIZE: |
9533 | return limits.maxPushConstantsSize; |
9534 | case LIMIT_MAX_UNIFORM_BUFFER_SIZE: |
9535 | return limits.maxUniformBufferRange; |
9536 | case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET: |
9537 | return limits.maxVertexInputAttributeOffset; |
9538 | case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES: |
9539 | return limits.maxVertexInputAttributes; |
9540 | case LIMIT_MAX_VERTEX_INPUT_BINDINGS: |
9541 | return limits.maxVertexInputBindings; |
9542 | case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE: |
9543 | return limits.maxVertexInputBindingStride; |
9544 | case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT: |
9545 | return limits.minUniformBufferOffsetAlignment; |
9546 | case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X: |
9547 | return limits.maxComputeWorkGroupCount[0]; |
9548 | case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y: |
9549 | return limits.maxComputeWorkGroupCount[1]; |
9550 | case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z: |
9551 | return limits.maxComputeWorkGroupCount[2]; |
9552 | case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS: |
9553 | return limits.maxComputeWorkGroupInvocations; |
9554 | case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X: |
9555 | return limits.maxComputeWorkGroupSize[0]; |
9556 | case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y: |
9557 | return limits.maxComputeWorkGroupSize[1]; |
9558 | case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z: |
9559 | return limits.maxComputeWorkGroupSize[2]; |
9560 | case LIMIT_MAX_VIEWPORT_DIMENSIONS_X: |
9561 | return limits.maxViewportDimensions[0]; |
9562 | case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y: |
9563 | return limits.maxViewportDimensions[1]; |
9564 | case LIMIT_SUBGROUP_SIZE: { |
9565 | VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); |
9566 | return subgroup_capabilities.size; |
9567 | } |
9568 | case LIMIT_SUBGROUP_IN_SHADERS: { |
9569 | VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); |
9570 | return subgroup_capabilities.supported_stages_flags_rd(); |
9571 | } |
9572 | case LIMIT_SUBGROUP_OPERATIONS: { |
9573 | VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); |
9574 | return subgroup_capabilities.supported_operations_flags_rd(); |
9575 | } |
9576 | case LIMIT_VRS_TEXEL_WIDTH: { |
9577 | return context->get_vrs_capabilities().texel_size.x; |
9578 | } |
9579 | case LIMIT_VRS_TEXEL_HEIGHT: { |
9580 | return context->get_vrs_capabilities().texel_size.y; |
9581 | } |
9582 | default: |
9583 | ERR_FAIL_V(0); |
9584 | } |
9585 | |
9586 | return 0; |
9587 | } |
9588 | |
9589 | void RenderingDeviceVulkan::finalize() { |
9590 | // Free all resources. |
9591 | |
9592 | _flush(false); |
9593 | |
9594 | _free_rids(render_pipeline_owner, "Pipeline" ); |
9595 | _free_rids(compute_pipeline_owner, "Compute" ); |
9596 | _free_rids(uniform_set_owner, "UniformSet" ); |
9597 | _free_rids(texture_buffer_owner, "TextureBuffer" ); |
9598 | _free_rids(storage_buffer_owner, "StorageBuffer" ); |
9599 | _free_rids(uniform_buffer_owner, "UniformBuffer" ); |
9600 | _free_rids(shader_owner, "Shader" ); |
9601 | _free_rids(index_array_owner, "IndexArray" ); |
9602 | _free_rids(index_buffer_owner, "IndexBuffer" ); |
9603 | _free_rids(vertex_array_owner, "VertexArray" ); |
9604 | _free_rids(vertex_buffer_owner, "VertexBuffer" ); |
9605 | _free_rids(framebuffer_owner, "Framebuffer" ); |
9606 | _free_rids(sampler_owner, "Sampler" ); |
9607 | { |
9608 | // For textures it's a bit more difficult because they may be shared. |
9609 | List<RID> owned; |
9610 | texture_owner.get_owned_list(&owned); |
9611 | if (owned.size()) { |
9612 | if (owned.size() == 1) { |
9613 | WARN_PRINT("1 RID of type \"Texture\" was leaked." ); |
9614 | } else { |
9615 | WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked." , owned.size())); |
9616 | } |
9617 | // Free shared first. |
9618 | for (List<RID>::Element *E = owned.front(); E;) { |
9619 | List<RID>::Element *N = E->next(); |
9620 | if (texture_is_shared(E->get())) { |
9621 | #ifdef DEV_ENABLED |
9622 | if (resource_names.has(E->get())) { |
9623 | print_line(String(" - " ) + resource_names[E->get()]); |
9624 | } |
9625 | #endif |
9626 | free(E->get()); |
9627 | owned.erase(E); |
9628 | } |
9629 | E = N; |
9630 | } |
9631 | // Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies. |
9632 | for (const RID &E : owned) { |
9633 | #ifdef DEV_ENABLED |
9634 | if (resource_names.has(E)) { |
9635 | print_line(String(" - " ) + resource_names[E]); |
9636 | } |
9637 | #endif |
9638 | free(E); |
9639 | } |
9640 | } |
9641 | } |
9642 | |
9643 | // Free everything pending. |
9644 | for (int i = 0; i < frame_count; i++) { |
9645 | int f = (frame + i) % frame_count; |
9646 | _free_pending_resources(f); |
9647 | vkDestroyCommandPool(device, frames[i].command_pool, nullptr); |
9648 | vkDestroyQueryPool(device, frames[i].timestamp_pool, nullptr); |
9649 | } |
9650 | _update_pipeline_cache(true); |
9651 | |
9652 | vkDestroyPipelineCache(device, pipelines_cache.cache_object, nullptr); |
9653 | |
9654 | for (int i = 0; i < split_draw_list_allocators.size(); i++) { |
9655 | vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, nullptr); |
9656 | } |
9657 | |
9658 | frames.clear(); |
9659 | |
9660 | for (int i = 0; i < staging_buffer_blocks.size(); i++) { |
9661 | vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation); |
9662 | } |
9663 | while (small_allocs_pools.size()) { |
9664 | HashMap<uint32_t, VmaPool>::Iterator E = small_allocs_pools.begin(); |
9665 | vmaDestroyPool(allocator, E->value); |
9666 | small_allocs_pools.remove(E); |
9667 | } |
9668 | vmaDestroyAllocator(allocator); |
9669 | |
9670 | while (vertex_formats.size()) { |
9671 | HashMap<VertexFormatID, VertexDescriptionCache>::Iterator temp = vertex_formats.begin(); |
9672 | memdelete_arr(temp->value.bindings); |
9673 | memdelete_arr(temp->value.attributes); |
9674 | vertex_formats.remove(temp); |
9675 | } |
9676 | |
9677 | for (KeyValue<FramebufferFormatID, FramebufferFormat> &E : framebuffer_formats) { |
9678 | vkDestroyRenderPass(device, E.value.render_pass, nullptr); |
9679 | } |
9680 | framebuffer_formats.clear(); |
9681 | |
9682 | // All these should be clear at this point. |
9683 | ERR_FAIL_COND(descriptor_pools.size()); |
9684 | ERR_FAIL_COND(dependency_map.size()); |
9685 | ERR_FAIL_COND(reverse_dependency_map.size()); |
9686 | } |
9687 | |
9688 | RenderingDevice *RenderingDeviceVulkan::create_local_device() { |
9689 | RenderingDeviceVulkan *rd = memnew(RenderingDeviceVulkan); |
9690 | rd->initialize(context, true); |
9691 | return rd; |
9692 | } |
9693 | |
9694 | bool RenderingDeviceVulkan::has_feature(const Features p_feature) const { |
9695 | switch (p_feature) { |
9696 | case SUPPORTS_MULTIVIEW: { |
9697 | VulkanContext::MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities(); |
9698 | return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1; |
9699 | } break; |
9700 | case SUPPORTS_FSR_HALF_FLOAT: { |
9701 | return context->get_shader_capabilities().shader_float16_is_supported && context->get_physical_device_features().shaderInt16 && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported; |
9702 | } break; |
9703 | case SUPPORTS_ATTACHMENT_VRS: { |
9704 | VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities(); |
9705 | return vrs_capabilities.attachment_vrs_supported && context->get_physical_device_features().shaderStorageImageExtendedFormats; |
9706 | } break; |
9707 | case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: { |
9708 | return true; |
9709 | } break; |
9710 | default: { |
9711 | return false; |
9712 | } |
9713 | } |
9714 | } |
9715 | |
9716 | RenderingDeviceVulkan::RenderingDeviceVulkan() { |
9717 | device_capabilities.device_family = DEVICE_VULKAN; |
9718 | } |
9719 | |
9720 | RenderingDeviceVulkan::~RenderingDeviceVulkan() { |
9721 | if (local_device.is_valid()) { |
9722 | finalize(); |
9723 | context->local_device_free(local_device); |
9724 | } |
9725 | } |
9726 | |