Path: blob/21.2-virgl/src/panfrost/vulkan/panvk_shader.c
4560 views
/*1* Copyright © 2021 Collabora Ltd.2*3* Derived from tu_shader.c which is:4* Copyright © 2019 Google LLC5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the "Software"),8* to deal in the Software without restriction, including without limitation9* the rights to use, copy, modify, merge, publish, distribute, sublicense,10* and/or sell copies of the Software, and to permit persons to whom the11* Software is furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice (including the next14* paragraph) shall be included in all copies or substantial portions of the15* Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL20* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING22* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER23* DEALINGS IN THE SOFTWARE.24*/2526#include "panvk_private.h"2728#include "nir_builder.h"29#include "nir_lower_blend.h"30#include "spirv/nir_spirv.h"31#include "util/mesa-sha1.h"3233#include "panfrost-quirks.h"34#include "pan_shader.h"3536static nir_shader *37panvk_spirv_to_nir(const void *code,38size_t codesize,39gl_shader_stage stage,40const char *entry_point_name,41const VkSpecializationInfo *spec_info,42const nir_shader_compiler_options *nir_options)43{44/* TODO these are made-up */45const struct spirv_to_nir_options spirv_options = {46.caps = { false },47.ubo_addr_format = nir_address_format_32bit_index_offset,48.ssbo_addr_format = nir_address_format_32bit_index_offset,49};5051/* convert VkSpecializationInfo */52struct nir_spirv_specialization *spec = NULL;53uint32_t num_spec = 0;54if (spec_info && spec_info->mapEntryCount) {55spec = malloc(sizeof(*spec) * spec_info->mapEntryCount);56if (!spec)57return NULL;5859for (uint32_t i = 0; i < spec_info->mapEntryCount; i++) {60const VkSpecializationMapEntry *entry = &spec_info->pMapEntries[i];61const void *data = spec_info->pData + entry->offset;62assert(data + entry->size <= spec_info->pData + spec_info->dataSize);63spec[i].id = entry->constantID;64switch (entry->size) {65case 8:66spec[i].value.u64 = *(const uint64_t *)data;67break;68case 4:69spec[i].value.u32 = *(const uint32_t *)data;70break;71case 2:72spec[i].value.u16 = *(const uint16_t *)data;73break;74case 1:75spec[i].value.u8 = *(const uint8_t *)data;76break;77default:78assert(!"Invalid spec constant size");79break;80}8182spec[i].defined_on_module = false;83}8485num_spec = spec_info->mapEntryCount;86}8788nir_shader *nir = spirv_to_nir(code, codesize / sizeof(uint32_t), spec,89num_spec, stage, entry_point_name,90&spirv_options, nir_options);9192free(spec);9394assert(nir->info.stage == stage);95nir_validate_shader(nir, "after spirv_to_nir");9697return nir;98}99100struct panvk_lower_misc_ctx {101struct panvk_shader *shader;102const struct panvk_pipeline_layout *layout;103};104105static unsigned106get_fixed_sampler_index(nir_deref_instr *deref,107const struct panvk_lower_misc_ctx *ctx)108{109nir_variable *var = nir_deref_instr_get_variable(deref);110unsigned set = var->data.descriptor_set;111unsigned binding = var->data.binding;112const struct panvk_descriptor_set_binding_layout *bind_layout =113&ctx->layout->sets[set].layout->bindings[binding];114115return bind_layout->sampler_idx + ctx->layout->sets[set].sampler_offset;116}117118static unsigned119get_fixed_texture_index(nir_deref_instr *deref,120const struct panvk_lower_misc_ctx *ctx)121{122nir_variable *var = nir_deref_instr_get_variable(deref);123unsigned set = var->data.descriptor_set;124unsigned binding = var->data.binding;125const struct panvk_descriptor_set_binding_layout *bind_layout =126&ctx->layout->sets[set].layout->bindings[binding];127128return bind_layout->tex_idx + ctx->layout->sets[set].tex_offset;129}130131static bool132lower_tex(nir_builder *b, nir_tex_instr *tex,133const struct panvk_lower_misc_ctx *ctx)134{135bool progress = false;136int sampler_src_idx = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);137138b->cursor = nir_before_instr(&tex->instr);139140if (sampler_src_idx >= 0) {141nir_deref_instr *deref = nir_src_as_deref(tex->src[sampler_src_idx].src);142tex->sampler_index = get_fixed_sampler_index(deref, ctx);143nir_tex_instr_remove_src(tex, sampler_src_idx);144progress = true;145}146147int tex_src_idx = nir_tex_instr_src_index(tex, nir_tex_src_texture_deref);148if (tex_src_idx >= 0) {149nir_deref_instr *deref = nir_src_as_deref(tex->src[tex_src_idx].src);150tex->texture_index = get_fixed_texture_index(deref, ctx);151nir_tex_instr_remove_src(tex, tex_src_idx);152progress = true;153}154155return progress;156}157158static void159lower_vulkan_resource_index(nir_builder *b, nir_intrinsic_instr *intr,160const struct panvk_lower_misc_ctx *ctx)161{162nir_ssa_def *vulkan_idx = intr->src[0].ssa;163164unsigned set = nir_intrinsic_desc_set(intr);165unsigned binding = nir_intrinsic_binding(intr);166struct panvk_descriptor_set_layout *set_layout = ctx->layout->sets[set].layout;167struct panvk_descriptor_set_binding_layout *binding_layout =168&set_layout->bindings[binding];169unsigned base;170171switch (binding_layout->type) {172case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:173case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:174base = binding_layout->ubo_idx + ctx->layout->sets[set].ubo_offset;175break;176case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:177case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:178base = binding_layout->ssbo_idx + ctx->layout->sets[set].ssbo_offset;179break;180default:181unreachable("Invalid descriptor type");182break;183}184185b->cursor = nir_before_instr(&intr->instr);186nir_ssa_def *idx = nir_iadd(b, nir_imm_int(b, base), vulkan_idx);187nir_ssa_def_rewrite_uses(&intr->dest.ssa, idx);188nir_instr_remove(&intr->instr);189}190191static void192lower_load_vulkan_descriptor(nir_builder *b, nir_intrinsic_instr *intrin)193{194/* Loading the descriptor happens as part of the load/store instruction so195* this is a no-op.196*/197b->cursor = nir_before_instr(&intrin->instr);198nir_ssa_def *val = nir_vec2(b, intrin->src[0].ssa, nir_imm_int(b, 0));199nir_ssa_def_rewrite_uses(&intrin->dest.ssa, val);200nir_instr_remove(&intrin->instr);201}202203static bool204lower_intrinsic(nir_builder *b, nir_intrinsic_instr *intr,205const struct panvk_lower_misc_ctx *ctx)206{207switch (intr->intrinsic) {208case nir_intrinsic_vulkan_resource_index:209lower_vulkan_resource_index(b, intr, ctx);210return true;211case nir_intrinsic_load_vulkan_descriptor:212lower_load_vulkan_descriptor(b, intr);213return true;214default:215return false;216}217218}219220static bool221panvk_lower_misc_instr(nir_builder *b,222nir_instr *instr,223void *data)224{225const struct panvk_lower_misc_ctx *ctx = data;226227switch (instr->type) {228case nir_instr_type_tex:229return lower_tex(b, nir_instr_as_tex(instr), ctx);230case nir_instr_type_intrinsic:231return lower_intrinsic(b, nir_instr_as_intrinsic(instr), ctx);232default:233return false;234}235}236237static bool238panvk_lower_misc(nir_shader *nir, const struct panvk_lower_misc_ctx *ctx)239{240return nir_shader_instructions_pass(nir, panvk_lower_misc_instr,241nir_metadata_block_index |242nir_metadata_dominance,243(void *)ctx);244}245246static void247panvk_lower_blend(struct panfrost_device *pdev,248nir_shader *nir,249struct pan_blend_state *blend_state,250bool static_blend_constants)251{252nir_lower_blend_options options = {253.logicop_enable = blend_state->logicop_enable,254.logicop_func = blend_state->logicop_func,255};256257bool lower_blend = false;258for (unsigned rt = 0; rt < blend_state->rt_count; rt++) {259if (!panvk_blend_needs_lowering(pdev, blend_state, rt))260continue;261262const struct pan_blend_rt_state *rt_state = &blend_state->rts[rt];263options.rt[rt].colormask = rt_state->equation.color_mask;264options.format[rt] = rt_state->format;265if (!rt_state->equation.blend_enable) {266static const nir_lower_blend_channel replace = {267.func = BLEND_FUNC_ADD,268.src_factor = BLEND_FACTOR_ZERO,269.invert_src_factor = true,270.dst_factor = BLEND_FACTOR_ZERO,271.invert_dst_factor = false,272};273274options.rt[rt].rgb = replace;275options.rt[rt].alpha = replace;276} else {277options.rt[rt].rgb.func = rt_state->equation.rgb_func;278options.rt[rt].rgb.src_factor = rt_state->equation.rgb_src_factor;279options.rt[rt].rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor;280options.rt[rt].rgb.dst_factor = rt_state->equation.rgb_dst_factor;281options.rt[rt].rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor;282options.rt[rt].alpha.func = rt_state->equation.alpha_func;283options.rt[rt].alpha.src_factor = rt_state->equation.alpha_src_factor;284options.rt[rt].alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor;285options.rt[rt].alpha.dst_factor = rt_state->equation.alpha_dst_factor;286options.rt[rt].alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor;287}288289lower_blend = true;290}291292/* FIXME: currently untested */293assert(!lower_blend);294295if (lower_blend)296NIR_PASS_V(nir, nir_lower_blend, options);297}298299struct panvk_shader *300panvk_shader_create(struct panvk_device *dev,301gl_shader_stage stage,302const VkPipelineShaderStageCreateInfo *stage_info,303const struct panvk_pipeline_layout *layout,304unsigned sysval_ubo,305struct pan_blend_state *blend_state,306bool static_blend_constants,307const VkAllocationCallbacks *alloc)308{309const struct panvk_shader_module *module = panvk_shader_module_from_handle(stage_info->module);310struct panfrost_device *pdev = &dev->physical_device->pdev;311struct panvk_shader *shader;312313shader = vk_zalloc2(&dev->vk.alloc, alloc, sizeof(*shader), 8,314VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);315if (!shader)316return NULL;317318util_dynarray_init(&shader->binary, NULL);319320/* translate SPIR-V to NIR */321assert(module->code_size % 4 == 0);322nir_shader *nir = panvk_spirv_to_nir(module->code,323module->code_size,324stage, stage_info->pName,325stage_info->pSpecializationInfo,326pan_shader_get_compiler_options(pdev));327if (!nir) {328vk_free2(&dev->vk.alloc, alloc, shader);329return NULL;330}331332if (stage == MESA_SHADER_FRAGMENT)333panvk_lower_blend(pdev, nir, blend_state, static_blend_constants);334335/* multi step inlining procedure */336NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);337NIR_PASS_V(nir, nir_lower_returns);338NIR_PASS_V(nir, nir_inline_functions);339NIR_PASS_V(nir, nir_copy_prop);340NIR_PASS_V(nir, nir_opt_deref);341foreach_list_typed_safe(nir_function, func, node, &nir->functions) {342if (!func->is_entrypoint)343exec_node_remove(&func->node);344}345assert(exec_list_length(&nir->functions) == 1);346NIR_PASS_V(nir, nir_lower_variable_initializers, ~nir_var_function_temp);347348/* Split member structs. We do this before lower_io_to_temporaries so that349* it doesn't lower system values to temporaries by accident.350*/351NIR_PASS_V(nir, nir_split_var_copies);352NIR_PASS_V(nir, nir_split_per_member_structs);353354NIR_PASS_V(nir, nir_remove_dead_variables,355nir_var_shader_in | nir_var_shader_out |356nir_var_system_value | nir_var_mem_shared,357NULL);358359NIR_PASS_V(nir, nir_lower_io_to_temporaries,360nir_shader_get_entrypoint(nir), true, true);361362NIR_PASS_V(nir, nir_lower_indirect_derefs,363nir_var_shader_in | nir_var_shader_out,364UINT32_MAX);365366NIR_PASS_V(nir, nir_opt_copy_prop_vars);367NIR_PASS_V(nir, nir_opt_combine_stores, nir_var_all);368369NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, true, false);370NIR_PASS_V(nir, nir_lower_explicit_io,371nir_var_mem_ubo | nir_var_mem_ssbo,372nir_address_format_32bit_index_offset);373374nir_assign_io_var_locations(nir, nir_var_shader_in, &nir->num_inputs, stage);375nir_assign_io_var_locations(nir, nir_var_shader_out, &nir->num_outputs, stage);376377NIR_PASS_V(nir, nir_lower_system_values);378NIR_PASS_V(nir, nir_lower_compute_system_values, NULL);379380NIR_PASS_V(nir, nir_lower_var_copies);381382struct panvk_lower_misc_ctx ctx = {383.shader = shader,384.layout = layout,385};386NIR_PASS_V(nir, panvk_lower_misc, &ctx);387388nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));389if (unlikely(dev->physical_device->instance->debug_flags & PANVK_DEBUG_NIR)) {390fprintf(stderr, "translated nir:\n");391nir_print_shader(nir, stderr);392}393394struct panfrost_compile_inputs inputs = {395.gpu_id = pdev->gpu_id,396.no_ubo_to_push = true,397.sysval_ubo = sysval_ubo,398};399400pan_shader_compile(pdev, nir, &inputs, &shader->binary, &shader->info);401402/* Patch the descriptor count */403shader->info.ubo_count =404shader->info.sysvals.sysval_count ? sysval_ubo + 1 : layout->num_ubos;405shader->info.sampler_count = layout->num_samplers;406shader->info.texture_count = layout->num_textures;407408shader->sysval_ubo = sysval_ubo;409410ralloc_free(nir);411412return shader;413}414415void416panvk_shader_destroy(struct panvk_device *dev,417struct panvk_shader *shader,418const VkAllocationCallbacks *alloc)419{420util_dynarray_fini(&shader->binary);421vk_free2(&dev->vk.alloc, alloc, shader);422}423424VkResult425panvk_CreateShaderModule(VkDevice _device,426const VkShaderModuleCreateInfo *pCreateInfo,427const VkAllocationCallbacks *pAllocator,428VkShaderModule *pShaderModule)429{430VK_FROM_HANDLE(panvk_device, device, _device);431struct panvk_shader_module *module;432433assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO);434assert(pCreateInfo->flags == 0);435assert(pCreateInfo->codeSize % 4 == 0);436437module = vk_object_zalloc(&device->vk, pAllocator,438sizeof(*module) + pCreateInfo->codeSize,439VK_OBJECT_TYPE_SHADER_MODULE);440if (module == NULL)441return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);442443module->code_size = pCreateInfo->codeSize;444memcpy(module->code, pCreateInfo->pCode, pCreateInfo->codeSize);445446_mesa_sha1_compute(module->code, module->code_size, module->sha1);447448*pShaderModule = panvk_shader_module_to_handle(module);449450return VK_SUCCESS;451}452453void454panvk_DestroyShaderModule(VkDevice _device,455VkShaderModule _module,456const VkAllocationCallbacks *pAllocator)457{458VK_FROM_HANDLE(panvk_device, device, _device);459VK_FROM_HANDLE(panvk_shader_module, module, _module);460461if (!module)462return;463464vk_object_free(&device->vk, pAllocator, module);465}466467468