b8ba9b552dfab744f202afdc7e2804173e793fc9
[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 <unistd.h>
30 #include "radeon_priv.h"
31 #include "radeon_drm.h"
32 #include "bof.h"
33
34 static int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo, unsigned state_id)
35 {
36 ctx->bo[ctx->nbo].bo = bo;
37 ctx->bo[ctx->nbo].bo_flushed = 0;
38 ctx->bo[ctx->nbo].state_id = state_id;
39 ctx->nbo++;
40 return 0;
41 }
42
43 void radeon_ctx_clear(struct radeon_ctx *ctx)
44 {
45 unsigned i;
46
47 /* FIXME somethings is wrong, it should be safe to
48 * delete bo here, kernel should postpone bo deletion
49 * until bo is no longer referenced by cs (through the
50 * fence association)
51 */
52 for (i = 0; i < 50; i++) {
53 usleep(10);
54 }
55 for (i = 0; i < ctx->nbo; i++) {
56 ctx->bo[i].bo = radeon_bo_decref(ctx->radeon, ctx->bo[i].bo);
57 }
58 ctx->id = 0;
59 ctx->npm4 = RADEON_CTX_MAX_PM4;
60 ctx->nreloc = 0;
61 ctx->nbo = 0;
62 memset(ctx->state_crc32, 0, ctx->radeon->nstate * 4);
63 }
64
65 struct radeon_ctx *radeon_ctx(struct radeon *radeon)
66 {
67 struct radeon_ctx *ctx;
68
69 if (radeon == NULL)
70 return NULL;
71 ctx = calloc(1, sizeof(*ctx));
72 if (ctx == NULL)
73 return NULL;
74 ctx->radeon = radeon_incref(radeon);
75 ctx->max_bo = 4096;
76 ctx->max_reloc = 4096;
77 ctx->pm4 = malloc(RADEON_CTX_MAX_PM4 * 4);
78 if (ctx->pm4 == NULL) {
79 return radeon_ctx_decref(ctx);
80 }
81 ctx->state_crc32 = malloc(ctx->radeon->nstate * 4);
82 if (ctx->state_crc32 == NULL) {
83 return radeon_ctx_decref(ctx);
84 }
85 ctx->bo = malloc(ctx->max_bo * sizeof(struct radeon_ctx_bo));
86 if (ctx->bo == NULL) {
87 return radeon_ctx_decref(ctx);
88 }
89 ctx->reloc = malloc(ctx->max_reloc * sizeof(struct radeon_cs_reloc));
90 if (ctx->reloc == NULL) {
91 return radeon_ctx_decref(ctx);
92 }
93 radeon_ctx_clear(ctx);
94 return ctx;
95 }
96
97 struct radeon_ctx *radeon_ctx_incref(struct radeon_ctx *ctx)
98 {
99 ctx->refcount++;
100 return ctx;
101 }
102
103 struct radeon_ctx *radeon_ctx_decref(struct radeon_ctx *ctx)
104 {
105 if (ctx == NULL)
106 return NULL;
107 if (--ctx->refcount > 0) {
108 return NULL;
109 }
110
111 ctx->radeon = radeon_decref(ctx->radeon);
112 free(ctx->bo);
113 free(ctx->pm4);
114 free(ctx->reloc);
115 free(ctx->state_crc32);
116 memset(ctx, 0, sizeof(*ctx));
117 free(ctx);
118 return NULL;
119 }
120
121 static int radeon_ctx_bo_id(struct radeon_ctx *ctx, struct radeon_bo *bo)
122 {
123 unsigned i;
124
125 for (i = 0; i < ctx->nbo; i++) {
126 if (bo == ctx->bo[i].bo)
127 return i;
128 }
129 return -1;
130 }
131
132 static int radeon_ctx_state_bo(struct radeon_ctx *ctx, struct radeon_state *state)
133 {
134 unsigned i, j;
135 int r;
136
137 if (state == NULL)
138 return 0;
139 for (i = 0; i < state->nbo; i++) {
140 for (j = 0; j < ctx->nbo; j++) {
141 if (state->bo[i] == ctx->bo[j].bo)
142 break;
143 }
144 if (j == ctx->nbo) {
145 if (ctx->nbo >= ctx->max_bo) {
146 return -EBUSY;
147 }
148 radeon_bo_incref(ctx->radeon, state->bo[i]);
149 r = radeon_ctx_set_bo_new(ctx, state->bo[i], state->id);
150 if (r)
151 return r;
152 }
153 }
154 return 0;
155 }
156
157 int radeon_ctx_submit(struct radeon_ctx *ctx)
158 {
159 struct drm_radeon_cs drmib;
160 struct drm_radeon_cs_chunk chunks[2];
161 uint64_t chunk_array[2];
162 int r = 0;
163
164 if (!ctx->id)
165 return 0;
166 #if 0
167 for (r = 0; r < ctx->id; r++) {
168 fprintf(stderr, "0x%08X\n", ctx->pm4[r]);
169 }
170 #endif
171 drmib.num_chunks = 2;
172 drmib.chunks = (uint64_t)(uintptr_t)chunk_array;
173 chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
174 chunks[0].length_dw = ctx->id;
175 chunks[0].chunk_data = (uint64_t)(uintptr_t)ctx->pm4;
176 chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
177 chunks[1].length_dw = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
178 chunks[1].chunk_data = (uint64_t)(uintptr_t)ctx->reloc;
179 chunk_array[0] = (uint64_t)(uintptr_t)&chunks[0];
180 chunk_array[1] = (uint64_t)(uintptr_t)&chunks[1];
181 #if 1
182 r = drmCommandWriteRead(ctx->radeon->fd, DRM_RADEON_CS, &drmib,
183 sizeof(struct drm_radeon_cs));
184 #endif
185 return r;
186 }
187
188 int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo,
189 unsigned id, unsigned *placement)
190 {
191 unsigned i;
192
193 for (i = 0; i < ctx->nreloc; i++) {
194 if (ctx->reloc[i].handle == bo->handle) {
195 ctx->pm4[id] = i * sizeof(struct radeon_cs_reloc) / 4;
196 return 0;
197 }
198 }
199 if (ctx->nreloc >= ctx->max_reloc) {
200 return -EBUSY;
201 }
202 ctx->reloc[ctx->nreloc].handle = bo->handle;
203 ctx->reloc[ctx->nreloc].read_domain = placement[0] | placement [1];
204 ctx->reloc[ctx->nreloc].write_domain = placement[0] | placement [1];
205 ctx->reloc[ctx->nreloc].flags = 0;
206 ctx->pm4[id] = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
207 ctx->nreloc++;
208 return 0;
209 }
210
211 static int radeon_ctx_state_schedule(struct radeon_ctx *ctx, struct radeon_state *state)
212 {
213 unsigned i, rid, cid;
214 u32 flags;
215 int r, bo_id[4];
216
217 if (state == NULL)
218 return 0;
219 for (i = 0; i < state->nbo; i++) {
220 bo_id[i] = radeon_ctx_bo_id(ctx, state->bo[i]);
221 if (bo_id[i] < 0) {
222 return -EINVAL;
223 }
224 flags = (~ctx->bo[bo_id[i]].bo_flushed) & ctx->radeon->type[state->id].flush_flags;
225 if (flags) {
226 r = ctx->radeon->bo_flush(ctx, state->bo[i], flags, &state->placement[i * 2]);
227 if (r) {
228 return r;
229 }
230 }
231 ctx->bo[bo_id[i]].bo_flushed |= ctx->radeon->type[state->id].flush_flags;
232 }
233 if ((ctx->radeon->type[state->id].header_cpm4 + state->cpm4) > ctx->npm4) {
234 /* need to flush */
235 return -EBUSY;
236 }
237 memcpy(&ctx->pm4[ctx->id], ctx->radeon->type[state->id].header_pm4, ctx->radeon->type[state->id].header_cpm4 * 4);
238 ctx->id += ctx->radeon->type[state->id].header_cpm4;
239 ctx->npm4 -= ctx->radeon->type[state->id].header_cpm4;
240 memcpy(&ctx->pm4[ctx->id], state->states, state->cpm4 * 4);
241 for (i = 0; i < state->nbo; i++) {
242 rid = state->reloc_pm4_id[i];
243 cid = ctx->id + rid;
244 r = radeon_ctx_reloc(ctx, state->bo[i], cid,
245 &state->placement[i * 2]);
246 if (r) {
247 fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->id);
248 return r;
249 }
250 }
251 ctx->id += state->cpm4;
252 ctx->npm4 -= state->cpm4;
253 for (i = 0; i < state->nbo; i++) {
254 ctx->bo[bo_id[i]].bo_flushed &= ~ctx->radeon->type[state->id].dirty_flags;
255 }
256 return 0;
257 }
258
259 int radeon_ctx_set_query_state(struct radeon_ctx *ctx, struct radeon_state *state)
260 {
261 unsigned ndw = 0;
262 int r = 0;
263
264 r = radeon_state_pm4(state);
265 if (r)
266 return r;
267
268 /* !!! ONLY ACCEPT QUERY STATE HERE !!! */
269 ndw = state->cpm4 + ctx->radeon->type[state->id].header_cpm4;
270 switch (state->id) {
271 case R600_QUERY_BEGIN:
272 /* account QUERY_END at same time of QUERY_BEGIN so we know we
273 * have room left for QUERY_END
274 */
275 if ((ndw * 2) > ctx->npm4) {
276 /* need to flush */
277 return -EBUSY;
278 }
279 ctx->npm4 -= ndw;
280 break;
281 case R600_QUERY_END:
282 /* add again ndw from previous accounting */
283 ctx->npm4 += ndw;
284 break;
285 default:
286 return -EINVAL;
287 }
288
289 return radeon_ctx_state_schedule(ctx, state);
290 }
291
292 int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw)
293 {
294 unsigned i, previous_id;
295 int r = 0;
296
297 for (i = 0; i < draw->nstate; i++) {
298 r = radeon_ctx_state_bo(ctx, draw->state[i]);
299 if (r)
300 return r;
301 }
302 r = radeon_draw_check(draw);
303 if (r)
304 return r;
305 if (draw->cpm4 >= RADEON_CTX_MAX_PM4) {
306 fprintf(stderr, "%s single draw too big %d, max %d\n",
307 __func__, draw->cpm4, RADEON_CTX_MAX_PM4);
308 return -EINVAL;
309 }
310 previous_id = ctx->id;
311 for (i = 0; i < draw->nstate; i++) {
312 /* FIXME always force draw state to schedule */
313 if (draw->state[i] && draw->state[i]->pm4_crc != ctx->state_crc32[draw->state[i]->id]) {
314 r = radeon_ctx_state_schedule(ctx, draw->state[i]);
315 if (r) {
316 ctx->id = previous_id;
317 return r;
318 }
319 }
320 }
321 return 0;
322 }
323
324 void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file)
325 {
326 bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root;
327 unsigned i;
328
329 root = device_id = bcs = blob = array = bo = size = handle = NULL;
330 root = bof_object();
331 if (root == NULL)
332 goto out_err;
333 device_id = bof_int32(ctx->radeon->device);
334 if (device_id == NULL)
335 return;
336 if (bof_object_set(root, "device_id", device_id))
337 goto out_err;
338 bof_decref(device_id);
339 device_id = NULL;
340 /* dump relocs */
341 printf("%d relocs\n", ctx->nreloc);
342 blob = bof_blob(ctx->nreloc * 16, ctx->reloc);
343 if (blob == NULL)
344 goto out_err;
345 if (bof_object_set(root, "reloc", blob))
346 goto out_err;
347 bof_decref(blob);
348 blob = NULL;
349 /* dump cs */
350 printf("%d pm4\n", ctx->id);
351 blob = bof_blob(ctx->id * 4, ctx->pm4);
352 if (blob == NULL)
353 goto out_err;
354 if (bof_object_set(root, "pm4", blob))
355 goto out_err;
356 bof_decref(blob);
357 blob = NULL;
358 /* dump bo */
359 array = bof_array();
360 if (array == NULL)
361 goto out_err;
362 for (i = 0; i < ctx->nbo; i++) {
363 bo = bof_object();
364 if (bo == NULL)
365 goto out_err;
366 size = bof_int32(ctx->bo[i].bo->size);
367 if (size == NULL)
368 goto out_err;
369 if (bof_object_set(bo, "size", size))
370 goto out_err;
371 bof_decref(size);
372 size = NULL;
373 handle = bof_int32(ctx->bo[i].bo->handle);
374 if (handle == NULL)
375 goto out_err;
376 if (bof_object_set(bo, "handle", handle))
377 goto out_err;
378 bof_decref(handle);
379 handle = NULL;
380 radeon_bo_map(ctx->radeon, ctx->bo[i].bo);
381 blob = bof_blob(ctx->bo[i].bo->size, ctx->bo[i].bo->data);
382 radeon_bo_unmap(ctx->radeon, ctx->bo[i].bo);
383 if (blob == NULL)
384 goto out_err;
385 if (bof_object_set(bo, "data", blob))
386 goto out_err;
387 bof_decref(blob);
388 blob = NULL;
389 if (bof_array_append(array, bo))
390 goto out_err;
391 bof_decref(bo);
392 bo = NULL;
393 }
394 if (bof_object_set(root, "bo", array))
395 goto out_err;
396 bof_dump_file(root, file);
397 printf("done dump\n");
398 out_err:
399 bof_decref(blob);
400 bof_decref(array);
401 bof_decref(bo);
402 bof_decref(size);
403 bof_decref(handle);
404 bof_decref(device_id);
405 bof_decref(root);
406 }