Path: blob/21.2-virgl/src/broadcom/vulkan/v3dvx_pipeline.c
4560 views
/*1* Copyright © 2021 Raspberry Pi2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "v3dv_private.h"24#include "broadcom/common/v3d_macros.h"25#include "broadcom/cle/v3dx_pack.h"26#include "broadcom/compiler/v3d_compiler.h"2728#include "vk_format_info.h"2930static uint8_t31blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants)32{33switch (factor) {34case VK_BLEND_FACTOR_ZERO:35case VK_BLEND_FACTOR_ONE:36case VK_BLEND_FACTOR_SRC_COLOR:37case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:38case VK_BLEND_FACTOR_DST_COLOR:39case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:40case VK_BLEND_FACTOR_SRC_ALPHA:41case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:42case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:43return factor;44case VK_BLEND_FACTOR_CONSTANT_COLOR:45case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:46case VK_BLEND_FACTOR_CONSTANT_ALPHA:47case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:48*needs_constants = true;49return factor;50case VK_BLEND_FACTOR_DST_ALPHA:51return dst_alpha_one ? V3D_BLEND_FACTOR_ONE :52V3D_BLEND_FACTOR_DST_ALPHA;53case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:54return dst_alpha_one ? V3D_BLEND_FACTOR_ZERO :55V3D_BLEND_FACTOR_INV_DST_ALPHA;56case VK_BLEND_FACTOR_SRC1_COLOR:57case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:58case VK_BLEND_FACTOR_SRC1_ALPHA:59case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:60assert(!"Invalid blend factor: dual source blending not supported.");61default:62assert(!"Unknown blend factor.");63}6465/* Should be handled by the switch, added to avoid a "end of non-void66* function" error67*/68unreachable("Unknown blend factor.");69}7071static void72pack_blend(struct v3dv_pipeline *pipeline,73const VkPipelineColorBlendStateCreateInfo *cb_info)74{75/* By default, we are not enabling blending and all color channel writes are76* enabled. Color write enables are independent of whether blending is77* enabled or not.78*79* Vulkan specifies color write masks so that bits set correspond to80* enabled channels. Our hardware does it the other way around.81*/82pipeline->blend.enables = 0;83pipeline->blend.color_write_masks = 0; /* All channels enabled */8485if (!cb_info)86return;8788assert(pipeline->subpass);89if (pipeline->subpass->color_count == 0)90return;9192assert(pipeline->subpass->color_count == cb_info->attachmentCount);9394pipeline->blend.needs_color_constants = false;95uint32_t color_write_masks = 0;96for (uint32_t i = 0; i < pipeline->subpass->color_count; i++) {97const VkPipelineColorBlendAttachmentState *b_state =98&cb_info->pAttachments[i];99100uint32_t attachment_idx =101pipeline->subpass->color_attachments[i].attachment;102if (attachment_idx == VK_ATTACHMENT_UNUSED)103continue;104105color_write_masks |= (~b_state->colorWriteMask & 0xf) << (4 * i);106107if (!b_state->blendEnable)108continue;109110VkAttachmentDescription *desc =111&pipeline->pass->attachments[attachment_idx].desc;112const struct v3dv_format *format = v3dX(get_format)(desc->format);113bool dst_alpha_one = (format->swizzle[3] == PIPE_SWIZZLE_1);114115uint8_t rt_mask = 1 << i;116pipeline->blend.enables |= rt_mask;117118v3dvx_pack(pipeline->blend.cfg[i], BLEND_CFG, config) {119config.render_target_mask = rt_mask;120121config.color_blend_mode = b_state->colorBlendOp;122config.color_blend_dst_factor =123blend_factor(b_state->dstColorBlendFactor, dst_alpha_one,124&pipeline->blend.needs_color_constants);125config.color_blend_src_factor =126blend_factor(b_state->srcColorBlendFactor, dst_alpha_one,127&pipeline->blend.needs_color_constants);128129config.alpha_blend_mode = b_state->alphaBlendOp;130config.alpha_blend_dst_factor =131blend_factor(b_state->dstAlphaBlendFactor, dst_alpha_one,132&pipeline->blend.needs_color_constants);133config.alpha_blend_src_factor =134blend_factor(b_state->srcAlphaBlendFactor, dst_alpha_one,135&pipeline->blend.needs_color_constants);136}137}138139pipeline->blend.color_write_masks = color_write_masks;140}141142/* This requires that pack_blend() had been called before so we can set143* the overall blend enable bit in the CFG_BITS packet.144*/145static void146pack_cfg_bits(struct v3dv_pipeline *pipeline,147const VkPipelineDepthStencilStateCreateInfo *ds_info,148const VkPipelineRasterizationStateCreateInfo *rs_info,149const VkPipelineMultisampleStateCreateInfo *ms_info)150{151assert(sizeof(pipeline->cfg_bits) == cl_packet_length(CFG_BITS));152153pipeline->msaa =154ms_info && ms_info->rasterizationSamples > VK_SAMPLE_COUNT_1_BIT;155156v3dvx_pack(pipeline->cfg_bits, CFG_BITS, config) {157config.enable_forward_facing_primitive =158rs_info ? !(rs_info->cullMode & VK_CULL_MODE_FRONT_BIT) : false;159160config.enable_reverse_facing_primitive =161rs_info ? !(rs_info->cullMode & VK_CULL_MODE_BACK_BIT) : false;162163/* Seems like the hardware is backwards regarding this setting... */164config.clockwise_primitives =165rs_info ? rs_info->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE : false;166167config.enable_depth_offset = rs_info ? rs_info->depthBiasEnable: false;168169/* This is required to pass line rasterization tests in CTS while170* exposing, at least, a minimum of 4-bits of subpixel precision171* (the minimum requirement).172*/173config.line_rasterization = 1; /* perp end caps */174175if (rs_info && rs_info->polygonMode != VK_POLYGON_MODE_FILL) {176config.direct3d_wireframe_triangles_mode = true;177config.direct3d_point_fill_mode =178rs_info->polygonMode == VK_POLYGON_MODE_POINT;179}180181config.rasterizer_oversample_mode = pipeline->msaa ? 1 : 0;182183/* From the Vulkan spec:184*185* "Provoking Vertex:186*187* The vertex in a primitive from which flat shaded attribute188* values are taken. This is generally the “first” vertex in the189* primitive, and depends on the primitive topology."190*191* First vertex is the Direct3D style for provoking vertex. OpenGL uses192* the last vertex by default.193*/194config.direct3d_provoking_vertex = true;195196config.blend_enable = pipeline->blend.enables != 0;197198/* Disable depth/stencil if we don't have a D/S attachment */199bool has_ds_attachment =200pipeline->subpass->ds_attachment.attachment != VK_ATTACHMENT_UNUSED;201202if (ds_info && ds_info->depthTestEnable && has_ds_attachment) {203config.z_updates_enable = ds_info->depthWriteEnable;204config.depth_test_function = ds_info->depthCompareOp;205} else {206config.depth_test_function = VK_COMPARE_OP_ALWAYS;207}208209/* EZ state will be updated at draw time based on bound pipeline state */210config.early_z_updates_enable = false;211config.early_z_enable = false;212213config.stencil_enable =214ds_info ? ds_info->stencilTestEnable && has_ds_attachment: false;215216pipeline->z_updates_enable = config.z_updates_enable;217};218}219220static uint32_t221translate_stencil_op(enum pipe_stencil_op op)222{223switch (op) {224case VK_STENCIL_OP_KEEP:225return V3D_STENCIL_OP_KEEP;226case VK_STENCIL_OP_ZERO:227return V3D_STENCIL_OP_ZERO;228case VK_STENCIL_OP_REPLACE:229return V3D_STENCIL_OP_REPLACE;230case VK_STENCIL_OP_INCREMENT_AND_CLAMP:231return V3D_STENCIL_OP_INCR;232case VK_STENCIL_OP_DECREMENT_AND_CLAMP:233return V3D_STENCIL_OP_DECR;234case VK_STENCIL_OP_INVERT:235return V3D_STENCIL_OP_INVERT;236case VK_STENCIL_OP_INCREMENT_AND_WRAP:237return V3D_STENCIL_OP_INCWRAP;238case VK_STENCIL_OP_DECREMENT_AND_WRAP:239return V3D_STENCIL_OP_DECWRAP;240default:241unreachable("bad stencil op");242}243}244245static void246pack_single_stencil_cfg(struct v3dv_pipeline *pipeline,247uint8_t *stencil_cfg,248bool is_front,249bool is_back,250const VkStencilOpState *stencil_state)251{252/* From the Vulkan spec:253*254* "Reference is an integer reference value that is used in the unsigned255* stencil comparison. The reference value used by stencil comparison256* must be within the range [0,2^s-1] , where s is the number of bits in257* the stencil framebuffer attachment, otherwise the reference value is258* considered undefined."259*260* In our case, 's' is always 8, so we clamp to that to prevent our packing261* functions to assert in debug mode if they see larger values.262*263* If we have dynamic state we need to make sure we set the corresponding264* state bits to 0, since cl_emit_with_prepacked ORs the new value with265* the old.266*/267const uint8_t write_mask =268pipeline->dynamic_state.mask & V3DV_DYNAMIC_STENCIL_WRITE_MASK ?2690 : stencil_state->writeMask & 0xff;270271const uint8_t compare_mask =272pipeline->dynamic_state.mask & V3DV_DYNAMIC_STENCIL_COMPARE_MASK ?2730 : stencil_state->compareMask & 0xff;274275const uint8_t reference =276pipeline->dynamic_state.mask & V3DV_DYNAMIC_STENCIL_COMPARE_MASK ?2770 : stencil_state->reference & 0xff;278279v3dvx_pack(stencil_cfg, STENCIL_CFG, config) {280config.front_config = is_front;281config.back_config = is_back;282config.stencil_write_mask = write_mask;283config.stencil_test_mask = compare_mask;284config.stencil_test_function = stencil_state->compareOp;285config.stencil_pass_op = translate_stencil_op(stencil_state->passOp);286config.depth_test_fail_op = translate_stencil_op(stencil_state->depthFailOp);287config.stencil_test_fail_op = translate_stencil_op(stencil_state->failOp);288config.stencil_ref_value = reference;289}290}291292static void293pack_stencil_cfg(struct v3dv_pipeline *pipeline,294const VkPipelineDepthStencilStateCreateInfo *ds_info)295{296assert(sizeof(pipeline->stencil_cfg) == 2 * cl_packet_length(STENCIL_CFG));297298if (!ds_info || !ds_info->stencilTestEnable)299return;300301if (pipeline->subpass->ds_attachment.attachment == VK_ATTACHMENT_UNUSED)302return;303304const uint32_t dynamic_stencil_states = V3DV_DYNAMIC_STENCIL_COMPARE_MASK |305V3DV_DYNAMIC_STENCIL_WRITE_MASK |306V3DV_DYNAMIC_STENCIL_REFERENCE;307308309/* If front != back or we have dynamic stencil state we can't emit a single310* packet for both faces.311*/312bool needs_front_and_back = false;313if ((pipeline->dynamic_state.mask & dynamic_stencil_states) ||314memcmp(&ds_info->front, &ds_info->back, sizeof(ds_info->front)))315needs_front_and_back = true;316317/* If the front and back configurations are the same we can emit both with318* a single packet.319*/320pipeline->emit_stencil_cfg[0] = true;321if (!needs_front_and_back) {322pack_single_stencil_cfg(pipeline, pipeline->stencil_cfg[0],323true, true, &ds_info->front);324} else {325pipeline->emit_stencil_cfg[1] = true;326pack_single_stencil_cfg(pipeline, pipeline->stencil_cfg[0],327true, false, &ds_info->front);328pack_single_stencil_cfg(pipeline, pipeline->stencil_cfg[1],329false, true, &ds_info->back);330}331}332333void334v3dX(pipeline_pack_state)(struct v3dv_pipeline *pipeline,335const VkPipelineColorBlendStateCreateInfo *cb_info,336const VkPipelineDepthStencilStateCreateInfo *ds_info,337const VkPipelineRasterizationStateCreateInfo *rs_info,338const VkPipelineMultisampleStateCreateInfo *ms_info)339{340pack_blend(pipeline, cb_info);341pack_cfg_bits(pipeline, ds_info, rs_info, ms_info);342pack_stencil_cfg(pipeline, ds_info);343}344345static void346pack_shader_state_record(struct v3dv_pipeline *pipeline)347{348assert(sizeof(pipeline->shader_state_record) ==349cl_packet_length(GL_SHADER_STATE_RECORD));350351struct v3d_fs_prog_data *prog_data_fs =352pipeline->shared_data->variants[BROADCOM_SHADER_FRAGMENT]->prog_data.fs;353354struct v3d_vs_prog_data *prog_data_vs =355pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX]->prog_data.vs;356357struct v3d_vs_prog_data *prog_data_vs_bin =358pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX_BIN]->prog_data.vs;359360361/* Note: we are not packing addresses, as we need the job (see362* cl_pack_emit_reloc). Additionally uniforms can't be filled up at this363* point as they depend on dynamic info that can be set after create the364* pipeline (like viewport), . Would need to be filled later, so we are365* doing a partial prepacking.366*/367v3dvx_pack(pipeline->shader_state_record, GL_SHADER_STATE_RECORD, shader) {368shader.enable_clipping = true;369370if (!pipeline->has_gs) {371shader.point_size_in_shaded_vertex_data =372pipeline->topology == PIPE_PRIM_POINTS;373} else {374struct v3d_gs_prog_data *prog_data_gs =375pipeline->shared_data->variants[BROADCOM_SHADER_GEOMETRY]->prog_data.gs;376shader.point_size_in_shaded_vertex_data = prog_data_gs->writes_psiz;377}378379/* Must be set if the shader modifies Z, discards, or modifies380* the sample mask. For any of these cases, the fragment381* shader needs to write the Z value (even just discards).382*/383shader.fragment_shader_does_z_writes = prog_data_fs->writes_z;384/* Set if the EZ test must be disabled (due to shader side385* effects and the early_z flag not being present in the386* shader).387*/388shader.turn_off_early_z_test = prog_data_fs->disable_ez;389390shader.fragment_shader_uses_real_pixel_centre_w_in_addition_to_centroid_w2 =391prog_data_fs->uses_center_w;392393/* The description for gl_SampleID states that if a fragment shader reads394* it, then we should automatically activate per-sample shading. However,395* the Vulkan spec also states that if a framebuffer has no attachments:396*397* "The subpass continues to use the width, height, and layers of the398* framebuffer to define the dimensions of the rendering area, and the399* rasterizationSamples from each pipeline’s400* VkPipelineMultisampleStateCreateInfo to define the number of401* samples used in rasterization multisample rasterization."402*403* So in this scenario, if the pipeline doesn't enable multiple samples404* but the fragment shader accesses gl_SampleID we would be requested405* to do per-sample shading in single sample rasterization mode, which406* is pointless, so just disable it in that case.407*/408shader.enable_sample_rate_shading =409pipeline->sample_rate_shading ||410(pipeline->msaa && prog_data_fs->force_per_sample_msaa);411412shader.any_shader_reads_hardware_written_primitive_id = false;413414shader.do_scoreboard_wait_on_first_thread_switch =415prog_data_fs->lock_scoreboard_on_first_thrsw;416shader.disable_implicit_point_line_varyings =417!prog_data_fs->uses_implicit_point_line_varyings;418419shader.number_of_varyings_in_fragment_shader =420prog_data_fs->num_inputs;421422shader.coordinate_shader_propagate_nans = true;423shader.vertex_shader_propagate_nans = true;424shader.fragment_shader_propagate_nans = true;425426/* Note: see previous note about adresses */427/* shader.coordinate_shader_code_address */428/* shader.vertex_shader_code_address */429/* shader.fragment_shader_code_address */430431/* FIXME: Use combined input/output size flag in the common case (also432* on v3d, see v3dx_draw).433*/434shader.coordinate_shader_has_separate_input_and_output_vpm_blocks =435prog_data_vs_bin->separate_segments;436shader.vertex_shader_has_separate_input_and_output_vpm_blocks =437prog_data_vs->separate_segments;438439shader.coordinate_shader_input_vpm_segment_size =440prog_data_vs_bin->separate_segments ?441prog_data_vs_bin->vpm_input_size : 1;442shader.vertex_shader_input_vpm_segment_size =443prog_data_vs->separate_segments ?444prog_data_vs->vpm_input_size : 1;445446shader.coordinate_shader_output_vpm_segment_size =447prog_data_vs_bin->vpm_output_size;448shader.vertex_shader_output_vpm_segment_size =449prog_data_vs->vpm_output_size;450451/* Note: see previous note about adresses */452/* shader.coordinate_shader_uniforms_address */453/* shader.vertex_shader_uniforms_address */454/* shader.fragment_shader_uniforms_address */455456shader.min_coord_shader_input_segments_required_in_play =457pipeline->vpm_cfg_bin.As;458shader.min_vertex_shader_input_segments_required_in_play =459pipeline->vpm_cfg.As;460461shader.min_coord_shader_output_segments_required_in_play_in_addition_to_vcm_cache_size =462pipeline->vpm_cfg_bin.Ve;463shader.min_vertex_shader_output_segments_required_in_play_in_addition_to_vcm_cache_size =464pipeline->vpm_cfg.Ve;465466shader.coordinate_shader_4_way_threadable =467prog_data_vs_bin->base.threads == 4;468shader.vertex_shader_4_way_threadable =469prog_data_vs->base.threads == 4;470shader.fragment_shader_4_way_threadable =471prog_data_fs->base.threads == 4;472473shader.coordinate_shader_start_in_final_thread_section =474prog_data_vs_bin->base.single_seg;475shader.vertex_shader_start_in_final_thread_section =476prog_data_vs->base.single_seg;477shader.fragment_shader_start_in_final_thread_section =478prog_data_fs->base.single_seg;479480shader.vertex_id_read_by_coordinate_shader =481prog_data_vs_bin->uses_vid;482shader.base_instance_id_read_by_coordinate_shader =483prog_data_vs_bin->uses_biid;484shader.instance_id_read_by_coordinate_shader =485prog_data_vs_bin->uses_iid;486shader.vertex_id_read_by_vertex_shader =487prog_data_vs->uses_vid;488shader.base_instance_id_read_by_vertex_shader =489prog_data_vs->uses_biid;490shader.instance_id_read_by_vertex_shader =491prog_data_vs->uses_iid;492493/* Note: see previous note about adresses */494/* shader.address_of_default_attribute_values */495}496}497498static void499pack_vcm_cache_size(struct v3dv_pipeline *pipeline)500{501assert(sizeof(pipeline->vcm_cache_size) ==502cl_packet_length(VCM_CACHE_SIZE));503504v3dvx_pack(pipeline->vcm_cache_size, VCM_CACHE_SIZE, vcm) {505vcm.number_of_16_vertex_batches_for_binning = pipeline->vpm_cfg_bin.Vc;506vcm.number_of_16_vertex_batches_for_rendering = pipeline->vpm_cfg.Vc;507}508}509510/* As defined on the GL_SHADER_STATE_ATTRIBUTE_RECORD */511static uint8_t512get_attr_type(const struct util_format_description *desc)513{514uint32_t r_size = desc->channel[0].size;515uint8_t attr_type = ATTRIBUTE_FLOAT;516517switch (desc->channel[0].type) {518case UTIL_FORMAT_TYPE_FLOAT:519if (r_size == 32) {520attr_type = ATTRIBUTE_FLOAT;521} else {522assert(r_size == 16);523attr_type = ATTRIBUTE_HALF_FLOAT;524}525break;526527case UTIL_FORMAT_TYPE_SIGNED:528case UTIL_FORMAT_TYPE_UNSIGNED:529switch (r_size) {530case 32:531attr_type = ATTRIBUTE_INT;532break;533case 16:534attr_type = ATTRIBUTE_SHORT;535break;536case 10:537attr_type = ATTRIBUTE_INT2_10_10_10;538break;539case 8:540attr_type = ATTRIBUTE_BYTE;541break;542default:543fprintf(stderr,544"format %s unsupported\n",545desc->name);546attr_type = ATTRIBUTE_BYTE;547abort();548}549break;550551default:552fprintf(stderr,553"format %s unsupported\n",554desc->name);555abort();556}557558return attr_type;559}560561static void562pack_shader_state_attribute_record(struct v3dv_pipeline *pipeline,563uint32_t index,564const VkVertexInputAttributeDescription *vi_desc)565{566const uint32_t packet_length =567cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD);568569const struct util_format_description *desc =570vk_format_description(vi_desc->format);571572uint32_t binding = vi_desc->binding;573574v3dvx_pack(&pipeline->vertex_attrs[index * packet_length],575GL_SHADER_STATE_ATTRIBUTE_RECORD, attr) {576577/* vec_size == 0 means 4 */578attr.vec_size = desc->nr_channels & 3;579attr.signed_int_type = (desc->channel[0].type ==580UTIL_FORMAT_TYPE_SIGNED);581attr.normalized_int_type = desc->channel[0].normalized;582attr.read_as_int_uint = desc->channel[0].pure_integer;583584attr.instance_divisor = MIN2(pipeline->vb[binding].instance_divisor,5850xffff);586attr.stride = pipeline->vb[binding].stride;587attr.type = get_attr_type(desc);588}589}590591void592v3dX(pipeline_pack_compile_state)(struct v3dv_pipeline *pipeline,593const VkPipelineVertexInputStateCreateInfo *vi_info)594{595pack_shader_state_record(pipeline);596pack_vcm_cache_size(pipeline);597598pipeline->vb_count = vi_info->vertexBindingDescriptionCount;599for (uint32_t i = 0; i < vi_info->vertexBindingDescriptionCount; i++) {600const VkVertexInputBindingDescription *desc =601&vi_info->pVertexBindingDescriptions[i];602603pipeline->vb[desc->binding].stride = desc->stride;604pipeline->vb[desc->binding].instance_divisor = desc->inputRate;605}606607pipeline->va_count = 0;608struct v3d_vs_prog_data *prog_data_vs =609pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX]->prog_data.vs;610611for (uint32_t i = 0; i < vi_info->vertexAttributeDescriptionCount; i++) {612const VkVertexInputAttributeDescription *desc =613&vi_info->pVertexAttributeDescriptions[i];614uint32_t location = desc->location + VERT_ATTRIB_GENERIC0;615616/* We use a custom driver_location_map instead of617* nir_find_variable_with_location because if we were able to get the618* shader variant from the cache, we would not have the nir shader619* available.620*/621uint32_t driver_location =622prog_data_vs->driver_location_map[location];623624if (driver_location != -1) {625assert(driver_location < MAX_VERTEX_ATTRIBS);626pipeline->va[driver_location].offset = desc->offset;627pipeline->va[driver_location].binding = desc->binding;628pipeline->va[driver_location].vk_format = desc->format;629630pack_shader_state_attribute_record(pipeline, driver_location, desc);631632pipeline->va_count++;633}634}635}636637638