Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/vulkan/panvk_shader.c
4560 views
1
/*
2
* Copyright © 2021 Collabora Ltd.
3
*
4
* Derived from tu_shader.c which is:
5
* Copyright © 2019 Google LLC
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining a
8
* copy of this software and associated documentation files (the "Software"),
9
* to deal in the Software without restriction, including without limitation
10
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
* and/or sell copies of the Software, and to permit persons to whom the
12
* Software is furnished to do so, subject to the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the next
15
* paragraph) shall be included in all copies or substantial portions of the
16
* Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
* DEALINGS IN THE SOFTWARE.
25
*/
26
27
#include "panvk_private.h"
28
29
#include "nir_builder.h"
30
#include "nir_lower_blend.h"
31
#include "spirv/nir_spirv.h"
32
#include "util/mesa-sha1.h"
33
34
#include "panfrost-quirks.h"
35
#include "pan_shader.h"
36
37
static nir_shader *
38
panvk_spirv_to_nir(const void *code,
39
size_t codesize,
40
gl_shader_stage stage,
41
const char *entry_point_name,
42
const VkSpecializationInfo *spec_info,
43
const nir_shader_compiler_options *nir_options)
44
{
45
/* TODO these are made-up */
46
const struct spirv_to_nir_options spirv_options = {
47
.caps = { false },
48
.ubo_addr_format = nir_address_format_32bit_index_offset,
49
.ssbo_addr_format = nir_address_format_32bit_index_offset,
50
};
51
52
/* convert VkSpecializationInfo */
53
struct nir_spirv_specialization *spec = NULL;
54
uint32_t num_spec = 0;
55
if (spec_info && spec_info->mapEntryCount) {
56
spec = malloc(sizeof(*spec) * spec_info->mapEntryCount);
57
if (!spec)
58
return NULL;
59
60
for (uint32_t i = 0; i < spec_info->mapEntryCount; i++) {
61
const VkSpecializationMapEntry *entry = &spec_info->pMapEntries[i];
62
const void *data = spec_info->pData + entry->offset;
63
assert(data + entry->size <= spec_info->pData + spec_info->dataSize);
64
spec[i].id = entry->constantID;
65
switch (entry->size) {
66
case 8:
67
spec[i].value.u64 = *(const uint64_t *)data;
68
break;
69
case 4:
70
spec[i].value.u32 = *(const uint32_t *)data;
71
break;
72
case 2:
73
spec[i].value.u16 = *(const uint16_t *)data;
74
break;
75
case 1:
76
spec[i].value.u8 = *(const uint8_t *)data;
77
break;
78
default:
79
assert(!"Invalid spec constant size");
80
break;
81
}
82
83
spec[i].defined_on_module = false;
84
}
85
86
num_spec = spec_info->mapEntryCount;
87
}
88
89
nir_shader *nir = spirv_to_nir(code, codesize / sizeof(uint32_t), spec,
90
num_spec, stage, entry_point_name,
91
&spirv_options, nir_options);
92
93
free(spec);
94
95
assert(nir->info.stage == stage);
96
nir_validate_shader(nir, "after spirv_to_nir");
97
98
return nir;
99
}
100
101
struct panvk_lower_misc_ctx {
102
struct panvk_shader *shader;
103
const struct panvk_pipeline_layout *layout;
104
};
105
106
static unsigned
107
get_fixed_sampler_index(nir_deref_instr *deref,
108
const struct panvk_lower_misc_ctx *ctx)
109
{
110
nir_variable *var = nir_deref_instr_get_variable(deref);
111
unsigned set = var->data.descriptor_set;
112
unsigned binding = var->data.binding;
113
const struct panvk_descriptor_set_binding_layout *bind_layout =
114
&ctx->layout->sets[set].layout->bindings[binding];
115
116
return bind_layout->sampler_idx + ctx->layout->sets[set].sampler_offset;
117
}
118
119
static unsigned
120
get_fixed_texture_index(nir_deref_instr *deref,
121
const struct panvk_lower_misc_ctx *ctx)
122
{
123
nir_variable *var = nir_deref_instr_get_variable(deref);
124
unsigned set = var->data.descriptor_set;
125
unsigned binding = var->data.binding;
126
const struct panvk_descriptor_set_binding_layout *bind_layout =
127
&ctx->layout->sets[set].layout->bindings[binding];
128
129
return bind_layout->tex_idx + ctx->layout->sets[set].tex_offset;
130
}
131
132
static bool
133
lower_tex(nir_builder *b, nir_tex_instr *tex,
134
const struct panvk_lower_misc_ctx *ctx)
135
{
136
bool progress = false;
137
int sampler_src_idx = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
138
139
b->cursor = nir_before_instr(&tex->instr);
140
141
if (sampler_src_idx >= 0) {
142
nir_deref_instr *deref = nir_src_as_deref(tex->src[sampler_src_idx].src);
143
tex->sampler_index = get_fixed_sampler_index(deref, ctx);
144
nir_tex_instr_remove_src(tex, sampler_src_idx);
145
progress = true;
146
}
147
148
int tex_src_idx = nir_tex_instr_src_index(tex, nir_tex_src_texture_deref);
149
if (tex_src_idx >= 0) {
150
nir_deref_instr *deref = nir_src_as_deref(tex->src[tex_src_idx].src);
151
tex->texture_index = get_fixed_texture_index(deref, ctx);
152
nir_tex_instr_remove_src(tex, tex_src_idx);
153
progress = true;
154
}
155
156
return progress;
157
}
158
159
static void
160
lower_vulkan_resource_index(nir_builder *b, nir_intrinsic_instr *intr,
161
const struct panvk_lower_misc_ctx *ctx)
162
{
163
nir_ssa_def *vulkan_idx = intr->src[0].ssa;
164
165
unsigned set = nir_intrinsic_desc_set(intr);
166
unsigned binding = nir_intrinsic_binding(intr);
167
struct panvk_descriptor_set_layout *set_layout = ctx->layout->sets[set].layout;
168
struct panvk_descriptor_set_binding_layout *binding_layout =
169
&set_layout->bindings[binding];
170
unsigned base;
171
172
switch (binding_layout->type) {
173
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
174
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
175
base = binding_layout->ubo_idx + ctx->layout->sets[set].ubo_offset;
176
break;
177
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
178
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
179
base = binding_layout->ssbo_idx + ctx->layout->sets[set].ssbo_offset;
180
break;
181
default:
182
unreachable("Invalid descriptor type");
183
break;
184
}
185
186
b->cursor = nir_before_instr(&intr->instr);
187
nir_ssa_def *idx = nir_iadd(b, nir_imm_int(b, base), vulkan_idx);
188
nir_ssa_def_rewrite_uses(&intr->dest.ssa, idx);
189
nir_instr_remove(&intr->instr);
190
}
191
192
static void
193
lower_load_vulkan_descriptor(nir_builder *b, nir_intrinsic_instr *intrin)
194
{
195
/* Loading the descriptor happens as part of the load/store instruction so
196
* this is a no-op.
197
*/
198
b->cursor = nir_before_instr(&intrin->instr);
199
nir_ssa_def *val = nir_vec2(b, intrin->src[0].ssa, nir_imm_int(b, 0));
200
nir_ssa_def_rewrite_uses(&intrin->dest.ssa, val);
201
nir_instr_remove(&intrin->instr);
202
}
203
204
static bool
205
lower_intrinsic(nir_builder *b, nir_intrinsic_instr *intr,
206
const struct panvk_lower_misc_ctx *ctx)
207
{
208
switch (intr->intrinsic) {
209
case nir_intrinsic_vulkan_resource_index:
210
lower_vulkan_resource_index(b, intr, ctx);
211
return true;
212
case nir_intrinsic_load_vulkan_descriptor:
213
lower_load_vulkan_descriptor(b, intr);
214
return true;
215
default:
216
return false;
217
}
218
219
}
220
221
static bool
222
panvk_lower_misc_instr(nir_builder *b,
223
nir_instr *instr,
224
void *data)
225
{
226
const struct panvk_lower_misc_ctx *ctx = data;
227
228
switch (instr->type) {
229
case nir_instr_type_tex:
230
return lower_tex(b, nir_instr_as_tex(instr), ctx);
231
case nir_instr_type_intrinsic:
232
return lower_intrinsic(b, nir_instr_as_intrinsic(instr), ctx);
233
default:
234
return false;
235
}
236
}
237
238
static bool
239
panvk_lower_misc(nir_shader *nir, const struct panvk_lower_misc_ctx *ctx)
240
{
241
return nir_shader_instructions_pass(nir, panvk_lower_misc_instr,
242
nir_metadata_block_index |
243
nir_metadata_dominance,
244
(void *)ctx);
245
}
246
247
static void
248
panvk_lower_blend(struct panfrost_device *pdev,
249
nir_shader *nir,
250
struct pan_blend_state *blend_state,
251
bool static_blend_constants)
252
{
253
nir_lower_blend_options options = {
254
.logicop_enable = blend_state->logicop_enable,
255
.logicop_func = blend_state->logicop_func,
256
};
257
258
bool lower_blend = false;
259
for (unsigned rt = 0; rt < blend_state->rt_count; rt++) {
260
if (!panvk_blend_needs_lowering(pdev, blend_state, rt))
261
continue;
262
263
const struct pan_blend_rt_state *rt_state = &blend_state->rts[rt];
264
options.rt[rt].colormask = rt_state->equation.color_mask;
265
options.format[rt] = rt_state->format;
266
if (!rt_state->equation.blend_enable) {
267
static const nir_lower_blend_channel replace = {
268
.func = BLEND_FUNC_ADD,
269
.src_factor = BLEND_FACTOR_ZERO,
270
.invert_src_factor = true,
271
.dst_factor = BLEND_FACTOR_ZERO,
272
.invert_dst_factor = false,
273
};
274
275
options.rt[rt].rgb = replace;
276
options.rt[rt].alpha = replace;
277
} else {
278
options.rt[rt].rgb.func = rt_state->equation.rgb_func;
279
options.rt[rt].rgb.src_factor = rt_state->equation.rgb_src_factor;
280
options.rt[rt].rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor;
281
options.rt[rt].rgb.dst_factor = rt_state->equation.rgb_dst_factor;
282
options.rt[rt].rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor;
283
options.rt[rt].alpha.func = rt_state->equation.alpha_func;
284
options.rt[rt].alpha.src_factor = rt_state->equation.alpha_src_factor;
285
options.rt[rt].alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor;
286
options.rt[rt].alpha.dst_factor = rt_state->equation.alpha_dst_factor;
287
options.rt[rt].alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor;
288
}
289
290
lower_blend = true;
291
}
292
293
/* FIXME: currently untested */
294
assert(!lower_blend);
295
296
if (lower_blend)
297
NIR_PASS_V(nir, nir_lower_blend, options);
298
}
299
300
struct panvk_shader *
301
panvk_shader_create(struct panvk_device *dev,
302
gl_shader_stage stage,
303
const VkPipelineShaderStageCreateInfo *stage_info,
304
const struct panvk_pipeline_layout *layout,
305
unsigned sysval_ubo,
306
struct pan_blend_state *blend_state,
307
bool static_blend_constants,
308
const VkAllocationCallbacks *alloc)
309
{
310
const struct panvk_shader_module *module = panvk_shader_module_from_handle(stage_info->module);
311
struct panfrost_device *pdev = &dev->physical_device->pdev;
312
struct panvk_shader *shader;
313
314
shader = vk_zalloc2(&dev->vk.alloc, alloc, sizeof(*shader), 8,
315
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
316
if (!shader)
317
return NULL;
318
319
util_dynarray_init(&shader->binary, NULL);
320
321
/* translate SPIR-V to NIR */
322
assert(module->code_size % 4 == 0);
323
nir_shader *nir = panvk_spirv_to_nir(module->code,
324
module->code_size,
325
stage, stage_info->pName,
326
stage_info->pSpecializationInfo,
327
pan_shader_get_compiler_options(pdev));
328
if (!nir) {
329
vk_free2(&dev->vk.alloc, alloc, shader);
330
return NULL;
331
}
332
333
if (stage == MESA_SHADER_FRAGMENT)
334
panvk_lower_blend(pdev, nir, blend_state, static_blend_constants);
335
336
/* multi step inlining procedure */
337
NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
338
NIR_PASS_V(nir, nir_lower_returns);
339
NIR_PASS_V(nir, nir_inline_functions);
340
NIR_PASS_V(nir, nir_copy_prop);
341
NIR_PASS_V(nir, nir_opt_deref);
342
foreach_list_typed_safe(nir_function, func, node, &nir->functions) {
343
if (!func->is_entrypoint)
344
exec_node_remove(&func->node);
345
}
346
assert(exec_list_length(&nir->functions) == 1);
347
NIR_PASS_V(nir, nir_lower_variable_initializers, ~nir_var_function_temp);
348
349
/* Split member structs. We do this before lower_io_to_temporaries so that
350
* it doesn't lower system values to temporaries by accident.
351
*/
352
NIR_PASS_V(nir, nir_split_var_copies);
353
NIR_PASS_V(nir, nir_split_per_member_structs);
354
355
NIR_PASS_V(nir, nir_remove_dead_variables,
356
nir_var_shader_in | nir_var_shader_out |
357
nir_var_system_value | nir_var_mem_shared,
358
NULL);
359
360
NIR_PASS_V(nir, nir_lower_io_to_temporaries,
361
nir_shader_get_entrypoint(nir), true, true);
362
363
NIR_PASS_V(nir, nir_lower_indirect_derefs,
364
nir_var_shader_in | nir_var_shader_out,
365
UINT32_MAX);
366
367
NIR_PASS_V(nir, nir_opt_copy_prop_vars);
368
NIR_PASS_V(nir, nir_opt_combine_stores, nir_var_all);
369
370
NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, true, false);
371
NIR_PASS_V(nir, nir_lower_explicit_io,
372
nir_var_mem_ubo | nir_var_mem_ssbo,
373
nir_address_format_32bit_index_offset);
374
375
nir_assign_io_var_locations(nir, nir_var_shader_in, &nir->num_inputs, stage);
376
nir_assign_io_var_locations(nir, nir_var_shader_out, &nir->num_outputs, stage);
377
378
NIR_PASS_V(nir, nir_lower_system_values);
379
NIR_PASS_V(nir, nir_lower_compute_system_values, NULL);
380
381
NIR_PASS_V(nir, nir_lower_var_copies);
382
383
struct panvk_lower_misc_ctx ctx = {
384
.shader = shader,
385
.layout = layout,
386
};
387
NIR_PASS_V(nir, panvk_lower_misc, &ctx);
388
389
nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
390
if (unlikely(dev->physical_device->instance->debug_flags & PANVK_DEBUG_NIR)) {
391
fprintf(stderr, "translated nir:\n");
392
nir_print_shader(nir, stderr);
393
}
394
395
struct panfrost_compile_inputs inputs = {
396
.gpu_id = pdev->gpu_id,
397
.no_ubo_to_push = true,
398
.sysval_ubo = sysval_ubo,
399
};
400
401
pan_shader_compile(pdev, nir, &inputs, &shader->binary, &shader->info);
402
403
/* Patch the descriptor count */
404
shader->info.ubo_count =
405
shader->info.sysvals.sysval_count ? sysval_ubo + 1 : layout->num_ubos;
406
shader->info.sampler_count = layout->num_samplers;
407
shader->info.texture_count = layout->num_textures;
408
409
shader->sysval_ubo = sysval_ubo;
410
411
ralloc_free(nir);
412
413
return shader;
414
}
415
416
void
417
panvk_shader_destroy(struct panvk_device *dev,
418
struct panvk_shader *shader,
419
const VkAllocationCallbacks *alloc)
420
{
421
util_dynarray_fini(&shader->binary);
422
vk_free2(&dev->vk.alloc, alloc, shader);
423
}
424
425
VkResult
426
panvk_CreateShaderModule(VkDevice _device,
427
const VkShaderModuleCreateInfo *pCreateInfo,
428
const VkAllocationCallbacks *pAllocator,
429
VkShaderModule *pShaderModule)
430
{
431
VK_FROM_HANDLE(panvk_device, device, _device);
432
struct panvk_shader_module *module;
433
434
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO);
435
assert(pCreateInfo->flags == 0);
436
assert(pCreateInfo->codeSize % 4 == 0);
437
438
module = vk_object_zalloc(&device->vk, pAllocator,
439
sizeof(*module) + pCreateInfo->codeSize,
440
VK_OBJECT_TYPE_SHADER_MODULE);
441
if (module == NULL)
442
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
443
444
module->code_size = pCreateInfo->codeSize;
445
memcpy(module->code, pCreateInfo->pCode, pCreateInfo->codeSize);
446
447
_mesa_sha1_compute(module->code, module->code_size, module->sha1);
448
449
*pShaderModule = panvk_shader_module_to_handle(module);
450
451
return VK_SUCCESS;
452
}
453
454
void
455
panvk_DestroyShaderModule(VkDevice _device,
456
VkShaderModule _module,
457
const VkAllocationCallbacks *pAllocator)
458
{
459
VK_FROM_HANDLE(panvk_device, device, _device);
460
VK_FROM_HANDLE(panvk_shader_module, module, _module);
461
462
if (!module)
463
return;
464
465
vk_object_free(&device->vk, pAllocator, module);
466
}
467
468