1 #include "zink_compiler.h"
2 #include "zink_context.h"
3 #include "zink_program.h"
4 #include "zink_resource.h"
5 #include "zink_screen.h"
6 #include "zink_state.h"
8 #include "indices/u_primconvert.h"
9 #include "util/hash_table.h"
10 #include "util/u_debug.h"
11 #include "util/u_helpers.h"
12 #include "util/u_inlines.h"
13 #include "util/u_prim.h"
15 static VkDescriptorSet
16 allocate_descriptor_set(struct zink_screen
*screen
,
17 struct zink_batch
*batch
,
18 struct zink_gfx_program
*prog
)
20 assert(batch
->descs_left
>= prog
->num_descriptors
);
21 VkDescriptorSetAllocateInfo dsai
;
22 memset((void *)&dsai
, 0, sizeof(dsai
));
23 dsai
.sType
= VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
;
25 dsai
.descriptorPool
= batch
->descpool
;
26 dsai
.descriptorSetCount
= 1;
27 dsai
.pSetLayouts
= &prog
->dsl
;
29 VkDescriptorSet desc_set
;
30 if (vkAllocateDescriptorSets(screen
->dev
, &dsai
, &desc_set
) != VK_SUCCESS
) {
31 debug_printf("ZINK: failed to allocate descriptor set :/");
32 return VK_NULL_HANDLE
;
35 batch
->descs_left
-= prog
->num_descriptors
;
40 zink_emit_xfb_counter_barrier(struct zink_context
*ctx
)
42 /* Between the pause and resume there needs to be a memory barrier for the counter buffers
43 * with a source access of VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT
44 * at pipeline stage VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT
45 * to a destination access of VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
46 * at pipeline stage VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT.
48 * - from VK_EXT_transform_feedback spec
50 VkBufferMemoryBarrier barriers
[PIPE_MAX_SO_OUTPUTS
] = {};
51 unsigned barrier_count
= 0;
53 for (unsigned i
= 0; i
< ctx
->num_so_targets
; i
++) {
54 struct zink_so_target
*t
= zink_so_target(ctx
->so_targets
[i
]);
55 if (t
->counter_buffer_valid
) {
56 barriers
[i
].sType
= VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER
;
57 barriers
[i
].srcAccessMask
= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT
;
58 barriers
[i
].dstAccessMask
= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
;
59 barriers
[i
].buffer
= zink_resource(t
->counter_buffer
)->buffer
;
60 barriers
[i
].size
= VK_WHOLE_SIZE
;
64 struct zink_batch
*batch
= zink_batch_no_rp(ctx
);
65 vkCmdPipelineBarrier(batch
->cmdbuf
,
66 VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT
,
67 VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
,
70 barrier_count
, barriers
,
73 ctx
->xfb_barrier
= false;
77 zink_emit_xfb_vertex_input_barrier(struct zink_context
*ctx
, struct zink_resource
*res
)
79 /* A pipeline barrier is required between using the buffers as
80 * transform feedback buffers and vertex buffers to
81 * ensure all writes to the transform feedback buffers are visible
82 * when the data is read as vertex attributes.
83 * The source access is VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT
84 * and the destination access is VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
85 * for the pipeline stages VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT
86 * and VK_PIPELINE_STAGE_VERTEX_INPUT_BIT respectively.
88 * - 20.3.1. Drawing Transform Feedback
90 VkBufferMemoryBarrier barriers
[1] = {};
91 barriers
[0].sType
= VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER
;
92 barriers
[0].srcAccessMask
= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT
;
93 barriers
[0].dstAccessMask
= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
;
94 barriers
[0].buffer
= res
->buffer
;
95 barriers
[0].size
= VK_WHOLE_SIZE
;
96 struct zink_batch
*batch
= zink_batch_no_rp(ctx
);
97 zink_batch_reference_resoure(batch
, res
);
98 vkCmdPipelineBarrier(batch
->cmdbuf
,
99 VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT
,
100 VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
,
103 ARRAY_SIZE(barriers
), barriers
,
106 res
->needs_xfb_barrier
= false;
110 zink_emit_stream_output_targets(struct pipe_context
*pctx
)
112 struct zink_context
*ctx
= zink_context(pctx
);
113 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
114 struct zink_batch
*batch
= zink_curr_batch(ctx
);
115 VkBuffer buffers
[PIPE_MAX_SO_OUTPUTS
];
116 VkDeviceSize buffer_offsets
[PIPE_MAX_SO_OUTPUTS
];
117 VkDeviceSize buffer_sizes
[PIPE_MAX_SO_OUTPUTS
];
119 for (unsigned i
= 0; i
< ctx
->num_so_targets
; i
++) {
120 struct zink_so_target
*t
= (struct zink_so_target
*)ctx
->so_targets
[i
];
121 buffers
[i
] = zink_resource(t
->base
.buffer
)->buffer
;
122 zink_batch_reference_resoure(batch
, zink_resource(t
->base
.buffer
));
123 buffer_offsets
[i
] = t
->base
.buffer_offset
;
124 buffer_sizes
[i
] = t
->base
.buffer_size
;
127 screen
->vk_CmdBindTransformFeedbackBuffersEXT(batch
->cmdbuf
, 0, ctx
->num_so_targets
,
128 buffers
, buffer_offsets
,
130 ctx
->dirty_so_targets
= false;
134 zink_bind_vertex_buffers(struct zink_batch
*batch
, struct zink_context
*ctx
)
136 VkBuffer buffers
[PIPE_MAX_ATTRIBS
];
137 VkDeviceSize buffer_offsets
[PIPE_MAX_ATTRIBS
];
138 const struct zink_vertex_elements_state
*elems
= ctx
->element_state
;
139 for (unsigned i
= 0; i
< elems
->hw_state
.num_bindings
; i
++) {
140 struct pipe_vertex_buffer
*vb
= ctx
->buffers
+ ctx
->element_state
->binding_map
[i
];
142 if (vb
->buffer
.resource
) {
143 struct zink_resource
*res
= zink_resource(vb
->buffer
.resource
);
144 buffers
[i
] = res
->buffer
;
145 buffer_offsets
[i
] = vb
->buffer_offset
;
146 zink_batch_reference_resoure(batch
, res
);
148 buffers
[i
] = zink_resource(ctx
->dummy_buffer
)->buffer
;
149 buffer_offsets
[i
] = 0;
153 if (elems
->hw_state
.num_bindings
> 0)
154 vkCmdBindVertexBuffers(batch
->cmdbuf
, 0,
155 elems
->hw_state
.num_bindings
,
156 buffers
, buffer_offsets
);
159 static struct zink_gfx_program
*
160 get_gfx_program(struct zink_context
*ctx
)
162 if (ctx
->dirty_program
) {
163 struct hash_entry
*entry
= _mesa_hash_table_search(ctx
->program_cache
,
166 struct zink_gfx_program
*prog
;
167 prog
= zink_create_gfx_program(ctx
, ctx
->gfx_stages
);
168 entry
= _mesa_hash_table_insert(ctx
->program_cache
, prog
->stages
, prog
);
172 ctx
->curr_program
= entry
->data
;
173 ctx
->dirty_program
= false;
176 assert(ctx
->curr_program
);
177 return ctx
->curr_program
;
181 line_width_needed(enum pipe_prim_type reduced_prim
,
182 VkPolygonMode polygon_mode
)
184 switch (reduced_prim
) {
185 case PIPE_PRIM_POINTS
:
188 case PIPE_PRIM_LINES
:
191 case PIPE_PRIM_TRIANGLES
:
192 return polygon_mode
== VK_POLYGON_MODE_LINE
;
195 unreachable("unexpected reduced prim");
200 zink_draw_vbo(struct pipe_context
*pctx
,
201 const struct pipe_draw_info
*dinfo
)
203 struct zink_context
*ctx
= zink_context(pctx
);
204 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
205 struct zink_rasterizer_state
*rast_state
= ctx
->rast_state
;
206 struct zink_so_target
*so_target
= zink_so_target(dinfo
->count_from_stream_output
);
207 VkBuffer counter_buffers
[PIPE_MAX_SO_OUTPUTS
];
208 VkDeviceSize counter_buffer_offsets
[PIPE_MAX_SO_OUTPUTS
] = {};
210 if (dinfo
->mode
>= PIPE_PRIM_QUADS
||
211 dinfo
->mode
== PIPE_PRIM_LINE_LOOP
||
212 (dinfo
->index_size
== 1 && !screen
->have_EXT_index_type_uint8
)) {
213 if (!u_trim_pipe_prim(dinfo
->mode
, (unsigned *)&dinfo
->count
))
216 util_primconvert_save_rasterizer_state(ctx
->primconvert
, &rast_state
->base
);
217 util_primconvert_draw_vbo(ctx
->primconvert
, dinfo
);
221 struct zink_gfx_program
*gfx_program
= get_gfx_program(ctx
);
225 VkPipeline pipeline
= zink_get_gfx_pipeline(screen
, gfx_program
,
226 &ctx
->gfx_pipeline_state
,
229 enum pipe_prim_type reduced_prim
= u_reduced_prim(dinfo
->mode
);
231 bool depth_bias
= false;
232 switch (reduced_prim
) {
233 case PIPE_PRIM_POINTS
:
234 depth_bias
= rast_state
->offset_point
;
237 case PIPE_PRIM_LINES
:
238 depth_bias
= rast_state
->offset_line
;
241 case PIPE_PRIM_TRIANGLES
:
242 depth_bias
= rast_state
->offset_tri
;
246 unreachable("unexpected reduced prim");
249 unsigned index_offset
= 0;
250 struct pipe_resource
*index_buffer
= NULL
;
251 if (dinfo
->index_size
> 0) {
252 if (dinfo
->has_user_indices
) {
253 if (!util_upload_index_buffer(pctx
, dinfo
, &index_buffer
, &index_offset
, 4)) {
254 debug_printf("util_upload_index_buffer() failed\n");
258 index_buffer
= dinfo
->index
.resource
;
261 VkWriteDescriptorSet wds
[PIPE_SHADER_TYPES
* PIPE_MAX_CONSTANT_BUFFERS
+ PIPE_SHADER_TYPES
* PIPE_MAX_SHADER_SAMPLER_VIEWS
];
262 VkDescriptorBufferInfo buffer_infos
[PIPE_SHADER_TYPES
* PIPE_MAX_CONSTANT_BUFFERS
];
263 VkDescriptorImageInfo image_infos
[PIPE_SHADER_TYPES
* PIPE_MAX_SHADER_SAMPLER_VIEWS
];
264 int num_wds
= 0, num_buffer_info
= 0, num_image_info
= 0;
266 struct zink_resource
*transitions
[PIPE_SHADER_TYPES
* PIPE_MAX_SHADER_SAMPLER_VIEWS
];
267 int num_transitions
= 0;
269 for (int i
= 0; i
< ARRAY_SIZE(ctx
->gfx_stages
); i
++) {
270 struct zink_shader
*shader
= ctx
->gfx_stages
[i
];
274 if (i
== MESA_SHADER_VERTEX
&& ctx
->num_so_targets
) {
275 for (unsigned i
= 0; i
< ctx
->num_so_targets
; i
++) {
276 struct zink_so_target
*t
= zink_so_target(ctx
->so_targets
[i
]);
277 t
->stride
= shader
->stream_output
.stride
[i
] * sizeof(uint32_t);
281 for (int j
= 0; j
< shader
->num_bindings
; j
++) {
282 int index
= shader
->bindings
[j
].index
;
283 if (shader
->bindings
[j
].type
== VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
) {
284 assert(ctx
->ubos
[i
][index
].buffer_size
> 0);
285 assert(ctx
->ubos
[i
][index
].buffer_size
<= screen
->props
.limits
.maxUniformBufferRange
);
286 assert(ctx
->ubos
[i
][index
].buffer
);
287 struct zink_resource
*res
= zink_resource(ctx
->ubos
[i
][index
].buffer
);
288 buffer_infos
[num_buffer_info
].buffer
= res
->buffer
;
289 buffer_infos
[num_buffer_info
].offset
= ctx
->ubos
[i
][index
].buffer_offset
;
290 buffer_infos
[num_buffer_info
].range
= ctx
->ubos
[i
][index
].buffer_size
;
291 wds
[num_wds
].pBufferInfo
= buffer_infos
+ num_buffer_info
;
294 struct pipe_sampler_view
*psampler_view
= ctx
->image_views
[i
][index
];
295 assert(psampler_view
);
296 struct zink_sampler_view
*sampler_view
= zink_sampler_view(psampler_view
);
298 struct zink_resource
*res
= zink_resource(psampler_view
->texture
);
299 VkImageLayout layout
= res
->layout
;
300 if (layout
!= VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
&&
301 layout
!= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
&&
302 layout
!= VK_IMAGE_LAYOUT_GENERAL
) {
303 transitions
[num_transitions
++] = res
;
304 layout
= VK_IMAGE_LAYOUT_GENERAL
;
306 image_infos
[num_image_info
].imageLayout
= layout
;
307 image_infos
[num_image_info
].imageView
= sampler_view
->image_view
;
308 image_infos
[num_image_info
].sampler
= ctx
->samplers
[i
][index
];
309 wds
[num_wds
].pImageInfo
= image_infos
+ num_image_info
;
313 wds
[num_wds
].sType
= VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
;
314 wds
[num_wds
].pNext
= NULL
;
315 wds
[num_wds
].dstBinding
= shader
->bindings
[j
].binding
;
316 wds
[num_wds
].dstArrayElement
= 0;
317 wds
[num_wds
].descriptorCount
= 1;
318 wds
[num_wds
].descriptorType
= shader
->bindings
[j
].type
;
323 struct zink_batch
*batch
;
324 if (num_transitions
> 0) {
325 batch
= zink_batch_no_rp(ctx
);
327 for (int i
= 0; i
< num_transitions
; ++i
)
328 zink_resource_barrier(batch
->cmdbuf
, transitions
[i
],
329 transitions
[i
]->aspect
,
330 VK_IMAGE_LAYOUT_GENERAL
);
333 if (ctx
->xfb_barrier
)
334 zink_emit_xfb_counter_barrier(ctx
);
336 if (ctx
->dirty_so_targets
)
337 zink_emit_stream_output_targets(pctx
);
339 if (so_target
&& zink_resource(so_target
->base
.buffer
)->needs_xfb_barrier
)
340 zink_emit_xfb_vertex_input_barrier(ctx
, zink_resource(so_target
->base
.buffer
));
343 batch
= zink_batch_rp(ctx
);
345 if (batch
->descs_left
< gfx_program
->num_descriptors
) {
346 ctx
->base
.flush(&ctx
->base
, NULL
, 0);
347 batch
= zink_batch_rp(ctx
);
348 assert(batch
->descs_left
>= gfx_program
->num_descriptors
);
351 VkDescriptorSet desc_set
= allocate_descriptor_set(screen
, batch
,
353 assert(desc_set
!= VK_NULL_HANDLE
);
355 for (int i
= 0; i
< ARRAY_SIZE(ctx
->gfx_stages
); i
++) {
356 struct zink_shader
*shader
= ctx
->gfx_stages
[i
];
360 for (int j
= 0; j
< shader
->num_bindings
; j
++) {
361 int index
= shader
->bindings
[j
].index
;
362 if (shader
->bindings
[j
].type
== VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
) {
363 struct zink_resource
*res
= zink_resource(ctx
->ubos
[i
][index
].buffer
);
364 zink_batch_reference_resoure(batch
, res
);
366 struct zink_sampler_view
*sampler_view
= zink_sampler_view(ctx
->image_views
[i
][index
]);
367 zink_batch_reference_sampler_view(batch
, sampler_view
);
372 vkCmdSetViewport(batch
->cmdbuf
, 0, ctx
->num_viewports
, ctx
->viewports
);
373 if (ctx
->rast_state
->base
.scissor
)
374 vkCmdSetScissor(batch
->cmdbuf
, 0, ctx
->num_viewports
, ctx
->scissors
);
375 else if (ctx
->fb_state
.width
&& ctx
->fb_state
.height
) {
376 VkRect2D fb_scissor
= {};
377 fb_scissor
.extent
.width
= ctx
->fb_state
.width
;
378 fb_scissor
.extent
.height
= ctx
->fb_state
.height
;
379 vkCmdSetScissor(batch
->cmdbuf
, 0, 1, &fb_scissor
);
382 if (line_width_needed(reduced_prim
, rast_state
->hw_state
.polygon_mode
)) {
383 if (screen
->feats
.wideLines
|| ctx
->line_width
== 1.0f
)
384 vkCmdSetLineWidth(batch
->cmdbuf
, ctx
->line_width
);
386 debug_printf("BUG: wide lines not supported, needs fallback!");
389 vkCmdSetStencilReference(batch
->cmdbuf
, VK_STENCIL_FACE_FRONT_BIT
, ctx
->stencil_ref
.ref_value
[0]);
390 vkCmdSetStencilReference(batch
->cmdbuf
, VK_STENCIL_FACE_BACK_BIT
, ctx
->stencil_ref
.ref_value
[1]);
393 vkCmdSetDepthBias(batch
->cmdbuf
, rast_state
->offset_units
, rast_state
->offset_clamp
, rast_state
->offset_scale
);
395 vkCmdSetDepthBias(batch
->cmdbuf
, 0.0f
, 0.0f
, 0.0f
);
397 if (ctx
->gfx_pipeline_state
.blend_state
->need_blend_constants
)
398 vkCmdSetBlendConstants(batch
->cmdbuf
, ctx
->blend_constants
);
401 for (int i
= 0; i
< num_wds
; ++i
)
402 wds
[i
].dstSet
= desc_set
;
403 vkUpdateDescriptorSets(screen
->dev
, num_wds
, wds
, 0, NULL
);
406 vkCmdBindPipeline(batch
->cmdbuf
, VK_PIPELINE_BIND_POINT_GRAPHICS
, pipeline
);
407 vkCmdBindDescriptorSets(batch
->cmdbuf
, VK_PIPELINE_BIND_POINT_GRAPHICS
,
408 gfx_program
->layout
, 0, 1, &desc_set
, 0, NULL
);
409 zink_bind_vertex_buffers(batch
, ctx
);
411 if (ctx
->num_so_targets
) {
412 for (unsigned i
= 0; i
< ctx
->num_so_targets
; i
++) {
413 struct zink_so_target
*t
= zink_so_target(ctx
->so_targets
[i
]);
414 struct zink_resource
*res
= zink_resource(t
->counter_buffer
);
415 if (t
->counter_buffer_valid
) {
416 zink_batch_reference_resoure(batch
, zink_resource(t
->counter_buffer
));
417 counter_buffers
[i
] = res
->buffer
;
418 counter_buffer_offsets
[i
] = t
->counter_buffer_offset
;
420 counter_buffers
[i
] = VK_NULL_HANDLE
;
422 screen
->vk_CmdBeginTransformFeedbackEXT(batch
->cmdbuf
, 0, ctx
->num_so_targets
, counter_buffers
, counter_buffer_offsets
);
425 if (dinfo
->index_size
> 0) {
426 VkIndexType index_type
;
427 switch (dinfo
->index_size
) {
429 assert(screen
->have_EXT_index_type_uint8
);
430 index_type
= VK_INDEX_TYPE_UINT8_EXT
;
433 index_type
= VK_INDEX_TYPE_UINT16
;
436 index_type
= VK_INDEX_TYPE_UINT32
;
439 unreachable("unknown index size!");
441 struct zink_resource
*res
= zink_resource(index_buffer
);
442 vkCmdBindIndexBuffer(batch
->cmdbuf
, res
->buffer
, index_offset
, index_type
);
443 zink_batch_reference_resoure(batch
, res
);
444 vkCmdDrawIndexed(batch
->cmdbuf
,
445 dinfo
->count
, dinfo
->instance_count
,
446 dinfo
->start
, dinfo
->index_bias
, dinfo
->start_instance
);
448 if (so_target
&& screen
->tf_props
.transformFeedbackDraw
) {
449 zink_batch_reference_resoure(batch
, zink_resource(so_target
->counter_buffer
));
450 screen
->vk_CmdDrawIndirectByteCountEXT(batch
->cmdbuf
, dinfo
->instance_count
, dinfo
->start_instance
,
451 zink_resource(so_target
->counter_buffer
)->buffer
, so_target
->counter_buffer_offset
, 0,
452 MIN2(so_target
->stride
, screen
->tf_props
.maxTransformFeedbackBufferDataStride
));
455 vkCmdDraw(batch
->cmdbuf
, dinfo
->count
, dinfo
->instance_count
, dinfo
->start
, dinfo
->start_instance
);
458 if (dinfo
->index_size
> 0 && dinfo
->has_user_indices
)
459 pipe_resource_reference(&index_buffer
, NULL
);
461 if (ctx
->num_so_targets
) {
462 for (unsigned i
= 0; i
< ctx
->num_so_targets
; i
++) {
463 struct zink_so_target
*t
= zink_so_target(ctx
->so_targets
[i
]);
464 counter_buffers
[i
] = zink_resource(t
->counter_buffer
)->buffer
;
465 counter_buffer_offsets
[i
] = t
->counter_buffer_offset
;
466 t
->counter_buffer_valid
= true;
467 zink_resource(ctx
->so_targets
[i
]->buffer
)->needs_xfb_barrier
= true;
469 screen
->vk_CmdEndTransformFeedbackEXT(batch
->cmdbuf
, 0, ctx
->num_so_targets
, counter_buffers
, counter_buffer_offsets
);