Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/broadcom/vulkan/v3dv_meta_clear.c
4560 views
1
/*
2
* Copyright © 2020 Raspberry Pi
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
*/
23
24
#include "v3dv_private.h"
25
26
#include "compiler/nir/nir_builder.h"
27
#include "vk_format_info.h"
28
#include "util/u_pack_color.h"
29
30
static void
31
destroy_color_clear_pipeline(VkDevice _device,
32
uint64_t pipeline,
33
VkAllocationCallbacks *alloc)
34
{
35
struct v3dv_meta_color_clear_pipeline *p =
36
(struct v3dv_meta_color_clear_pipeline *) (uintptr_t) pipeline;
37
v3dv_DestroyPipeline(_device, p->pipeline, alloc);
38
if (p->cached)
39
v3dv_DestroyRenderPass(_device, p->pass, alloc);
40
vk_free(alloc, p);
41
}
42
43
static void
44
destroy_depth_clear_pipeline(VkDevice _device,
45
struct v3dv_meta_depth_clear_pipeline *p,
46
VkAllocationCallbacks *alloc)
47
{
48
v3dv_DestroyPipeline(_device, p->pipeline, alloc);
49
vk_free(alloc, p);
50
}
51
52
static VkResult
53
create_color_clear_pipeline_layout(struct v3dv_device *device,
54
VkPipelineLayout *pipeline_layout)
55
{
56
/* FIXME: this is abusing a bit the API, since not all of our clear
57
* pipelines have a geometry shader. We could create 2 different pipeline
58
* layouts, but this works for us for now.
59
*/
60
VkPushConstantRange ranges[2] = {
61
{ VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16 },
62
{ VK_SHADER_STAGE_GEOMETRY_BIT, 16, 4 },
63
};
64
65
VkPipelineLayoutCreateInfo info = {
66
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
67
.setLayoutCount = 0,
68
.pushConstantRangeCount = 2,
69
.pPushConstantRanges = ranges,
70
};
71
72
return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
73
&info, &device->vk.alloc, pipeline_layout);
74
}
75
76
static VkResult
77
create_depth_clear_pipeline_layout(struct v3dv_device *device,
78
VkPipelineLayout *pipeline_layout)
79
{
80
/* FIXME: this is abusing a bit the API, since not all of our clear
81
* pipelines have a geometry shader. We could create 2 different pipeline
82
* layouts, but this works for us for now.
83
*/
84
VkPushConstantRange ranges[2] = {
85
{ VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4 },
86
{ VK_SHADER_STAGE_GEOMETRY_BIT, 4, 4 },
87
};
88
89
VkPipelineLayoutCreateInfo info = {
90
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
91
.setLayoutCount = 0,
92
.pushConstantRangeCount = 2,
93
.pPushConstantRanges = ranges
94
};
95
96
return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
97
&info, &device->vk.alloc, pipeline_layout);
98
}
99
100
void
101
v3dv_meta_clear_init(struct v3dv_device *device)
102
{
103
device->meta.color_clear.cache =
104
_mesa_hash_table_create(NULL, u64_hash, u64_compare);
105
106
create_color_clear_pipeline_layout(device,
107
&device->meta.color_clear.p_layout);
108
109
device->meta.depth_clear.cache =
110
_mesa_hash_table_create(NULL, u64_hash, u64_compare);
111
112
create_depth_clear_pipeline_layout(device,
113
&device->meta.depth_clear.p_layout);
114
}
115
116
void
117
v3dv_meta_clear_finish(struct v3dv_device *device)
118
{
119
VkDevice _device = v3dv_device_to_handle(device);
120
121
hash_table_foreach(device->meta.color_clear.cache, entry) {
122
struct v3dv_meta_color_clear_pipeline *item = entry->data;
123
destroy_color_clear_pipeline(_device, (uintptr_t)item, &device->vk.alloc);
124
}
125
_mesa_hash_table_destroy(device->meta.color_clear.cache, NULL);
126
127
if (device->meta.color_clear.p_layout) {
128
v3dv_DestroyPipelineLayout(_device, device->meta.color_clear.p_layout,
129
&device->vk.alloc);
130
}
131
132
hash_table_foreach(device->meta.depth_clear.cache, entry) {
133
struct v3dv_meta_depth_clear_pipeline *item = entry->data;
134
destroy_depth_clear_pipeline(_device, item, &device->vk.alloc);
135
}
136
_mesa_hash_table_destroy(device->meta.depth_clear.cache, NULL);
137
138
if (device->meta.depth_clear.p_layout) {
139
v3dv_DestroyPipelineLayout(_device, device->meta.depth_clear.p_layout,
140
&device->vk.alloc);
141
}
142
}
143
144
static nir_ssa_def *
145
gen_rect_vertices(nir_builder *b)
146
{
147
nir_ssa_def *vertex_id = nir_load_vertex_id(b);
148
149
/* vertex 0: -1.0, -1.0
150
* vertex 1: -1.0, 1.0
151
* vertex 2: 1.0, -1.0
152
* vertex 3: 1.0, 1.0
153
*
154
* so:
155
*
156
* channel 0 is vertex_id < 2 ? -1.0 : 1.0
157
* channel 1 is vertex id & 1 ? 1.0 : -1.0
158
*/
159
160
nir_ssa_def *one = nir_imm_int(b, 1);
161
nir_ssa_def *c0cmp = nir_ilt(b, vertex_id, nir_imm_int(b, 2));
162
nir_ssa_def *c1cmp = nir_ieq(b, nir_iand(b, vertex_id, one), one);
163
164
nir_ssa_def *comp[4];
165
comp[0] = nir_bcsel(b, c0cmp,
166
nir_imm_float(b, -1.0f),
167
nir_imm_float(b, 1.0f));
168
169
comp[1] = nir_bcsel(b, c1cmp,
170
nir_imm_float(b, 1.0f),
171
nir_imm_float(b, -1.0f));
172
comp[2] = nir_imm_float(b, 0.0f);
173
comp[3] = nir_imm_float(b, 1.0f);
174
return nir_vec(b, comp, 4);
175
}
176
177
static nir_shader *
178
get_clear_rect_vs()
179
{
180
const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
181
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, options,
182
"meta clear vs");
183
184
const struct glsl_type *vec4 = glsl_vec4_type();
185
nir_variable *vs_out_pos =
186
nir_variable_create(b.shader, nir_var_shader_out, vec4, "gl_Position");
187
vs_out_pos->data.location = VARYING_SLOT_POS;
188
189
nir_ssa_def *pos = gen_rect_vertices(&b);
190
nir_store_var(&b, vs_out_pos, pos, 0xf);
191
192
return b.shader;
193
}
194
195
static nir_shader *
196
get_clear_rect_gs(uint32_t push_constant_layer_base)
197
{
198
/* FIXME: this creates a geometry shader that takes the index of a single
199
* layer to clear from push constants, so we need to emit a draw call for
200
* each layer that we want to clear. We could actually do better and have it
201
* take a range of layers and then emit one triangle per layer to clear,
202
* however, if we were to do this we would need to be careful not to exceed
203
* the maximum number of output vertices allowed in a geometry shader.
204
*/
205
const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
206
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, options,
207
"meta clear gs");
208
nir_shader *nir = b.shader;
209
nir->info.inputs_read = 1ull << VARYING_SLOT_POS;
210
nir->info.outputs_written = (1ull << VARYING_SLOT_POS) |
211
(1ull << VARYING_SLOT_LAYER);
212
nir->info.gs.input_primitive = GL_TRIANGLES;
213
nir->info.gs.output_primitive = GL_TRIANGLE_STRIP;
214
nir->info.gs.vertices_in = 3;
215
nir->info.gs.vertices_out = 3;
216
nir->info.gs.invocations = 1;
217
nir->info.gs.active_stream_mask = 0x1;
218
219
/* in vec4 gl_Position[3] */
220
nir_variable *gs_in_pos =
221
nir_variable_create(b.shader, nir_var_shader_in,
222
glsl_array_type(glsl_vec4_type(), 3, 0),
223
"in_gl_Position");
224
gs_in_pos->data.location = VARYING_SLOT_POS;
225
226
/* out vec4 gl_Position */
227
nir_variable *gs_out_pos =
228
nir_variable_create(b.shader, nir_var_shader_out, glsl_vec4_type(),
229
"out_gl_Position");
230
gs_out_pos->data.location = VARYING_SLOT_POS;
231
232
/* out float gl_Layer */
233
nir_variable *gs_out_layer =
234
nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
235
"out_gl_Layer");
236
gs_out_layer->data.location = VARYING_SLOT_LAYER;
237
238
/* Emit output triangle */
239
for (uint32_t i = 0; i < 3; i++) {
240
/* gl_Position from shader input */
241
nir_deref_instr *in_pos_i =
242
nir_build_deref_array_imm(&b, nir_build_deref_var(&b, gs_in_pos), i);
243
nir_copy_deref(&b, nir_build_deref_var(&b, gs_out_pos), in_pos_i);
244
245
/* gl_Layer from push constants */
246
nir_ssa_def *layer =
247
nir_load_push_constant(&b, 1, 32, nir_imm_int(&b, 0),
248
.base = push_constant_layer_base, .range = 4);
249
nir_store_var(&b, gs_out_layer, layer, 0x1);
250
251
nir_emit_vertex(&b, 0);
252
}
253
254
nir_end_primitive(&b, 0);
255
256
return nir;
257
}
258
259
static nir_shader *
260
get_color_clear_rect_fs(uint32_t rt_idx, VkFormat format)
261
{
262
const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
263
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, options,
264
"meta clear fs");
265
266
enum pipe_format pformat = vk_format_to_pipe_format(format);
267
const struct glsl_type *fs_out_type =
268
util_format_is_float(pformat) ? glsl_vec4_type() : glsl_uvec4_type();
269
270
nir_variable *fs_out_color =
271
nir_variable_create(b.shader, nir_var_shader_out, fs_out_type, "out_color");
272
fs_out_color->data.location = FRAG_RESULT_DATA0 + rt_idx;
273
274
nir_ssa_def *color_load = nir_load_push_constant(&b, 4, 32, nir_imm_int(&b, 0), .base = 0, .range = 16);
275
nir_store_var(&b, fs_out_color, color_load, 0xf);
276
277
return b.shader;
278
}
279
280
static nir_shader *
281
get_depth_clear_rect_fs()
282
{
283
const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
284
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, options,
285
"meta depth clear fs");
286
287
nir_variable *fs_out_depth =
288
nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
289
"out_depth");
290
fs_out_depth->data.location = FRAG_RESULT_DEPTH;
291
292
nir_ssa_def *depth_load =
293
nir_load_push_constant(&b, 1, 32, nir_imm_int(&b, 0), .base = 0, .range = 4);
294
295
nir_store_var(&b, fs_out_depth, depth_load, 0x1);
296
297
return b.shader;
298
}
299
300
static VkResult
301
create_pipeline(struct v3dv_device *device,
302
struct v3dv_render_pass *pass,
303
uint32_t subpass_idx,
304
uint32_t samples,
305
struct nir_shader *vs_nir,
306
struct nir_shader *gs_nir,
307
struct nir_shader *fs_nir,
308
const VkPipelineVertexInputStateCreateInfo *vi_state,
309
const VkPipelineDepthStencilStateCreateInfo *ds_state,
310
const VkPipelineColorBlendStateCreateInfo *cb_state,
311
const VkPipelineLayout layout,
312
VkPipeline *pipeline)
313
{
314
VkPipelineShaderStageCreateInfo stages[3] = { 0 };
315
struct vk_shader_module vs_m;
316
struct vk_shader_module gs_m;
317
struct vk_shader_module fs_m;
318
319
uint32_t stage_count = 0;
320
v3dv_shader_module_internal_init(device, &vs_m, vs_nir);
321
stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
322
stages[stage_count].stage = VK_SHADER_STAGE_VERTEX_BIT;
323
stages[stage_count].module = vk_shader_module_to_handle(&vs_m);
324
stages[stage_count].pName = "main";
325
stage_count++;
326
327
if (gs_nir) {
328
v3dv_shader_module_internal_init(device, &gs_m, gs_nir);
329
stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
330
stages[stage_count].stage = VK_SHADER_STAGE_GEOMETRY_BIT;
331
stages[stage_count].module = vk_shader_module_to_handle(&gs_m);
332
stages[stage_count].pName = "main";
333
stage_count++;
334
}
335
336
if (fs_nir) {
337
v3dv_shader_module_internal_init(device, &fs_m, fs_nir);
338
stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
339
stages[stage_count].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
340
stages[stage_count].module = vk_shader_module_to_handle(&fs_m);
341
stages[stage_count].pName = "main";
342
stage_count++;
343
}
344
345
VkGraphicsPipelineCreateInfo info = {
346
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
347
348
.stageCount = stage_count,
349
.pStages = stages,
350
351
.pVertexInputState = vi_state,
352
353
.pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
354
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
355
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
356
.primitiveRestartEnable = false,
357
},
358
359
.pViewportState = &(VkPipelineViewportStateCreateInfo) {
360
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
361
.viewportCount = 1,
362
.scissorCount = 1,
363
},
364
365
.pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
366
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
367
.rasterizerDiscardEnable = false,
368
.polygonMode = VK_POLYGON_MODE_FILL,
369
.cullMode = VK_CULL_MODE_NONE,
370
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
371
.depthBiasEnable = false,
372
},
373
374
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
375
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
376
.rasterizationSamples = samples,
377
.sampleShadingEnable = false,
378
.pSampleMask = NULL,
379
.alphaToCoverageEnable = false,
380
.alphaToOneEnable = false,
381
},
382
383
.pDepthStencilState = ds_state,
384
385
.pColorBlendState = cb_state,
386
387
/* The meta clear pipeline declares all state as dynamic.
388
* As a consequence, vkCmdBindPipeline writes no dynamic state
389
* to the cmd buffer. Therefore, at the end of the meta clear,
390
* we need only restore dynamic state that was vkCmdSet.
391
*/
392
.pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
393
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
394
.dynamicStateCount = 6,
395
.pDynamicStates = (VkDynamicState[]) {
396
VK_DYNAMIC_STATE_VIEWPORT,
397
VK_DYNAMIC_STATE_SCISSOR,
398
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
399
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
400
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
401
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
402
VK_DYNAMIC_STATE_DEPTH_BIAS,
403
VK_DYNAMIC_STATE_LINE_WIDTH,
404
},
405
},
406
407
.flags = 0,
408
.layout = layout,
409
.renderPass = v3dv_render_pass_to_handle(pass),
410
.subpass = subpass_idx,
411
};
412
413
VkResult result =
414
v3dv_CreateGraphicsPipelines(v3dv_device_to_handle(device),
415
VK_NULL_HANDLE,
416
1, &info,
417
&device->vk.alloc,
418
pipeline);
419
420
ralloc_free(vs_nir);
421
ralloc_free(fs_nir);
422
423
return result;
424
}
425
426
static VkResult
427
create_color_clear_pipeline(struct v3dv_device *device,
428
struct v3dv_render_pass *pass,
429
uint32_t subpass_idx,
430
uint32_t rt_idx,
431
VkFormat format,
432
uint32_t samples,
433
uint32_t components,
434
bool is_layered,
435
VkPipelineLayout pipeline_layout,
436
VkPipeline *pipeline)
437
{
438
nir_shader *vs_nir = get_clear_rect_vs();
439
nir_shader *fs_nir = get_color_clear_rect_fs(rt_idx, format);
440
nir_shader *gs_nir = is_layered ? get_clear_rect_gs(16) : NULL;
441
442
const VkPipelineVertexInputStateCreateInfo vi_state = {
443
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
444
.vertexBindingDescriptionCount = 0,
445
.vertexAttributeDescriptionCount = 0,
446
};
447
448
const VkPipelineDepthStencilStateCreateInfo ds_state = {
449
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
450
.depthTestEnable = false,
451
.depthWriteEnable = false,
452
.depthBoundsTestEnable = false,
453
.stencilTestEnable = false,
454
};
455
456
assert(subpass_idx < pass->subpass_count);
457
const uint32_t color_count = pass->subpasses[subpass_idx].color_count;
458
assert(rt_idx < color_count);
459
460
VkPipelineColorBlendAttachmentState blend_att_state[V3D_MAX_DRAW_BUFFERS];
461
for (uint32_t i = 0; i < color_count; i++) {
462
blend_att_state[i] = (VkPipelineColorBlendAttachmentState) {
463
.blendEnable = false,
464
.colorWriteMask = i == rt_idx ? components : 0,
465
};
466
}
467
468
const VkPipelineColorBlendStateCreateInfo cb_state = {
469
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
470
.logicOpEnable = false,
471
.attachmentCount = color_count,
472
.pAttachments = blend_att_state
473
};
474
475
return create_pipeline(device,
476
pass, subpass_idx,
477
samples,
478
vs_nir, gs_nir, fs_nir,
479
&vi_state,
480
&ds_state,
481
&cb_state,
482
pipeline_layout,
483
pipeline);
484
}
485
486
static VkResult
487
create_depth_clear_pipeline(struct v3dv_device *device,
488
VkImageAspectFlags aspects,
489
struct v3dv_render_pass *pass,
490
uint32_t subpass_idx,
491
uint32_t samples,
492
bool is_layered,
493
VkPipelineLayout pipeline_layout,
494
VkPipeline *pipeline)
495
{
496
const bool has_depth = aspects & VK_IMAGE_ASPECT_DEPTH_BIT;
497
const bool has_stencil = aspects & VK_IMAGE_ASPECT_STENCIL_BIT;
498
assert(has_depth || has_stencil);
499
500
nir_shader *vs_nir = get_clear_rect_vs();
501
nir_shader *fs_nir = has_depth ? get_depth_clear_rect_fs() : NULL;
502
nir_shader *gs_nir = is_layered ? get_clear_rect_gs(4) : NULL;
503
504
const VkPipelineVertexInputStateCreateInfo vi_state = {
505
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
506
.vertexBindingDescriptionCount = 0,
507
.vertexAttributeDescriptionCount = 0,
508
};
509
510
const VkPipelineDepthStencilStateCreateInfo ds_state = {
511
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
512
.depthTestEnable = has_depth,
513
.depthWriteEnable = has_depth,
514
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
515
.depthBoundsTestEnable = false,
516
.stencilTestEnable = has_stencil,
517
.front = {
518
.passOp = VK_STENCIL_OP_REPLACE,
519
.compareOp = VK_COMPARE_OP_ALWAYS,
520
/* compareMask, writeMask and reference are dynamic state */
521
},
522
.back = { 0 },
523
};
524
525
assert(subpass_idx < pass->subpass_count);
526
VkPipelineColorBlendAttachmentState blend_att_state[V3D_MAX_DRAW_BUFFERS] = { 0 };
527
const VkPipelineColorBlendStateCreateInfo cb_state = {
528
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
529
.logicOpEnable = false,
530
.attachmentCount = pass->subpasses[subpass_idx].color_count,
531
.pAttachments = blend_att_state,
532
};
533
534
return create_pipeline(device,
535
pass, subpass_idx,
536
samples,
537
vs_nir, gs_nir, fs_nir,
538
&vi_state,
539
&ds_state,
540
&cb_state,
541
pipeline_layout,
542
pipeline);
543
}
544
545
static VkResult
546
create_color_clear_render_pass(struct v3dv_device *device,
547
uint32_t rt_idx,
548
VkFormat format,
549
uint32_t samples,
550
VkRenderPass *pass)
551
{
552
VkAttachmentDescription att = {
553
.format = format,
554
.samples = samples,
555
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
556
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
557
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
558
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
559
};
560
561
VkAttachmentReference att_ref = {
562
.attachment = rt_idx,
563
.layout = VK_IMAGE_LAYOUT_GENERAL,
564
};
565
566
VkSubpassDescription subpass = {
567
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
568
.inputAttachmentCount = 0,
569
.colorAttachmentCount = 1,
570
.pColorAttachments = &att_ref,
571
.pResolveAttachments = NULL,
572
.pDepthStencilAttachment = NULL,
573
.preserveAttachmentCount = 0,
574
.pPreserveAttachments = NULL,
575
};
576
577
VkRenderPassCreateInfo info = {
578
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
579
.attachmentCount = 1,
580
.pAttachments = &att,
581
.subpassCount = 1,
582
.pSubpasses = &subpass,
583
.dependencyCount = 0,
584
.pDependencies = NULL,
585
};
586
587
return v3dv_CreateRenderPass(v3dv_device_to_handle(device),
588
&info, &device->vk.alloc, pass);
589
}
590
591
static inline uint64_t
592
get_color_clear_pipeline_cache_key(uint32_t rt_idx,
593
VkFormat format,
594
uint32_t samples,
595
uint32_t components,
596
bool is_layered)
597
{
598
assert(rt_idx < V3D_MAX_DRAW_BUFFERS);
599
600
uint64_t key = 0;
601
uint32_t bit_offset = 0;
602
603
key |= rt_idx;
604
bit_offset += 2;
605
606
key |= ((uint64_t) format) << bit_offset;
607
bit_offset += 32;
608
609
key |= ((uint64_t) samples) << bit_offset;
610
bit_offset += 4;
611
612
key |= ((uint64_t) components) << bit_offset;
613
bit_offset += 4;
614
615
key |= (is_layered ? 1ull : 0ull) << bit_offset;
616
bit_offset += 1;
617
618
assert(bit_offset <= 64);
619
return key;
620
}
621
622
static inline uint64_t
623
get_depth_clear_pipeline_cache_key(VkImageAspectFlags aspects,
624
VkFormat format,
625
uint32_t samples,
626
bool is_layered)
627
{
628
uint64_t key = 0;
629
uint32_t bit_offset = 0;
630
631
key |= format;
632
bit_offset += 32;
633
634
key |= ((uint64_t) samples) << bit_offset;
635
bit_offset += 4;
636
637
const bool has_depth = (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) ? 1 : 0;
638
key |= ((uint64_t) has_depth) << bit_offset;
639
bit_offset++;
640
641
const bool has_stencil = (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) ? 1 : 0;
642
key |= ((uint64_t) has_stencil) << bit_offset;
643
bit_offset++;;
644
645
key |= (is_layered ? 1ull : 0ull) << bit_offset;
646
bit_offset += 1;
647
648
assert(bit_offset <= 64);
649
return key;
650
}
651
652
static VkResult
653
get_color_clear_pipeline(struct v3dv_device *device,
654
struct v3dv_render_pass *pass,
655
uint32_t subpass_idx,
656
uint32_t rt_idx,
657
uint32_t attachment_idx,
658
VkFormat format,
659
uint32_t samples,
660
uint32_t components,
661
bool is_layered,
662
struct v3dv_meta_color_clear_pipeline **pipeline)
663
{
664
assert(vk_format_is_color(format));
665
666
VkResult result = VK_SUCCESS;
667
668
/* If pass != NULL it means that we are emitting the clear as a draw call
669
* in the current pass bound by the application. In that case, we can't
670
* cache the pipeline, since it will be referencing that pass and the
671
* application could be destroying it at any point. Hopefully, the perf
672
* impact is not too big since we still have the device pipeline cache
673
* around and we won't end up re-compiling the clear shader.
674
*
675
* FIXME: alternatively, we could refcount (or maybe clone) the render pass
676
* provided by the application and include it in the pipeline key setup
677
* to make caching safe in this scenario, however, based on tests with
678
* vkQuake3, the fact that we are not caching here doesn't seem to have
679
* any significant impact in performance, so it might not be worth it.
680
*/
681
const bool can_cache_pipeline = (pass == NULL);
682
683
uint64_t key;
684
if (can_cache_pipeline) {
685
key = get_color_clear_pipeline_cache_key(rt_idx, format, samples,
686
components, is_layered);
687
mtx_lock(&device->meta.mtx);
688
struct hash_entry *entry =
689
_mesa_hash_table_search(device->meta.color_clear.cache, &key);
690
if (entry) {
691
mtx_unlock(&device->meta.mtx);
692
*pipeline = entry->data;
693
return VK_SUCCESS;
694
}
695
}
696
697
*pipeline = vk_zalloc2(&device->vk.alloc, NULL, sizeof(**pipeline), 8,
698
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
699
700
if (*pipeline == NULL) {
701
result = VK_ERROR_OUT_OF_HOST_MEMORY;
702
goto fail;
703
}
704
705
if (!pass) {
706
result = create_color_clear_render_pass(device,
707
rt_idx,
708
format,
709
samples,
710
&(*pipeline)->pass);
711
if (result != VK_SUCCESS)
712
goto fail;
713
714
pass = v3dv_render_pass_from_handle((*pipeline)->pass);
715
} else {
716
(*pipeline)->pass = v3dv_render_pass_to_handle(pass);
717
}
718
719
result = create_color_clear_pipeline(device,
720
pass,
721
subpass_idx,
722
rt_idx,
723
format,
724
samples,
725
components,
726
is_layered,
727
device->meta.color_clear.p_layout,
728
&(*pipeline)->pipeline);
729
if (result != VK_SUCCESS)
730
goto fail;
731
732
if (can_cache_pipeline) {
733
(*pipeline)->key = key;
734
(*pipeline)->cached = true;
735
_mesa_hash_table_insert(device->meta.color_clear.cache,
736
&(*pipeline)->key, *pipeline);
737
738
mtx_unlock(&device->meta.mtx);
739
}
740
741
return VK_SUCCESS;
742
743
fail:
744
if (can_cache_pipeline)
745
mtx_unlock(&device->meta.mtx);
746
747
VkDevice _device = v3dv_device_to_handle(device);
748
if (*pipeline) {
749
if ((*pipeline)->cached)
750
v3dv_DestroyRenderPass(_device, (*pipeline)->pass, &device->vk.alloc);
751
if ((*pipeline)->pipeline)
752
v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->vk.alloc);
753
vk_free(&device->vk.alloc, *pipeline);
754
*pipeline = NULL;
755
}
756
757
return result;
758
}
759
760
static VkResult
761
get_depth_clear_pipeline(struct v3dv_device *device,
762
VkImageAspectFlags aspects,
763
struct v3dv_render_pass *pass,
764
uint32_t subpass_idx,
765
uint32_t attachment_idx,
766
bool is_layered,
767
struct v3dv_meta_depth_clear_pipeline **pipeline)
768
{
769
assert(subpass_idx < pass->subpass_count);
770
assert(attachment_idx != VK_ATTACHMENT_UNUSED);
771
assert(attachment_idx < pass->attachment_count);
772
773
VkResult result = VK_SUCCESS;
774
775
const uint32_t samples = pass->attachments[attachment_idx].desc.samples;
776
const VkFormat format = pass->attachments[attachment_idx].desc.format;
777
assert(vk_format_is_depth_or_stencil(format));
778
779
const uint64_t key =
780
get_depth_clear_pipeline_cache_key(aspects, format, samples, is_layered);
781
mtx_lock(&device->meta.mtx);
782
struct hash_entry *entry =
783
_mesa_hash_table_search(device->meta.depth_clear.cache, &key);
784
if (entry) {
785
mtx_unlock(&device->meta.mtx);
786
*pipeline = entry->data;
787
return VK_SUCCESS;
788
}
789
790
*pipeline = vk_zalloc2(&device->vk.alloc, NULL, sizeof(**pipeline), 8,
791
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
792
793
if (*pipeline == NULL) {
794
result = VK_ERROR_OUT_OF_HOST_MEMORY;
795
goto fail;
796
}
797
798
result = create_depth_clear_pipeline(device,
799
aspects,
800
pass,
801
subpass_idx,
802
samples,
803
is_layered,
804
device->meta.depth_clear.p_layout,
805
&(*pipeline)->pipeline);
806
if (result != VK_SUCCESS)
807
goto fail;
808
809
(*pipeline)->key = key;
810
_mesa_hash_table_insert(device->meta.depth_clear.cache,
811
&(*pipeline)->key, *pipeline);
812
813
mtx_unlock(&device->meta.mtx);
814
return VK_SUCCESS;
815
816
fail:
817
mtx_unlock(&device->meta.mtx);
818
819
VkDevice _device = v3dv_device_to_handle(device);
820
if (*pipeline) {
821
if ((*pipeline)->pipeline)
822
v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->vk.alloc);
823
vk_free(&device->vk.alloc, *pipeline);
824
*pipeline = NULL;
825
}
826
827
return result;
828
}
829
830
/* Emits a scissored quad in the clear color */
831
static void
832
emit_subpass_color_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
833
struct v3dv_render_pass *pass,
834
struct v3dv_subpass *subpass,
835
uint32_t rt_idx,
836
const VkClearColorValue *clear_color,
837
bool is_layered,
838
bool all_rects_same_layers,
839
uint32_t rect_count,
840
const VkClearRect *rects)
841
{
842
/* Skip if attachment is unused in the current subpass */
843
assert(rt_idx < subpass->color_count);
844
const uint32_t attachment_idx = subpass->color_attachments[rt_idx].attachment;
845
if (attachment_idx == VK_ATTACHMENT_UNUSED)
846
return;
847
848
/* Obtain a pipeline for this clear */
849
assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
850
const VkFormat format =
851
cmd_buffer->state.pass->attachments[attachment_idx].desc.format;
852
const VkFormat samples =
853
cmd_buffer->state.pass->attachments[attachment_idx].desc.samples;
854
const uint32_t components = VK_COLOR_COMPONENT_R_BIT |
855
VK_COLOR_COMPONENT_G_BIT |
856
VK_COLOR_COMPONENT_B_BIT |
857
VK_COLOR_COMPONENT_A_BIT;
858
struct v3dv_meta_color_clear_pipeline *pipeline = NULL;
859
VkResult result = get_color_clear_pipeline(cmd_buffer->device,
860
pass,
861
cmd_buffer->state.subpass_idx,
862
rt_idx,
863
attachment_idx,
864
format,
865
samples,
866
components,
867
is_layered,
868
&pipeline);
869
if (result != VK_SUCCESS) {
870
if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
871
v3dv_flag_oom(cmd_buffer, NULL);
872
return;
873
}
874
assert(pipeline && pipeline->pipeline);
875
876
/* Emit clear rects */
877
v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
878
879
VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
880
v3dv_CmdPushConstants(cmd_buffer_handle,
881
cmd_buffer->device->meta.depth_clear.p_layout,
882
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16,
883
clear_color->float32);
884
885
v3dv_CmdBindPipeline(cmd_buffer_handle,
886
VK_PIPELINE_BIND_POINT_GRAPHICS,
887
pipeline->pipeline);
888
889
uint32_t dynamic_states = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
890
891
for (uint32_t i = 0; i < rect_count; i++) {
892
const VkViewport viewport = {
893
.x = rects[i].rect.offset.x,
894
.y = rects[i].rect.offset.y,
895
.width = rects[i].rect.extent.width,
896
.height = rects[i].rect.extent.height,
897
.minDepth = 0.0f,
898
.maxDepth = 1.0f
899
};
900
v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
901
v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rects[i].rect);
902
903
if (is_layered) {
904
for (uint32_t layer_offset = 0; layer_offset < rects[i].layerCount;
905
layer_offset++) {
906
uint32_t layer = rects[i].baseArrayLayer + layer_offset;
907
v3dv_CmdPushConstants(cmd_buffer_handle,
908
cmd_buffer->device->meta.depth_clear.p_layout,
909
VK_SHADER_STAGE_GEOMETRY_BIT, 16, 4, &layer);
910
v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
911
}
912
} else {
913
assert(rects[i].baseArrayLayer == 0 && rects[i].layerCount == 1);
914
v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
915
}
916
}
917
918
/* Subpass pipelines can't be cached because they include a reference to the
919
* render pass currently bound by the application, which means that we need
920
* to destroy them manually here.
921
*/
922
assert(!pipeline->cached);
923
v3dv_cmd_buffer_add_private_obj(
924
cmd_buffer, (uintptr_t)pipeline,
925
(v3dv_cmd_buffer_private_obj_destroy_cb) destroy_color_clear_pipeline);
926
927
v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
928
}
929
930
/* Emits a scissored quad, clearing the depth aspect by writing to gl_FragDepth
931
* and the stencil aspect by using stencil testing.
932
*/
933
static void
934
emit_subpass_ds_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
935
struct v3dv_render_pass *pass,
936
struct v3dv_subpass *subpass,
937
VkImageAspectFlags aspects,
938
const VkClearDepthStencilValue *clear_ds,
939
bool is_layered,
940
bool all_rects_same_layers,
941
uint32_t rect_count,
942
const VkClearRect *rects)
943
{
944
/* Skip if attachment is unused in the current subpass */
945
const uint32_t attachment_idx = subpass->ds_attachment.attachment;
946
if (attachment_idx == VK_ATTACHMENT_UNUSED)
947
return;
948
949
/* Obtain a pipeline for this clear */
950
assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
951
struct v3dv_meta_depth_clear_pipeline *pipeline = NULL;
952
VkResult result = get_depth_clear_pipeline(cmd_buffer->device,
953
aspects,
954
pass,
955
cmd_buffer->state.subpass_idx,
956
attachment_idx,
957
is_layered,
958
&pipeline);
959
if (result != VK_SUCCESS) {
960
if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
961
v3dv_flag_oom(cmd_buffer, NULL);
962
return;
963
}
964
assert(pipeline && pipeline->pipeline);
965
966
/* Emit clear rects */
967
v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
968
969
VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
970
v3dv_CmdPushConstants(cmd_buffer_handle,
971
cmd_buffer->device->meta.depth_clear.p_layout,
972
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4,
973
&clear_ds->depth);
974
975
v3dv_CmdBindPipeline(cmd_buffer_handle,
976
VK_PIPELINE_BIND_POINT_GRAPHICS,
977
pipeline->pipeline);
978
979
uint32_t dynamic_states = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
980
if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
981
v3dv_CmdSetStencilReference(cmd_buffer_handle,
982
VK_STENCIL_FACE_FRONT_AND_BACK,
983
clear_ds->stencil);
984
v3dv_CmdSetStencilWriteMask(cmd_buffer_handle,
985
VK_STENCIL_FACE_FRONT_AND_BACK, 0xff);
986
v3dv_CmdSetStencilCompareMask(cmd_buffer_handle,
987
VK_STENCIL_FACE_FRONT_AND_BACK, 0xff);
988
dynamic_states |= VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK |
989
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK |
990
VK_DYNAMIC_STATE_STENCIL_REFERENCE;
991
}
992
993
for (uint32_t i = 0; i < rect_count; i++) {
994
const VkViewport viewport = {
995
.x = rects[i].rect.offset.x,
996
.y = rects[i].rect.offset.y,
997
.width = rects[i].rect.extent.width,
998
.height = rects[i].rect.extent.height,
999
.minDepth = 0.0f,
1000
.maxDepth = 1.0f
1001
};
1002
v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
1003
v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rects[i].rect);
1004
if (is_layered) {
1005
for (uint32_t layer_offset = 0; layer_offset < rects[i].layerCount;
1006
layer_offset++) {
1007
uint32_t layer = rects[i].baseArrayLayer + layer_offset;
1008
v3dv_CmdPushConstants(cmd_buffer_handle,
1009
cmd_buffer->device->meta.depth_clear.p_layout,
1010
VK_SHADER_STAGE_GEOMETRY_BIT, 4, 4, &layer);
1011
v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
1012
}
1013
} else {
1014
assert(rects[i].baseArrayLayer == 0 && rects[i].layerCount == 1);
1015
v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
1016
}
1017
}
1018
1019
v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
1020
}
1021
1022
static void
1023
gather_layering_info(uint32_t rect_count, const VkClearRect *rects,
1024
bool *is_layered, bool *all_rects_same_layers)
1025
{
1026
*all_rects_same_layers = true;
1027
1028
uint32_t min_layer = rects[0].baseArrayLayer;
1029
uint32_t max_layer = rects[0].baseArrayLayer + rects[0].layerCount - 1;
1030
for (uint32_t i = 1; i < rect_count; i++) {
1031
if (rects[i].baseArrayLayer != rects[i - 1].baseArrayLayer ||
1032
rects[i].layerCount != rects[i - 1].layerCount) {
1033
*all_rects_same_layers = false;
1034
min_layer = MIN2(min_layer, rects[i].baseArrayLayer);
1035
max_layer = MAX2(max_layer, rects[i].baseArrayLayer +
1036
rects[i].layerCount - 1);
1037
}
1038
}
1039
1040
*is_layered = !(min_layer == 0 && max_layer == 0);
1041
}
1042
1043
VKAPI_ATTR void VKAPI_CALL
1044
v3dv_CmdClearAttachments(VkCommandBuffer commandBuffer,
1045
uint32_t attachmentCount,
1046
const VkClearAttachment *pAttachments,
1047
uint32_t rectCount,
1048
const VkClearRect *pRects)
1049
{
1050
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
1051
1052
/* We can only clear attachments in the current subpass */
1053
assert(attachmentCount <= 5); /* 4 color + D/S */
1054
1055
struct v3dv_render_pass *pass = cmd_buffer->state.pass;
1056
1057
assert(cmd_buffer->state.subpass_idx < pass->subpass_count);
1058
struct v3dv_subpass *subpass =
1059
&cmd_buffer->state.pass->subpasses[cmd_buffer->state.subpass_idx];
1060
1061
/* Emit a clear rect inside the current job for this subpass. For layered
1062
* framebuffers, we use a geometry shader to redirect clears to the
1063
* appropriate layers.
1064
*/
1065
bool is_layered, all_rects_same_layers;
1066
gather_layering_info(rectCount, pRects, &is_layered, &all_rects_same_layers);
1067
for (uint32_t i = 0; i < attachmentCount; i++) {
1068
if (pAttachments[i].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
1069
emit_subpass_color_clear_rects(cmd_buffer, pass, subpass,
1070
pAttachments[i].colorAttachment,
1071
&pAttachments[i].clearValue.color,
1072
is_layered, all_rects_same_layers,
1073
rectCount, pRects);
1074
} else {
1075
emit_subpass_ds_clear_rects(cmd_buffer, pass, subpass,
1076
pAttachments[i].aspectMask,
1077
&pAttachments[i].clearValue.depthStencil,
1078
is_layered, all_rects_same_layers,
1079
rectCount, pRects);
1080
}
1081
}
1082
}
1083
1084