• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
bit_bo_create(struct panfrost_device * dev,size_t size)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->ptr.gpu, bo->ptr.cpu, bo->size, NULL);
40         return bo;
41 }
42 
43 struct panfrost_device *
bit_initialize(void * memctx)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
bit_submit(struct panfrost_device * dev,enum mali_job_type T,void * payload,size_t payload_size,struct panfrost_bo ** bos,size_t bo_count,enum bit_debug debug)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 panfrost_bo *job = bit_bo_create(dev, 4096);
67         pan_pack(job->ptr.cpu, JOB_HEADER, cfg) {
68                 cfg.type = T;
69                 cfg.index = 1;
70         }
71         memcpy(job->ptr.cpu + MALI_JOB_HEADER_LENGTH, payload, payload_size);
72 
73         uint32_t *bo_handles = calloc(sizeof(uint32_t), bo_count);
74 
75         for (unsigned i = 0; i < bo_count; ++i)
76                 bo_handles[i] = bos[i]->gem_handle;
77 
78         uint32_t syncobj = 0;
79         int ret = 0;
80 
81         ret = drmSyncobjCreate(dev->fd, DRM_SYNCOBJ_CREATE_SIGNALED, &syncobj);
82         assert(!ret);
83 
84         struct drm_panfrost_submit submit = {
85                 .jc = job->ptr.gpu,
86                 .bo_handles = (uintptr_t) bo_handles,
87                 .bo_handle_count = bo_count,
88                 .out_sync = syncobj,
89         };
90 
91         ret = drmIoctl(dev->fd, DRM_IOCTL_PANFROST_SUBMIT, &submit);
92         assert(!ret);
93         free(bo_handles);
94 
95         drmSyncobjWait(dev->fd, &syncobj, 1, INT64_MAX, 0, NULL);
96         if (debug >= BIT_DEBUG_ALL)
97                 pandecode_jc(submit.jc, true, dev->gpu_id, false);
98         return true;
99 }
100 
101 /* Checks that the device is alive and responding to basic jobs as a sanity
102  * check - prerequisite to running code on the device. We test this via a
103  * WRITE_VALUE job */
104 
105 bool
bit_sanity_check(struct panfrost_device * dev)106 bit_sanity_check(struct panfrost_device *dev)
107 {
108         struct panfrost_bo *scratch = bit_bo_create(dev, 65536);
109         ((uint32_t *) scratch->ptr.cpu)[0] = 0xAA;
110 
111         struct mali_write_value_job_payload_packed payload;
112 
113         pan_pack(&payload, WRITE_VALUE_JOB_PAYLOAD, cfg) {
114                 cfg.address = scratch->ptr.gpu;
115                 cfg.type = MALI_WRITE_VALUE_TYPE_ZERO;
116         };
117 
118         struct panfrost_bo *bos[] = { scratch };
119         bool success = bit_submit(dev, MALI_JOB_TYPE_WRITE_VALUE,
120                         &payload, sizeof(payload), bos, 1, false);
121 
122         return success && (((uint8_t *) scratch->ptr.cpu)[0] == 0x0);
123 }
124 
125 /* Constructs a vertex job */
126 
127 bool
bit_vertex(struct panfrost_device * dev,panfrost_program * prog,uint32_t * iubo,size_t sz_ubo,uint32_t * iattr,size_t sz_attr,uint32_t * expected,size_t sz_expected,enum bit_debug debug)128 bit_vertex(struct panfrost_device *dev, panfrost_program *prog,
129                 uint32_t *iubo, size_t sz_ubo,
130                 uint32_t *iattr, size_t sz_attr,
131                 uint32_t *expected, size_t sz_expected, enum bit_debug debug)
132 {
133         struct panfrost_bo *shader = bit_bo_create(dev, prog->compiled.size);
134         struct panfrost_bo *shader_desc = bit_bo_create(dev, 4096);
135         struct panfrost_bo *ubo = bit_bo_create(dev, 4096);
136         struct panfrost_bo *var = bit_bo_create(dev, 4096);
137         struct panfrost_bo *attr = bit_bo_create(dev, 4096);
138 
139         pan_pack(attr->ptr.cpu, ATTRIBUTE, cfg) {
140                 cfg.format = (MALI_RGBA32UI << 12);
141                 cfg.offset_enable = true;
142         }
143 
144         pan_pack(var->ptr.cpu, ATTRIBUTE, cfg) {
145                 cfg.format = (MALI_RGBA32UI << 12);
146                 cfg.offset_enable = false;
147         }
148 
149         pan_pack(var->ptr.cpu + 256, ATTRIBUTE_BUFFER, cfg) {
150                 cfg.pointer = (var->ptr.gpu + 1024);
151                 cfg.size = 1024;
152         }
153 
154         pan_pack(attr->ptr.cpu + 256, ATTRIBUTE_BUFFER, cfg) {
155                 cfg.pointer = (attr->ptr.gpu + 1024);
156                 cfg.size = 1024;
157         }
158 
159         pan_pack(ubo->ptr.cpu, UNIFORM_BUFFER, cfg) {
160                 cfg.entries = sz_ubo / 16;
161                 cfg.pointer = ubo->ptr.gpu + 1024;
162         }
163 
164         if (sz_ubo)
165                 memcpy(ubo->ptr.cpu + 1024, iubo, sz_ubo);
166 
167         if (sz_attr)
168                 memcpy(attr->ptr.cpu + 1024, iattr, sz_attr);
169 
170         struct panfrost_bo *shmem = bit_bo_create(dev, 4096);
171 
172         pan_pack(shmem->ptr.cpu, LOCAL_STORAGE, cfg) {
173                 cfg.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM;
174         }
175 
176         pan_pack(shader_desc->ptr.cpu, RENDERER_STATE, cfg) {
177                 cfg.shader.shader = shader->ptr.gpu;
178                 cfg.shader.attribute_count = cfg.shader.varying_count = 1;
179                 cfg.properties.uniform_buffer_count = 1;
180                 cfg.properties.bifrost.zs_update_operation = MALI_PIXEL_KILL_STRONG_EARLY;
181                 cfg.preload.vertex.vertex_id = true;
182                 cfg.preload.vertex.instance_id = true;
183                 cfg.preload.uniform_count = (sz_ubo / 16);
184         }
185 
186         memcpy(shader->ptr.cpu, prog->compiled.data, prog->compiled.size);
187 
188         struct mali_compute_job_packed job;
189 
190         pan_section_pack(&job, COMPUTE_JOB, PARAMETERS, cfg) {
191                 cfg.job_task_split = 5;
192         }
193 
194         pan_section_pack(&job, COMPUTE_JOB, DRAW, cfg) {
195                 cfg.draw_descriptor_is_64b = true;
196                 cfg.thread_storage = shmem->ptr.gpu;
197                 cfg.state = shader_desc->ptr.gpu;
198                 cfg.push_uniforms = ubo->ptr.gpu + 1024;
199                 cfg.uniform_buffers = ubo->ptr.gpu;
200                 cfg.attributes = attr->ptr.gpu;
201                 cfg.attribute_buffers = attr->ptr.gpu + 256;
202                 cfg.varyings = var->ptr.gpu;
203                 cfg.varying_buffers = var->ptr.gpu + 256;
204         }
205 
206         void *invocation = pan_section_ptr(&job, COMPUTE_JOB, INVOCATION);
207         panfrost_pack_work_groups_compute(invocation,
208                                           1, 1, 1,
209                                           1, 1, 1,
210                                           true);
211 
212         struct panfrost_bo *bos[] = {
213                 shmem, shader, shader_desc, ubo, var, attr
214         };
215 
216         bool succ = bit_submit(dev, MALI_JOB_TYPE_VERTEX,
217                                ((void *)&job) + MALI_JOB_HEADER_LENGTH,
218                                MALI_COMPUTE_JOB_LENGTH - MALI_JOB_HEADER_LENGTH,
219                                bos, ARRAY_SIZE(bos), debug);
220 
221         /* Check the output varyings */
222 
223         uint32_t *output = (uint32_t *) (var->ptr.cpu + 1024);
224         float *foutput = (float *) output;
225         float *fexpected = (float *) expected;
226 
227         if (sz_expected) {
228                 unsigned comp = memcmp(output, expected, sz_expected);
229                 succ &= (comp == 0);
230 
231                 if (comp && (debug >= BIT_DEBUG_FAIL)) {
232                         fprintf(stderr, "expected [");
233 
234                         for (unsigned i = 0; i < (sz_expected >> 2); ++i)
235                                 fprintf(stderr, "%08X /* %f */ ", expected[i], fexpected[i]);
236 
237                         fprintf(stderr, "], got [");
238 
239                         for (unsigned i = 0; i < (sz_expected >> 2); ++i)
240                                 fprintf(stderr, "%08X /* %f */ ", output[i], foutput[i]);
241 
242                         fprintf(stderr, "\n");
243                 }
244         } else if (debug == BIT_DEBUG_ALL) {
245                 fprintf(stderr, "got [");
246 
247                 for (unsigned i = 0; i < 4; ++i)
248                         fprintf(stderr, "%08X /* %f */ ", output[i], foutput[i]);
249 
250                 fprintf(stderr, "\n");
251         }
252 
253         return succ;
254 }
255