a131adda55a7d118cbd26b8bd216fd90424abb3d
[mesa.git] / src / panfrost / bifrost / test / bi_submit.c
1 /*
2 * Copyright (C) 2020 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * 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 NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE 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 * Authors (Collabora):
24 * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
25 */
26
27 #include "bit.h"
28 #include "panfrost/lib/decode.h"
29 #include "drm-uapi/panfrost_drm.h"
30 #include "panfrost/lib/pan_encoder.h"
31
32 /* Standalone compiler tests submitting jobs directly to the hardware. Uses the
33 * `bit` prefix for `BIfrost Tests` and because bit sounds wicked cool. */
34
35 static struct panfrost_bo *
36 bit_bo_create(struct panfrost_device *dev, size_t size)
37 {
38 struct panfrost_bo *bo = panfrost_bo_create(dev, size, PAN_BO_EXECUTE);
39 pandecode_inject_mmap(bo->gpu, bo->cpu, bo->size, NULL);
40 return bo;
41 }
42
43 struct panfrost_device *
44 bit_initialize(void *memctx)
45 {
46 int fd = drmOpenWithType("panfrost", NULL, DRM_NODE_RENDER);
47
48 if (fd < 0)
49 unreachable("No panfrost device found. Try chmod?");
50
51 struct panfrost_device *dev = rzalloc(memctx, struct panfrost_device);
52 panfrost_open_device(memctx, fd, dev);
53
54 pandecode_initialize(true);
55 printf("%X\n", dev->gpu_id);
56
57 return dev;
58 }
59
60 static bool
61 bit_submit(struct panfrost_device *dev,
62 enum mali_job_type T,
63 void *payload, size_t payload_size,
64 struct panfrost_bo **bos, size_t bo_count, enum bit_debug debug)
65 {
66 struct mali_job_descriptor_header header = {
67 .job_descriptor_size = MALI_JOB_64,
68 .job_type = T,
69 .job_index = 1
70 };
71
72 struct panfrost_bo *job = bit_bo_create(dev, 4096);
73 memcpy(job->cpu, &header, sizeof(header));
74 memcpy(job->cpu + sizeof(header), payload, payload_size);
75
76 uint32_t *bo_handles = calloc(sizeof(uint32_t), bo_count);
77
78 for (unsigned i = 0; i < bo_count; ++i)
79 bo_handles[i] = bos[i]->gem_handle;
80
81 uint32_t syncobj = 0;
82 int ret = 0;
83
84 ret = drmSyncobjCreate(dev->fd, DRM_SYNCOBJ_CREATE_SIGNALED, &syncobj);
85 assert(!ret);
86
87 struct drm_panfrost_submit submit = {
88 .jc = job->gpu,
89 .bo_handles = (uintptr_t) bo_handles,
90 .bo_handle_count = bo_count,
91 .out_sync = syncobj,
92 };
93
94 ret = drmIoctl(dev->fd, DRM_IOCTL_PANFROST_SUBMIT, &submit);
95 assert(!ret);
96 free(bo_handles);
97
98 drmSyncobjWait(dev->fd, &syncobj, 1, INT64_MAX, 0, NULL);
99 if (debug >= BIT_DEBUG_ALL)
100 pandecode_jc(submit.jc, true, dev->gpu_id, false);
101 return true;
102 }
103
104 /* Checks that the device is alive and responding to basic jobs as a sanity
105 * check - prerequisite to running code on the device. We test this via a
106 * WRITE_VALUE job */
107
108 bool
109 bit_sanity_check(struct panfrost_device *dev)
110 {
111 struct panfrost_bo *scratch = bit_bo_create(dev, 65536);
112 ((uint32_t *) scratch->cpu)[0] = 0xAA;
113
114 struct mali_payload_write_value payload = {
115 .address = scratch->gpu,
116 .value_descriptor = MALI_WRITE_VALUE_ZERO
117 };
118
119 struct panfrost_bo *bos[] = { scratch };
120 bool success = bit_submit(dev, MALI_JOB_TYPE_WRITE_VALUE,
121 &payload, sizeof(payload), bos, 1, false);
122
123 return success && (((uint8_t *) scratch->cpu)[0] == 0x0);
124 }
125
126 /* Constructs a vertex job */
127
128 bool
129 bit_vertex(struct panfrost_device *dev, panfrost_program prog,
130 uint32_t *iubo, size_t sz_ubo,
131 uint32_t *iattr, size_t sz_attr,
132 uint32_t *expected, size_t sz_expected, enum bit_debug debug)
133 {
134
135 struct panfrost_bo *scratchpad = bit_bo_create(dev, 4096);
136 struct panfrost_bo *shader = bit_bo_create(dev, prog.compiled.size);
137 struct panfrost_bo *shader_desc = bit_bo_create(dev, 4096);
138 struct panfrost_bo *ubo = bit_bo_create(dev, 4096);
139 struct panfrost_bo *var = bit_bo_create(dev, 4096);
140 struct panfrost_bo *attr = bit_bo_create(dev, 4096);
141
142 struct mali_attr_meta vmeta = {
143 .index = 0,
144 .format = MALI_RGBA32UI
145 };
146
147 union mali_attr vary = {
148 .elements = (var->gpu + 1024) | MALI_ATTR_LINEAR,
149 .size = 1024
150 };
151
152 union mali_attr attr_ = {
153 .elements = (attr->gpu + 1024) | MALI_ATTR_LINEAR,
154 .size = 1024
155 };
156
157 uint64_t my_ubo = MALI_MAKE_UBO(64, ubo->gpu + 1024);
158
159 memcpy(ubo->cpu, &my_ubo, sizeof(my_ubo));
160 memcpy(var->cpu, &vmeta, sizeof(vmeta));
161
162 vmeta.unknown1 = 0x2; /* XXX: only attrib? */
163 memcpy(attr->cpu, &vmeta, sizeof(vmeta));
164 memcpy(var->cpu + 256, &vary, sizeof(vary));
165 memcpy(attr->cpu + 256, &attr_, sizeof(vary));
166
167 if (sz_ubo)
168 memcpy(ubo->cpu + 1024, iubo, sz_ubo);
169
170 if (sz_attr)
171 memcpy(attr->cpu + 1024, iattr, sz_attr);
172
173 struct panfrost_bo *shmem = bit_bo_create(dev, 4096);
174 struct mali_shared_memory shmemp = {
175 .scratchpad = scratchpad->gpu,
176 .shared_workgroup_count = 0x1f,
177 };
178
179 memcpy(shmem->cpu, &shmemp, sizeof(shmemp));
180
181 struct mali_shader_meta meta = {
182 .shader = shader->gpu,
183 .attribute_count = 1,
184 .varying_count = 1,
185 .bifrost1 = {
186 .unk1 = 0x800200,
187 .uniform_buffer_count = 1,
188 },
189 .bifrost2 = {
190 .unk3 = 0x0,
191 .preload_regs = 0xc0,
192 .uniform_count = sz_ubo / 16,
193 .unk4 = 0x0,
194 },
195 };
196
197 memcpy(shader_desc->cpu, &meta, sizeof(meta));
198 memcpy(shader->cpu, prog.compiled.data, prog.compiled.size);
199
200 struct bifrost_payload_vertex payload = {
201 .prefix = {
202 },
203 .postfix = {
204 .gl_enables = 0x2,
205 .shared_memory = shmem->gpu,
206 .shader = shader_desc->gpu,
207 .uniforms = ubo->gpu + 1024,
208 .uniform_buffers = ubo->gpu,
209 .attribute_meta = attr->gpu,
210 .attributes = attr->gpu + 256,
211 .varying_meta = var->gpu,
212 .varyings = var->gpu + 256,
213 },
214 };
215
216 panfrost_pack_work_groups_compute(&payload.prefix,
217 1, 1, 1,
218 1, 1, 1,
219 true);
220
221 payload.prefix.workgroups_x_shift_3 = 5;
222
223 struct panfrost_bo *bos[] = {
224 scratchpad, shmem, shader, shader_desc, ubo, var, attr
225 };
226
227 bool succ = bit_submit(dev, MALI_JOB_TYPE_VERTEX, &payload,
228 sizeof(payload), bos, ARRAY_SIZE(bos), debug);
229
230 /* Check the output varyings */
231
232 uint32_t *output = (uint32_t *) (var->cpu + 1024);
233 float *foutput = (float *) output;
234 float *fexpected = (float *) expected;
235
236 if (sz_expected) {
237 unsigned comp = memcmp(output, expected, sz_expected);
238 succ &= (comp == 0);
239
240 if (comp && (debug >= BIT_DEBUG_FAIL)) {
241 fprintf(stderr, "expected [");
242
243 for (unsigned i = 0; i < (sz_expected >> 2); ++i)
244 fprintf(stderr, "%08X /* %f */ ", expected[i], fexpected[i]);
245
246 fprintf(stderr, "], got [");
247
248 for (unsigned i = 0; i < (sz_expected >> 2); ++i)
249 fprintf(stderr, "%08X /* %f */ ", output[i], foutput[i]);
250
251 fprintf(stderr, "\n");
252 }
253 } else if (debug == BIT_DEBUG_ALL) {
254 fprintf(stderr, "got [");
255
256 for (unsigned i = 0; i < 4; ++i)
257 fprintf(stderr, "%08X /* %f */ ", output[i], foutput[i]);
258
259 fprintf(stderr, "\n");
260 }
261
262 return succ;
263 }