1 /*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include <stdbool.h>
25 #include <stddef.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <vulkan/vulkan_core.h>
29
30 #include "compiler/shader_enums.h"
31 #include "hwdef/rogue_hw_utils.h"
32 #include "pvr_device_info.h"
33 #include "pvr_hardcode.h"
34 #include "pvr_private.h"
35 #include "rogue/rogue.h"
36 #include "usc/hardcoded_apps/pvr_simple_compute.h"
37 #include "util/macros.h"
38 #include "util/u_dynarray.h"
39 #include "util/u_process.h"
40
41 /**
42 * \file pvr_hardcode.c
43 *
44 * \brief Contains hard coding functions.
45 * This should eventually be deleted as the compiler becomes more capable.
46 */
47
48 #define PVR_AXE_1_16M_BVNC PVR_BVNC_PACK(33, 15, 11, 3)
49 #define PVR_GX6250_BVNC PVR_BVNC_PACK(4, 40, 2, 51)
50
51 #define util_dynarray_append_mem(buf, size, mem) \
52 memcpy(util_dynarray_grow_bytes((buf), 1, size), mem, size)
53
54 enum pvr_hard_code_shader_type {
55 PVR_HARD_CODE_SHADER_TYPE_COMPUTE,
56 PVR_HARD_CODE_SHADER_TYPE_GRAPHICS,
57 };
58
59 static const struct pvr_hard_coding_data {
60 const char *const name;
61 uint64_t bvnc;
62 enum pvr_hard_code_shader_type type;
63
64 union {
65 struct {
66 const uint8_t *const shader;
67 size_t shader_size;
68
69 /* Note that the bo field will be unused. */
70 const struct pvr_compute_shader_state shader_info;
71
72 const struct pvr_hard_code_compute_build_info build_info;
73 } compute;
74
75 struct {
76 /* Mask of MESA_SHADER_* (gl_shader_stage). */
77 uint32_t flags;
78
79 uint8_t *const *const vert_shaders;
80 unsigned *vert_shader_sizes;
81 uint8_t *const *const frag_shaders;
82 unsigned *frag_shader_sizes;
83
84 const struct pvr_vertex_shader_state *const *const vert_shader_states;
85 const struct pvr_fragment_shader_state *const *const frag_shader_states;
86
87 const struct pvr_hard_code_graphics_build_info *const
88 *const build_infos;
89
90 uint32_t shader_count;
91 } graphics;
92 };
93
94 } hard_coding_table[] = {
95 {
96 .name = "simple-compute",
97 .bvnc = PVR_GX6250_BVNC,
98 .type = PVR_HARD_CODE_SHADER_TYPE_COMPUTE,
99
100 .compute = {
101 .shader = pvr_simple_compute_shader,
102 .shader_size = sizeof(pvr_simple_compute_shader),
103
104 .shader_info = {
105 .uses_atomic_ops = false,
106 .uses_barrier = false,
107 .uses_num_workgroups = false,
108
109 .const_shared_reg_count = 4,
110 .input_register_count = 8,
111 .work_size = 1 * 1 * 1,
112 .coefficient_register_count = 4,
113 },
114
115 .build_info = {
116 .ubo_data = { 0 },
117 .compile_time_consts_data = {
118 .static_consts = { 0 },
119 },
120
121 .local_invocation_regs = { 0, 1 },
122 .work_group_regs = { 0, 1, 2 },
123 .barrier_reg = ROGUE_REG_UNUSED,
124 .usc_temps = 0,
125
126 .explicit_conts_usage = {
127 .start_offset = 0,
128 },
129 },
130 }
131 },
132 };
133
134 static inline uint64_t
pvr_device_get_bvnc(const struct pvr_device_info * const dev_info)135 pvr_device_get_bvnc(const struct pvr_device_info *const dev_info)
136 {
137 const struct pvr_device_ident *const ident = &dev_info->ident;
138
139 return PVR_BVNC_PACK(ident->b, ident->v, ident->n, ident->c);
140 }
141
pvr_has_hard_coded_shaders(const struct pvr_device_info * const dev_info)142 bool pvr_has_hard_coded_shaders(const struct pvr_device_info *const dev_info)
143 {
144 const char *const program = util_get_process_name();
145 const uint64_t bvnc = pvr_device_get_bvnc(dev_info);
146
147 for (uint32_t i = 0; i < ARRAY_SIZE(hard_coding_table); i++) {
148 if (bvnc != hard_coding_table[i].bvnc)
149 continue;
150
151 if (strcmp(program, hard_coding_table[i].name) == 0)
152 return true;
153 }
154
155 return false;
156 }
157
158 static const struct pvr_hard_coding_data *
pvr_get_hard_coding_data(const struct pvr_device_info * const dev_info)159 pvr_get_hard_coding_data(const struct pvr_device_info *const dev_info)
160 {
161 const char *const program = util_get_process_name();
162 const uint64_t bvnc = pvr_device_get_bvnc(dev_info);
163
164 for (uint32_t i = 0; i < ARRAY_SIZE(hard_coding_table); i++) {
165 if (bvnc != hard_coding_table[i].bvnc)
166 continue;
167
168 if (strcmp(program, hard_coding_table[i].name) == 0)
169 return &hard_coding_table[i];
170 }
171
172 mesa_loge("Could not find hard coding data for %s", program);
173
174 return NULL;
175 }
176
pvr_hard_code_compute_pipeline(struct pvr_device * const device,struct pvr_compute_shader_state * const shader_state_out,struct pvr_hard_code_compute_build_info * const build_info_out)177 VkResult pvr_hard_code_compute_pipeline(
178 struct pvr_device *const device,
179 struct pvr_compute_shader_state *const shader_state_out,
180 struct pvr_hard_code_compute_build_info *const build_info_out)
181 {
182 const uint32_t cache_line_size =
183 rogue_get_slc_cache_line_size(&device->pdevice->dev_info);
184 const struct pvr_hard_coding_data *const data =
185 pvr_get_hard_coding_data(&device->pdevice->dev_info);
186
187 assert(data->type == PVR_HARD_CODE_SHADER_TYPE_COMPUTE);
188
189 mesa_logd("Hard coding compute pipeline for %s", data->name);
190
191 *build_info_out = data->compute.build_info;
192 *shader_state_out = data->compute.shader_info;
193
194 return pvr_gpu_upload_usc(device,
195 data->compute.shader,
196 data->compute.shader_size,
197 cache_line_size,
198 &shader_state_out->bo);
199 }
200
201 uint32_t
pvr_hard_code_graphics_get_flags(const struct pvr_device_info * const dev_info)202 pvr_hard_code_graphics_get_flags(const struct pvr_device_info *const dev_info)
203 {
204 const struct pvr_hard_coding_data *const data =
205 pvr_get_hard_coding_data(dev_info);
206
207 assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS);
208
209 return data->graphics.flags;
210 }
211
pvr_hard_code_graphics_shader(const struct pvr_device_info * const dev_info,uint32_t pipeline_n,gl_shader_stage stage,struct util_dynarray * shader_out)212 void pvr_hard_code_graphics_shader(const struct pvr_device_info *const dev_info,
213 uint32_t pipeline_n,
214 gl_shader_stage stage,
215 struct util_dynarray *shader_out)
216 {
217 const struct pvr_hard_coding_data *const data =
218 pvr_get_hard_coding_data(dev_info);
219
220 assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS);
221 assert(pipeline_n < data->graphics.shader_count);
222 assert(data->graphics.flags & BITFIELD_BIT(stage));
223
224 mesa_logd("Hard coding %s stage shader for \"%s\" demo.",
225 _mesa_shader_stage_to_string(stage),
226 data->name);
227
228 switch (stage) {
229 case MESA_SHADER_VERTEX:
230 util_dynarray_append_mem(shader_out,
231 data->graphics.vert_shader_sizes[pipeline_n],
232 data->graphics.vert_shaders[pipeline_n]);
233 break;
234
235 case MESA_SHADER_FRAGMENT:
236 util_dynarray_append_mem(shader_out,
237 data->graphics.frag_shader_sizes[pipeline_n],
238 data->graphics.frag_shaders[pipeline_n]);
239 break;
240
241 default:
242 unreachable("Unsupported stage.");
243 }
244 }
245
pvr_hard_code_graphics_vertex_state(const struct pvr_device_info * const dev_info,uint32_t pipeline_n,struct pvr_vertex_shader_state * const vert_state_out)246 void pvr_hard_code_graphics_vertex_state(
247 const struct pvr_device_info *const dev_info,
248 uint32_t pipeline_n,
249 struct pvr_vertex_shader_state *const vert_state_out)
250 {
251 const struct pvr_hard_coding_data *const data =
252 pvr_get_hard_coding_data(dev_info);
253
254 assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS);
255 assert(pipeline_n < data->graphics.shader_count);
256 assert(data->graphics.flags & BITFIELD_BIT(MESA_SHADER_VERTEX));
257
258 *vert_state_out = *data->graphics.vert_shader_states[0];
259 }
260
pvr_hard_code_graphics_fragment_state(const struct pvr_device_info * const dev_info,uint32_t pipeline_n,struct pvr_fragment_shader_state * const frag_state_out)261 void pvr_hard_code_graphics_fragment_state(
262 const struct pvr_device_info *const dev_info,
263 uint32_t pipeline_n,
264 struct pvr_fragment_shader_state *const frag_state_out)
265 {
266 const struct pvr_hard_coding_data *const data =
267 pvr_get_hard_coding_data(dev_info);
268
269 assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS);
270 assert(pipeline_n < data->graphics.shader_count);
271 assert(data->graphics.flags & BITFIELD_BIT(MESA_SHADER_FRAGMENT));
272
273 *frag_state_out = *data->graphics.frag_shader_states[0];
274 }
275
pvr_hard_code_graphics_get_build_info(const struct pvr_device_info * const dev_info,uint32_t pipeline_n,gl_shader_stage stage,struct rogue_common_build_data * const common_build_data,struct rogue_build_data * const build_data,struct pvr_explicit_constant_usage * const explicit_const_usage)276 void pvr_hard_code_graphics_get_build_info(
277 const struct pvr_device_info *const dev_info,
278 uint32_t pipeline_n,
279 gl_shader_stage stage,
280 struct rogue_common_build_data *const common_build_data,
281 struct rogue_build_data *const build_data,
282 struct pvr_explicit_constant_usage *const explicit_const_usage)
283 {
284 const struct pvr_hard_coding_data *const data =
285 pvr_get_hard_coding_data(dev_info);
286
287 assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS);
288 assert(pipeline_n < data->graphics.shader_count);
289 assert(data->graphics.flags & BITFIELD_BIT(stage));
290
291 switch (stage) {
292 case MESA_SHADER_VERTEX:
293 assert(data->graphics.build_infos[pipeline_n]->vert_common_data.temps ==
294 data->graphics.vert_shader_states[pipeline_n]
295 ->stage_state.pds_temps_count);
296
297 assert(data->graphics.build_infos[pipeline_n]->vert_common_data.coeffs ==
298 data->graphics.vert_shader_states[pipeline_n]
299 ->stage_state.coefficient_size);
300
301 build_data->vs = data->graphics.build_infos[pipeline_n]->stage_data.vs;
302 *common_build_data =
303 data->graphics.build_infos[pipeline_n]->vert_common_data;
304 *explicit_const_usage =
305 data->graphics.build_infos[pipeline_n]->vert_explicit_conts_usage;
306
307 break;
308
309 case MESA_SHADER_FRAGMENT:
310 assert(data->graphics.build_infos[pipeline_n]->frag_common_data.temps ==
311 data->graphics.frag_shader_states[pipeline_n]
312 ->stage_state.pds_temps_count);
313
314 assert(data->graphics.build_infos[pipeline_n]->frag_common_data.coeffs ==
315 data->graphics.frag_shader_states[pipeline_n]
316 ->stage_state.coefficient_size);
317
318 build_data->fs = data->graphics.build_infos[pipeline_n]->stage_data.fs;
319 *common_build_data =
320 data->graphics.build_infos[pipeline_n]->frag_common_data;
321 *explicit_const_usage =
322 data->graphics.build_infos[pipeline_n]->frag_explicit_conts_usage;
323
324 break;
325
326 default:
327 unreachable("Unsupported stage.");
328 }
329 }
330
pvr_hard_code_get_idfwdf_program(const struct pvr_device_info * const dev_info,struct util_dynarray * program_out,uint32_t * usc_shareds_out,uint32_t * usc_temps_out)331 void pvr_hard_code_get_idfwdf_program(
332 const struct pvr_device_info *const dev_info,
333 struct util_dynarray *program_out,
334 uint32_t *usc_shareds_out,
335 uint32_t *usc_temps_out)
336 {
337 static const uint8_t shader[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
338
339 mesa_loge("No hard coded idfwdf program. Returning empty program.");
340
341 util_dynarray_append_mem(program_out, ARRAY_SIZE(shader), &shader[0]);
342
343 *usc_shareds_out = 12U;
344 *usc_temps_out = 4U;
345 }
346
pvr_hard_code_get_passthrough_vertex_shader(const struct pvr_device_info * const dev_info,struct util_dynarray * program_out)347 void pvr_hard_code_get_passthrough_vertex_shader(
348 const struct pvr_device_info *const dev_info,
349 struct util_dynarray *program_out)
350 {
351 static const uint8_t shader[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
352
353 mesa_loge(
354 "No hard coded passthrough vertex shader. Returning empty shader.");
355
356 util_dynarray_append_mem(program_out, ARRAY_SIZE(shader), &shader[0]);
357 };
358
359 /* Render target array (RTA). */
pvr_hard_code_get_passthrough_rta_vertex_shader(const struct pvr_device_info * const dev_info,struct util_dynarray * program_out)360 void pvr_hard_code_get_passthrough_rta_vertex_shader(
361 const struct pvr_device_info *const dev_info,
362 struct util_dynarray *program_out)
363 {
364 uint32_t shader[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
365
366 util_dynarray_append_mem(program_out, ARRAY_SIZE(shader), &shader);
367
368 mesa_loge("No hard coded passthrough rta vertex shader. Returning "
369 "empty shader.");
370 }
371