turnip: parse VkPipelineViewportStateCreateInfo
[mesa.git] / src / freedreno / vulkan / tu_pipeline.c
1 /*
2 * Copyright © 2016 Red Hat.
3 * Copyright © 2016 Bas Nieuwenhuizen
4 *
5 * based in part on anv driver which is:
6 * Copyright © 2015 Intel Corporation
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 */
27
28 #include "tu_private.h"
29
30 #include "main/menums.h"
31 #include "nir/nir.h"
32 #include "nir/nir_builder.h"
33 #include "spirv/nir_spirv.h"
34 #include "util/debug.h"
35 #include "util/mesa-sha1.h"
36 #include "util/u_atomic.h"
37 #include "vk_format.h"
38 #include "vk_util.h"
39
40 #include "tu_cs.h"
41
42 struct tu_pipeline_builder
43 {
44 struct tu_device *device;
45 struct tu_pipeline_cache *cache;
46 const VkAllocationCallbacks *alloc;
47 const VkGraphicsPipelineCreateInfo *create_info;
48
49 bool rasterizer_discard;
50 };
51
52 static enum tu_dynamic_state_bits
53 tu_dynamic_state_bit(VkDynamicState state)
54 {
55 switch (state) {
56 case VK_DYNAMIC_STATE_VIEWPORT:
57 return TU_DYNAMIC_VIEWPORT;
58 case VK_DYNAMIC_STATE_SCISSOR:
59 return TU_DYNAMIC_SCISSOR;
60 case VK_DYNAMIC_STATE_LINE_WIDTH:
61 return TU_DYNAMIC_LINE_WIDTH;
62 case VK_DYNAMIC_STATE_DEPTH_BIAS:
63 return TU_DYNAMIC_DEPTH_BIAS;
64 case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
65 return TU_DYNAMIC_BLEND_CONSTANTS;
66 case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
67 return TU_DYNAMIC_DEPTH_BOUNDS;
68 case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
69 return TU_DYNAMIC_STENCIL_COMPARE_MASK;
70 case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
71 return TU_DYNAMIC_STENCIL_WRITE_MASK;
72 case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
73 return TU_DYNAMIC_STENCIL_REFERENCE;
74 default:
75 unreachable("invalid dynamic state");
76 return 0;
77 }
78 }
79
80 static enum pc_di_primtype
81 tu6_primtype(VkPrimitiveTopology topology)
82 {
83 switch (topology) {
84 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
85 return DI_PT_POINTLIST;
86 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
87 return DI_PT_LINELIST;
88 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
89 return DI_PT_LINESTRIP;
90 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
91 return DI_PT_TRILIST;
92 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
93 return DI_PT_TRILIST;
94 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
95 return DI_PT_TRIFAN;
96 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
97 return DI_PT_LINE_ADJ;
98 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
99 return DI_PT_LINESTRIP_ADJ;
100 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
101 return DI_PT_TRI_ADJ;
102 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
103 return DI_PT_TRISTRIP_ADJ;
104 case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
105 default:
106 unreachable("invalid primitive topology");
107 return DI_PT_NONE;
108 }
109 }
110
111 static uint32_t
112 tu6_guardband_adj(uint32_t v)
113 {
114 if (v > 256)
115 return (uint32_t)(511.0 - 65.0 * (log2(v) - 8.0));
116 else
117 return 511;
118 }
119
120 void
121 tu6_emit_viewport(struct tu_cs *cs, const VkViewport *viewport)
122 {
123 float offsets[3];
124 float scales[3];
125 scales[0] = viewport->width / 2.0f;
126 scales[1] = viewport->height / 2.0f;
127 scales[2] = viewport->maxDepth - viewport->minDepth;
128 offsets[0] = viewport->x + scales[0];
129 offsets[1] = viewport->y + scales[1];
130 offsets[2] = viewport->minDepth;
131
132 VkOffset2D min;
133 VkOffset2D max;
134 min.x = (int32_t) viewport->x;
135 max.x = (int32_t) ceilf(viewport->x + viewport->width);
136 if (viewport->height >= 0.0f) {
137 min.y = (int32_t) viewport->y;
138 max.y = (int32_t) ceilf(viewport->y + viewport->height);
139 } else {
140 min.y = (int32_t)(viewport->y + viewport->height);
141 max.y = (int32_t) ceilf(viewport->y);
142 }
143 /* the spec allows viewport->height to be 0.0f */
144 if (min.y == max.y)
145 max.y++;
146 assert(min.x >= 0 && min.x < max.x);
147 assert(min.y >= 0 && min.y < max.y);
148
149 VkExtent2D guardband_adj;
150 guardband_adj.width = tu6_guardband_adj(max.x - min.x);
151 guardband_adj.height = tu6_guardband_adj(max.y - min.y);
152
153 tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_CL_VPORT_XOFFSET_0, 6);
154 tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_XOFFSET_0(offsets[0]));
155 tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_XSCALE_0(scales[0]));
156 tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_YOFFSET_0(offsets[1]));
157 tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_YSCALE_0(scales[1]));
158 tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_ZOFFSET_0(offsets[2]));
159 tu_cs_emit(cs, A6XX_GRAS_CL_VPORT_ZSCALE_0(scales[2]));
160
161 tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0, 2);
162 tu_cs_emit(cs, A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X(min.x) |
163 A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y(min.y));
164 tu_cs_emit(cs, A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X(max.x - 1) |
165 A6XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y(max.y - 1));
166
167 tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_CL_GUARDBAND_CLIP_ADJ, 1);
168 tu_cs_emit(cs,
169 A6XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ(guardband_adj.width) |
170 A6XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT(guardband_adj.height));
171 }
172
173 void
174 tu6_emit_scissor(struct tu_cs *cs, const VkRect2D *scissor)
175 {
176 const VkOffset2D min = scissor->offset;
177 const VkOffset2D max = {
178 scissor->offset.x + scissor->extent.width,
179 scissor->offset.y + scissor->extent.height,
180 };
181
182 tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SC_SCREEN_SCISSOR_TL_0, 2);
183 tu_cs_emit(cs, A6XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X(min.x) |
184 A6XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y(min.y));
185 tu_cs_emit(cs, A6XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X(max.x - 1) |
186 A6XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y(max.y - 1));
187 }
188
189 static VkResult
190 tu_pipeline_builder_create_pipeline(struct tu_pipeline_builder *builder,
191 struct tu_pipeline **out_pipeline)
192 {
193 struct tu_device *dev = builder->device;
194
195 struct tu_pipeline *pipeline =
196 vk_zalloc2(&dev->alloc, builder->alloc, sizeof(*pipeline), 8,
197 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
198 if (!pipeline)
199 return VK_ERROR_OUT_OF_HOST_MEMORY;
200
201 tu_cs_init(&pipeline->cs, TU_CS_MODE_SUB_STREAM, 2048);
202
203 /* reserve the space now such that tu_cs_begin_sub_stream never fails */
204 VkResult result = tu_cs_reserve_space(dev, &pipeline->cs, 2048);
205 if (result != VK_SUCCESS) {
206 vk_free2(&dev->alloc, builder->alloc, pipeline);
207 return result;
208 }
209
210 *out_pipeline = pipeline;
211
212 return VK_SUCCESS;
213 }
214
215 static void
216 tu_pipeline_builder_parse_dynamic(struct tu_pipeline_builder *builder,
217 struct tu_pipeline *pipeline)
218 {
219 const VkPipelineDynamicStateCreateInfo *dynamic_info =
220 builder->create_info->pDynamicState;
221
222 if (!dynamic_info)
223 return;
224
225 for (uint32_t i = 0; i < dynamic_info->dynamicStateCount; i++) {
226 pipeline->dynamic_state.mask |=
227 tu_dynamic_state_bit(dynamic_info->pDynamicStates[i]);
228 }
229 }
230
231 static void
232 tu_pipeline_builder_parse_input_assembly(struct tu_pipeline_builder *builder,
233 struct tu_pipeline *pipeline)
234 {
235 const VkPipelineInputAssemblyStateCreateInfo *ia_info =
236 builder->create_info->pInputAssemblyState;
237
238 pipeline->ia.primtype = tu6_primtype(ia_info->topology);
239 pipeline->ia.primitive_restart = ia_info->primitiveRestartEnable;
240 }
241
242 static void
243 tu_pipeline_builder_parse_viewport(struct tu_pipeline_builder *builder,
244 struct tu_pipeline *pipeline)
245 {
246 /* The spec says:
247 *
248 * pViewportState is a pointer to an instance of the
249 * VkPipelineViewportStateCreateInfo structure, and is ignored if the
250 * pipeline has rasterization disabled."
251 *
252 * We leave the relevant registers stale in that case.
253 */
254 if (builder->rasterizer_discard)
255 return;
256
257 const VkPipelineViewportStateCreateInfo *vp_info =
258 builder->create_info->pViewportState;
259
260 struct tu_cs vp_cs;
261 tu_cs_begin_sub_stream(builder->device, &pipeline->cs, 15, &vp_cs);
262
263 if (!(pipeline->dynamic_state.mask & TU_DYNAMIC_VIEWPORT)) {
264 assert(vp_info->viewportCount == 1);
265 tu6_emit_viewport(&vp_cs, vp_info->pViewports);
266 }
267
268 if (!(pipeline->dynamic_state.mask & TU_DYNAMIC_SCISSOR)) {
269 assert(vp_info->scissorCount == 1);
270 tu6_emit_scissor(&vp_cs, vp_info->pScissors);
271 }
272
273 pipeline->vp.state_ib = tu_cs_end_sub_stream(&pipeline->cs, &vp_cs);
274 }
275
276 static void
277 tu_pipeline_finish(struct tu_pipeline *pipeline,
278 struct tu_device *dev,
279 const VkAllocationCallbacks *alloc)
280 {
281 tu_cs_finish(dev, &pipeline->cs);
282 }
283
284 static VkResult
285 tu_pipeline_builder_build(struct tu_pipeline_builder *builder,
286 struct tu_pipeline **pipeline)
287 {
288 VkResult result = tu_pipeline_builder_create_pipeline(builder, pipeline);
289 if (result != VK_SUCCESS)
290 return result;
291
292 tu_pipeline_builder_parse_dynamic(builder, *pipeline);
293 tu_pipeline_builder_parse_input_assembly(builder, *pipeline);
294 tu_pipeline_builder_parse_viewport(builder, *pipeline);
295
296 /* we should have reserved enough space upfront such that the CS never
297 * grows
298 */
299 assert((*pipeline)->cs.bo_count == 1);
300
301 return VK_SUCCESS;
302 }
303
304 static void
305 tu_pipeline_builder_init_graphics(
306 struct tu_pipeline_builder *builder,
307 struct tu_device *dev,
308 struct tu_pipeline_cache *cache,
309 const VkGraphicsPipelineCreateInfo *create_info,
310 const VkAllocationCallbacks *alloc)
311 {
312 *builder = (struct tu_pipeline_builder) {
313 .device = dev,
314 .cache = cache,
315 .create_info = create_info,
316 .alloc = alloc,
317 };
318
319 builder->rasterizer_discard =
320 create_info->pRasterizationState->rasterizerDiscardEnable;
321 }
322
323 VkResult
324 tu_CreateGraphicsPipelines(VkDevice device,
325 VkPipelineCache pipelineCache,
326 uint32_t count,
327 const VkGraphicsPipelineCreateInfo *pCreateInfos,
328 const VkAllocationCallbacks *pAllocator,
329 VkPipeline *pPipelines)
330 {
331 TU_FROM_HANDLE(tu_device, dev, device);
332 TU_FROM_HANDLE(tu_pipeline_cache, cache, pipelineCache);
333
334 for (uint32_t i = 0; i < count; i++) {
335 struct tu_pipeline_builder builder;
336 tu_pipeline_builder_init_graphics(&builder, dev, cache,
337 &pCreateInfos[i], pAllocator);
338
339 struct tu_pipeline *pipeline;
340 VkResult result = tu_pipeline_builder_build(&builder, &pipeline);
341
342 if (result != VK_SUCCESS) {
343 for (uint32_t j = 0; j < i; j++) {
344 tu_DestroyPipeline(device, pPipelines[j], pAllocator);
345 pPipelines[j] = VK_NULL_HANDLE;
346 }
347
348 return result;
349 }
350
351 pPipelines[i] = tu_pipeline_to_handle(pipeline);
352 }
353
354 return VK_SUCCESS;
355 }
356
357 static VkResult
358 tu_compute_pipeline_create(VkDevice _device,
359 VkPipelineCache _cache,
360 const VkComputePipelineCreateInfo *pCreateInfo,
361 const VkAllocationCallbacks *pAllocator,
362 VkPipeline *pPipeline)
363 {
364 return VK_SUCCESS;
365 }
366
367 VkResult
368 tu_CreateComputePipelines(VkDevice _device,
369 VkPipelineCache pipelineCache,
370 uint32_t count,
371 const VkComputePipelineCreateInfo *pCreateInfos,
372 const VkAllocationCallbacks *pAllocator,
373 VkPipeline *pPipelines)
374 {
375 VkResult result = VK_SUCCESS;
376
377 unsigned i = 0;
378 for (; i < count; i++) {
379 VkResult r;
380 r = tu_compute_pipeline_create(_device, pipelineCache, &pCreateInfos[i],
381 pAllocator, &pPipelines[i]);
382 if (r != VK_SUCCESS) {
383 result = r;
384 pPipelines[i] = VK_NULL_HANDLE;
385 }
386 }
387
388 return result;
389 }
390
391 void
392 tu_DestroyPipeline(VkDevice _device,
393 VkPipeline _pipeline,
394 const VkAllocationCallbacks *pAllocator)
395 {
396 TU_FROM_HANDLE(tu_device, dev, _device);
397 TU_FROM_HANDLE(tu_pipeline, pipeline, _pipeline);
398
399 if (!_pipeline)
400 return;
401
402 tu_pipeline_finish(pipeline, dev, pAllocator);
403 vk_free2(&dev->alloc, pAllocator, pipeline);
404 }