af270d5d20be82a118bd4fe840a6702fdc1b3029
[mesa.git] / src / gallium / winsys / r600 / drm / radeon_ctx.c
1 /*
2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
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 * Authors:
24 * Jerome Glisse
25 */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "radeon_priv.h"
30 #include "radeon_drm.h"
31 #include "bof.h"
32
33 int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo)
34 {
35 if (ctx->nbo >= 2048)
36 return -EBUSY;
37 ctx->bo[ctx->nbo] = bo;
38 ctx->nbo++;
39 return 0;
40 }
41
42 struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc)
43 {
44 struct radeon_cs_reloc *greloc;
45 unsigned i;
46
47 greloc = (void *)(((u8 *)ctx->reloc) + reloc * 4);
48 for (i = 0; i < ctx->nbo; i++) {
49 if (ctx->bo[i]->handle == greloc->handle) {
50 return radeon_bo_incref(ctx->radeon, ctx->bo[i]);
51 }
52 }
53 fprintf(stderr, "%s no bo for reloc[%d 0x%08X] %d\n", __func__, reloc, greloc->handle, ctx->nbo);
54 return NULL;
55 }
56
57 void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement)
58 {
59 struct radeon_cs_reloc *greloc;
60 unsigned i;
61
62 placement[0] = 0;
63 placement[1] = 0;
64 greloc = (void *)(((u8 *)ctx->reloc) + reloc * 4);
65 for (i = 0; i < ctx->nbo; i++) {
66 if (ctx->bo[i]->handle == greloc->handle) {
67 placement[0] = greloc->read_domain | greloc->write_domain;
68 placement[1] = placement[0];
69 return;
70 }
71 }
72 }
73
74 static void radeon_ctx_clear(struct radeon_ctx *ctx)
75 {
76 ctx->draw_cpm4 = 0;
77 ctx->cpm4 = 0;
78 ctx->ndraw = 0;
79 ctx->nbo = 0;
80 ctx->nreloc = 0;
81 }
82
83 int radeon_ctx_init(struct radeon_ctx *ctx, struct radeon *radeon)
84 {
85 memset(ctx, 0, sizeof(struct radeon_ctx));
86 ctx->radeon = radeon_incref(radeon);
87 radeon_ctx_clear(ctx);
88 free(ctx->pm4);
89 ctx->cpm4 = 0;
90 ctx->pm4 = malloc(64 * 1024);
91 if (ctx->pm4 == NULL)
92 return -ENOMEM;
93 return 0;
94 }
95
96 static int radeon_ctx_state_bo(struct radeon_ctx *ctx, struct radeon_state *state)
97 {
98 unsigned i, j;
99 int r;
100
101 if (state == NULL)
102 return 0;
103 for (i = 0; i < state->nbo; i++) {
104 for (j = 0; j < ctx->nbo; j++) {
105 if (state->bo[i] == ctx->bo[j])
106 break;
107 }
108 if (j == ctx->nbo) {
109 radeon_bo_incref(ctx->radeon, state->bo[i]);
110 r = radeon_ctx_set_bo_new(ctx, state->bo[i]);
111 if (r)
112 return r;
113 }
114 }
115 return 0;
116 }
117
118 int radeon_ctx_submit(struct radeon_ctx *ctx)
119 {
120 struct drm_radeon_cs drmib;
121 struct drm_radeon_cs_chunk chunks[2];
122 uint64_t chunk_array[2];
123 int r = 0;
124
125 #if 0
126 for (r = 0; r < ctx->cpm4; r++) {
127 fprintf(stderr, "0x%08X\n", ctx->pm4[r]);
128 }
129 #endif
130 drmib.num_chunks = 2;
131 drmib.chunks = (uint64_t)(uintptr_t)chunk_array;
132 chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
133 chunks[0].length_dw = ctx->cpm4;
134 chunks[0].chunk_data = (uint64_t)(uintptr_t)ctx->pm4;
135 chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
136 chunks[1].length_dw = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
137 chunks[1].chunk_data = (uint64_t)(uintptr_t)ctx->reloc;
138 chunk_array[0] = (uint64_t)(uintptr_t)&chunks[0];
139 chunk_array[1] = (uint64_t)(uintptr_t)&chunks[1];
140 #if 1
141 r = drmCommandWriteRead(ctx->radeon->fd, DRM_RADEON_CS, &drmib,
142 sizeof(struct drm_radeon_cs));
143 #endif
144 radeon_ctx_clear(ctx);
145 return r;
146 }
147
148 static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo,
149 unsigned id, unsigned *placement)
150 {
151 unsigned i;
152
153 for (i = 0; i < ctx->nreloc; i++) {
154 if (ctx->reloc[i].handle == bo->handle) {
155 ctx->pm4[id] = i * sizeof(struct radeon_cs_reloc) / 4;
156 return 0;
157 }
158 }
159 if (ctx->nreloc >= 2048)
160 return -EINVAL;
161 ctx->reloc[ctx->nreloc].handle = bo->handle;
162 ctx->reloc[ctx->nreloc].read_domain = placement[0] | placement [1];
163 ctx->reloc[ctx->nreloc].write_domain = placement[0] | placement [1];
164 ctx->reloc[ctx->nreloc].flags = 0;
165 ctx->pm4[id] = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
166 ctx->nreloc++;
167 return 0;
168 }
169
170 static int radeon_ctx_state_schedule(struct radeon_ctx *ctx, struct radeon_state *state)
171 {
172 unsigned i, rid, bid, cid;
173 int r;
174
175 if (state == NULL)
176 return 0;
177 memcpy(&ctx->pm4[ctx->id], state->pm4, state->cpm4 * 4);
178 for (i = 0; i < state->nreloc; i++) {
179 rid = state->reloc_pm4_id[i];
180 bid = state->reloc_bo_id[i];
181 cid = ctx->id + rid;
182 r = radeon_ctx_reloc(ctx, state->bo[bid], cid,
183 &state->placement[bid * 2]);
184 if (r) {
185 fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->type);
186 return r;
187 }
188 }
189 ctx->id += state->cpm4;
190 return 0;
191 }
192
193 int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw)
194 {
195 unsigned cpm4, i;
196 int r = 0;
197
198 for (i = 0; i < draw->nstate; i++) {
199 r = radeon_ctx_state_bo(ctx, &draw->state[i]);
200 if (r)
201 return r;
202 }
203 r = radeon_draw_check(draw);
204 if (r)
205 return r;
206 if (draw->cpm4 >= RADEON_CTX_MAX_PM4) {
207 fprintf(stderr, "%s single draw too big %d, max %d\n",
208 __func__, draw->cpm4, RADEON_CTX_MAX_PM4);
209 return -EINVAL;
210 }
211 ctx->draw[ctx->ndraw] = *draw;
212 for (i = 0, cpm4 = 0; i < draw->nstate - 1; i++) {
213 ctx->draw[ctx->ndraw].state[i].valid &= ~2;
214 if (ctx->draw[ctx->ndraw].state[i].valid) {
215 if (ctx->ndraw > 1 && ctx->draw[ctx->ndraw - 1].state[i].valid) {
216 if (ctx->draw[ctx->ndraw - 1].state[i].pm4_crc == draw->state[i].pm4_crc)
217 continue;
218 }
219 ctx->draw[ctx->ndraw].state[i].valid |= 2;
220 cpm4 += ctx->draw[ctx->ndraw].state[i].cpm4;
221 }
222 }
223 /* The last state is the draw state always add it */
224 if (!draw->state[i].valid) {
225 fprintf(stderr, "%s no draw command\n", __func__);
226 return -EINVAL;
227 }
228 ctx->draw[ctx->ndraw].state[i].valid |= 2;
229 cpm4 += ctx->draw[ctx->ndraw].state[i].cpm4;
230 if ((ctx->draw_cpm4 + cpm4) > RADEON_CTX_MAX_PM4) {
231 /* need to flush */
232 return -EBUSY;
233 }
234 ctx->draw_cpm4 += cpm4;
235 ctx->ndraw++;
236 return 0;
237 }
238
239 int radeon_ctx_pm4(struct radeon_ctx *ctx)
240 {
241 unsigned i, j, c;
242 int r;
243
244 for (i = 0, c = 0, ctx->id = 0; i < ctx->ndraw; i++) {
245 for (j = 0; j < ctx->draw[i].nstate; j++) {
246 if (ctx->draw[i].state[j].valid & 2) {
247 r = radeon_ctx_state_schedule(ctx, &ctx->draw[i].state[j]);
248 if (r)
249 return r;
250 c += ctx->draw[i].state[j].cpm4;
251 }
252 }
253 }
254 if (ctx->id != ctx->draw_cpm4) {
255 fprintf(stderr, "%s miss predicted pm4 size %d for %d\n",
256 __func__, ctx->draw_cpm4, ctx->id);
257 return -EINVAL;
258 }
259 ctx->cpm4 = ctx->draw_cpm4;
260 return 0;
261 }
262
263 void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file)
264 {
265 bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root;
266 unsigned i;
267
268 root = device_id = bcs = blob = array = bo = size = handle = NULL;
269 root = bof_object();
270 if (root == NULL)
271 goto out_err;
272 device_id = bof_int32(ctx->radeon->device);
273 if (device_id == NULL)
274 return;
275 if (bof_object_set(root, "device_id", device_id))
276 goto out_err;
277 bof_decref(device_id);
278 device_id = NULL;
279 /* dump relocs */
280 printf("%d relocs\n", ctx->nreloc);
281 blob = bof_blob(ctx->nreloc * 16, ctx->reloc);
282 if (blob == NULL)
283 goto out_err;
284 if (bof_object_set(root, "reloc", blob))
285 goto out_err;
286 bof_decref(blob);
287 blob = NULL;
288 /* dump cs */
289 printf("%d pm4\n", ctx->cpm4);
290 blob = bof_blob(ctx->cpm4 * 4, ctx->pm4);
291 if (blob == NULL)
292 goto out_err;
293 if (bof_object_set(root, "pm4", blob))
294 goto out_err;
295 bof_decref(blob);
296 blob = NULL;
297 /* dump bo */
298 array = bof_array();
299 if (array == NULL)
300 goto out_err;
301 for (i = 0; i < ctx->nbo; i++) {
302 bo = bof_object();
303 if (bo == NULL)
304 goto out_err;
305 size = bof_int32(ctx->bo[i]->size);
306 printf("[%d] %d bo\n", i, size);
307 if (size == NULL)
308 goto out_err;
309 if (bof_object_set(bo, "size", size))
310 goto out_err;
311 bof_decref(size);
312 size = NULL;
313 handle = bof_int32(ctx->bo[i]->handle);
314 if (handle == NULL)
315 goto out_err;
316 if (bof_object_set(bo, "handle", handle))
317 goto out_err;
318 bof_decref(handle);
319 handle = NULL;
320 radeon_bo_map(ctx->radeon, ctx->bo[i]);
321 blob = bof_blob(ctx->bo[i]->size, ctx->bo[i]->data);
322 radeon_bo_unmap(ctx->radeon, ctx->bo[i]);
323 if (blob == NULL)
324 goto out_err;
325 if (bof_object_set(bo, "data", blob))
326 goto out_err;
327 bof_decref(blob);
328 blob = NULL;
329 if (bof_array_append(array, bo))
330 goto out_err;
331 bof_decref(bo);
332 bo = NULL;
333 }
334 if (bof_object_set(root, "bo", array))
335 goto out_err;
336 bof_dump_file(root, file);
337 printf("done dump\n");
338 out_err:
339 bof_decref(blob);
340 bof_decref(array);
341 bof_decref(bo);
342 bof_decref(size);
343 bof_decref(handle);
344 bof_decref(device_id);
345 bof_decref(root);
346 }