turnip: enable sampleRateShading feature
[mesa.git] / src / freedreno / vulkan / tu_pipeline.c
index c3aaf9f38a51c96bdf0df141ffa2fbbb07bcb47a..ba13e7b4008b746a054cad323b0393d616b96e8b 100644 (file)
@@ -43,6 +43,7 @@ struct tu_pipeline_builder
 {
    struct tu_device *device;
    struct tu_pipeline_cache *cache;
+   struct tu_pipeline_layout *layout;
    const VkAllocationCallbacks *alloc;
    const VkGraphicsPipelineCreateInfo *create_info;
 
@@ -357,8 +358,18 @@ tu6_blend_op(VkBlendOp op)
    }
 }
 
+static unsigned
+tu_shader_nibo(const struct tu_shader *shader)
+{
+   /* Don't use ir3_shader_nibo(), because that would include declared but
+    * unused storage images and SSBOs.
+    */
+   return shader->ssbo_map.num_desc + shader->image_map.num_desc;
+}
+
 static void
-tu6_emit_vs_config(struct tu_cs *cs, const struct ir3_shader_variant *vs)
+tu6_emit_vs_config(struct tu_cs *cs, struct tu_shader *shader,
+                   const struct ir3_shader_variant *vs)
 {
    uint32_t sp_vs_ctrl =
       A6XX_SP_VS_CTRL_REG0_THREADSIZE(FOUR_QUADS) |
@@ -367,9 +378,11 @@ tu6_emit_vs_config(struct tu_cs *cs, const struct ir3_shader_variant *vs)
       A6XX_SP_VS_CTRL_REG0_BRANCHSTACK(vs->branchstack);
    if (vs->need_pixlod)
       sp_vs_ctrl |= A6XX_SP_VS_CTRL_REG0_PIXLODENABLE;
+   if (vs->need_fine_derivatives)
+      sp_vs_ctrl |= A6XX_SP_VS_CTRL_REG0_DIFF_FINE;
 
-   uint32_t sp_vs_config = A6XX_SP_VS_CONFIG_NTEX(vs->num_samp) |
-                           A6XX_SP_VS_CONFIG_NSAMP(vs->num_samp);
+   uint32_t sp_vs_config = A6XX_SP_VS_CONFIG_NTEX(shader->texture_map.num_desc) |
+                           A6XX_SP_VS_CONFIG_NSAMP(shader->sampler_map.num_desc);
    if (vs->instrlen)
       sp_vs_config |= A6XX_SP_VS_CONFIG_ENABLED;
 
@@ -386,7 +399,8 @@ tu6_emit_vs_config(struct tu_cs *cs, const struct ir3_shader_variant *vs)
 }
 
 static void
-tu6_emit_hs_config(struct tu_cs *cs, const struct ir3_shader_variant *hs)
+tu6_emit_hs_config(struct tu_cs *cs, struct tu_shader *shader,
+                   const struct ir3_shader_variant *hs)
 {
    uint32_t sp_hs_config = 0;
    if (hs->instrlen)
@@ -404,7 +418,8 @@ tu6_emit_hs_config(struct tu_cs *cs, const struct ir3_shader_variant *hs)
 }
 
 static void
-tu6_emit_ds_config(struct tu_cs *cs, const struct ir3_shader_variant *ds)
+tu6_emit_ds_config(struct tu_cs *cs, struct tu_shader *shader,
+                   const struct ir3_shader_variant *ds)
 {
    uint32_t sp_ds_config = 0;
    if (ds->instrlen)
@@ -419,7 +434,8 @@ tu6_emit_ds_config(struct tu_cs *cs, const struct ir3_shader_variant *ds)
 }
 
 static void
-tu6_emit_gs_config(struct tu_cs *cs, const struct ir3_shader_variant *gs)
+tu6_emit_gs_config(struct tu_cs *cs, struct tu_shader *shader,
+                   const struct ir3_shader_variant *gs)
 {
    uint32_t sp_gs_config = 0;
    if (gs->instrlen)
@@ -437,21 +453,30 @@ tu6_emit_gs_config(struct tu_cs *cs, const struct ir3_shader_variant *gs)
 }
 
 static void
-tu6_emit_fs_config(struct tu_cs *cs, const struct ir3_shader_variant *fs)
+tu6_emit_fs_config(struct tu_cs *cs, struct tu_shader *shader,
+                   const struct ir3_shader_variant *fs)
 {
    uint32_t sp_fs_ctrl =
       A6XX_SP_FS_CTRL_REG0_THREADSIZE(FOUR_QUADS) | 0x1000000 |
       A6XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(fs->info.max_reg + 1) |
       A6XX_SP_FS_CTRL_REG0_MERGEDREGS |
       A6XX_SP_FS_CTRL_REG0_BRANCHSTACK(fs->branchstack);
-   if (fs->total_in > 0 || fs->frag_coord)
+   if (fs->total_in > 0)
       sp_fs_ctrl |= A6XX_SP_FS_CTRL_REG0_VARYING;
    if (fs->need_pixlod)
       sp_fs_ctrl |= A6XX_SP_FS_CTRL_REG0_PIXLODENABLE;
+   if (fs->need_fine_derivatives)
+      sp_fs_ctrl |= A6XX_SP_FS_CTRL_REG0_DIFF_FINE;
+
+   uint32_t sp_fs_config = 0;
+   unsigned shader_nibo = 0;
+   if (shader) {
+      shader_nibo = tu_shader_nibo(shader);
+      sp_fs_config = A6XX_SP_FS_CONFIG_NTEX(shader->texture_map.num_desc) |
+                     A6XX_SP_FS_CONFIG_NSAMP(shader->sampler_map.num_desc) |
+                     A6XX_SP_FS_CONFIG_NIBO(shader_nibo);
+   }
 
-   uint32_t sp_fs_config = A6XX_SP_FS_CONFIG_NTEX(fs->num_samp) |
-                           A6XX_SP_FS_CONFIG_NSAMP(fs->num_samp) |
-                           A6XX_SP_FS_CONFIG_NIBO(fs->image_mapping.num_ibo);
    if (fs->instrlen)
       sp_fs_config |= A6XX_SP_FS_CONFIG_ENABLED;
 
@@ -473,11 +498,12 @@ tu6_emit_fs_config(struct tu_cs *cs, const struct ir3_shader_variant *fs)
                   A6XX_HLSQ_FS_CNTL_ENABLED);
 
    tu_cs_emit_pkt4(cs, REG_A6XX_SP_IBO_COUNT, 1);
-   tu_cs_emit(cs, fs->image_mapping.num_ibo);
+   tu_cs_emit(cs, shader_nibo);
 }
 
 static void
-tu6_emit_cs_config(struct tu_cs *cs, const struct ir3_shader_variant *v)
+tu6_emit_cs_config(struct tu_cs *cs, const struct tu_shader *shader,
+                   const struct ir3_shader_variant *v)
 {
    tu_cs_emit_pkt4(cs, REG_A6XX_HLSQ_UPDATE_CNTL, 1);
    tu_cs_emit(cs, 0xff);
@@ -489,10 +515,9 @@ tu6_emit_cs_config(struct tu_cs *cs, const struct ir3_shader_variant *v)
 
    tu_cs_emit_pkt4(cs, REG_A6XX_SP_CS_CONFIG, 2);
    tu_cs_emit(cs, A6XX_SP_CS_CONFIG_ENABLED |
-              A6XX_SP_CS_CONFIG_NIBO(v->image_mapping.num_ibo) |
-              A6XX_SP_CS_CONFIG_NTEX(v->num_samp) |
-              A6XX_SP_CS_CONFIG_NSAMP(v->num_samp) |
-              A6XX_SP_CS_CONFIG_NIBO(v->image_mapping.num_ibo));
+              A6XX_SP_CS_CONFIG_NIBO(tu_shader_nibo(shader)) |
+              A6XX_SP_CS_CONFIG_NTEX(shader->texture_map.num_desc) |
+              A6XX_SP_CS_CONFIG_NSAMP(shader->sampler_map.num_desc));
    tu_cs_emit(cs, v->instrlen);
 
    tu_cs_emit_pkt4(cs, REG_A6XX_SP_CS_CTRL_REG0, 1);
@@ -500,7 +525,8 @@ tu6_emit_cs_config(struct tu_cs *cs, const struct ir3_shader_variant *v)
               A6XX_SP_CS_CTRL_REG0_FULLREGFOOTPRINT(v->info.max_reg + 1) |
               A6XX_SP_CS_CTRL_REG0_MERGEDREGS |
               A6XX_SP_CS_CTRL_REG0_BRANCHSTACK(v->branchstack) |
-              COND(v->need_pixlod, A6XX_SP_CS_CTRL_REG0_PIXLODENABLE));
+              COND(v->need_pixlod, A6XX_SP_CS_CTRL_REG0_PIXLODENABLE) |
+              COND(v->need_fine_derivatives, A6XX_SP_CS_CTRL_REG0_DIFF_FINE));
 
    tu_cs_emit_pkt4(cs, REG_A6XX_SP_CS_UNKNOWN_A9B1, 1);
    tu_cs_emit(cs, 0x41);
@@ -519,7 +545,7 @@ tu6_emit_cs_config(struct tu_cs *cs, const struct ir3_shader_variant *v)
    tu_cs_emit(cs, 0x2fc);             /* HLSQ_CS_UNKNOWN_B998 */
 
    tu_cs_emit_pkt4(cs, REG_A6XX_SP_CS_IBO_COUNT, 1);
-   tu_cs_emit(cs, v->image_mapping.num_ibo);
+   tu_cs_emit(cs, tu_shader_nibo(shader));
 }
 
 static void
@@ -740,10 +766,10 @@ tu6_emit_fs_inputs(struct tu_cs *cs, const struct ir3_shader_variant *fs)
    face_regid      = ir3_find_sysval_regid(fs, SYSTEM_VALUE_FRONT_FACE);
    coord_regid     = ir3_find_sysval_regid(fs, SYSTEM_VALUE_FRAG_COORD);
    zwcoord_regid   = VALIDREG(coord_regid) ? coord_regid + 2 : regid(63, 0);
-   ij_pix_regid    = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_PIXEL);
-   ij_samp_regid   = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_SAMPLE);
-   ij_cent_regid   = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_CENTROID);
-   ij_size_regid   = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_SIZE);
+   ij_pix_regid    = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL);
+   ij_samp_regid   = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE);
+   ij_cent_regid   = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID);
+   ij_size_regid   = ir3_find_sysval_regid(fs, SYSTEM_VALUE_BARYCENTRIC_PERSP_SIZE);
 
    if (fs->num_sampler_prefetch > 0) {
       assert(VALIDREG(ij_pix_regid));
@@ -825,6 +851,15 @@ tu6_emit_fs_inputs(struct tu_cs *cs, const struct ir3_shader_variant *fs)
          CONDREG(samp_id_regid, A6XX_RB_RENDER_CONTROL1_SAMPLEID) |
          CONDREG(ij_size_regid, A6XX_RB_RENDER_CONTROL1_SIZE) |
          COND(fs->frag_face, A6XX_RB_RENDER_CONTROL1_FACENESS));
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_SAMPLE_CNTL, 1);
+   tu_cs_emit(cs, COND(sample_shading, A6XX_RB_SAMPLE_CNTL_PER_SAMP_MODE));
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_UNKNOWN_8101, 1);
+   tu_cs_emit(cs, COND(sample_shading, 0x6));  // XXX
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SAMPLE_CNTL, 1);
+   tu_cs_emit(cs, COND(sample_shading, A6XX_GRAS_SAMPLE_CNTL_PER_SAMP_MODE));
 }
 
 static void
@@ -868,7 +903,7 @@ tu6_emit_fs_outputs(struct tu_cs *cs,
 
    uint32_t gras_su_depth_plane_cntl = 0;
    uint32_t rb_depth_plane_cntl = 0;
-   if (fs->no_earlyz | fs->writes_pos) {
+   if (fs->no_earlyz || fs->writes_pos) {
       gras_su_depth_plane_cntl |= A6XX_GRAS_SU_DEPTH_PLANE_CNTL_FRAG_WRITES_Z;
       rb_depth_plane_cntl |= A6XX_RB_DEPTH_PLANE_CNTL_FRAG_WRITES_Z;
    }
@@ -1037,11 +1072,11 @@ tu6_emit_program(struct tu_cs *cs,
       fs = &dummy_variant;
    }
 
-   tu6_emit_vs_config(cs, vs);
-   tu6_emit_hs_config(cs, hs);
-   tu6_emit_ds_config(cs, ds);
-   tu6_emit_gs_config(cs, gs);
-   tu6_emit_fs_config(cs, fs);
+   tu6_emit_vs_config(cs, builder->shaders[MESA_SHADER_VERTEX], vs);
+   tu6_emit_hs_config(cs, builder->shaders[MESA_SHADER_TESS_CTRL], hs);
+   tu6_emit_ds_config(cs, builder->shaders[MESA_SHADER_TESS_EVAL], ds);
+   tu6_emit_gs_config(cs, builder->shaders[MESA_SHADER_GEOMETRY], gs);
+   tu6_emit_fs_config(cs, builder->shaders[MESA_SHADER_FRAGMENT], fs);
 
    tu6_emit_vs_system_values(cs, vs);
    tu6_emit_vpc(cs, vs, fs, binning_pass);
@@ -1165,12 +1200,12 @@ tu6_emit_viewport(struct tu_cs *cs, const VkViewport *viewport)
    guardband_adj.height = tu6_guardband_adj(max.y - min.y);
 
    tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_CL_VPORT_XOFFSET_0, 6);
-   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_XOFFSET_0(offsets[0]));
-   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_XSCALE_0(scales[0]));
-   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_YOFFSET_0(offsets[1]));
-   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_YSCALE_0(scales[1]));
-   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_ZOFFSET_0(offsets[2]));
-   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_ZSCALE_0(scales[2]));
+   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_XOFFSET_0(offsets[0]).value);
+   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_XSCALE_0(scales[0]).value);
+   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_YOFFSET_0(offsets[1]).value);
+   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_YSCALE_0(scales[1]).value);
+   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_ZOFFSET_0(offsets[2]).value);
+   tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_ZSCALE_0(scales[2]).value);
 
    tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0, 2);
    tu_cs_emit(cs, A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X(min.x) |
@@ -1203,8 +1238,8 @@ tu6_emit_scissor(struct tu_cs *cs, const VkRect2D *scissor)
 static void
 tu6_emit_gras_unknowns(struct tu_cs *cs)
 {
-   tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_UNKNOWN_8000, 1);
-   tu_cs_emit(cs, 0x80);
+   tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_DISABLE_CNTL, 1);
+   tu_cs_emit(cs, A6XX_GRAS_DISABLE_CNTL_VP_CLIP_CODE_IGNORE);
    tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_UNKNOWN_8001, 1);
    tu_cs_emit(cs, 0x0);
    tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_LAYER_CNTL, 1);
@@ -1217,7 +1252,7 @@ tu6_emit_point_size(struct tu_cs *cs)
    tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SU_POINT_MINMAX, 2);
    tu_cs_emit(cs, A6XX_GRAS_SU_POINT_MINMAX_MIN(1.0f / 16.0f) |
                      A6XX_GRAS_SU_POINT_MINMAX_MAX(4092.0f));
-   tu_cs_emit(cs, A6XX_GRAS_SU_POINT_SIZE(1.0f));
+   tu_cs_emit(cs, A6XX_GRAS_SU_POINT_SIZE(1.0f).value);
 }
 
 static uint32_t
@@ -1264,9 +1299,9 @@ tu6_emit_depth_bias(struct tu_cs *cs,
                     float slope_factor)
 {
    tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SU_POLY_OFFSET_SCALE, 3);
-   tu_cs_emit(cs, A6XX_GRAS_SU_POLY_OFFSET_SCALE(slope_factor));
-   tu_cs_emit(cs, A6XX_GRAS_SU_POLY_OFFSET_OFFSET(constant_factor));
-   tu_cs_emit(cs, A6XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP(clamp));
+   tu_cs_emit(cs, A6XX_GRAS_SU_POLY_OFFSET_SCALE(slope_factor).value);
+   tu_cs_emit(cs, A6XX_GRAS_SU_POLY_OFFSET_OFFSET(constant_factor).value);
+   tu_cs_emit(cs, A6XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP(clamp).value);
 }
 
 static void
@@ -1452,7 +1487,6 @@ tu6_emit_blend_control(struct tu_cs *cs,
                        uint32_t blend_enable_mask,
                        const VkPipelineMultisampleStateCreateInfo *msaa_info)
 {
-   assert(!msaa_info->sampleShadingEnable);
    assert(!msaa_info->alphaToOneEnable);
 
    uint32_t sp_blend_cntl = A6XX_SP_BLEND_CNTL_UNK8;
@@ -1498,10 +1532,10 @@ tu_pipeline_create(struct tu_device *dev,
    if (!pipeline)
       return VK_ERROR_OUT_OF_HOST_MEMORY;
 
-   tu_cs_init(&pipeline->cs, TU_CS_MODE_SUB_STREAM, 2048);
+   tu_cs_init(&pipeline->cs, dev, TU_CS_MODE_SUB_STREAM, 2048);
 
    /* reserve the space now such that tu_cs_begin_sub_stream never fails */
-   VkResult result = tu_cs_reserve_space(dev, &pipeline->cs, 2048);
+   VkResult result = tu_cs_reserve_space(&pipeline->cs, 2048);
    if (result != VK_SUCCESS) {
       vk_free2(&dev->alloc, pAllocator, pipeline);
       return result;
@@ -1536,7 +1570,8 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder)
          continue;
 
       struct tu_shader *shader =
-         tu_shader_create(builder->device, stage, stage_info, builder->alloc);
+         tu_shader_create(builder->device, stage, stage_info, builder->layout,
+                          builder->alloc);
       if (!shader)
          return VK_ERROR_OUT_OF_HOST_MEMORY;
 
@@ -1613,16 +1648,31 @@ tu_pipeline_builder_parse_dynamic(struct tu_pipeline_builder *builder,
    }
 }
 
+static void
+tu_pipeline_set_linkage(struct tu_program_descriptor_linkage *link,
+                        struct tu_shader *shader,
+                        struct ir3_shader_variant *v)
+{
+   link->ubo_state = v->shader->ubo_state;
+   link->const_state = v->shader->const_state;
+   link->constlen = v->constlen;
+   link->texture_map = shader->texture_map;
+   link->sampler_map = shader->sampler_map;
+   link->ubo_map = shader->ubo_map;
+   link->ssbo_map = shader->ssbo_map;
+   link->image_map = shader->image_map;
+}
+
 static void
 tu_pipeline_builder_parse_shader_stages(struct tu_pipeline_builder *builder,
                                         struct tu_pipeline *pipeline)
 {
    struct tu_cs prog_cs;
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, 512, &prog_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, 512, &prog_cs);
    tu6_emit_program(&prog_cs, builder, &pipeline->program.binary_bo, false);
    pipeline->program.state_ib = tu_cs_end_sub_stream(&pipeline->cs, &prog_cs);
 
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, 512, &prog_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, 512, &prog_cs);
    tu6_emit_program(&prog_cs, builder, &pipeline->program.binary_bo, true);
    pipeline->program.binning_state_ib =
       tu_cs_end_sub_stream(&pipeline->cs, &prog_cs);
@@ -1631,17 +1681,9 @@ tu_pipeline_builder_parse_shader_stages(struct tu_pipeline_builder *builder,
       if (!builder->shaders[i])
          continue;
 
-      struct tu_program_descriptor_linkage *link = &pipeline->program.link[i];
-      struct ir3_shader *shader = builder->shaders[i]->variants[0].shader;
-
-      link->ubo_state = shader->ubo_state;
-      link->const_state = shader->const_state;
-      link->constlen = builder->shaders[i]->variants[0].constlen;
-      link->texture_map = builder->shaders[i]->texture_map;
-      link->sampler_map = builder->shaders[i]->sampler_map;
-      link->ubo_map = builder->shaders[i]->ubo_map;
-      link->ssbo_map = builder->shaders[i]->ssbo_map;
-      link->image_mapping =  builder->shaders[i]->variants[0].image_mapping;
+      tu_pipeline_set_linkage(&pipeline->program.link[i],
+                              builder->shaders[i],
+                              &builder->shaders[i]->variants[0]);
    }
 }
 
@@ -1654,7 +1696,7 @@ tu_pipeline_builder_parse_vertex_input(struct tu_pipeline_builder *builder,
    const struct tu_shader *vs = builder->shaders[MESA_SHADER_VERTEX];
 
    struct tu_cs vi_cs;
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs,
+   tu_cs_begin_sub_stream(&pipeline->cs,
                           MAX_VERTEX_ATTRIBS * 5 + 2, &vi_cs);
    tu6_emit_vertex_input(&vi_cs, &vs->variants[0], vi_info,
                          pipeline->vi.bindings, pipeline->vi.strides,
@@ -1662,7 +1704,7 @@ tu_pipeline_builder_parse_vertex_input(struct tu_pipeline_builder *builder,
    pipeline->vi.state_ib = tu_cs_end_sub_stream(&pipeline->cs, &vi_cs);
 
    if (vs->has_binning_pass) {
-      tu_cs_begin_sub_stream(builder->device, &pipeline->cs,
+      tu_cs_begin_sub_stream(&pipeline->cs,
                              MAX_VERTEX_ATTRIBS * 5 + 2, &vi_cs);
       tu6_emit_vertex_input(
          &vi_cs, &vs->variants[1], vi_info, pipeline->vi.binning_bindings,
@@ -1703,7 +1745,7 @@ tu_pipeline_builder_parse_viewport(struct tu_pipeline_builder *builder,
       builder->create_info->pViewportState;
 
    struct tu_cs vp_cs;
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, 15, &vp_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, 15, &vp_cs);
 
    if (!(pipeline->dynamic_state.mask & TU_DYNAMIC_VIEWPORT)) {
       assert(vp_info->viewportCount == 1);
@@ -1729,7 +1771,7 @@ tu_pipeline_builder_parse_rasterization(struct tu_pipeline_builder *builder,
    assert(rast_info->polygonMode == VK_POLYGON_MODE_FILL);
 
    struct tu_cs rast_cs;
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, 20, &rast_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, 20, &rast_cs);
 
    /* move to hw ctx init? */
    tu6_emit_gras_unknowns(&rast_cs);
@@ -1773,7 +1815,7 @@ tu_pipeline_builder_parse_depth_stencil(struct tu_pipeline_builder *builder,
          : &dummy_ds_info;
 
    struct tu_cs ds_cs;
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, 12, &ds_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, 12, &ds_cs);
 
    /* move to hw ctx init? */
    tu6_emit_alpha_control_disable(&ds_cs);
@@ -1828,8 +1870,7 @@ tu_pipeline_builder_parse_multisample_and_color_blend(
                                      : &dummy_blend_info;
 
    struct tu_cs blend_cs;
-   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, MAX_RTS * 3 + 9,
-                          &blend_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, MAX_RTS * 3 + 9, &blend_cs);
 
    uint32_t blend_enable_mask;
    tu6_emit_rb_mrt_controls(&blend_cs, blend_info,
@@ -1849,7 +1890,7 @@ tu_pipeline_finish(struct tu_pipeline *pipeline,
                    struct tu_device *dev,
                    const VkAllocationCallbacks *alloc)
 {
-   tu_cs_finish(dev, &pipeline->cs);
+   tu_cs_finish(&pipeline->cs);
 
    if (pipeline->program.binary_bo.gem_handle)
       tu_bo_finish(dev, &pipeline->program.binary_bo);
@@ -1911,11 +1952,14 @@ tu_pipeline_builder_init_graphics(
    const VkGraphicsPipelineCreateInfo *create_info,
    const VkAllocationCallbacks *alloc)
 {
+   TU_FROM_HANDLE(tu_pipeline_layout, layout, create_info->layout);
+
    *builder = (struct tu_pipeline_builder) {
       .device = dev,
       .cache = cache,
       .create_info = create_info,
       .alloc = alloc,
+      .layout = layout,
    };
 
    builder->rasterizer_discard =
@@ -1970,7 +2014,7 @@ tu_graphics_pipeline_create(VkDevice device,
    if (result == VK_SUCCESS)
       *pPipeline = tu_pipeline_to_handle(pipeline);
    else
-      *pPipeline = NULL;
+      *pPipeline = VK_NULL_HANDLE;
 
    return result;
 }
@@ -2004,7 +2048,7 @@ tu6_emit_compute_program(struct tu_cs *cs,
 {
    const struct ir3_shader_variant *v = &shader->variants[0];
 
-   tu6_emit_cs_config(cs, v);
+   tu6_emit_cs_config(cs, shader, v);
 
    /* The compute program is the only one in the pipeline, so 0 offset. */
    tu6_emit_shader_object(cs, MESA_SHADER_COMPUTE, v, binary_bo, 0);
@@ -2045,20 +2089,25 @@ tu_compute_pipeline_create(VkDevice device,
                            VkPipeline *pPipeline)
 {
    TU_FROM_HANDLE(tu_device, dev, device);
+   TU_FROM_HANDLE(tu_pipeline_layout, layout, pCreateInfo->layout);
    const VkPipelineShaderStageCreateInfo *stage_info = &pCreateInfo->stage;
    VkResult result;
 
    struct tu_pipeline *pipeline;
 
+   *pPipeline = VK_NULL_HANDLE;
+
    result = tu_pipeline_create(dev, pAllocator, &pipeline);
    if (result != VK_SUCCESS)
       return result;
 
+   pipeline->layout = layout;
+
    struct tu_shader_compile_options options;
    tu_shader_compile_options_init(&options, NULL);
 
    struct tu_shader *shader =
-      tu_shader_create(dev, MESA_SHADER_COMPUTE, stage_info, pAllocator);
+      tu_shader_create(dev, MESA_SHADER_COMPUTE, stage_info, layout, pAllocator);
    if (!shader) {
       result = VK_ERROR_OUT_OF_HOST_MEMORY;
       goto fail;
@@ -2066,29 +2115,22 @@ tu_compute_pipeline_create(VkDevice device,
 
    result = tu_shader_compile(dev, shader, NULL, &options, pAllocator);
    if (result != VK_SUCCESS)
-      return result;
+      goto fail;
 
-   struct tu_program_descriptor_linkage *link = &pipeline->program.link[MESA_SHADER_COMPUTE];
    struct ir3_shader_variant *v = &shader->variants[0];
 
-   link->ubo_state = v->shader->ubo_state;
-   link->const_state = v->shader->const_state;
-   link->constlen = v->constlen;
-   link->texture_map = shader->texture_map;
-   link->sampler_map = shader->sampler_map;
-   link->ubo_map = shader->ubo_map;
-   link->ssbo_map = shader->ssbo_map;
-   link->image_mapping =  v->image_mapping;
+   tu_pipeline_set_linkage(&pipeline->program.link[MESA_SHADER_COMPUTE],
+                           shader, v);
 
    result = tu_compute_upload_shader(device, pipeline, shader);
    if (result != VK_SUCCESS)
-      return result;
+      goto fail;
 
    for (int i = 0; i < 3; i++)
       pipeline->compute.local_size[i] = v->shader->nir->info.cs.local_size[i];
 
    struct tu_cs prog_cs;
-   tu_cs_begin_sub_stream(dev, &pipeline->cs, 512, &prog_cs);
+   tu_cs_begin_sub_stream(&pipeline->cs, 512, &prog_cs);
    tu6_emit_compute_program(&prog_cs, shader, &pipeline->program.binary_bo);
    pipeline->program.state_ib = tu_cs_end_sub_stream(&pipeline->cs, &prog_cs);
 
@@ -2096,11 +2138,11 @@ tu_compute_pipeline_create(VkDevice device,
    return VK_SUCCESS;
 
 fail:
-   tu_shader_destroy(dev, shader, pAllocator);
-   if (result != VK_SUCCESS) {
-      tu_pipeline_finish(pipeline, dev, pAllocator);
-      vk_free2(&dev->alloc, pAllocator, pipeline);
-   }
+   if (shader)
+      tu_shader_destroy(dev, shader, pAllocator);
+
+   tu_pipeline_finish(pipeline, dev, pAllocator);
+   vk_free2(&dev->alloc, pAllocator, pipeline);
 
    return result;
 }