Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include "gpu.h"
19 : : #include "cache.h"
20 : : #include "glsl/spirv.h"
21 : :
22 : : // For pl_pass.priv
23 : : struct pl_pass_vk {
24 : : // Pipeline / render pass
25 : : VkPipeline base;
26 : : VkPipeline pipe;
27 : : VkPipelineLayout pipeLayout;
28 : : VkRenderPass renderPass;
29 : : // Descriptor set (bindings)
30 : : bool use_pushd;
31 : : VkDescriptorSetLayout dsLayout;
32 : : VkDescriptorPool dsPool;
33 : : // To keep track of which descriptor sets are and aren't available, we
34 : : // allocate a fixed number and use a bitmask of all available sets.
35 : : VkDescriptorSet dss[16];
36 : : uint16_t dmask;
37 : :
38 : : // For recompilation
39 : : VkVertexInputAttributeDescription *attrs;
40 : : VkPipelineCache cache;
41 : : VkShaderModule vert;
42 : : VkShaderModule shader;
43 : :
44 : : // For updating
45 : : VkWriteDescriptorSet *dswrite;
46 : : VkDescriptorImageInfo *dsiinfo;
47 : : VkDescriptorBufferInfo *dsbinfo;
48 : : VkSpecializationInfo specInfo;
49 : : size_t spec_size;
50 : : };
51 : :
52 : 1209 : int vk_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
53 : : {
54 : 1209 : return 0;
55 : : }
56 : :
57 : 160 : static void pass_destroy_cb(pl_gpu gpu, pl_pass pass)
58 : : {
59 : 160 : struct pl_vk *p = PL_PRIV(gpu);
60 : 160 : struct vk_ctx *vk = p->vk;
61 : 160 : struct pl_pass_vk *pass_vk = PL_PRIV(pass);
62 : :
63 : 160 : vk->DestroyPipeline(vk->dev, pass_vk->pipe, PL_VK_ALLOC);
64 : 160 : vk->DestroyPipeline(vk->dev, pass_vk->base, PL_VK_ALLOC);
65 : 160 : vk->DestroyRenderPass(vk->dev, pass_vk->renderPass, PL_VK_ALLOC);
66 : 160 : vk->DestroyPipelineLayout(vk->dev, pass_vk->pipeLayout, PL_VK_ALLOC);
67 : 160 : vk->DestroyPipelineCache(vk->dev, pass_vk->cache, PL_VK_ALLOC);
68 : 160 : vk->DestroyDescriptorPool(vk->dev, pass_vk->dsPool, PL_VK_ALLOC);
69 : 160 : vk->DestroyDescriptorSetLayout(vk->dev, pass_vk->dsLayout, PL_VK_ALLOC);
70 : 160 : vk->DestroyShaderModule(vk->dev, pass_vk->vert, PL_VK_ALLOC);
71 : 160 : vk->DestroyShaderModule(vk->dev, pass_vk->shader, PL_VK_ALLOC);
72 : :
73 : 160 : pl_free((void *) pass);
74 : 160 : }
75 : :
76 : 160 : VK_CB_FUNC_DEF(pass_destroy_cb);
77 : :
78 : 160 : void vk_pass_destroy(pl_gpu gpu, pl_pass pass)
79 : : {
80 : 160 : vk_gpu_idle_callback(gpu, VK_CB_FUNC(pass_destroy_cb), gpu, pass);
81 : 160 : }
82 : :
83 : : static const VkDescriptorType dsType[] = {
84 : : [PL_DESC_SAMPLED_TEX] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
85 : : [PL_DESC_STORAGE_IMG] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
86 : : [PL_DESC_BUF_UNIFORM] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
87 : : [PL_DESC_BUF_STORAGE] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
88 : : [PL_DESC_BUF_TEXEL_UNIFORM] = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
89 : : [PL_DESC_BUF_TEXEL_STORAGE] = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
90 : : };
91 : :
92 : 267 : static VkResult vk_compile_glsl(pl_gpu gpu, void *alloc,
93 : : enum glsl_shader_stage stage,
94 : : const char *shader,
95 : : pl_cache_obj *out_spirv)
96 : : {
97 : 267 : struct pl_vk *p = PL_PRIV(gpu);
98 : 267 : pl_cache cache = pl_gpu_cache(gpu);
99 : : uint64_t key = CACHE_KEY_SPIRV;
100 [ + + ]: 267 : if (cache) { // skip computing key if `cache
101 : 2 : pl_hash_merge(&key, p->spirv->signature);
102 : 2 : pl_hash_merge(&key, pl_str0_hash(shader));
103 : 2 : out_spirv->key = key;
104 [ + + ]: 2 : if (pl_cache_get(cache, out_spirv)) {
105 : 1 : PL_DEBUG(gpu, "Re-using cached SPIR-V object 0x%"PRIx64, key);
106 : 1 : return VK_SUCCESS;
107 : : }
108 : : }
109 : :
110 : : pl_clock_t start = pl_clock_now();
111 : 266 : pl_str spirv = pl_spirv_compile_glsl(p->spirv, alloc, gpu->glsl, stage, shader);
112 : 266 : pl_log_cpu_time(gpu->log, start, pl_clock_now(), "translating SPIR-V");
113 : 266 : out_spirv->data = spirv.buf;
114 : 266 : out_spirv->size = spirv.len;
115 : 266 : out_spirv->free = pl_free;
116 [ + - ]: 266 : return spirv.len ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
117 : : }
118 : :
119 : : static const VkShaderStageFlags stageFlags[] = {
120 : : [PL_PASS_RASTER] = VK_SHADER_STAGE_FRAGMENT_BIT |
121 : : VK_SHADER_STAGE_VERTEX_BIT,
122 : : [PL_PASS_COMPUTE] = VK_SHADER_STAGE_COMPUTE_BIT,
123 : : };
124 : :
125 : : static inline void destroy_pipeline(struct vk_ctx *vk, void *pipeline)
126 : : {
127 : 0 : vk->DestroyPipeline(vk->dev, vk_unwrap_handle(pipeline), PL_VK_ALLOC);
128 : : }
129 : :
130 : 0 : VK_CB_FUNC_DEF(destroy_pipeline);
131 : :
132 : 161 : static VkResult vk_recreate_pipelines(struct vk_ctx *vk, pl_pass pass,
133 : : bool derivable, VkPipeline base,
134 : : VkPipeline *out_pipe)
135 : : {
136 : 161 : struct pl_pass_vk *pass_vk = PL_PRIV(pass);
137 : : const struct pl_pass_params *params = &pass->params;
138 : :
139 : : // The old pipeline might still be in use, so we have to destroy it
140 : : // asynchronously with a device idle callback
141 [ - + ]: 161 : if (*out_pipe) {
142 : : // We don't need to use `vk_gpu_idle_callback` because the only command
143 : : // that can access a VkPipeline, `vk_pass_run`, always flushes `p->cmd`.
144 : 0 : vk_dev_callback(vk, VK_CB_FUNC(destroy_pipeline), vk, vk_wrap_handle(*out_pipe));
145 : 0 : *out_pipe = VK_NULL_HANDLE;
146 : : }
147 : :
148 : : VkPipelineCreateFlags flags = 0;
149 [ + + ]: 161 : if (derivable)
150 : : flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
151 [ + + ]: 161 : if (base)
152 : 1 : flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
153 : :
154 : 161 : const VkSpecializationInfo *specInfo = &pass_vk->specInfo;
155 [ + + ]: 161 : if (!specInfo->dataSize)
156 : : specInfo = NULL;
157 : :
158 [ + + - ]: 161 : switch (params->type) {
159 : 108 : case PL_PASS_RASTER: {
160 : : static const VkBlendFactor blendFactors[] = {
161 : : [PL_BLEND_ZERO] = VK_BLEND_FACTOR_ZERO,
162 : : [PL_BLEND_ONE] = VK_BLEND_FACTOR_ONE,
163 : : [PL_BLEND_SRC_ALPHA] = VK_BLEND_FACTOR_SRC_ALPHA,
164 : : [PL_BLEND_ONE_MINUS_SRC_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
165 : : };
166 : :
167 : 108 : VkPipelineColorBlendAttachmentState blendState = {
168 : : .colorBlendOp = VK_BLEND_OP_ADD,
169 : : .alphaBlendOp = VK_BLEND_OP_ADD,
170 : : .colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
171 : : VK_COLOR_COMPONENT_G_BIT |
172 : : VK_COLOR_COMPONENT_B_BIT |
173 : : VK_COLOR_COMPONENT_A_BIT,
174 : : };
175 : :
176 : 108 : const struct pl_blend_params *blend = params->blend_params;
177 [ + + ]: 108 : if (blend) {
178 : 2 : blendState.blendEnable = true;
179 : 2 : blendState.srcColorBlendFactor = blendFactors[blend->src_rgb];
180 : 2 : blendState.dstColorBlendFactor = blendFactors[blend->dst_rgb];
181 : 2 : blendState.srcAlphaBlendFactor = blendFactors[blend->src_alpha];
182 : 2 : blendState.dstAlphaBlendFactor = blendFactors[blend->dst_alpha];
183 : : }
184 : :
185 : : static const VkPrimitiveTopology topologies[PL_PRIM_TYPE_COUNT] = {
186 : : [PL_PRIM_TRIANGLE_LIST] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
187 : : [PL_PRIM_TRIANGLE_STRIP] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
188 : : };
189 : :
190 : 108 : VkGraphicsPipelineCreateInfo cinfo = {
191 : : .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
192 : : .flags = flags,
193 : : .stageCount = 2,
194 : 108 : .pStages = (VkPipelineShaderStageCreateInfo[]) {
195 : : {
196 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
197 : : .stage = VK_SHADER_STAGE_VERTEX_BIT,
198 : 108 : .module = pass_vk->vert,
199 : : .pName = "main",
200 : : }, {
201 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
202 : : .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
203 : 108 : .module = pass_vk->shader,
204 : : .pName = "main",
205 : : .pSpecializationInfo = specInfo,
206 : : }
207 : : },
208 : 108 : .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {
209 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
210 : : .vertexBindingDescriptionCount = 1,
211 : 108 : .pVertexBindingDescriptions = &(VkVertexInputBindingDescription) {
212 : : .binding = 0,
213 : 108 : .stride = params->vertex_stride,
214 : : .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
215 : : },
216 : 108 : .vertexAttributeDescriptionCount = params->num_vertex_attribs,
217 : 108 : .pVertexAttributeDescriptions = pass_vk->attrs,
218 : : },
219 : 108 : .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
220 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
221 : 108 : .topology = topologies[params->vertex_type],
222 : : },
223 : 108 : .pViewportState = &(VkPipelineViewportStateCreateInfo) {
224 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
225 : : .viewportCount = 1,
226 : : .scissorCount = 1,
227 : : },
228 : 108 : .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
229 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
230 : : .polygonMode = VK_POLYGON_MODE_FILL,
231 : : .cullMode = VK_CULL_MODE_NONE,
232 : : .lineWidth = 1.0f,
233 : : },
234 : 108 : .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
235 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
236 : : .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
237 : : },
238 : 108 : .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
239 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
240 : : .attachmentCount = 1,
241 : : .pAttachments = &blendState,
242 : : },
243 : 108 : .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
244 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
245 : : .dynamicStateCount = 2,
246 : 108 : .pDynamicStates = (VkDynamicState[]){
247 : : VK_DYNAMIC_STATE_VIEWPORT,
248 : : VK_DYNAMIC_STATE_SCISSOR,
249 : : },
250 : : },
251 : 108 : .layout = pass_vk->pipeLayout,
252 : 108 : .renderPass = pass_vk->renderPass,
253 : : .basePipelineHandle = base,
254 : : .basePipelineIndex = -1,
255 : : };
256 : :
257 : 108 : return vk->CreateGraphicsPipelines(vk->dev, pass_vk->cache, 1, &cinfo,
258 : : PL_VK_ALLOC, out_pipe);
259 : : }
260 : :
261 : 53 : case PL_PASS_COMPUTE: {
262 : 53 : VkComputePipelineCreateInfo cinfo = {
263 : : .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
264 : : .flags = flags,
265 : : .stage = {
266 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
267 : : .stage = VK_SHADER_STAGE_COMPUTE_BIT,
268 : 53 : .module = pass_vk->shader,
269 : : .pName = "main",
270 : : .pSpecializationInfo = specInfo,
271 : : },
272 : 53 : .layout = pass_vk->pipeLayout,
273 : : .basePipelineHandle = base,
274 : : .basePipelineIndex = -1,
275 : : };
276 : :
277 : 53 : return vk->CreateComputePipelines(vk->dev, pass_vk->cache, 1, &cinfo,
278 : : PL_VK_ALLOC, out_pipe);
279 : : }
280 : :
281 : : case PL_PASS_INVALID:
282 : : case PL_PASS_TYPE_COUNT:
283 : : break;
284 : : }
285 : :
286 : 0 : pl_unreachable();
287 : : }
288 : :
289 : 160 : pl_pass vk_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
290 : : {
291 : 160 : struct pl_vk *p = PL_PRIV(gpu);
292 : 160 : struct vk_ctx *vk = p->vk;
293 : : bool success = false;
294 : :
295 : 160 : struct pl_pass_t *pass = pl_zalloc_obj(NULL, pass, struct pl_pass_vk);
296 : 160 : pass->params = pl_pass_params_copy(pass, params);
297 : :
298 : 160 : struct pl_pass_vk *pass_vk = PL_PRIV(pass);
299 : 160 : pass_vk->dmask = -1; // all descriptors available
300 : :
301 : : // temporary allocations
302 : 160 : void *tmp = pl_tmp(NULL);
303 : :
304 : 160 : int num_desc = params->num_descriptors;
305 [ + + ]: 160 : if (!num_desc)
306 : 4 : goto no_descriptors;
307 [ - + ]: 156 : if (num_desc > vk->props.limits.maxPerStageResources) {
308 : 0 : PL_ERR(gpu, "Pass with %d descriptors exceeds the maximum number of "
309 : : "per-stage resources %" PRIu32"!",
310 : : num_desc, vk->props.limits.maxPerStageResources);
311 : 0 : goto error;
312 : : }
313 : :
314 : 156 : pass_vk->dswrite = pl_calloc(pass, num_desc, sizeof(VkWriteDescriptorSet));
315 : 156 : pass_vk->dsiinfo = pl_calloc(pass, num_desc, sizeof(VkDescriptorImageInfo));
316 : 156 : pass_vk->dsbinfo = pl_calloc(pass, num_desc, sizeof(VkDescriptorBufferInfo));
317 : :
318 : : #define NUM_DS (PL_ARRAY_SIZE(pass_vk->dss))
319 : :
320 : 156 : int dsSize[PL_DESC_TYPE_COUNT] = {0};
321 : : VkDescriptorSetLayoutBinding *bindings = pl_calloc_ptr(tmp, num_desc, bindings);
322 : :
323 : 156 : uint32_t max_tex = vk->props.limits.maxPerStageDescriptorSampledImages,
324 : 156 : max_img = vk->props.limits.maxPerStageDescriptorStorageImages,
325 : 156 : max_ubo = vk->props.limits.maxPerStageDescriptorUniformBuffers,
326 : 156 : max_ssbo = vk->props.limits.maxPerStageDescriptorStorageBuffers;
327 : :
328 : 156 : uint32_t *dsLimits[PL_DESC_TYPE_COUNT] = {
329 : : [PL_DESC_SAMPLED_TEX] = &max_tex,
330 : : [PL_DESC_STORAGE_IMG] = &max_img,
331 : : [PL_DESC_BUF_UNIFORM] = &max_ubo,
332 : : [PL_DESC_BUF_STORAGE] = &max_ssbo,
333 : : [PL_DESC_BUF_TEXEL_UNIFORM] = &max_tex,
334 : : [PL_DESC_BUF_TEXEL_STORAGE] = &max_img,
335 : : };
336 : :
337 [ + + ]: 478 : for (int i = 0; i < num_desc; i++) {
338 : 322 : struct pl_desc *desc = ¶ms->descriptors[i];
339 [ - + ]: 322 : if (!(*dsLimits[desc->type])--) {
340 : 0 : PL_ERR(gpu, "Pass exceeds the maximum number of per-stage "
341 : : "descriptors of type %u!", (unsigned) desc->type);
342 : 0 : goto error;
343 : : }
344 : :
345 : 322 : dsSize[desc->type]++;
346 : 322 : bindings[i] = (VkDescriptorSetLayoutBinding) {
347 : 322 : .binding = desc->binding,
348 : 322 : .descriptorType = dsType[desc->type],
349 : : .descriptorCount = 1,
350 : 322 : .stageFlags = stageFlags[params->type],
351 : : };
352 : : }
353 : :
354 : 156 : VkDescriptorSetLayoutCreateInfo dinfo = {
355 : : .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
356 : : .pBindings = bindings,
357 : : .bindingCount = num_desc,
358 : : };
359 : :
360 [ + - + - ]: 156 : if (p->max_push_descriptors && num_desc <= p->max_push_descriptors) {
361 : 156 : dinfo.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
362 : 156 : pass_vk->use_pushd = true;
363 [ # # ]: 0 : } else if (p->max_push_descriptors) {
364 : 0 : PL_INFO(gpu, "Pass with %d descriptors exceeds the maximum push "
365 : : "descriptor count (%d). Falling back to descriptor sets!",
366 : : num_desc, p->max_push_descriptors);
367 : : }
368 : :
369 [ - + ]: 156 : VK(vk->CreateDescriptorSetLayout(vk->dev, &dinfo, PL_VK_ALLOC,
370 : : &pass_vk->dsLayout));
371 : :
372 [ + - ]: 156 : if (!pass_vk->use_pushd) {
373 : : PL_ARRAY(VkDescriptorPoolSize) dsPoolSizes = {0};
374 : :
375 [ # # ]: 0 : for (enum pl_desc_type t = 0; t < PL_DESC_TYPE_COUNT; t++) {
376 [ # # ]: 0 : if (dsSize[t] > 0) {
377 [ # # # # : 0 : PL_ARRAY_APPEND(tmp, dsPoolSizes, (VkDescriptorPoolSize) {
# # ]
378 : : .type = dsType[t],
379 : : .descriptorCount = dsSize[t] * NUM_DS,
380 : : });
381 : : }
382 : : }
383 : :
384 [ # # ]: 0 : if (dsPoolSizes.num) {
385 : 0 : VkDescriptorPoolCreateInfo pinfo = {
386 : : .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
387 : : .maxSets = NUM_DS,
388 : : .pPoolSizes = dsPoolSizes.elem,
389 : 0 : .poolSizeCount = dsPoolSizes.num,
390 : : };
391 : :
392 [ # # ]: 0 : VK(vk->CreateDescriptorPool(vk->dev, &pinfo, PL_VK_ALLOC, &pass_vk->dsPool));
393 : :
394 : : VkDescriptorSetLayout layouts[NUM_DS];
395 [ # # ]: 0 : for (int i = 0; i < NUM_DS; i++)
396 : 0 : layouts[i] = pass_vk->dsLayout;
397 : :
398 : 0 : VkDescriptorSetAllocateInfo ainfo = {
399 : : .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
400 : 0 : .descriptorPool = pass_vk->dsPool,
401 : : .descriptorSetCount = NUM_DS,
402 : : .pSetLayouts = layouts,
403 : : };
404 : :
405 [ # # ]: 0 : VK(vk->AllocateDescriptorSets(vk->dev, &ainfo, pass_vk->dss));
406 : : }
407 : : }
408 : :
409 : 156 : no_descriptors: ;
410 : :
411 : 160 : bool has_spec = params->num_constants;
412 [ + + ]: 160 : if (has_spec) {
413 : : PL_ARRAY(VkSpecializationMapEntry) entries = {0};
414 [ + - ]: 154 : PL_ARRAY_RESIZE(pass, entries, params->num_constants);
415 : : size_t spec_size = 0;
416 : :
417 [ + + ]: 1187 : for (int i = 0; i < params->num_constants; i++) {
418 : 1033 : const struct pl_constant *con = ¶ms->constants[i];
419 : 1033 : size_t con_size = pl_var_type_size(con->type);
420 : 1033 : entries.elem[i] = (VkSpecializationMapEntry) {
421 : 1033 : .constantID = con->id,
422 : 1033 : .offset = con->offset,
423 : : .size = con_size,
424 : : };
425 : :
426 : 1033 : size_t req_size = con->offset + con_size;
427 : 1033 : spec_size = PL_MAX(spec_size, req_size);
428 : : }
429 : :
430 : 154 : pass_vk->spec_size = spec_size;
431 : 154 : pass_vk->specInfo = (VkSpecializationInfo) {
432 : 154 : .mapEntryCount = params->num_constants,
433 : : .pMapEntries = entries.elem,
434 : : };
435 : :
436 [ + - ]: 154 : if (params->constant_data) {
437 : 154 : pass_vk->specInfo.pData = pl_memdup(pass, params->constant_data, spec_size);
438 : 154 : pass_vk->specInfo.dataSize = spec_size;
439 : : }
440 : : }
441 : :
442 : 160 : VkPipelineLayoutCreateInfo linfo = {
443 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
444 : 160 : .setLayoutCount = num_desc ? 1 : 0,
445 : 160 : .pSetLayouts = &pass_vk->dsLayout,
446 : 160 : .pushConstantRangeCount = params->push_constants_size ? 1 : 0,
447 : 160 : .pPushConstantRanges = &(VkPushConstantRange){
448 : 160 : .stageFlags = stageFlags[params->type],
449 : : .offset = 0,
450 : : .size = params->push_constants_size,
451 : : },
452 : : };
453 : :
454 [ - + ]: 160 : VK(vk->CreatePipelineLayout(vk->dev, &linfo, PL_VK_ALLOC,
455 : : &pass_vk->pipeLayout));
456 : :
457 : 160 : pl_cache_obj vert = {0}, frag = {0}, comp = {0};
458 [ + + - - ]: 160 : switch (params->type) {
459 : 107 : case PL_PASS_RASTER: ;
460 [ - + ]: 107 : VK(vk_compile_glsl(gpu, tmp, GLSL_SHADER_VERTEX, params->vertex_shader, &vert));
461 [ - + ]: 107 : VK(vk_compile_glsl(gpu, tmp, GLSL_SHADER_FRAGMENT, params->glsl_shader, &frag));
462 : : break;
463 : 53 : case PL_PASS_COMPUTE:
464 [ - + ]: 53 : VK(vk_compile_glsl(gpu, tmp, GLSL_SHADER_COMPUTE, params->glsl_shader, &comp));
465 : : break;
466 : : case PL_PASS_INVALID:
467 : : case PL_PASS_TYPE_COUNT:
468 : 0 : pl_unreachable();
469 : : }
470 : :
471 : : // Use hash of generated SPIR-V as key for pipeline cache
472 : 160 : const pl_cache cache = pl_gpu_cache(gpu);
473 : 160 : pl_cache_obj pipecache = {0};
474 [ + + ]: 160 : if (cache) {
475 : 2 : pipecache.key = CACHE_KEY_VK_PIPE;
476 : 2 : pl_hash_merge(&pipecache.key, pl_var_hash(vk->props.pipelineCacheUUID));
477 : 2 : pl_hash_merge(&pipecache.key, pl_mem_hash(vert.data, vert.size));
478 : 2 : pl_hash_merge(&pipecache.key, pl_mem_hash(frag.data, frag.size));
479 : 2 : pl_hash_merge(&pipecache.key, pl_mem_hash(comp.data, comp.size));
480 : 2 : pl_cache_get(cache, &pipecache);
481 : : }
482 : :
483 [ + + ]: 160 : if (cache || has_spec) {
484 : : // Don't create pipeline cache unless we either plan on caching the
485 : : // result of this shader to a pl_cache, or if we will possibly re-use
486 : : // it due to the presence of specialization constants
487 : 154 : VkPipelineCacheCreateInfo pcinfo = {
488 : : .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
489 : 154 : .pInitialData = pipecache.data,
490 : 154 : .initialDataSize = pipecache.size,
491 : : };
492 : :
493 [ - + ]: 154 : VK(vk->CreatePipelineCache(vk->dev, &pcinfo, PL_VK_ALLOC, &pass_vk->cache));
494 : : }
495 : :
496 : 160 : VkShaderModuleCreateInfo sinfo = {
497 : : .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
498 : : };
499 : :
500 : : pl_clock_t start = pl_clock_now();
501 [ + + - - ]: 160 : switch (params->type) {
502 : 107 : case PL_PASS_RASTER: {
503 : 107 : sinfo.pCode = (uint32_t *) vert.data;
504 : 107 : sinfo.codeSize = vert.size;
505 [ - + ]: 107 : VK(vk->CreateShaderModule(vk->dev, &sinfo, PL_VK_ALLOC, &pass_vk->vert));
506 [ + - ]: 107 : PL_VK_NAME(SHADER_MODULE, pass_vk->vert, "vertex");
507 : :
508 : 107 : sinfo.pCode = (uint32_t *) frag.data;
509 : 107 : sinfo.codeSize = frag.size;
510 [ - + ]: 107 : VK(vk->CreateShaderModule(vk->dev, &sinfo, PL_VK_ALLOC, &pass_vk->shader));
511 [ + - ]: 107 : PL_VK_NAME(SHADER_MODULE, pass_vk->shader, "fragment");
512 : :
513 : 107 : pass_vk->attrs = pl_calloc_ptr(pass, params->num_vertex_attribs, pass_vk->attrs);
514 [ + + ]: 327 : for (int i = 0; i < params->num_vertex_attribs; i++) {
515 : 220 : struct pl_vertex_attrib *va = ¶ms->vertex_attribs[i];
516 : 220 : const struct vk_format **pfmt_vk = PL_PRIV(va->fmt);
517 : :
518 : 440 : pass_vk->attrs[i] = (VkVertexInputAttributeDescription) {
519 : : .binding = 0,
520 : 220 : .location = va->location,
521 : 220 : .offset = va->offset,
522 [ + - ]: 220 : .format = PL_DEF((*pfmt_vk)->bfmt, (*pfmt_vk)->tfmt),
523 : : };
524 : : }
525 : :
526 : 214 : VkRenderPassCreateInfo rinfo = {
527 : : .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
528 : : .attachmentCount = 1,
529 : 214 : .pAttachments = &(VkAttachmentDescription) {
530 : 107 : .format = (VkFormat) params->target_format->signature,
531 : : .samples = VK_SAMPLE_COUNT_1_BIT,
532 : 107 : .loadOp = pass->params.load_target
533 : : ? VK_ATTACHMENT_LOAD_OP_LOAD
534 [ + + ]: 107 : : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
535 : : .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
536 : : .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
537 : : .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
538 : : },
539 : : .subpassCount = 1,
540 : 107 : .pSubpasses = &(VkSubpassDescription) {
541 : : .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
542 : : .colorAttachmentCount = 1,
543 : 107 : .pColorAttachments = &(VkAttachmentReference) {
544 : : .attachment = 0,
545 : : .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
546 : : },
547 : : },
548 : : };
549 : :
550 [ - + ]: 107 : VK(vk->CreateRenderPass(vk->dev, &rinfo, PL_VK_ALLOC, &pass_vk->renderPass));
551 : 107 : break;
552 : : }
553 : 53 : case PL_PASS_COMPUTE: {
554 : 53 : sinfo.pCode = (uint32_t *) comp.data;
555 : 53 : sinfo.codeSize = comp.size;
556 [ - + ]: 53 : VK(vk->CreateShaderModule(vk->dev, &sinfo, PL_VK_ALLOC, &pass_vk->shader));
557 [ + - ]: 53 : PL_VK_NAME(SHADER_MODULE, pass_vk->shader, "compute");
558 : : break;
559 : : }
560 : : case PL_PASS_INVALID:
561 : : case PL_PASS_TYPE_COUNT:
562 : 0 : pl_unreachable();
563 : : }
564 : :
565 : : pl_clock_t after_compilation = pl_clock_now();
566 : 160 : pl_log_cpu_time(gpu->log, start, after_compilation, "compiling shader");
567 : :
568 : : // Update cache entries on successful compilation
569 : 160 : pl_cache_steal(cache, &vert);
570 : 160 : pl_cache_steal(cache, &frag);
571 : 160 : pl_cache_steal(cache, &comp);
572 : :
573 : : // Create the graphics/compute pipeline
574 [ + + ]: 160 : VkPipeline *pipe = has_spec ? &pass_vk->base : &pass_vk->pipe;
575 [ - + ]: 160 : VK(vk_recreate_pipelines(vk, pass, has_spec, VK_NULL_HANDLE, pipe));
576 : 160 : pl_log_cpu_time(gpu->log, after_compilation, pl_clock_now(), "creating pipeline");
577 : :
578 : : // Update pipeline cache
579 [ + + ]: 160 : if (cache) {
580 : 2 : size_t size = 0;
581 [ - + ]: 2 : VK(vk->GetPipelineCacheData(vk->dev, pass_vk->cache, &size, NULL));
582 : 2 : pl_cache_obj_resize(tmp, &pipecache, size);
583 [ - + ]: 2 : VK(vk->GetPipelineCacheData(vk->dev, pass_vk->cache, &size, pipecache.data));
584 : 2 : pl_cache_steal(cache, &pipecache);
585 : : }
586 : :
587 [ + + ]: 160 : if (!has_spec) {
588 : : // We can free these if we no longer need them for specialization
589 : 6 : pl_free_ptr(&pass_vk->attrs);
590 : 6 : vk->DestroyShaderModule(vk->dev, pass_vk->vert, PL_VK_ALLOC);
591 : 6 : vk->DestroyShaderModule(vk->dev, pass_vk->shader, PL_VK_ALLOC);
592 : 6 : vk->DestroyPipelineCache(vk->dev, pass_vk->cache, PL_VK_ALLOC);
593 : 6 : pass_vk->vert = VK_NULL_HANDLE;
594 : 6 : pass_vk->shader = VK_NULL_HANDLE;
595 : 6 : pass_vk->cache = VK_NULL_HANDLE;
596 : : }
597 : :
598 : 160 : PL_DEBUG(vk, "Pass statistics: size %zu, SPIR-V: vert %zu frag %zu comp %zu",
599 : : pipecache.size, vert.size, frag.size, comp.size);
600 : :
601 : : success = true;
602 : :
603 : : error:
604 : : if (!success) {
605 : 0 : pass_destroy_cb(gpu, pass);
606 : : pass = NULL;
607 : : }
608 : :
609 : : #undef NUM_DS
610 : :
611 : 160 : pl_free(tmp);
612 : 160 : return pass;
613 : : }
614 : :
615 : : static const VkPipelineStageFlags2 shaderStages[] = {
616 : : [PL_PASS_RASTER] = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
617 : : [PL_PASS_COMPUTE] = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
618 : : };
619 : :
620 : 887 : static void vk_update_descriptor(pl_gpu gpu, struct vk_cmd *cmd, pl_pass pass,
621 : : struct pl_desc_binding db,
622 : : VkDescriptorSet ds, int idx)
623 : : {
624 : 887 : struct pl_vk *p = PL_PRIV(gpu);
625 : 887 : struct pl_pass_vk *pass_vk = PL_PRIV(pass);
626 : 887 : struct pl_desc *desc = &pass->params.descriptors[idx];
627 : :
628 : 887 : VkWriteDescriptorSet *wds = &pass_vk->dswrite[idx];
629 : 887 : *wds = (VkWriteDescriptorSet) {
630 : : .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
631 : : .dstSet = ds,
632 : 887 : .dstBinding = desc->binding,
633 : : .descriptorCount = 1,
634 : 887 : .descriptorType = dsType[desc->type],
635 : : };
636 : :
637 : : static const VkAccessFlags2 storageAccess[PL_DESC_ACCESS_COUNT] = {
638 : : [PL_DESC_ACCESS_READONLY] = VK_ACCESS_2_SHADER_STORAGE_READ_BIT,
639 : : [PL_DESC_ACCESS_WRITEONLY] = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
640 : : [PL_DESC_ACCESS_READWRITE] = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
641 : : VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
642 : : };
643 : :
644 [ + + + + : 887 : switch (desc->type) {
- ]
645 : 779 : case PL_DESC_SAMPLED_TEX: {
646 : : pl_tex tex = db.object;
647 : 779 : struct pl_tex_vk *tex_vk = PL_PRIV(tex);
648 : :
649 : 779 : vk_tex_barrier(gpu, cmd, tex, shaderStages[pass->params.type],
650 : : VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
651 : : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
652 : : VK_QUEUE_FAMILY_IGNORED);
653 : :
654 : 779 : VkDescriptorImageInfo *iinfo = &pass_vk->dsiinfo[idx];
655 : 779 : *iinfo = (VkDescriptorImageInfo) {
656 : 779 : .sampler = p->samplers[db.sample_mode][db.address_mode],
657 : 779 : .imageView = tex_vk->view,
658 : 779 : .imageLayout = tex_vk->layout,
659 : : };
660 : :
661 : 779 : wds->pImageInfo = iinfo;
662 : : return;
663 : : }
664 : 66 : case PL_DESC_STORAGE_IMG: {
665 : : pl_tex tex = db.object;
666 : 66 : struct pl_tex_vk *tex_vk = PL_PRIV(tex);
667 : :
668 : 66 : vk_tex_barrier(gpu, cmd, tex, shaderStages[pass->params.type],
669 : 66 : storageAccess[desc->access], VK_IMAGE_LAYOUT_GENERAL,
670 : : VK_QUEUE_FAMILY_IGNORED);
671 : :
672 : 66 : VkDescriptorImageInfo *iinfo = &pass_vk->dsiinfo[idx];
673 : 66 : *iinfo = (VkDescriptorImageInfo) {
674 : 66 : .imageView = tex_vk->view,
675 : 66 : .imageLayout = tex_vk->layout,
676 : : };
677 : :
678 : 66 : wds->pImageInfo = iinfo;
679 : : return;
680 : : }
681 : 24 : case PL_DESC_BUF_UNIFORM:
682 : : case PL_DESC_BUF_STORAGE: {
683 : : pl_buf buf = db.object;
684 : 24 : struct pl_buf_vk *buf_vk = PL_PRIV(buf);
685 : :
686 : : VkAccessFlags2 access = VK_ACCESS_2_UNIFORM_READ_BIT;
687 [ + + ]: 24 : if (desc->type == PL_DESC_BUF_STORAGE)
688 : 11 : access = storageAccess[desc->access];
689 : :
690 : 24 : vk_buf_barrier(gpu, cmd, buf, shaderStages[pass->params.type],
691 : 24 : access, 0, buf->params.size, false);
692 : :
693 : 24 : VkDescriptorBufferInfo *binfo = &pass_vk->dsbinfo[idx];
694 : 24 : *binfo = (VkDescriptorBufferInfo) {
695 : 24 : .buffer = buf_vk->mem.buf,
696 : 24 : .offset = buf_vk->mem.offset,
697 : 24 : .range = buf->params.size,
698 : : };
699 : :
700 : 24 : wds->pBufferInfo = binfo;
701 : : return;
702 : : }
703 : 18 : case PL_DESC_BUF_TEXEL_UNIFORM:
704 : : case PL_DESC_BUF_TEXEL_STORAGE: {
705 : : pl_buf buf = db.object;
706 : 18 : struct pl_buf_vk *buf_vk = PL_PRIV(buf);
707 : :
708 : : VkAccessFlags2 access = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
709 [ + - ]: 18 : if (desc->type == PL_DESC_BUF_TEXEL_STORAGE)
710 : 18 : access = storageAccess[desc->access];
711 : :
712 : 18 : vk_buf_barrier(gpu, cmd, buf, shaderStages[pass->params.type],
713 : 18 : access, 0, buf->params.size, false);
714 : :
715 : 18 : wds->pTexelBufferView = &buf_vk->view;
716 : 18 : return;
717 : : }
718 : : case PL_DESC_INVALID:
719 : : case PL_DESC_TYPE_COUNT:
720 : : break;
721 : : }
722 : :
723 : 0 : pl_unreachable();
724 : : }
725 : :
726 : 887 : static void vk_release_descriptor(pl_gpu gpu, struct vk_cmd *cmd, pl_pass pass,
727 : : struct pl_desc_binding db, int idx)
728 : : {
729 : 887 : const struct pl_desc *desc = &pass->params.descriptors[idx];
730 : :
731 [ + - + ]: 887 : switch (desc->type) {
732 : 42 : case PL_DESC_BUF_UNIFORM:
733 : : case PL_DESC_BUF_STORAGE:
734 : : case PL_DESC_BUF_TEXEL_UNIFORM:
735 : : case PL_DESC_BUF_TEXEL_STORAGE:
736 [ + + ]: 42 : if (desc->access != PL_DESC_ACCESS_READONLY) {
737 : 41 : pl_buf buf = db.object;
738 : 41 : vk_buf_flush(gpu, cmd, buf, 0, buf->params.size);
739 : : }
740 : : return;
741 : : case PL_DESC_SAMPLED_TEX:
742 : : case PL_DESC_STORAGE_IMG:
743 : : return;
744 : : case PL_DESC_INVALID:
745 : : case PL_DESC_TYPE_COUNT:
746 : : break;
747 : : }
748 : :
749 : 0 : pl_unreachable();
750 : : }
751 : :
752 : : static void set_ds(struct pl_pass_vk *pass_vk, void *dsbit)
753 : : {
754 : 6 : pass_vk->dmask |= (uintptr_t) dsbit;
755 : : }
756 : :
757 : 6 : VK_CB_FUNC_DEF(set_ds);
758 : :
759 : 536 : static bool need_respec(pl_pass pass, const struct pl_pass_run_params *params)
760 : : {
761 : 536 : struct pl_pass_vk *pass_vk = PL_PRIV(pass);
762 [ + + + - ]: 536 : if (!pass_vk->spec_size || !params->constant_data)
763 : : return false;
764 : :
765 : : VkSpecializationInfo *specInfo = &pass_vk->specInfo;
766 : : size_t size = pass_vk->spec_size;
767 [ - + ]: 528 : if (!specInfo->pData) {
768 : : // Shader was never specialized before
769 : 0 : specInfo->pData = pl_memdup((void *) pass, params->constant_data, size);
770 : 0 : specInfo->dataSize = size;
771 : 0 : return true;
772 : : }
773 : :
774 : : // Shader is being re-specialized with new values
775 [ + + ]: 528 : if (memcmp(specInfo->pData, params->constant_data, size) != 0) {
776 : : memcpy((void *) specInfo->pData, params->constant_data, size);
777 : 1 : return true;
778 : : }
779 : :
780 : : return false;
781 : : }
782 : :
783 : 1005 : void vk_pass_run(pl_gpu gpu, const struct pl_pass_run_params *params)
784 : : {
785 : 1005 : struct pl_vk *p = PL_PRIV(gpu);
786 : 1005 : struct vk_ctx *vk = p->vk;
787 : 1005 : pl_pass pass = params->pass;
788 : 1005 : struct pl_pass_vk *pass_vk = PL_PRIV(pass);
789 : :
790 [ + + - + ]: 1005 : if (params->vertex_data || params->index_data)
791 : 469 : return pl_pass_run_vbo(gpu, params);
792 : :
793 : : // Check if we need to re-specialize this pipeline
794 [ + + ]: 536 : if (need_respec(pass, params)) {
795 : : pl_clock_t start = pl_clock_now();
796 [ - + ]: 1 : VK(vk_recreate_pipelines(vk, pass, false, pass_vk->base, &pass_vk->pipe));
797 : 1 : pl_log_cpu_time(gpu->log, start, pl_clock_now(), "re-specializing shader");
798 : : }
799 : :
800 [ + + ]: 536 : if (!pass_vk->use_pushd) {
801 : : // Wait for a free descriptor set
802 [ - + ]: 6 : while (!pass_vk->dmask) {
803 : 0 : PL_TRACE(gpu, "No free descriptor sets! ...blocking (slow path)");
804 : 0 : vk_poll_commands(vk, 10000000); // 10 ms
805 : : }
806 : : }
807 : :
808 : : static const enum queue_type types[] = {
809 : : [PL_PASS_RASTER] = GRAPHICS,
810 : : [PL_PASS_COMPUTE] = COMPUTE,
811 : : };
812 : :
813 : 536 : struct vk_cmd *cmd = CMD_BEGIN_TIMED(types[pass->params.type], params->timer);
814 [ - + ]: 536 : if (!cmd)
815 : 0 : goto error;
816 : :
817 : : // Find a descriptor set to use
818 : 536 : VkDescriptorSet ds = VK_NULL_HANDLE;
819 [ + + ]: 536 : if (!pass_vk->use_pushd) {
820 [ + - ]: 6 : for (int i = 0; i < PL_ARRAY_SIZE(pass_vk->dss); i++) {
821 : 6 : uint16_t dsbit = 1u << i;
822 [ + - ]: 6 : if (pass_vk->dmask & dsbit) {
823 : 6 : ds = pass_vk->dss[i];
824 : 6 : pass_vk->dmask &= ~dsbit; // unset
825 : 6 : vk_cmd_callback(cmd, VK_CB_FUNC(set_ds), pass_vk,
826 : 6 : (void *)(uintptr_t) dsbit);
827 : 6 : break;
828 : : }
829 : : }
830 : : }
831 : :
832 : : // Update the dswrite structure with all of the new values
833 [ + + ]: 1423 : for (int i = 0; i < pass->params.num_descriptors; i++)
834 : 887 : vk_update_descriptor(gpu, cmd, pass, params->desc_bindings[i], ds, i);
835 : :
836 [ + + ]: 536 : if (!pass_vk->use_pushd) {
837 : 6 : vk->UpdateDescriptorSets(vk->dev, pass->params.num_descriptors,
838 : 6 : pass_vk->dswrite, 0, NULL);
839 : : }
840 : :
841 : : // Bind the pipeline, descriptor set, etc.
842 : : static const VkPipelineBindPoint bindPoint[] = {
843 : : [PL_PASS_RASTER] = VK_PIPELINE_BIND_POINT_GRAPHICS,
844 : : [PL_PASS_COMPUTE] = VK_PIPELINE_BIND_POINT_COMPUTE,
845 : : };
846 : :
847 : 536 : vk->CmdBindPipeline(cmd->buf, bindPoint[pass->params.type],
848 [ + + ]: 536 : PL_DEF(pass_vk->pipe, pass_vk->base));
849 : :
850 [ - + ]: 536 : if (ds) {
851 : 0 : vk->CmdBindDescriptorSets(cmd->buf, bindPoint[pass->params.type],
852 : : pass_vk->pipeLayout, 0, 1, &ds, 0, NULL);
853 : : }
854 : :
855 [ + + ]: 536 : if (pass_vk->use_pushd) {
856 : 530 : vk->CmdPushDescriptorSetKHR(cmd->buf, bindPoint[pass->params.type],
857 : : pass_vk->pipeLayout, 0,
858 : 530 : pass->params.num_descriptors,
859 : 530 : pass_vk->dswrite);
860 : : }
861 : :
862 [ + + ]: 536 : if (pass->params.push_constants_size) {
863 : 488 : vk->CmdPushConstants(cmd->buf, pass_vk->pipeLayout,
864 : 488 : stageFlags[pass->params.type], 0,
865 : : pass->params.push_constants_size,
866 : 488 : params->push_constants);
867 : : }
868 : :
869 [ + + - - ]: 536 : switch (pass->params.type) {
870 : 470 : case PL_PASS_RASTER: {
871 : 470 : pl_tex tex = params->target;
872 : 470 : struct pl_tex_vk *tex_vk = PL_PRIV(tex);
873 : 470 : pl_buf vert = params->vertex_buf;
874 : 470 : struct pl_buf_vk *vert_vk = PL_PRIV(vert);
875 : 470 : pl_buf index = params->index_buf;
876 [ + + ]: 470 : struct pl_buf_vk *index_vk = index ? PL_PRIV(index) : NULL;
877 [ - + ]: 470 : pl_assert(vert);
878 : :
879 : : // In the edge case that vert = index buffer, we need to synchronize
880 : : // for both flags simultaneously
881 : : VkPipelineStageFlags2 vbo_stage = VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT;
882 : : VkAccessFlags2 vbo_flags = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT;
883 [ - + ]: 470 : if (index == vert) {
884 : : vbo_stage |= VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT;
885 : : vbo_flags |= VK_ACCESS_2_INDEX_READ_BIT;
886 : : }
887 : :
888 : 470 : vk_buf_barrier(gpu, cmd, vert, vbo_stage, vbo_flags, 0, vert->params.size, false);
889 : :
890 : 470 : VkDeviceSize offset = vert_vk->mem.offset + params->buf_offset;
891 : 470 : vk->CmdBindVertexBuffers(cmd->buf, 0, 1, &vert_vk->mem.buf, &offset);
892 : :
893 [ + + ]: 470 : if (index) {
894 [ + - ]: 5 : if (index != vert) {
895 : 5 : vk_buf_barrier(gpu, cmd, index, VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT,
896 : 5 : VK_ACCESS_2_INDEX_READ_BIT, 0, index->params.size,
897 : : false);
898 : : }
899 : :
900 : : static const VkIndexType index_fmts[PL_INDEX_FORMAT_COUNT] = {
901 : : [PL_INDEX_UINT16] = VK_INDEX_TYPE_UINT16,
902 : : [PL_INDEX_UINT32] = VK_INDEX_TYPE_UINT32,
903 : : };
904 : :
905 : 5 : vk->CmdBindIndexBuffer(cmd->buf, index_vk->mem.buf,
906 : 5 : index_vk->mem.offset + params->index_offset,
907 : 5 : index_fmts[params->index_fmt]);
908 : : }
909 : :
910 : :
911 : : VkAccessFlags2 fbo_access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
912 [ + + ]: 470 : if (pass->params.load_target)
913 : : fbo_access |= VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT;
914 : :
915 : 470 : vk_tex_barrier(gpu, cmd, tex, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
916 : : fbo_access, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
917 : : VK_QUEUE_FAMILY_IGNORED);
918 : :
919 : 470 : VkViewport viewport = {
920 : 470 : .x = params->viewport.x0,
921 : 470 : .y = params->viewport.y0,
922 : 470 : .width = pl_rect_w(params->viewport),
923 : 470 : .height = pl_rect_h(params->viewport),
924 : : };
925 : :
926 : 470 : VkRect2D scissor = {
927 : 470 : .offset = {params->scissors.x0, params->scissors.y0},
928 : 470 : .extent = {pl_rect_w(params->scissors), pl_rect_h(params->scissors)},
929 : : };
930 : :
931 : 470 : vk->CmdSetViewport(cmd->buf, 0, 1, &viewport);
932 : 470 : vk->CmdSetScissor(cmd->buf, 0, 1, &scissor);
933 : :
934 : 470 : VkRenderPassBeginInfo binfo = {
935 : : .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
936 : 470 : .renderPass = pass_vk->renderPass,
937 : 470 : .framebuffer = tex_vk->framebuffer,
938 : 470 : .renderArea.extent = {tex->params.w, tex->params.h},
939 : : };
940 : :
941 : 470 : vk->CmdBeginRenderPass(cmd->buf, &binfo, VK_SUBPASS_CONTENTS_INLINE);
942 : :
943 [ + + ]: 470 : if (index) {
944 : 5 : vk->CmdDrawIndexed(cmd->buf, params->vertex_count, 1, 0, 0, 0);
945 : : } else {
946 : 465 : vk->CmdDraw(cmd->buf, params->vertex_count, 1, 0, 0);
947 : : }
948 : :
949 : 470 : vk->CmdEndRenderPass(cmd->buf);
950 : : break;
951 : : }
952 : 66 : case PL_PASS_COMPUTE:
953 : 66 : vk->CmdDispatch(cmd->buf, params->compute_groups[0],
954 : 66 : params->compute_groups[1],
955 : 66 : params->compute_groups[2]);
956 : 66 : break;
957 : : case PL_PASS_INVALID:
958 : : case PL_PASS_TYPE_COUNT:
959 : 0 : pl_unreachable();
960 : : };
961 : :
962 [ + + ]: 1423 : for (int i = 0; i < pass->params.num_descriptors; i++)
963 : 887 : vk_release_descriptor(gpu, cmd, pass, params->desc_bindings[i], i);
964 : :
965 : : // submit this command buffer for better intra-frame granularity
966 : 536 : CMD_SUBMIT(&cmd);
967 : :
968 : 1005 : error:
969 : : return;
970 : : }
|