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