zink: fixup return-value
[mesa.git] / src / gallium / drivers / zink / zink_program.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_program.h"
25
26 #include "zink_compiler.h"
27 #include "zink_context.h"
28 #include "zink_render_pass.h"
29 #include "zink_screen.h"
30
31 #include "util/hash_table.h"
32 #include "util/set.h"
33 #include "util/u_debug.h"
34 #include "util/u_memory.h"
35
36 static VkDescriptorSetLayout
37 create_desc_set_layout(VkDevice dev,
38 struct zink_shader *stages[PIPE_SHADER_TYPES - 1],
39 unsigned *num_descriptors)
40 {
41 VkDescriptorSetLayoutBinding bindings[PIPE_SHADER_TYPES * PIPE_MAX_CONSTANT_BUFFERS];
42 int num_bindings = 0;
43
44 for (int i = 0; i < PIPE_SHADER_TYPES - 1; i++) {
45 struct zink_shader *shader = stages[i];
46 if (!shader)
47 continue;
48
49 VkShaderStageFlagBits stage_flags = zink_shader_stage(i);
50 for (int j = 0; j < shader->num_bindings; j++) {
51 assert(num_bindings < ARRAY_SIZE(bindings));
52 bindings[num_bindings].binding = shader->bindings[j].binding;
53 bindings[num_bindings].descriptorType = shader->bindings[j].type;
54 bindings[num_bindings].descriptorCount = 1;
55 bindings[num_bindings].stageFlags = stage_flags;
56 bindings[num_bindings].pImmutableSamplers = NULL;
57 ++num_bindings;
58 }
59 }
60
61 VkDescriptorSetLayoutCreateInfo dcslci = {};
62 dcslci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
63 dcslci.pNext = NULL;
64 dcslci.flags = 0;
65 dcslci.bindingCount = num_bindings;
66 dcslci.pBindings = bindings;
67
68 VkDescriptorSetLayout dsl;
69 if (vkCreateDescriptorSetLayout(dev, &dcslci, 0, &dsl) != VK_SUCCESS) {
70 debug_printf("vkCreateDescriptorSetLayout failed\n");
71 return VK_NULL_HANDLE;
72 }
73
74 *num_descriptors = num_bindings;
75 return dsl;
76 }
77
78 static VkPipelineLayout
79 create_pipeline_layout(VkDevice dev, VkDescriptorSetLayout dsl)
80 {
81 assert(dsl != VK_NULL_HANDLE);
82
83 VkPipelineLayoutCreateInfo plci = {};
84 plci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
85
86 plci.pSetLayouts = &dsl;
87 plci.setLayoutCount = 1;
88
89 VkPipelineLayout layout;
90 if (vkCreatePipelineLayout(dev, &plci, NULL, &layout) != VK_SUCCESS) {
91 debug_printf("vkCreatePipelineLayout failed!\n");
92 return VK_NULL_HANDLE;
93 }
94
95 return layout;
96 }
97
98 static uint32_t
99 hash_gfx_pipeline_state(const void *key)
100 {
101 return _mesa_hash_data(key, sizeof(struct zink_gfx_pipeline_state));
102 }
103
104 static bool
105 equals_gfx_pipeline_state(const void *a, const void *b)
106 {
107 return memcmp(a, b, sizeof(struct zink_gfx_pipeline_state)) == 0;
108 }
109
110 struct zink_gfx_program *
111 zink_create_gfx_program(struct zink_screen *screen,
112 struct zink_shader *stages[PIPE_SHADER_TYPES - 1])
113 {
114 struct zink_gfx_program *prog = CALLOC_STRUCT(zink_gfx_program);
115 if (!prog)
116 goto fail;
117
118 for (int i = 0; i < ARRAY_SIZE(prog->pipelines); ++i) {
119 prog->pipelines[i] = _mesa_hash_table_create(NULL,
120 hash_gfx_pipeline_state,
121 equals_gfx_pipeline_state);
122 if (!prog->pipelines[i])
123 goto fail;
124 }
125
126 for (int i = 0; i < PIPE_SHADER_TYPES - 1; ++i)
127 prog->stages[i] = stages[i];
128
129 prog->dsl = create_desc_set_layout(screen->dev, stages,
130 &prog->num_descriptors);
131 if (!prog->dsl)
132 goto fail;
133
134 prog->layout = create_pipeline_layout(screen->dev, prog->dsl);
135 if (!prog->layout)
136 goto fail;
137
138 prog->render_passes = _mesa_set_create(NULL, _mesa_hash_pointer,
139 _mesa_key_pointer_equal);
140 if (!prog->render_passes)
141 goto fail;
142
143 return prog;
144
145 fail:
146 if (prog)
147 zink_destroy_gfx_program(screen, prog);
148 return NULL;
149 }
150
151 void
152 zink_destroy_gfx_program(struct zink_screen *screen,
153 struct zink_gfx_program *prog)
154 {
155 if (prog->layout)
156 vkDestroyPipelineLayout(screen->dev, prog->layout, NULL);
157
158 if (prog->dsl)
159 vkDestroyDescriptorSetLayout(screen->dev, prog->dsl, NULL);
160
161 /* unref all used render-passes */
162 if (prog->render_passes) {
163 set_foreach(prog->render_passes, entry) {
164 struct zink_render_pass *pres = (struct zink_render_pass *)entry->key;
165 zink_render_pass_reference(screen, &pres, NULL);
166 }
167 _mesa_set_destroy(prog->render_passes, NULL);
168 }
169
170 FREE(prog);
171 }
172
173 struct pipeline_cache_entry {
174 struct zink_gfx_pipeline_state state;
175 VkPipeline pipeline;
176 };
177
178 static VkPrimitiveTopology
179 primitive_topology(enum pipe_prim_type mode)
180 {
181 switch (mode) {
182 case PIPE_PRIM_POINTS:
183 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
184
185 case PIPE_PRIM_LINES:
186 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
187
188 case PIPE_PRIM_LINE_STRIP:
189 return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
190
191 case PIPE_PRIM_TRIANGLES:
192 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
193
194 case PIPE_PRIM_TRIANGLE_STRIP:
195 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
196
197 case PIPE_PRIM_TRIANGLE_FAN:
198 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
199
200 default:
201 unreachable("unexpected enum pipe_prim_type");
202 }
203 }
204
205 static void
206 reference_render_pass(struct zink_screen *screen,
207 struct zink_gfx_program *prog,
208 struct zink_render_pass *render_pass)
209 {
210 struct set_entry *entry = _mesa_set_search(prog->render_passes,
211 render_pass);
212 if (!entry) {
213 struct zink_render_pass *tmp = NULL;
214 entry = _mesa_set_add(prog->render_passes, render_pass);
215 zink_render_pass_reference(screen, &tmp, render_pass);
216 }
217 }
218
219 VkPipeline
220 zink_get_gfx_pipeline(struct zink_screen *screen,
221 struct zink_gfx_program *prog,
222 struct zink_gfx_pipeline_state *state,
223 enum pipe_prim_type mode)
224 {
225 assert(mode <= ARRAY_SIZE(prog->pipelines));
226
227 /* TODO: use pre-hashed versions to save some time (can re-hash only when
228 state changes) */
229 struct hash_entry *entry = _mesa_hash_table_search(prog->pipelines[mode], state);
230 if (!entry) {
231 VkPrimitiveTopology vkmode = primitive_topology(mode);
232 VkPipeline pipeline = zink_create_gfx_pipeline(screen->dev, prog,
233 state, vkmode);
234 if (pipeline == VK_NULL_HANDLE)
235 return VK_NULL_HANDLE;
236
237 struct pipeline_cache_entry *pc_entry = CALLOC_STRUCT(pipeline_cache_entry);
238 if (!pc_entry)
239 return VK_NULL_HANDLE;
240
241 memcpy(&pc_entry->state, state, sizeof(*state));
242 pc_entry->pipeline = pipeline;
243
244 entry = _mesa_hash_table_insert(prog->pipelines[mode], &pc_entry->state, pc_entry);
245 assert(entry);
246
247 reference_render_pass(screen, prog, state->render_pass);
248 }
249
250 return ((struct pipeline_cache_entry *)(entry->data))->pipeline;
251 }