zink: don't crash when setting rast-state to NULL
[mesa.git] / src / gallium / drivers / zink / zink_state.c
1 /*
2 * Copyright 2018 Collabora Ltd.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "zink_state.h"
25
26 #include "zink_context.h"
27 #include "zink_screen.h"
28
29 #include "util/u_memory.h"
30
31 #include <math.h>
32
33 static void *
34 zink_create_vertex_elements_state(struct pipe_context *pctx,
35 unsigned num_elements,
36 const struct pipe_vertex_element *elements)
37 {
38 unsigned int i;
39 struct zink_vertex_elements_state *ves = CALLOC_STRUCT(zink_vertex_elements_state);
40 if (!ves)
41 return NULL;
42
43 int buffer_map[PIPE_MAX_ATTRIBS];
44 for (int i = 0; i < ARRAY_SIZE(buffer_map); ++i)
45 buffer_map[i] = -1;
46
47 int num_bindings = 0;
48 for (i = 0; i < num_elements; ++i) {
49 const struct pipe_vertex_element *elem = elements + i;
50 assert(!elem->instance_divisor);
51
52 int binding = elem->vertex_buffer_index;
53 if (buffer_map[binding] < 0) {
54 ves->binding_map[num_bindings] = binding;
55 buffer_map[binding] = num_bindings++;
56 }
57 binding = buffer_map[binding];
58
59
60 ves->bindings[binding].binding = binding;
61 ves->bindings[binding].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
62
63 ves->hw_state.attribs[i].binding = binding;
64 ves->hw_state.attribs[i].location = i; // TODO: unsure
65 ves->hw_state.attribs[i].format = zink_get_format(elem->src_format);
66 assert(ves->hw_state.attribs[i].format != VK_FORMAT_UNDEFINED);
67 ves->hw_state.attribs[i].offset = elem->src_offset;
68 }
69
70 ves->hw_state.num_bindings = num_bindings;
71 ves->hw_state.num_attribs = num_elements;
72 return ves;
73 }
74
75 static void
76 zink_bind_vertex_elements_state(struct pipe_context *pctx,
77 void *cso)
78 {
79 struct zink_context *ctx = zink_context(pctx);
80 struct zink_gfx_pipeline_state *state = &ctx->gfx_pipeline_state;
81 ctx->element_state = cso;
82 if (cso) {
83 state->element_state = &ctx->element_state->hw_state;
84 struct zink_vertex_elements_state *ves = cso;
85 for (int i = 0; i < state->element_state->num_bindings; ++i) {
86 state->bindings[i].binding = ves->bindings[i].binding;
87 state->bindings[i].inputRate = ves->bindings[i].inputRate;
88 }
89 } else
90 state->element_state = NULL;
91 }
92
93 static void
94 zink_delete_vertex_elements_state(struct pipe_context *pctx,
95 void *ves)
96 {
97 }
98
99 static VkBlendFactor
100 blend_factor(enum pipe_blendfactor factor)
101 {
102 switch (factor) {
103 case PIPE_BLENDFACTOR_ONE: return VK_BLEND_FACTOR_ONE;
104 case PIPE_BLENDFACTOR_SRC_COLOR: return VK_BLEND_FACTOR_SRC_COLOR;
105 case PIPE_BLENDFACTOR_SRC_ALPHA: return VK_BLEND_FACTOR_SRC_ALPHA;
106 case PIPE_BLENDFACTOR_DST_ALPHA: return VK_BLEND_FACTOR_DST_ALPHA;
107 case PIPE_BLENDFACTOR_DST_COLOR: return VK_BLEND_FACTOR_DST_COLOR;
108 case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
109 return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
110 case PIPE_BLENDFACTOR_CONST_COLOR: return VK_BLEND_FACTOR_CONSTANT_COLOR;
111 case PIPE_BLENDFACTOR_CONST_ALPHA: return VK_BLEND_FACTOR_CONSTANT_ALPHA;
112 case PIPE_BLENDFACTOR_SRC1_COLOR: return VK_BLEND_FACTOR_SRC1_COLOR;
113 case PIPE_BLENDFACTOR_SRC1_ALPHA: return VK_BLEND_FACTOR_SRC1_ALPHA;
114
115 case PIPE_BLENDFACTOR_ZERO: return VK_BLEND_FACTOR_ZERO;
116
117 case PIPE_BLENDFACTOR_INV_SRC_COLOR:
118 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
119 case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
120 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
121 case PIPE_BLENDFACTOR_INV_DST_ALPHA:
122 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
123 case PIPE_BLENDFACTOR_INV_DST_COLOR:
124 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
125
126 case PIPE_BLENDFACTOR_INV_CONST_COLOR:
127 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
128 case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
129 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
130 case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
131 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
132 case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
133 return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
134 }
135 unreachable("unexpected blend factor");
136 }
137
138
139 static bool
140 need_blend_constants(enum pipe_blendfactor factor)
141 {
142 switch (factor) {
143 case PIPE_BLENDFACTOR_CONST_COLOR:
144 case PIPE_BLENDFACTOR_CONST_ALPHA:
145 case PIPE_BLENDFACTOR_INV_CONST_COLOR:
146 case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
147 return true;
148
149 default:
150 return false;
151 }
152 }
153
154 static VkBlendOp
155 blend_op(enum pipe_blend_func func)
156 {
157 switch (func) {
158 case PIPE_BLEND_ADD: return VK_BLEND_OP_ADD;
159 case PIPE_BLEND_SUBTRACT: return VK_BLEND_OP_SUBTRACT;
160 case PIPE_BLEND_REVERSE_SUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT;
161 case PIPE_BLEND_MIN: return VK_BLEND_OP_MIN;
162 case PIPE_BLEND_MAX: return VK_BLEND_OP_MAX;
163 }
164 unreachable("unexpected blend function");
165 }
166
167 static VkLogicOp
168 logic_op(enum pipe_logicop func)
169 {
170 switch (func) {
171 case PIPE_LOGICOP_CLEAR: return VK_LOGIC_OP_CLEAR;
172 case PIPE_LOGICOP_NOR: return VK_LOGIC_OP_NOR;
173 case PIPE_LOGICOP_AND_INVERTED: return VK_LOGIC_OP_AND_INVERTED;
174 case PIPE_LOGICOP_COPY_INVERTED: return VK_LOGIC_OP_COPY_INVERTED;
175 case PIPE_LOGICOP_AND_REVERSE: return VK_LOGIC_OP_AND_REVERSE;
176 case PIPE_LOGICOP_INVERT: return VK_LOGIC_OP_INVERT;
177 case PIPE_LOGICOP_XOR: return VK_LOGIC_OP_XOR;
178 case PIPE_LOGICOP_NAND: return VK_LOGIC_OP_NAND;
179 case PIPE_LOGICOP_AND: return VK_LOGIC_OP_AND;
180 case PIPE_LOGICOP_EQUIV: return VK_LOGIC_OP_EQUIVALENT;
181 case PIPE_LOGICOP_NOOP: return VK_LOGIC_OP_NO_OP;
182 case PIPE_LOGICOP_OR_INVERTED: return VK_LOGIC_OP_OR_INVERTED;
183 case PIPE_LOGICOP_COPY: return VK_LOGIC_OP_COPY;
184 case PIPE_LOGICOP_OR_REVERSE: return VK_LOGIC_OP_OR_REVERSE;
185 case PIPE_LOGICOP_OR: return VK_LOGIC_OP_OR;
186 case PIPE_LOGICOP_SET: return VK_LOGIC_OP_SET;
187 }
188 unreachable("unexpected logicop function");
189 }
190
191 static void *
192 zink_create_blend_state(struct pipe_context *pctx,
193 const struct pipe_blend_state *blend_state)
194 {
195 struct zink_blend_state *cso = CALLOC_STRUCT(zink_blend_state);
196 if (!cso)
197 return NULL;
198
199 if (blend_state->logicop_enable) {
200 cso->logicop_enable = VK_TRUE;
201 cso->logicop_func = logic_op(blend_state->logicop_func);
202 }
203
204 /* TODO: figure out what to do with dither (nothing is probably "OK" for now,
205 * as dithering is undefined in GL
206 */
207
208 /* TODO: these are multisampling-state, and should be set there instead of
209 * here, as that's closer tied to the update-frequency
210 */
211 cso->alpha_to_coverage = blend_state->alpha_to_coverage;
212 cso->alpha_to_one = blend_state->alpha_to_one;
213
214 cso->need_blend_constants = false;
215
216 for (int i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {
217 const struct pipe_rt_blend_state *rt = blend_state->rt;
218 if (blend_state->independent_blend_enable)
219 rt = blend_state->rt + i;
220
221 VkPipelineColorBlendAttachmentState att = { };
222
223 if (rt->blend_enable) {
224 att.blendEnable = VK_TRUE;
225 att.srcColorBlendFactor = blend_factor(rt->rgb_src_factor);
226 att.dstColorBlendFactor = blend_factor(rt->rgb_dst_factor);
227 att.colorBlendOp = blend_op(rt->rgb_func);
228 att.srcAlphaBlendFactor = blend_factor(rt->alpha_src_factor);
229 att.dstAlphaBlendFactor = blend_factor(rt->alpha_dst_factor);
230 att.alphaBlendOp = blend_op(rt->alpha_func);
231
232 if (need_blend_constants(rt->rgb_src_factor) ||
233 need_blend_constants(rt->rgb_dst_factor) ||
234 need_blend_constants(rt->alpha_src_factor) ||
235 need_blend_constants(rt->alpha_dst_factor))
236 cso->need_blend_constants = true;
237 }
238
239 if (rt->colormask & PIPE_MASK_R)
240 att.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
241 if (rt->colormask & PIPE_MASK_G)
242 att.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
243 if (rt->colormask & PIPE_MASK_B)
244 att.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
245 if (rt->colormask & PIPE_MASK_A)
246 att.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
247
248 cso->attachments[i] = att;
249 }
250
251 return cso;
252 }
253
254 static void
255 zink_bind_blend_state(struct pipe_context *pctx, void *cso)
256 {
257 zink_context(pctx)->gfx_pipeline_state.blend_state = cso;
258 }
259
260 static void
261 zink_delete_blend_state(struct pipe_context *pctx, void *blend_state)
262 {
263 FREE(blend_state);
264 }
265
266 static VkCompareOp
267 compare_op(enum pipe_compare_func func)
268 {
269 switch (func) {
270 case PIPE_FUNC_NEVER: return VK_COMPARE_OP_NEVER;
271 case PIPE_FUNC_LESS: return VK_COMPARE_OP_LESS;
272 case PIPE_FUNC_EQUAL: return VK_COMPARE_OP_EQUAL;
273 case PIPE_FUNC_LEQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL;
274 case PIPE_FUNC_GREATER: return VK_COMPARE_OP_GREATER;
275 case PIPE_FUNC_NOTEQUAL: return VK_COMPARE_OP_NOT_EQUAL;
276 case PIPE_FUNC_GEQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL;
277 case PIPE_FUNC_ALWAYS: return VK_COMPARE_OP_ALWAYS;
278 }
279 unreachable("unexpected func");
280 }
281
282 static VkStencilOp
283 stencil_op(enum pipe_stencil_op op)
284 {
285 switch (op) {
286 case PIPE_STENCIL_OP_KEEP: return VK_STENCIL_OP_KEEP;
287 case PIPE_STENCIL_OP_ZERO: return VK_STENCIL_OP_ZERO;
288 case PIPE_STENCIL_OP_REPLACE: return VK_STENCIL_OP_REPLACE;
289 case PIPE_STENCIL_OP_INCR: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
290 case PIPE_STENCIL_OP_DECR: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
291 case PIPE_STENCIL_OP_INCR_WRAP: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
292 case PIPE_STENCIL_OP_DECR_WRAP: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
293 case PIPE_STENCIL_OP_INVERT: return VK_STENCIL_OP_INVERT;
294 }
295 unreachable("unexpected op");
296 }
297
298 static VkStencilOpState
299 stencil_op_state(const struct pipe_stencil_state *src)
300 {
301 VkStencilOpState ret;
302 ret.failOp = stencil_op(src->fail_op);
303 ret.passOp = stencil_op(src->zpass_op);
304 ret.depthFailOp = stencil_op(src->zfail_op);
305 ret.compareOp = compare_op(src->func);
306 ret.compareMask = src->valuemask;
307 ret.writeMask = src->writemask;
308 ret.reference = 0; // not used: we'll use a dynamic state for this
309 return ret;
310 }
311
312 static void *
313 zink_create_depth_stencil_alpha_state(struct pipe_context *pctx,
314 const struct pipe_depth_stencil_alpha_state *depth_stencil_alpha)
315 {
316 struct zink_depth_stencil_alpha_state *cso = CALLOC_STRUCT(zink_depth_stencil_alpha_state);
317 if (!cso)
318 return NULL;
319
320 if (depth_stencil_alpha->depth.enabled) {
321 cso->depth_test = VK_TRUE;
322 cso->depth_compare_op = compare_op(depth_stencil_alpha->depth.func);
323 }
324
325 if (depth_stencil_alpha->depth.bounds_test) {
326 cso->depth_bounds_test = VK_TRUE;
327 cso->min_depth_bounds = depth_stencil_alpha->depth.bounds_min;
328 cso->max_depth_bounds = depth_stencil_alpha->depth.bounds_max;
329 }
330
331 if (depth_stencil_alpha->stencil[0].enabled) {
332 cso->stencil_test = VK_TRUE;
333 cso->stencil_front = stencil_op_state(depth_stencil_alpha->stencil);
334 }
335
336 if (depth_stencil_alpha->stencil[0].enabled)
337 cso->stencil_back = stencil_op_state(depth_stencil_alpha->stencil + 1);
338 else
339 cso->stencil_back = cso->stencil_front;
340
341 cso->depth_write = depth_stencil_alpha->depth.writemask;
342
343 return cso;
344 }
345
346 static void
347 zink_bind_depth_stencil_alpha_state(struct pipe_context *pctx, void *cso)
348 {
349 zink_context(pctx)->gfx_pipeline_state.depth_stencil_alpha_state = cso;
350 }
351
352 static void
353 zink_delete_depth_stencil_alpha_state(struct pipe_context *pctx,
354 void *depth_stencil_alpha)
355 {
356 FREE(depth_stencil_alpha);
357 }
358
359 static float
360 round_to_granularity(float value, float granularity)
361 {
362 return (float)(round(value / granularity) * granularity);
363 }
364
365 static void *
366 zink_create_rasterizer_state(struct pipe_context *pctx,
367 const struct pipe_rasterizer_state *rs_state)
368 {
369 struct zink_screen *screen = zink_screen(pctx->screen);
370
371 struct zink_rasterizer_state *state = CALLOC_STRUCT(zink_rasterizer_state);
372 if (!state)
373 return NULL;
374
375 state->base = *rs_state;
376
377 assert(rs_state->depth_clip_far == rs_state->depth_clip_near);
378 state->hw_state.depth_clamp = rs_state->depth_clip_near == 0;
379 state->hw_state.rasterizer_discard = rs_state->rasterizer_discard;
380
381 assert(rs_state->fill_front <= PIPE_POLYGON_MODE_POINT);
382 if (rs_state->fill_back != rs_state->fill_front)
383 debug_printf("BUG: vulkan doesn't support different front and back fill modes\n");
384 state->hw_state.polygon_mode = (VkPolygonMode)rs_state->fill_front; // same values
385 state->hw_state.cull_mode = (VkCullModeFlags)rs_state->cull_face; // same bits
386
387 state->hw_state.front_face = rs_state->front_ccw ?
388 VK_FRONT_FACE_COUNTER_CLOCKWISE :
389 VK_FRONT_FACE_CLOCKWISE;
390
391 state->offset_point = rs_state->offset_point;
392 state->offset_line = rs_state->offset_line;
393 state->offset_tri = rs_state->offset_tri;
394 state->offset_units = rs_state->offset_units;
395 state->offset_clamp = rs_state->offset_clamp;
396 state->offset_scale = rs_state->offset_scale;
397
398 state->line_width = round_to_granularity(rs_state->line_width,
399 screen->props.limits.lineWidthGranularity);
400
401 return state;
402 }
403
404 static void
405 zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso)
406 {
407 struct zink_context *ctx = zink_context(pctx);
408 ctx->rast_state = cso;
409
410 if (ctx->rast_state)
411 ctx->gfx_pipeline_state.rast_state = &ctx->rast_state->hw_state;
412 }
413
414 static void
415 zink_delete_rasterizer_state(struct pipe_context *pctx, void *rs_state)
416 {
417 FREE(rs_state);
418 }
419
420 void
421 zink_context_state_init(struct pipe_context *pctx)
422 {
423 pctx->create_vertex_elements_state = zink_create_vertex_elements_state;
424 pctx->bind_vertex_elements_state = zink_bind_vertex_elements_state;
425 pctx->delete_vertex_elements_state = zink_delete_vertex_elements_state;
426
427 pctx->create_blend_state = zink_create_blend_state;
428 pctx->bind_blend_state = zink_bind_blend_state;
429 pctx->delete_blend_state = zink_delete_blend_state;
430
431 pctx->create_depth_stencil_alpha_state = zink_create_depth_stencil_alpha_state;
432 pctx->bind_depth_stencil_alpha_state = zink_bind_depth_stencil_alpha_state;
433 pctx->delete_depth_stencil_alpha_state = zink_delete_depth_stencil_alpha_state;
434
435 pctx->create_rasterizer_state = zink_create_rasterizer_state;
436 pctx->bind_rasterizer_state = zink_bind_rasterizer_state;
437 pctx->delete_rasterizer_state = zink_delete_rasterizer_state;
438 }