1a12c1023e1bcec105afc25450395c89a22e080b
[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 void *ptr;
36
37 ptr = realloc(ctx->bo, sizeof(struct radeon_bo) * (ctx->nbo + 1));
38 if (ptr == NULL) {
39 return -ENOMEM;
40 }
41 ctx->bo = ptr;
42 ctx->bo[ctx->nbo] = bo;
43 ctx->nbo++;
44 return 0;
45 }
46
47 struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc)
48 {
49 struct radeon_cs_reloc *greloc;
50 unsigned i;
51
52 greloc = (void *)(((u8 *)ctx->reloc) + reloc * 4);
53 for (i = 0; i < ctx->nbo; i++) {
54 if (ctx->bo[i]->handle == greloc->handle) {
55 return radeon_bo_incref(ctx->radeon, ctx->bo[i]);
56 }
57 }
58 fprintf(stderr, "%s no bo for reloc[%d 0x%08X] %d\n", __func__, reloc, greloc->handle, ctx->nbo);
59 return NULL;
60 }
61
62 void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement)
63 {
64 struct radeon_cs_reloc *greloc;
65 unsigned i;
66
67 placement[0] = 0;
68 placement[1] = 0;
69 greloc = (void *)(((u8 *)ctx->reloc) + reloc * 4);
70 for (i = 0; i < ctx->nbo; i++) {
71 if (ctx->bo[i]->handle == greloc->handle) {
72 placement[0] = greloc->read_domain | greloc->write_domain;
73 placement[1] = placement[0];
74 return;
75 }
76 }
77 }
78
79 struct radeon_ctx *radeon_ctx(struct radeon *radeon)
80 {
81 struct radeon_ctx *ctx;
82
83 if (radeon == NULL)
84 return NULL;
85 ctx = calloc(1, sizeof(*ctx));
86 if (ctx == NULL)
87 return NULL;
88 ctx->radeon = radeon_incref(radeon);
89 return ctx;
90 }
91
92 struct radeon_ctx *radeon_ctx_incref(struct radeon_ctx *ctx)
93 {
94 ctx->refcount++;
95 return ctx;
96 }
97
98 struct radeon_ctx *radeon_ctx_decref(struct radeon_ctx *ctx)
99 {
100 unsigned i;
101
102 if (ctx == NULL)
103 return NULL;
104 if (--ctx->refcount > 0) {
105 return NULL;
106 }
107
108 for (i = 0; i < ctx->ndraw; i++) {
109 ctx->draw[i] = radeon_draw_decref(ctx->draw[i]);
110 }
111 for (i = 0; i < ctx->nbo; i++) {
112 ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]);
113 }
114 ctx->radeon = radeon_decref(ctx->radeon);
115 free(ctx->state);
116 free(ctx->draw);
117 free(ctx->bo);
118 free(ctx->pm4);
119 free(ctx->reloc);
120 memset(ctx, 0, sizeof(*ctx));
121 free(ctx);
122 return NULL;
123 }
124
125 static int radeon_ctx_state_bo(struct radeon_ctx *ctx, struct radeon_state *state)
126 {
127 unsigned i, j;
128 int r;
129
130 if (state == NULL)
131 return 0;
132 for (i = 0; i < state->nbo; i++) {
133 for (j = 0; j < ctx->nbo; j++) {
134 if (state->bo[i] == ctx->bo[j])
135 break;
136 }
137 if (j == ctx->nbo) {
138 radeon_bo_incref(ctx->radeon, state->bo[i]);
139 r = radeon_ctx_set_bo_new(ctx, state->bo[i]);
140 if (r)
141 return r;
142 }
143 }
144 return 0;
145 }
146
147
148 int radeon_ctx_submit(struct radeon_ctx *ctx)
149 {
150 struct drm_radeon_cs drmib;
151 struct drm_radeon_cs_chunk chunks[2];
152 uint64_t chunk_array[2];
153 int r = 0;
154
155 if (!ctx->cpm4)
156 return 0;
157 #if 0
158 for (r = 0; r < ctx->cpm4; r++) {
159 fprintf(stderr, "0x%08X\n", ctx->pm4[r]);
160 }
161 #endif
162 drmib.num_chunks = 2;
163 drmib.chunks = (uint64_t)(uintptr_t)chunk_array;
164 chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
165 chunks[0].length_dw = ctx->cpm4;
166 chunks[0].chunk_data = (uint64_t)(uintptr_t)ctx->pm4;
167 chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
168 chunks[1].length_dw = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
169 chunks[1].chunk_data = (uint64_t)(uintptr_t)ctx->reloc;
170 chunk_array[0] = (uint64_t)(uintptr_t)&chunks[0];
171 chunk_array[1] = (uint64_t)(uintptr_t)&chunks[1];
172 #if 1
173 r = drmCommandWriteRead(ctx->radeon->fd, DRM_RADEON_CS, &drmib,
174 sizeof(struct drm_radeon_cs));
175 #endif
176 return r;
177 }
178
179 static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo,
180 unsigned id, unsigned *placement)
181 {
182 unsigned i;
183 struct radeon_cs_reloc *ptr;
184
185 for (i = 0; i < ctx->nreloc; i++) {
186 if (ctx->reloc[i].handle == bo->handle) {
187 ctx->pm4[id] = i * sizeof(struct radeon_cs_reloc) / 4;
188 return 0;
189 }
190 }
191 ptr = realloc(ctx->reloc, sizeof(struct radeon_cs_reloc) * (ctx->nreloc + 1));
192 if (ptr == NULL)
193 return -ENOMEM;
194 ctx->reloc = ptr;
195 ptr[ctx->nreloc].handle = bo->handle;
196 ptr[ctx->nreloc].read_domain = placement[0] | placement [1];
197 ptr[ctx->nreloc].write_domain = placement[0] | placement [1];
198 ptr[ctx->nreloc].flags = 0;
199 ctx->pm4[id] = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
200 ctx->nreloc++;
201 return 0;
202 }
203
204 static int radeon_ctx_state_schedule(struct radeon_ctx *ctx, struct radeon_state *state)
205 {
206 unsigned i, rid, bid, cid;
207 int r;
208
209 if (state == NULL)
210 return 0;
211 memcpy(&ctx->pm4[ctx->id], state->pm4, state->cpm4 * 4);
212 for (i = 0; i < state->nreloc; i++) {
213 rid = state->reloc_pm4_id[i];
214 bid = state->reloc_bo_id[i];
215 cid = ctx->id + rid;
216 r = radeon_ctx_reloc(ctx, state->bo[bid], cid,
217 &state->placement[bid * 2]);
218 if (r) {
219 fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->stype->stype);
220 return r;
221 }
222 }
223 ctx->id += state->cpm4;
224 return 0;
225 }
226
227 int radeon_ctx_set_query_state(struct radeon_ctx *ctx, struct radeon_state *state)
228 {
229 void *tmp;
230 int r = 0;
231
232 /* !!! ONLY ACCEPT QUERY STATE HERE !!! */
233 if (state->stype->stype != R600_STATE_QUERY_BEGIN && state->stype->stype != R600_STATE_QUERY_END) {
234 return -EINVAL;
235 }
236 r = radeon_state_pm4(state);
237 if (r)
238 return r;
239 if ((ctx->draw_cpm4 + state->cpm4) > RADEON_CTX_MAX_PM4) {
240 /* need to flush */
241 return -EBUSY;
242 }
243 if (state->cpm4 >= RADEON_CTX_MAX_PM4) {
244 fprintf(stderr, "%s single state too big %d, max %d\n",
245 __func__, state->cpm4, RADEON_CTX_MAX_PM4);
246 return -EINVAL;
247 }
248 tmp = realloc(ctx->state, (ctx->nstate + 1) * sizeof(void*));
249 if (tmp == NULL)
250 return -ENOMEM;
251 ctx->state = tmp;
252 ctx->state[ctx->nstate++] = radeon_state_incref(state);
253 /* BEGIN/END query are balanced in the same cs so account for END
254 * END query when scheduling BEGIN query
255 */
256 if (state->stype->stype == R600_STATE_QUERY_BEGIN) {
257 ctx->draw_cpm4 += state->cpm4 * 2;
258 }
259 return 0;
260 }
261
262 int radeon_ctx_set_draw_new(struct radeon_ctx *ctx, struct radeon_draw *draw)
263 {
264 struct radeon_draw *pdraw = NULL;
265 struct radeon_draw **ndraw;
266 struct radeon_state *nstate, *ostate;
267 unsigned cpm4, i, cstate;
268 void *tmp;
269 int r = 0;
270
271 ndraw = realloc(ctx->draw, sizeof(void*) * (ctx->ndraw + 1));
272 if (ndraw == NULL)
273 return -ENOMEM;
274 ctx->draw = ndraw;
275 for (i = 0; i < draw->nstate; i++) {
276 r = radeon_ctx_state_bo(ctx, draw->state[i]);
277 if (r)
278 return r;
279 }
280 r = radeon_draw_check(draw);
281 if (r)
282 return r;
283 if (draw->cpm4 >= RADEON_CTX_MAX_PM4) {
284 fprintf(stderr, "%s single draw too big %d, max %d\n",
285 __func__, draw->cpm4, RADEON_CTX_MAX_PM4);
286 return -EINVAL;
287 }
288 tmp = realloc(ctx->state, (ctx->nstate + draw->nstate) * sizeof(void*));
289 if (tmp == NULL)
290 return -ENOMEM;
291 ctx->state = tmp;
292 pdraw = ctx->cdraw;
293 for (i = 0, cpm4 = 0, cstate = ctx->nstate; i < draw->nstate - 1; i++) {
294 nstate = draw->state[i];
295 if (nstate) {
296 if (pdraw && pdraw->state[i]) {
297 ostate = pdraw->state[i];
298 if (ostate->pm4_crc != nstate->pm4_crc) {
299 ctx->state[cstate++] = nstate;
300 cpm4 += nstate->cpm4;
301 }
302 } else {
303 ctx->state[cstate++] = nstate;
304 cpm4 += nstate->cpm4;
305 }
306 }
307 }
308 /* The last state is the draw state always add it */
309 if (draw->state[i] == NULL) {
310 fprintf(stderr, "%s no draw command\n", __func__);
311 return -EINVAL;
312 }
313 ctx->state[cstate++] = draw->state[i];
314 cpm4 += draw->state[i]->cpm4;
315 if ((ctx->draw_cpm4 + cpm4) > RADEON_CTX_MAX_PM4) {
316 /* need to flush */
317 return -EBUSY;
318 }
319 ctx->draw_cpm4 += cpm4;
320 ctx->nstate = cstate;
321 ctx->draw[ctx->ndraw++] = draw;
322 ctx->cdraw = draw;
323 return 0;
324 }
325
326 int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw)
327 {
328 int r;
329
330 radeon_draw_incref(draw);
331 r = radeon_ctx_set_draw_new(ctx, draw);
332 if (r)
333 radeon_draw_decref(draw);
334 return r;
335 }
336
337 int radeon_ctx_pm4(struct radeon_ctx *ctx)
338 {
339 unsigned i;
340 int r;
341
342 free(ctx->pm4);
343 ctx->cpm4 = 0;
344 ctx->pm4 = malloc(ctx->draw_cpm4 * 4);
345 if (ctx->pm4 == NULL)
346 return -EINVAL;
347 for (i = 0, ctx->id = 0; i < ctx->nstate; i++) {
348 r = radeon_ctx_state_schedule(ctx, ctx->state[i]);
349 if (r)
350 return r;
351 }
352 if (ctx->id != ctx->draw_cpm4) {
353 fprintf(stderr, "%s miss predicted pm4 size %d for %d\n",
354 __func__, ctx->draw_cpm4, ctx->id);
355 return -EINVAL;
356 }
357 ctx->cpm4 = ctx->draw_cpm4;
358 return 0;
359 }
360
361 void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file)
362 {
363 bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root;
364 unsigned i;
365
366 root = device_id = bcs = blob = array = bo = size = handle = NULL;
367 root = bof_object();
368 if (root == NULL)
369 goto out_err;
370 device_id = bof_int32(ctx->radeon->device);
371 if (device_id == NULL)
372 return;
373 if (bof_object_set(root, "device_id", device_id))
374 goto out_err;
375 bof_decref(device_id);
376 device_id = NULL;
377 /* dump relocs */
378 printf("%d relocs\n", ctx->nreloc);
379 blob = bof_blob(ctx->nreloc * 16, ctx->reloc);
380 if (blob == NULL)
381 goto out_err;
382 if (bof_object_set(root, "reloc", blob))
383 goto out_err;
384 bof_decref(blob);
385 blob = NULL;
386 /* dump cs */
387 printf("%d pm4\n", ctx->cpm4);
388 blob = bof_blob(ctx->cpm4 * 4, ctx->pm4);
389 if (blob == NULL)
390 goto out_err;
391 if (bof_object_set(root, "pm4", blob))
392 goto out_err;
393 bof_decref(blob);
394 blob = NULL;
395 /* dump bo */
396 array = bof_array();
397 if (array == NULL)
398 goto out_err;
399 for (i = 0; i < ctx->nbo; i++) {
400 bo = bof_object();
401 if (bo == NULL)
402 goto out_err;
403 size = bof_int32(ctx->bo[i]->size);
404 if (size == NULL)
405 goto out_err;
406 if (bof_object_set(bo, "size", size))
407 goto out_err;
408 bof_decref(size);
409 size = NULL;
410 handle = bof_int32(ctx->bo[i]->handle);
411 if (handle == NULL)
412 goto out_err;
413 if (bof_object_set(bo, "handle", handle))
414 goto out_err;
415 bof_decref(handle);
416 handle = NULL;
417 radeon_bo_map(ctx->radeon, ctx->bo[i]);
418 blob = bof_blob(ctx->bo[i]->size, ctx->bo[i]->data);
419 radeon_bo_unmap(ctx->radeon, ctx->bo[i]);
420 if (blob == NULL)
421 goto out_err;
422 if (bof_object_set(bo, "data", blob))
423 goto out_err;
424 bof_decref(blob);
425 blob = NULL;
426 if (bof_array_append(array, bo))
427 goto out_err;
428 bof_decref(bo);
429 bo = NULL;
430 }
431 if (bof_object_set(root, "bo", array))
432 goto out_err;
433 bof_dump_file(root, file);
434 printf("done dump\n");
435 out_err:
436 bof_decref(blob);
437 bof_decref(array);
438 bof_decref(bo);
439 bof_decref(size);
440 bof_decref(handle);
441 bof_decref(device_id);
442 bof_decref(root);
443 }