2bccbb578ec6c06b1933954a0384d495a0d7e843
[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 pan_pack(var->cpu, ATTRIBUTE, cfg) {
143 cfg.format = (MALI_RGBA32UI << 12);
144 cfg.unknown = true;
145 }
146
147 pan_pack(attr->cpu, ATTRIBUTE, cfg)
148 cfg.format = (MALI_RGBA32UI << 12);
149
150 pan_pack(var->cpu + 256, ATTRIBUTE_BUFFER, cfg) {
151 cfg.pointer = (var->gpu + 1024);
152 cfg.size = 1024;
153 }
154
155 pan_pack(attr->cpu + 256, ATTRIBUTE_BUFFER, cfg) {
156 cfg.pointer = (attr->gpu + 1024);
157 cfg.size = 1024;
158 }
159
160 if (sz_ubo)
161 memcpy(ubo->cpu + 1024, iubo, sz_ubo);
162
163 if (sz_attr)
164 memcpy(attr->cpu + 1024, iattr, sz_attr);
165
166 struct panfrost_bo *shmem = bit_bo_create(dev, 4096);
167 struct mali_shared_memory shmemp = {
168 .scratchpad = scratchpad->gpu,
169 .shared_workgroup_count = 0x1f,
170 };
171
172 memcpy(shmem->cpu, &shmemp, sizeof(shmemp));
173
174 struct mali_shader_meta meta = {
175 .shader = { .opaque = {
176 (uint32_t) shader->gpu & 0xFFFFFFFF, /* PC lo */
177 (uint32_t) (shader->gpu >> 32ull), /* PC hi */
178 (uint32_t) (1 << 16) | 1, /* attr/vary */
179 (uint32_t) 0, /* tex/sampl */
180 } },
181 .bifrost_props = { .opaque = { 0x80020001 } },
182 .bifrost_preload = { .opaque = { (sz_ubo / 16) << 15 } },
183 };
184
185 memcpy(shader_desc->cpu, &meta, sizeof(meta));
186 memcpy(shader->cpu, prog.compiled.data, prog.compiled.size);
187
188 struct bifrost_payload_vertex payload = {
189 .prefix = {
190 },
191 .postfix = {
192 .gl_enables = 0x2,
193 .shared_memory = shmem->gpu,
194 .shader = shader_desc->gpu,
195 .uniforms = ubo->gpu + 1024,
196 .uniform_buffers = ubo->gpu,
197 .attribute_meta = attr->gpu,
198 .attributes = attr->gpu + 256,
199 .varying_meta = var->gpu,
200 .varyings = var->gpu + 256,
201 },
202 };
203
204 panfrost_pack_work_groups_compute(&payload.prefix,
205 1, 1, 1,
206 1, 1, 1,
207 true);
208
209 payload.prefix.workgroups_x_shift_3 = 5;
210
211 struct panfrost_bo *bos[] = {
212 scratchpad, shmem, shader, shader_desc, ubo, var, attr
213 };
214
215 bool succ = bit_submit(dev, MALI_JOB_TYPE_VERTEX, &payload,
216 sizeof(payload), bos, ARRAY_SIZE(bos), debug);
217
218 /* Check the output varyings */
219
220 uint32_t *output = (uint32_t *) (var->cpu + 1024);
221 float *foutput = (float *) output;
222 float *fexpected = (float *) expected;
223
224 if (sz_expected) {
225 unsigned comp = memcmp(output, expected, sz_expected);
226 succ &= (comp == 0);
227
228 if (comp && (debug >= BIT_DEBUG_FAIL)) {
229 fprintf(stderr, "expected [");
230
231 for (unsigned i = 0; i < (sz_expected >> 2); ++i)
232 fprintf(stderr, "%08X /* %f */ ", expected[i], fexpected[i]);
233
234 fprintf(stderr, "], got [");
235
236 for (unsigned i = 0; i < (sz_expected >> 2); ++i)
237 fprintf(stderr, "%08X /* %f */ ", output[i], foutput[i]);
238
239 fprintf(stderr, "\n");
240 }
241 } else if (debug == BIT_DEBUG_ALL) {
242 fprintf(stderr, "got [");
243
244 for (unsigned i = 0; i < 4; ++i)
245 fprintf(stderr, "%08X /* %f */ ", output[i], foutput[i]);
246
247 fprintf(stderr, "\n");
248 }
249
250 return succ;
251 }