Path: blob/21.2-virgl/src/panfrost/vulkan/panvk_pipeline.c
4560 views
/*1* Copyright © 2021 Collabora Ltd.2*3* Derived from tu_pipeline.c which is:4* Copyright © 2016 Red Hat.5* Copyright © 2016 Bas Nieuwenhuizen6* Copyright © 2015 Intel Corporation7*8* Permission is hereby granted, free of charge, to any person obtaining a9* copy of this software and associated documentation files (the "Software"),10* to deal in the Software without restriction, including without limitation11* the rights to use, copy, modify, merge, publish, distribute, sublicense,12* and/or sell copies of the Software, and to permit persons to whom the13* Software is furnished to do so, subject to the following conditions:14*15* The above copyright notice and this permission notice (including the next16* paragraph) shall be included in all copies or substantial portions of the17* Software.18*19* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR20* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,21* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL22* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER23* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING24* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER25* DEALINGS IN THE SOFTWARE.26*/2728#include "panvk_cs.h"29#include "panvk_private.h"3031#include "pan_bo.h"3233#include "nir/nir.h"34#include "nir/nir_builder.h"35#include "spirv/nir_spirv.h"36#include "util/debug.h"37#include "util/mesa-sha1.h"38#include "util/u_atomic.h"39#include "vk_format.h"40#include "vk_util.h"4142#include "panfrost/util/pan_lower_framebuffer.h"4344#include "panfrost-quirks.h"4546struct panvk_pipeline_builder47{48struct panvk_device *device;49struct panvk_pipeline_cache *cache;50const VkAllocationCallbacks *alloc;51const VkGraphicsPipelineCreateInfo *create_info;52const struct panvk_pipeline_layout *layout;5354struct panvk_shader *shaders[MESA_SHADER_STAGES];55struct {56uint32_t shader_offset;57uint32_t rsd_offset;58uint32_t sysvals_offset;59} stages[MESA_SHADER_STAGES];60uint32_t blend_shader_offsets[MAX_RTS];61uint32_t shader_total_size;62uint32_t static_state_size;63uint32_t vpd_offset;6465bool rasterizer_discard;66/* these states are affectd by rasterizer_discard */67VkSampleCountFlagBits samples;68bool use_depth_stencil_attachment;69uint8_t active_color_attachments;70enum pipe_format color_attachment_formats[MAX_RTS];71};7273static VkResult74panvk_pipeline_builder_create_pipeline(struct panvk_pipeline_builder *builder,75struct panvk_pipeline **out_pipeline)76{77struct panvk_device *dev = builder->device;7879struct panvk_pipeline *pipeline =80vk_object_zalloc(&dev->vk, builder->alloc,81sizeof(*pipeline), VK_OBJECT_TYPE_PIPELINE);82if (!pipeline)83return VK_ERROR_OUT_OF_HOST_MEMORY;8485pipeline->layout = builder->layout;86*out_pipeline = pipeline;87return VK_SUCCESS;88}8990static void91panvk_pipeline_builder_finish(struct panvk_pipeline_builder *builder)92{93for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {94if (!builder->shaders[i])95continue;96panvk_shader_destroy(builder->device, builder->shaders[i], builder->alloc);97}98}99100static bool101panvk_pipeline_static_state(struct panvk_pipeline *pipeline, uint32_t id)102{103return !(pipeline->dynamic_state_mask & (1 << id));104}105106static VkResult107panvk_pipeline_builder_compile_shaders(struct panvk_pipeline_builder *builder,108struct panvk_pipeline *pipeline)109{110const VkPipelineShaderStageCreateInfo *stage_infos[MESA_SHADER_STAGES] = {111NULL112};113for (uint32_t i = 0; i < builder->create_info->stageCount; i++) {114gl_shader_stage stage = vk_to_mesa_shader_stage(builder->create_info->pStages[i].stage);115stage_infos[stage] = &builder->create_info->pStages[i];116}117118/* compile shaders in reverse order */119unsigned sysval_ubo = builder->layout->num_ubos;120121for (gl_shader_stage stage = MESA_SHADER_STAGES - 1;122stage > MESA_SHADER_NONE; stage--) {123const VkPipelineShaderStageCreateInfo *stage_info = stage_infos[stage];124if (!stage_info)125continue;126127struct panvk_shader *shader;128129shader = panvk_shader_create(builder->device, stage, stage_info,130builder->layout, sysval_ubo,131&pipeline->blend.state,132panvk_pipeline_static_state(pipeline,133VK_DYNAMIC_STATE_BLEND_CONSTANTS),134builder->alloc);135if (!shader)136return VK_ERROR_OUT_OF_HOST_MEMORY;137138if (shader->info.sysvals.sysval_count)139sysval_ubo++;140141builder->shaders[stage] = shader;142builder->shader_total_size = ALIGN_POT(builder->shader_total_size, 128);143builder->stages[stage].shader_offset = builder->shader_total_size;144builder->shader_total_size +=145util_dynarray_num_elements(&shader->binary, uint8_t);146}147148return VK_SUCCESS;149}150151static VkResult152panvk_pipeline_builder_upload_shaders(struct panvk_pipeline_builder *builder,153struct panvk_pipeline *pipeline)154{155struct panfrost_bo *bin_bo =156panfrost_bo_create(&builder->device->physical_device->pdev,157builder->shader_total_size, PAN_BO_EXECUTE,158"Shader");159160pipeline->binary_bo = bin_bo;161panfrost_bo_mmap(bin_bo);162163for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {164const struct panvk_shader *shader = builder->shaders[i];165if (!shader)166continue;167168memcpy(pipeline->binary_bo->ptr.cpu + builder->stages[i].shader_offset,169util_dynarray_element(&shader->binary, uint8_t, 0),170util_dynarray_num_elements(&shader->binary, uint8_t));171}172173return VK_SUCCESS;174}175176static bool177panvk_pipeline_static_sysval(struct panvk_pipeline *pipeline,178unsigned id)179{180switch (id) {181case PAN_SYSVAL_VIEWPORT_SCALE:182case PAN_SYSVAL_VIEWPORT_OFFSET:183return panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT);184default:185return false;186}187}188189static void190panvk_pipeline_builder_alloc_static_state_bo(struct panvk_pipeline_builder *builder,191struct panvk_pipeline *pipeline)192{193struct panfrost_device *pdev =194&builder->device->physical_device->pdev;195unsigned bo_size = 0;196197for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {198const struct panvk_shader *shader = builder->shaders[i];199if (!shader)200continue;201202if (pipeline->fs.dynamic_rsd && i == MESA_SHADER_FRAGMENT)203continue;204205bo_size = ALIGN_POT(bo_size, MALI_RENDERER_STATE_ALIGN);206builder->stages[i].rsd_offset = bo_size;207bo_size += MALI_RENDERER_STATE_LENGTH;208if (i == MESA_SHADER_FRAGMENT)209bo_size += MALI_BLEND_LENGTH * pipeline->blend.state.rt_count;210}211212if (panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT) &&213panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR)) {214bo_size = ALIGN_POT(bo_size, MALI_VIEWPORT_ALIGN);215builder->vpd_offset = bo_size;216bo_size += MALI_VIEWPORT_LENGTH;217}218219for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {220const struct panvk_shader *shader = builder->shaders[i];221if (!shader || !shader->info.sysvals.sysval_count)222continue;223224bool static_sysvals = true;225for (unsigned s = 0; s < shader->info.sysvals.sysval_count; s++) {226unsigned id = shader->info.sysvals.sysvals[i];227static_sysvals &= panvk_pipeline_static_sysval(pipeline, id);228switch (PAN_SYSVAL_TYPE(id)) {229case PAN_SYSVAL_VIEWPORT_SCALE:230case PAN_SYSVAL_VIEWPORT_OFFSET:231pipeline->sysvals[i].dirty_mask |= PANVK_DYNAMIC_VIEWPORT;232break;233default:234break;235}236}237238if (!static_sysvals) {239builder->stages[i].sysvals_offset = ~0;240continue;241}242243bo_size = ALIGN_POT(bo_size, 16);244builder->stages[i].sysvals_offset = bo_size;245bo_size += shader->info.sysvals.sysval_count * 16;246}247248if (bo_size) {249pipeline->state_bo =250panfrost_bo_create(pdev, bo_size, 0, "Pipeline descriptors");251panfrost_bo_mmap(pipeline->state_bo);252}253}254255static void256panvk_pipeline_builder_upload_sysval(struct panvk_pipeline_builder *builder,257struct panvk_pipeline *pipeline,258unsigned id, union panvk_sysval_data *data)259{260switch (PAN_SYSVAL_TYPE(id)) {261case PAN_SYSVAL_VIEWPORT_SCALE:262panvk_sysval_upload_viewport_scale(builder->create_info->pViewportState->pViewports,263data);264break;265case PAN_SYSVAL_VIEWPORT_OFFSET:266panvk_sysval_upload_viewport_scale(builder->create_info->pViewportState->pViewports,267data);268break;269default:270unreachable("Invalid static sysval");271}272}273274static void275panvk_pipeline_builder_init_sysvals(struct panvk_pipeline_builder *builder,276struct panvk_pipeline *pipeline,277gl_shader_stage stage)278{279const struct panvk_shader *shader = builder->shaders[stage];280281pipeline->sysvals[stage].ids = shader->info.sysvals;282pipeline->sysvals[stage].ubo_idx = shader->sysval_ubo;283284if (!shader->info.sysvals.sysval_count ||285builder->stages[stage].sysvals_offset == ~0)286return;287288union panvk_sysval_data *static_data =289pipeline->state_bo->ptr.cpu + builder->stages[stage].sysvals_offset;290291pipeline->sysvals[stage].ubo =292pipeline->state_bo->ptr.gpu + builder->stages[stage].sysvals_offset;293294for (unsigned i = 0; i < shader->info.sysvals.sysval_count; i++) {295unsigned id = shader->info.sysvals.sysvals[i];296297panvk_pipeline_builder_upload_sysval(builder,298pipeline,299id, &static_data[i]);300}301}302303static void304panvk_pipeline_builder_init_shaders(struct panvk_pipeline_builder *builder,305struct panvk_pipeline *pipeline)306{307for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {308const struct panvk_shader *shader = builder->shaders[i];309if (!shader)310continue;311312pipeline->tls_size = MAX2(pipeline->tls_size, shader->info.tls_size);313pipeline->wls_size = MAX2(pipeline->tls_size, shader->info.wls_size);314315if (i == MESA_SHADER_VERTEX && shader->info.vs.writes_point_size)316pipeline->ia.writes_point_size = true;317318mali_ptr shader_ptr = pipeline->binary_bo->ptr.gpu +319builder->stages[i].shader_offset;320321void *rsd = pipeline->state_bo->ptr.cpu + builder->stages[i].rsd_offset;322mali_ptr gpu_rsd = pipeline->state_bo->ptr.gpu + builder->stages[i].rsd_offset;323324if (i != MESA_SHADER_FRAGMENT) {325panvk_emit_non_fs_rsd(builder->device, &shader->info, shader_ptr, rsd);326} else if (!pipeline->fs.dynamic_rsd) {327void *bd = rsd + MALI_RENDERER_STATE_LENGTH;328329panvk_emit_base_fs_rsd(builder->device, pipeline, rsd);330for (unsigned rt = 0; rt < MAX2(pipeline->blend.state.rt_count, 1); rt++) {331panvk_emit_blend(builder->device, pipeline, rt, bd);332bd += MALI_BLEND_LENGTH;333}334} else {335gpu_rsd = 0;336panvk_emit_base_fs_rsd(builder->device, pipeline, &pipeline->fs.rsd_template);337for (unsigned rt = 0; rt < MAX2(pipeline->blend.state.rt_count, 1); rt++) {338panvk_emit_blend(builder->device, pipeline, rt,339&pipeline->blend.bd_template[rt]);340}341}342343pipeline->rsds[i] = gpu_rsd;344panvk_pipeline_builder_init_sysvals(builder, pipeline, i);345}346347pipeline->num_ubos = builder->layout->num_ubos;348for (unsigned i = 0; i < ARRAY_SIZE(pipeline->sysvals); i++) {349if (pipeline->sysvals[i].ids.sysval_count)350pipeline->num_ubos = MAX2(pipeline->num_ubos, pipeline->sysvals[i].ubo_idx + 1);351}352353pipeline->num_sysvals = 0;354for (unsigned i = 0; i < ARRAY_SIZE(pipeline->sysvals); i++)355pipeline->num_sysvals += pipeline->sysvals[i].ids.sysval_count;356}357358359static void360panvk_pipeline_builder_parse_viewport(struct panvk_pipeline_builder *builder,361struct panvk_pipeline *pipeline)362{363/* The spec says:364*365* pViewportState is a pointer to an instance of the366* VkPipelineViewportStateCreateInfo structure, and is ignored if the367* pipeline has rasterization disabled.368*/369if (!builder->rasterizer_discard &&370panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT) &&371panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR)) {372void *vpd = pipeline->state_bo->ptr.cpu + builder->vpd_offset;373panvk_emit_viewport(builder->create_info->pViewportState->pViewports,374builder->create_info->pViewportState->pScissors,375vpd);376pipeline->vpd = pipeline->state_bo->ptr.gpu +377builder->vpd_offset;378} else {379if (builder->create_info->pViewportState->pViewports)380pipeline->viewport = builder->create_info->pViewportState->pViewports[0];381382if (builder->create_info->pViewportState->pScissors)383pipeline->scissor = builder->create_info->pViewportState->pScissors[0];384}385}386387static void388panvk_pipeline_builder_parse_dynamic(struct panvk_pipeline_builder *builder,389struct panvk_pipeline *pipeline)390{391const VkPipelineDynamicStateCreateInfo *dynamic_info =392builder->create_info->pDynamicState;393394if (!dynamic_info)395return;396397for (uint32_t i = 0; i < dynamic_info->dynamicStateCount; i++) {398VkDynamicState state = dynamic_info->pDynamicStates[i];399switch (state) {400case VK_DYNAMIC_STATE_VIEWPORT ... VK_DYNAMIC_STATE_STENCIL_REFERENCE:401pipeline->dynamic_state_mask |= 1 << state;402break;403default:404unreachable("unsupported dynamic state");405}406}407408}409410static enum mali_draw_mode411translate_prim_topology(VkPrimitiveTopology in)412{413switch (in) {414case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:415return MALI_DRAW_MODE_POINTS;416case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:417return MALI_DRAW_MODE_LINES;418case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:419return MALI_DRAW_MODE_LINE_STRIP;420case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:421return MALI_DRAW_MODE_TRIANGLES;422case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:423return MALI_DRAW_MODE_TRIANGLE_STRIP;424case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:425return MALI_DRAW_MODE_TRIANGLE_FAN;426case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:427case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:428case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:429case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:430case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:431default:432unreachable("Invalid primitive type");433}434}435436static void437panvk_pipeline_builder_parse_input_assembly(struct panvk_pipeline_builder *builder,438struct panvk_pipeline *pipeline)439{440pipeline->ia.primitive_restart =441builder->create_info->pInputAssemblyState->primitiveRestartEnable;442pipeline->ia.topology =443translate_prim_topology(builder->create_info->pInputAssemblyState->topology);444}445446static enum pipe_logicop447translate_logicop(VkLogicOp in)448{449switch (in) {450case VK_LOGIC_OP_CLEAR: return PIPE_LOGICOP_CLEAR;451case VK_LOGIC_OP_AND: return PIPE_LOGICOP_AND;452case VK_LOGIC_OP_AND_REVERSE: return PIPE_LOGICOP_AND_REVERSE;453case VK_LOGIC_OP_COPY: return PIPE_LOGICOP_COPY;454case VK_LOGIC_OP_AND_INVERTED: return PIPE_LOGICOP_AND_INVERTED;455case VK_LOGIC_OP_NO_OP: return PIPE_LOGICOP_NOOP;456case VK_LOGIC_OP_XOR: return PIPE_LOGICOP_XOR;457case VK_LOGIC_OP_OR: return PIPE_LOGICOP_OR;458case VK_LOGIC_OP_NOR: return PIPE_LOGICOP_NOR;459case VK_LOGIC_OP_EQUIVALENT: return PIPE_LOGICOP_EQUIV;460case VK_LOGIC_OP_INVERT: return PIPE_LOGICOP_INVERT;461case VK_LOGIC_OP_OR_REVERSE: return PIPE_LOGICOP_OR_REVERSE;462case VK_LOGIC_OP_COPY_INVERTED: return PIPE_LOGICOP_COPY_INVERTED;463case VK_LOGIC_OP_OR_INVERTED: return PIPE_LOGICOP_OR_INVERTED;464case VK_LOGIC_OP_NAND: return PIPE_LOGICOP_NAND;465case VK_LOGIC_OP_SET: return PIPE_LOGICOP_SET;466default: unreachable("Invalid logicop");467}468}469470static enum blend_func471translate_blend_op(VkBlendOp in)472{473switch (in) {474case VK_BLEND_OP_ADD: return BLEND_FUNC_ADD;475case VK_BLEND_OP_SUBTRACT: return BLEND_FUNC_SUBTRACT;476case VK_BLEND_OP_REVERSE_SUBTRACT: return BLEND_FUNC_REVERSE_SUBTRACT;477case VK_BLEND_OP_MIN: return BLEND_FUNC_MIN;478case VK_BLEND_OP_MAX: return BLEND_FUNC_MAX;479default: unreachable("Invalid blend op");480}481}482483static enum blend_factor484translate_blend_factor(VkBlendFactor in, bool dest_has_alpha)485{486switch (in) {487case VK_BLEND_FACTOR_ZERO:488case VK_BLEND_FACTOR_ONE:489return BLEND_FACTOR_ZERO;490case VK_BLEND_FACTOR_SRC_COLOR:491case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:492return BLEND_FACTOR_SRC_COLOR;493case VK_BLEND_FACTOR_DST_COLOR:494case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:495return BLEND_FACTOR_DST_COLOR;496case VK_BLEND_FACTOR_SRC_ALPHA:497case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:498return BLEND_FACTOR_SRC_ALPHA;499case VK_BLEND_FACTOR_DST_ALPHA:500case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:501return dest_has_alpha ? BLEND_FACTOR_DST_ALPHA : BLEND_FACTOR_ZERO;502case VK_BLEND_FACTOR_CONSTANT_COLOR:503case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:504return BLEND_FACTOR_CONSTANT_COLOR;505case VK_BLEND_FACTOR_CONSTANT_ALPHA:506case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:507return BLEND_FACTOR_CONSTANT_ALPHA;508case VK_BLEND_FACTOR_SRC1_COLOR:509case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:510return BLEND_FACTOR_SRC1_COLOR;511case VK_BLEND_FACTOR_SRC1_ALPHA:512case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:513return BLEND_FACTOR_SRC1_ALPHA;514case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:515return BLEND_FACTOR_SRC_ALPHA_SATURATE;516default: unreachable("Invalid blend factor");517}518}519520static bool521inverted_blend_factor(VkBlendFactor in, bool dest_has_alpha)522{523switch (in) {524case VK_BLEND_FACTOR_ONE:525case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:526case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:527case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:528case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:529case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:530case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:531case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:532return true;533case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:534return dest_has_alpha ? true : false;535case VK_BLEND_FACTOR_DST_ALPHA:536return !dest_has_alpha ? true : false;537default:538return false;539}540}541542bool543panvk_blend_needs_lowering(const struct panfrost_device *dev,544const struct pan_blend_state *state,545unsigned rt)546{547/* LogicOp requires a blend shader */548if (state->logicop_enable)549return true;550551/* Not all formats can be blended by fixed-function hardware */552if (!panfrost_blendable_formats_v7[state->rts[rt].format].internal)553return true;554555unsigned constant_mask = pan_blend_constant_mask(state->rts[rt].equation);556557/* v6 doesn't support blend constants in FF blend equations.558* v7 only uses the constant from RT 0 (TODO: what if it's the same559* constant? or a constant is shared?)560*/561if (constant_mask && (dev->arch == 6 || (dev->arch == 7 && rt > 0)))562return true;563564if (!pan_blend_is_homogenous_constant(constant_mask, state->constants))565return true;566567return !pan_blend_can_fixed_function(state->rts[rt].equation);568}569570static void571panvk_pipeline_builder_parse_color_blend(struct panvk_pipeline_builder *builder,572struct panvk_pipeline *pipeline)573{574struct panfrost_device *pdev = &builder->device->physical_device->pdev;575pipeline->blend.state.logicop_enable =576builder->create_info->pColorBlendState->logicOpEnable;577pipeline->blend.state.logicop_func =578translate_logicop(builder->create_info->pColorBlendState->logicOp);579pipeline->blend.state.rt_count = util_last_bit(builder->active_color_attachments);580memcpy(pipeline->blend.state.constants,581builder->create_info->pColorBlendState->blendConstants,582sizeof(pipeline->blend.state.constants));583584for (unsigned i = 0; i < pipeline->blend.state.rt_count; i++) {585const VkPipelineColorBlendAttachmentState *in =586&builder->create_info->pColorBlendState->pAttachments[i];587struct pan_blend_rt_state *out = &pipeline->blend.state.rts[i];588589out->format = builder->color_attachment_formats[i];590591bool dest_has_alpha = util_format_has_alpha(out->format);592593out->nr_samples = builder->create_info->pMultisampleState->rasterizationSamples;594out->equation.blend_enable = in->blendEnable;595out->equation.color_mask = in->colorWriteMask;596out->equation.rgb_func = translate_blend_op(in->colorBlendOp);597out->equation.rgb_src_factor = translate_blend_factor(in->srcColorBlendFactor, dest_has_alpha);598out->equation.rgb_invert_src_factor = inverted_blend_factor(in->srcColorBlendFactor, dest_has_alpha);599out->equation.rgb_dst_factor = translate_blend_factor(in->dstColorBlendFactor, dest_has_alpha);600out->equation.rgb_invert_dst_factor = inverted_blend_factor(in->dstColorBlendFactor, dest_has_alpha);601out->equation.alpha_func = translate_blend_op(in->alphaBlendOp);602out->equation.alpha_src_factor = translate_blend_factor(in->srcAlphaBlendFactor, dest_has_alpha);603out->equation.alpha_invert_src_factor = inverted_blend_factor(in->srcAlphaBlendFactor, dest_has_alpha);604out->equation.alpha_dst_factor = translate_blend_factor(in->dstAlphaBlendFactor, dest_has_alpha);605out->equation.alpha_invert_dst_factor = inverted_blend_factor(in->dstAlphaBlendFactor, dest_has_alpha);606607unsigned constant_mask =608panvk_blend_needs_lowering(pdev, &pipeline->blend.state, i) ?6090 : pan_blend_constant_mask(out->equation);610pipeline->blend.constant[i].index = ffs(constant_mask) - 1;611if (constant_mask && pan_is_bifrost(pdev)) {612/* On Bifrost, the blend constant is expressed with a UNORM of the613* size of the target format. The value is then shifted such that614* used bits are in the MSB. Here we calculate the factor at pipeline615* creation time so we only have to do a616* hw_constant = float_constant * factor;617* at descriptor emission time.618*/619const struct util_format_description *format_desc =620util_format_description(out->format);621unsigned chan_size = 0;622for (unsigned c = 0; c < format_desc->nr_channels; c++)623chan_size = MAX2(format_desc->channel[c].size, chan_size);624pipeline->blend.constant[i].bifrost_factor =625((1 << chan_size) - 1) << (16 - chan_size);626}627}628}629630static void631panvk_pipeline_builder_parse_multisample(struct panvk_pipeline_builder *builder,632struct panvk_pipeline *pipeline)633{634unsigned nr_samples =635MAX2(builder->create_info->pMultisampleState->rasterizationSamples, 1);636637pipeline->ms.rast_samples =638builder->create_info->pMultisampleState->rasterizationSamples;639pipeline->ms.sample_mask =640builder->create_info->pMultisampleState->pSampleMask ?641builder->create_info->pMultisampleState->pSampleMask[0] : UINT16_MAX;642pipeline->ms.min_samples =643MAX2(builder->create_info->pMultisampleState->minSampleShading * nr_samples, 1);644}645646static enum mali_stencil_op647translate_stencil_op(VkStencilOp in)648{649switch (in) {650case VK_STENCIL_OP_KEEP: return MALI_STENCIL_OP_KEEP;651case VK_STENCIL_OP_ZERO: return MALI_STENCIL_OP_ZERO;652case VK_STENCIL_OP_REPLACE: return MALI_STENCIL_OP_REPLACE;653case VK_STENCIL_OP_INCREMENT_AND_CLAMP: return MALI_STENCIL_OP_INCR_SAT;654case VK_STENCIL_OP_DECREMENT_AND_CLAMP: return MALI_STENCIL_OP_DECR_SAT;655case VK_STENCIL_OP_INCREMENT_AND_WRAP: return MALI_STENCIL_OP_INCR_WRAP;656case VK_STENCIL_OP_DECREMENT_AND_WRAP: return MALI_STENCIL_OP_DECR_WRAP;657case VK_STENCIL_OP_INVERT: return MALI_STENCIL_OP_INVERT;658default: unreachable("Invalid stencil op");659}660}661662static void663panvk_pipeline_builder_parse_zs(struct panvk_pipeline_builder *builder,664struct panvk_pipeline *pipeline)665{666pipeline->zs.z_test = builder->create_info->pDepthStencilState->depthTestEnable;667pipeline->zs.z_write = builder->create_info->pDepthStencilState->depthWriteEnable;668pipeline->zs.z_compare_func =669panvk_translate_compare_func(builder->create_info->pDepthStencilState->depthCompareOp);670pipeline->zs.s_test = builder->create_info->pDepthStencilState->stencilTestEnable;671pipeline->zs.s_front.fail_op =672translate_stencil_op(builder->create_info->pDepthStencilState->front.failOp);673pipeline->zs.s_front.pass_op =674translate_stencil_op(builder->create_info->pDepthStencilState->front.passOp);675pipeline->zs.s_front.z_fail_op =676translate_stencil_op(builder->create_info->pDepthStencilState->front.depthFailOp);677pipeline->zs.s_front.compare_func =678panvk_translate_compare_func(builder->create_info->pDepthStencilState->front.compareOp);679pipeline->zs.s_front.compare_mask =680builder->create_info->pDepthStencilState->front.compareMask;681pipeline->zs.s_front.write_mask =682builder->create_info->pDepthStencilState->front.writeMask;683pipeline->zs.s_front.ref =684builder->create_info->pDepthStencilState->front.reference;685pipeline->zs.s_back.fail_op =686translate_stencil_op(builder->create_info->pDepthStencilState->back.failOp);687pipeline->zs.s_back.pass_op =688translate_stencil_op(builder->create_info->pDepthStencilState->back.passOp);689pipeline->zs.s_back.z_fail_op =690translate_stencil_op(builder->create_info->pDepthStencilState->back.depthFailOp);691pipeline->zs.s_back.compare_func =692panvk_translate_compare_func(builder->create_info->pDepthStencilState->back.compareOp);693pipeline->zs.s_back.compare_mask =694builder->create_info->pDepthStencilState->back.compareMask;695pipeline->zs.s_back.write_mask =696builder->create_info->pDepthStencilState->back.writeMask;697pipeline->zs.s_back.ref =698builder->create_info->pDepthStencilState->back.reference;699}700701static void702panvk_pipeline_builder_parse_rast(struct panvk_pipeline_builder *builder,703struct panvk_pipeline *pipeline)704{705pipeline->rast.clamp_depth = builder->create_info->pRasterizationState->depthClampEnable;706pipeline->rast.depth_bias.enable = builder->create_info->pRasterizationState->depthBiasEnable;707pipeline->rast.depth_bias.constant_factor =708builder->create_info->pRasterizationState->depthBiasConstantFactor;709pipeline->rast.depth_bias.clamp = builder->create_info->pRasterizationState->depthBiasClamp;710pipeline->rast.depth_bias.slope_factor = builder->create_info->pRasterizationState->depthBiasSlopeFactor;711pipeline->rast.front_ccw = builder->create_info->pRasterizationState->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE;712pipeline->rast.cull_front_face = builder->create_info->pRasterizationState->cullMode & VK_CULL_MODE_FRONT_BIT;713pipeline->rast.cull_back_face = builder->create_info->pRasterizationState->cullMode & VK_CULL_MODE_BACK_BIT;714}715716static bool717panvk_fs_required(struct panvk_pipeline *pipeline)718{719const struct pan_shader_info *info = &pipeline->fs.info;720721/* If we generally have side effects */722if (info->fs.sidefx)723return true;724725/* If colour is written we need to execute */726const struct pan_blend_state *blend = &pipeline->blend.state;727for (unsigned i = 0; i < blend->rt_count; ++i) {728if (blend->rts[i].equation.color_mask)729return true;730}731732/* If depth is written and not implied we need to execute.733* TODO: Predicate on Z/S writes being enabled */734return (info->fs.writes_depth || info->fs.writes_stencil);735}736737#define PANVK_DYNAMIC_FS_RSD_MASK \738((1 << VK_DYNAMIC_STATE_DEPTH_BIAS) | \739(1 << VK_DYNAMIC_STATE_BLEND_CONSTANTS) | \740(1 << VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) | \741(1 << VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) | \742(1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE))743744static void745panvk_pipeline_builder_init_fs_state(struct panvk_pipeline_builder *builder,746struct panvk_pipeline *pipeline)747{748if (!builder->shaders[MESA_SHADER_FRAGMENT])749return;750751pipeline->fs.dynamic_rsd =752pipeline->dynamic_state_mask & PANVK_DYNAMIC_FS_RSD_MASK;753pipeline->fs.address = pipeline->binary_bo->ptr.gpu +754builder->stages[MESA_SHADER_FRAGMENT].shader_offset;755pipeline->fs.info = builder->shaders[MESA_SHADER_FRAGMENT]->info;756pipeline->fs.required = panvk_fs_required(pipeline);757}758759static void760panvk_pipeline_update_varying_slot(struct panvk_varyings_info *varyings,761gl_shader_stage stage,762const struct pan_shader_varying *varying,763bool input)764{765bool fs = stage == MESA_SHADER_FRAGMENT;766gl_varying_slot loc = varying->location;767enum panvk_varying_buf_id buf_id =768panvk_varying_buf_id(fs, loc);769770varyings->stage[stage].loc[varyings->stage[stage].count++] = loc;771772if (panvk_varying_is_builtin(stage, loc)) {773varyings->buf_mask |= 1 << buf_id;774return;775}776777assert(loc < ARRAY_SIZE(varyings->varying));778779enum pipe_format new_fmt = varying->format;780enum pipe_format old_fmt = varyings->varying[loc].format;781782BITSET_SET(varyings->active, loc);783784/* We expect inputs to either be set by a previous stage or be built785* in, skip the entry if that's not the case, we'll emit a const786* varying returning zero for those entries.787*/788if (input && old_fmt == PIPE_FORMAT_NONE)789return;790791unsigned new_size = util_format_get_blocksize(new_fmt);792unsigned old_size = util_format_get_blocksize(old_fmt);793794if (old_size < new_size)795varyings->varying[loc].format = new_fmt;796797varyings->buf_mask |= 1 << buf_id;798}799800static void801panvk_pipeline_builder_collect_varyings(struct panvk_pipeline_builder *builder,802struct panvk_pipeline *pipeline)803{804for (uint32_t s = 0; s < MESA_SHADER_STAGES; s++) {805if (!builder->shaders[s])806continue;807808const struct pan_shader_info *info = &builder->shaders[s]->info;809810for (unsigned i = 0; i < info->varyings.input_count; i++) {811panvk_pipeline_update_varying_slot(&pipeline->varyings, s,812&info->varyings.input[i],813true);814}815816for (unsigned i = 0; i < info->varyings.output_count; i++) {817panvk_pipeline_update_varying_slot(&pipeline->varyings, s,818&info->varyings.output[i],819false);820}821}822823/* TODO: Xfb */824gl_varying_slot loc;825BITSET_FOREACH_SET(loc, pipeline->varyings.active, VARYING_SLOT_MAX) {826enum panvk_varying_buf_id buf_id =827panvk_varying_buf_id(false, loc);828unsigned buf_idx = panvk_varying_buf_index(&pipeline->varyings, buf_id);829unsigned varying_sz = panvk_varying_size(&pipeline->varyings, loc);830831pipeline->varyings.varying[loc].buf = buf_idx;832pipeline->varyings.varying[loc].offset =833pipeline->varyings.buf[buf_idx].stride;834pipeline->varyings.buf[buf_idx].stride += varying_sz;835}836}837838static void839panvk_pipeline_builder_parse_vertex_input(struct panvk_pipeline_builder *builder,840struct panvk_pipeline *pipeline)841{842struct panvk_attribs_info *attribs = &pipeline->attribs;843const VkPipelineVertexInputStateCreateInfo *info =844builder->create_info->pVertexInputState;845846for (unsigned i = 0; i < info->vertexBindingDescriptionCount; i++) {847const VkVertexInputBindingDescription *desc =848&info->pVertexBindingDescriptions[i];849attribs->buf_count = MAX2(desc->binding + 1, attribs->buf_count);850attribs->buf[desc->binding].stride = desc->stride;851attribs->buf[desc->binding].special = false;852}853854for (unsigned i = 0; i < info->vertexAttributeDescriptionCount; i++) {855const VkVertexInputAttributeDescription *desc =856&info->pVertexAttributeDescriptions[i];857attribs->attrib[desc->location].buf = desc->binding;858attribs->attrib[desc->location].format =859vk_format_to_pipe_format(desc->format);860attribs->attrib[desc->location].offset = desc->offset;861}862863const struct pan_shader_info *vs =864&builder->shaders[MESA_SHADER_VERTEX]->info;865866if (vs->attribute_count >= PAN_VERTEX_ID) {867attribs->buf[attribs->buf_count].special = true;868attribs->buf[attribs->buf_count].special_id = PAN_VERTEX_ID;869attribs->attrib[PAN_VERTEX_ID].buf = attribs->buf_count++;870attribs->attrib[PAN_VERTEX_ID].format = PIPE_FORMAT_R32_UINT;871}872873if (vs->attribute_count >= PAN_INSTANCE_ID) {874attribs->buf[attribs->buf_count].special = true;875attribs->buf[attribs->buf_count].special_id = PAN_INSTANCE_ID;876attribs->attrib[PAN_INSTANCE_ID].buf = attribs->buf_count++;877attribs->attrib[PAN_INSTANCE_ID].format = PIPE_FORMAT_R32_UINT;878}879880attribs->attrib_count = MAX2(attribs->attrib_count, vs->attribute_count);881}882883static VkResult884panvk_pipeline_builder_build(struct panvk_pipeline_builder *builder,885struct panvk_pipeline **pipeline)886{887VkResult result = panvk_pipeline_builder_create_pipeline(builder, pipeline);888if (result != VK_SUCCESS)889return result;890891/* TODO: make those functions return a result and handle errors */892panvk_pipeline_builder_parse_dynamic(builder, *pipeline);893panvk_pipeline_builder_parse_color_blend(builder, *pipeline);894panvk_pipeline_builder_compile_shaders(builder, *pipeline);895panvk_pipeline_builder_collect_varyings(builder, *pipeline);896panvk_pipeline_builder_parse_input_assembly(builder, *pipeline);897panvk_pipeline_builder_parse_multisample(builder, *pipeline);898panvk_pipeline_builder_parse_zs(builder, *pipeline);899panvk_pipeline_builder_parse_rast(builder, *pipeline);900panvk_pipeline_builder_parse_vertex_input(builder, *pipeline);901902903panvk_pipeline_builder_upload_shaders(builder, *pipeline);904panvk_pipeline_builder_init_fs_state(builder, *pipeline);905panvk_pipeline_builder_alloc_static_state_bo(builder, *pipeline);906panvk_pipeline_builder_init_shaders(builder, *pipeline);907panvk_pipeline_builder_parse_viewport(builder, *pipeline);908909return VK_SUCCESS;910}911912static void913panvk_pipeline_builder_init_graphics(struct panvk_pipeline_builder *builder,914struct panvk_device *dev,915struct panvk_pipeline_cache *cache,916const VkGraphicsPipelineCreateInfo *create_info,917const VkAllocationCallbacks *alloc)918{919VK_FROM_HANDLE(panvk_pipeline_layout, layout, create_info->layout);920assert(layout);921*builder = (struct panvk_pipeline_builder) {922.device = dev,923.cache = cache,924.layout = layout,925.create_info = create_info,926.alloc = alloc,927};928929builder->rasterizer_discard =930create_info->pRasterizationState->rasterizerDiscardEnable;931932if (builder->rasterizer_discard) {933builder->samples = VK_SAMPLE_COUNT_1_BIT;934} else {935builder->samples = create_info->pMultisampleState->rasterizationSamples;936937const struct panvk_render_pass *pass = panvk_render_pass_from_handle(create_info->renderPass);938const struct panvk_subpass *subpass = &pass->subpasses[create_info->subpass];939940builder->use_depth_stencil_attachment =941subpass->zs_attachment.idx != VK_ATTACHMENT_UNUSED;942943assert(subpass->color_count == create_info->pColorBlendState->attachmentCount);944builder->active_color_attachments = 0;945for (uint32_t i = 0; i < subpass->color_count; i++) {946uint32_t idx = subpass->color_attachments[i].idx;947if (idx == VK_ATTACHMENT_UNUSED)948continue;949950builder->active_color_attachments |= 1 << i;951builder->color_attachment_formats[i] = pass->attachments[idx].format;952}953}954}955956VkResult957panvk_CreateGraphicsPipelines(VkDevice device,958VkPipelineCache pipelineCache,959uint32_t count,960const VkGraphicsPipelineCreateInfo *pCreateInfos,961const VkAllocationCallbacks *pAllocator,962VkPipeline *pPipelines)963{964VK_FROM_HANDLE(panvk_device, dev, device);965VK_FROM_HANDLE(panvk_pipeline_cache, cache, pipelineCache);966967for (uint32_t i = 0; i < count; i++) {968struct panvk_pipeline_builder builder;969panvk_pipeline_builder_init_graphics(&builder, dev, cache,970&pCreateInfos[i], pAllocator);971972struct panvk_pipeline *pipeline;973VkResult result = panvk_pipeline_builder_build(&builder, &pipeline);974panvk_pipeline_builder_finish(&builder);975976if (result != VK_SUCCESS) {977for (uint32_t j = 0; j < i; j++) {978panvk_DestroyPipeline(device, pPipelines[j], pAllocator);979pPipelines[j] = VK_NULL_HANDLE;980}981982return result;983}984985pPipelines[i] = panvk_pipeline_to_handle(pipeline);986}987988return VK_SUCCESS;989}990991VkResult992panvk_CreateComputePipelines(VkDevice _device,993VkPipelineCache pipelineCache,994uint32_t count,995const VkComputePipelineCreateInfo *pCreateInfos,996const VkAllocationCallbacks *pAllocator,997VkPipeline *pPipelines)998{999panvk_stub();1000return VK_SUCCESS;1001}10021003void1004panvk_DestroyPipeline(VkDevice _device,1005VkPipeline _pipeline,1006const VkAllocationCallbacks *pAllocator)1007{1008VK_FROM_HANDLE(panvk_device, device, _device);1009VK_FROM_HANDLE(panvk_pipeline, pipeline, _pipeline);10101011panfrost_bo_unreference(pipeline->binary_bo);1012panfrost_bo_unreference(pipeline->state_bo);1013vk_object_free(&device->vk, pAllocator, pipeline);1014}101510161017