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