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