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