Merge branch 'llvm-cliptest-viewport'
[mesa.git] / src / mesa / drivers / dri / r600 / r600_cmdbuf.c
1 /*
2 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
3
4 The Weather Channel (TM) funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86 license.
6 This notice must be preserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 **************************************************************************/
29
30 /**
31 * Mostly coppied from \radeon\radeon_cs_legacy.c
32 */
33
34 #include <errno.h>
35
36 #include "main/glheader.h"
37 #include "main/state.h"
38 #include "main/imports.h"
39 #include "main/macros.h"
40 #include "main/context.h"
41 #include "main/simple_list.h"
42
43 #include "drm.h"
44 #include "radeon_drm.h"
45
46 #include "r600_context.h"
47 #include "radeon_reg.h"
48 #include "r600_cmdbuf.h"
49 #include "radeon_bocs_wrapper.h"
50
51 #ifdef HAVE_LIBDRM_RADEON
52 #include "radeon_cs_int.h"
53 #else
54 #include "radeon_cs_int_drm.h"
55 #endif
56
57 struct r600_cs_manager_legacy
58 {
59 struct radeon_cs_manager base;
60 struct radeon_context *ctx;
61 /* hack for scratch stuff */
62 uint32_t pending_age;
63 uint32_t pending_count;
64 };
65
66 struct r600_cs_reloc_legacy {
67 struct radeon_cs_reloc base;
68 uint32_t cindices;
69 uint32_t *indices;
70 uint32_t *reloc_indices;
71 };
72
73 static struct radeon_cs_int *r600_cs_create(struct radeon_cs_manager *csm,
74 uint32_t ndw)
75 {
76 struct radeon_cs_int *csi;
77
78 csi = (struct radeon_cs_int*)calloc(1, sizeof(struct radeon_cs_int));
79 if (csi == NULL) {
80 return NULL;
81 }
82 csi->csm = csm;
83 csi->ndw = (ndw + 0x3FF) & (~0x3FF);
84 csi->packets = (uint32_t*)malloc(4*csi->ndw);
85 if (csi->packets == NULL) {
86 free(csi);
87 return NULL;
88 }
89 csi->relocs_total_size = 0;
90 return csi;
91 }
92
93 static int r600_cs_write_reloc(struct radeon_cs_int *csi,
94 struct radeon_bo *bo,
95 uint32_t read_domain,
96 uint32_t write_domain,
97 uint32_t flags)
98 {
99 struct r600_cs_reloc_legacy *relocs;
100 int i;
101
102 relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
103 /* check domains */
104 if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
105 /* in one CS a bo can only be in read or write domain but not
106 * in read & write domain at the same sime
107 */
108 return -EINVAL;
109 }
110 if (read_domain == RADEON_GEM_DOMAIN_CPU) {
111 return -EINVAL;
112 }
113 if (write_domain == RADEON_GEM_DOMAIN_CPU) {
114 return -EINVAL;
115 }
116 /* check if bo is already referenced */
117 for(i = 0; i < csi->crelocs; i++) {
118 uint32_t *indices;
119 uint32_t *reloc_indices;
120
121 if (relocs[i].base.bo->handle == bo->handle) {
122 /* Check domains must be in read or write. As we check already
123 * checked that in argument one of the read or write domain was
124 * set we only need to check that if previous reloc as the read
125 * domain set then the read_domain should also be set for this
126 * new relocation.
127 */
128 if (relocs[i].base.read_domain && !read_domain) {
129 return -EINVAL;
130 }
131 if (relocs[i].base.write_domain && !write_domain) {
132 return -EINVAL;
133 }
134 relocs[i].base.read_domain |= read_domain;
135 relocs[i].base.write_domain |= write_domain;
136 /* save indice */
137 relocs[i].cindices++;
138 indices = (uint32_t*)realloc(relocs[i].indices,
139 relocs[i].cindices * 4);
140 reloc_indices = (uint32_t*)realloc(relocs[i].reloc_indices,
141 relocs[i].cindices * 4);
142 if ( (indices == NULL) || (reloc_indices == NULL) ) {
143 relocs[i].cindices -= 1;
144 return -ENOMEM;
145 }
146 relocs[i].indices = indices;
147 relocs[i].reloc_indices = reloc_indices;
148 relocs[i].indices[relocs[i].cindices - 1] = csi->cdw;
149 relocs[i].reloc_indices[relocs[i].cindices - 1] = csi->cdw;
150 csi->section_cdw += 2;
151 csi->cdw += 2;
152
153 return 0;
154 }
155 }
156 /* add bo to reloc */
157 relocs = (struct r600_cs_reloc_legacy*)
158 realloc(csi->relocs,
159 sizeof(struct r600_cs_reloc_legacy) * (csi->crelocs + 1));
160 if (relocs == NULL) {
161 return -ENOMEM;
162 }
163 csi->relocs = relocs;
164 relocs[csi->crelocs].base.bo = bo;
165 relocs[csi->crelocs].base.read_domain = read_domain;
166 relocs[csi->crelocs].base.write_domain = write_domain;
167 relocs[csi->crelocs].base.flags = flags;
168 relocs[csi->crelocs].indices = (uint32_t*)malloc(4);
169 relocs[csi->crelocs].reloc_indices = (uint32_t*)malloc(4);
170 if ( (relocs[csi->crelocs].indices == NULL) || (relocs[csi->crelocs].reloc_indices == NULL) )
171 {
172 return -ENOMEM;
173 }
174
175 relocs[csi->crelocs].indices[0] = csi->cdw;
176 relocs[csi->crelocs].reloc_indices[0] = csi->cdw;
177 csi->section_cdw += 2;
178 csi->cdw += 2;
179 relocs[csi->crelocs].cindices = 1;
180 csi->relocs_total_size += radeon_bo_legacy_relocs_size(bo);
181 csi->crelocs++;
182
183 radeon_bo_ref(bo);
184
185 return 0;
186 }
187
188 static int r600_cs_begin(struct radeon_cs_int *csi,
189 uint32_t ndw,
190 const char *file,
191 const char *func,
192 int line)
193 {
194 if (csi->section_ndw) {
195 fprintf(stderr, "CS already in a section(%s,%s,%d)\n",
196 csi->section_file, csi->section_func, csi->section_line);
197 fprintf(stderr, "CS can't start section(%s,%s,%d)\n",
198 file, func, line);
199 return -EPIPE;
200 }
201
202 csi->section_ndw = ndw;
203 csi->section_cdw = 0;
204 csi->section_file = file;
205 csi->section_func = func;
206 csi->section_line = line;
207
208 if (csi->cdw + ndw > csi->ndw) {
209 uint32_t tmp, *ptr;
210 int num = (ndw > 0x400) ? ndw : 0x400;
211
212 tmp = (csi->cdw + num + 0x3FF) & (~0x3FF);
213 ptr = (uint32_t*)realloc(csi->packets, 4 * tmp);
214 if (ptr == NULL) {
215 return -ENOMEM;
216 }
217 csi->packets = ptr;
218 csi->ndw = tmp;
219 }
220
221 return 0;
222 }
223
224 static int r600_cs_end(struct radeon_cs_int *csi,
225 const char *file,
226 const char *func,
227 int line)
228
229 {
230 if (!csi->section_ndw) {
231 fprintf(stderr, "CS no section to end at (%s,%s,%d)\n",
232 file, func, line);
233 return -EPIPE;
234 }
235
236 if ( csi->section_ndw != csi->section_cdw ) {
237 fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
238 csi->section_file, csi->section_func, csi->section_line, csi->section_ndw, csi->section_cdw);
239 fprintf(stderr, "csi->section_ndw = %d, csi->cdw = %d, csi->section_cdw = %d \n",
240 csi->section_ndw, csi->cdw, csi->section_cdw);
241 fprintf(stderr, "CS section end at (%s,%s,%d)\n",
242 file, func, line);
243 return -EPIPE;
244 }
245 csi->section_ndw = 0;
246
247 if (csi->cdw > csi->ndw) {
248 fprintf(stderr, "CS section overflow at (%s,%s,%d) cdw %d ndw %d\n",
249 csi->section_file, csi->section_func, csi->section_line,csi->cdw,csi->ndw);
250 fprintf(stderr, "CS section end at (%s,%s,%d)\n",
251 file, func, line);
252 assert(0);
253 }
254
255 return 0;
256 }
257
258 static int r600_cs_process_relocs(struct radeon_cs_int *csi,
259 uint32_t * reloc_chunk,
260 uint32_t * length_dw_reloc_chunk)
261 {
262 struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
263 struct r600_cs_reloc_legacy *relocs;
264 int i, j, r;
265
266 uint32_t offset_dw = 0;
267
268 csm = (struct r600_cs_manager_legacy*)csi->csm;
269 relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
270 restart:
271 for (i = 0; i < csi->crelocs; i++) {
272 uint32_t soffset, eoffset;
273
274 r = radeon_bo_legacy_validate(relocs[i].base.bo,
275 &soffset, &eoffset);
276 if (r == -EAGAIN) {
277 goto restart;
278 }
279 if (r) {
280 fprintf(stderr, "invalid bo(%p) [0x%08X, 0x%08X]\n",
281 relocs[i].base.bo, soffset, eoffset);
282 return r;
283 }
284
285 for (j = 0; j < relocs[i].cindices; j++) {
286 /* pkt3 nop header in ib chunk */
287 csi->packets[relocs[i].reloc_indices[j]] = 0xC0001000;
288 /* reloc index in ib chunk */
289 csi->packets[relocs[i].reloc_indices[j] + 1] = offset_dw;
290 }
291
292 /* asic offset in reloc chunk */ /* see alex drm r600_nomm_relocate */
293 reloc_chunk[offset_dw] = soffset;
294 reloc_chunk[offset_dw + 3] = 0;
295
296 offset_dw += 4;
297 }
298
299 *length_dw_reloc_chunk = offset_dw;
300
301 return 0;
302 }
303
304 static int r600_cs_set_age(struct radeon_cs_int *csi) /* -------------- */
305 {
306 struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
307 struct r600_cs_reloc_legacy *relocs;
308 int i;
309
310 relocs = (struct r600_cs_reloc_legacy *)csi->relocs;
311 for (i = 0; i < csi->crelocs; i++) {
312 radeon_bo_legacy_pending(relocs[i].base.bo, csm->pending_age);
313 radeon_bo_unref(relocs[i].base.bo);
314 }
315 return 0;
316 }
317
318 #if 0
319 static void dump_cmdbuf(struct radeon_cs_int *csi)
320 {
321 int i;
322 fprintf(stderr,"--start--\n");
323 for (i = 0; i < csi->cdw; i++){
324 fprintf(stderr,"0x%08x\n", csi->packets[i]);
325 }
326 fprintf(stderr,"--end--\n");
327
328 }
329 #endif
330
331 static int r600_cs_emit(struct radeon_cs_int *csi)
332 {
333 struct r600_cs_manager_legacy *csm = (struct r600_cs_manager_legacy*)csi->csm;
334 struct drm_radeon_cs cs_cmd;
335 struct drm_radeon_cs_chunk cs_chunk[2];
336 uint32_t length_dw_reloc_chunk;
337 uint64_t chunk_ptrs[2];
338 uint32_t *reloc_chunk;
339 int r;
340 int retry = 0;
341
342 /* TODO : put chip level things here if need. */
343 /* csm->ctx->vtbl.emit_cs_header(cs, csm->ctx); */
344
345 csm->pending_count = 1;
346
347 reloc_chunk = (uint32_t*)calloc(1, csi->crelocs * 4 * 4);
348
349 r = r600_cs_process_relocs(csi, reloc_chunk, &length_dw_reloc_chunk);
350 if (r) {
351 free(reloc_chunk);
352 return 0;
353 }
354
355 /* raw ib chunk */
356 cs_chunk[0].chunk_id = RADEON_CHUNK_ID_IB;
357 cs_chunk[0].length_dw = csi->cdw;
358 cs_chunk[0].chunk_data = (unsigned long)(csi->packets);
359
360 /* reloc chaunk */
361 cs_chunk[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
362 cs_chunk[1].length_dw = length_dw_reloc_chunk;
363 cs_chunk[1].chunk_data = (unsigned long)reloc_chunk;
364
365 chunk_ptrs[0] = (uint64_t)(unsigned long)&(cs_chunk[0]);
366 chunk_ptrs[1] = (uint64_t)(unsigned long)&(cs_chunk[1]);
367
368 cs_cmd.num_chunks = 2;
369 /* cs_cmd.cs_id = 0; */
370 cs_cmd.chunks = (uint64_t)(unsigned long)chunk_ptrs;
371
372 //dump_cmdbuf(cs);
373
374 do
375 {
376 r = drmCommandWriteRead(csi->csm->fd, DRM_RADEON_CS, &cs_cmd, sizeof(cs_cmd));
377 retry++;
378 } while (r == -EAGAIN && retry < 1000);
379
380 if (r) {
381 free(reloc_chunk);
382 return r;
383 }
384
385 csm->pending_age = cs_cmd.cs_id;
386
387 r600_cs_set_age(csi);
388
389 csi->csm->read_used = 0;
390 csi->csm->vram_write_used = 0;
391 csi->csm->gart_write_used = 0;
392
393 free(reloc_chunk);
394
395 return 0;
396 }
397
398 static void inline r600_cs_free_reloc(void *relocs_p, int crelocs)
399 {
400 struct r600_cs_reloc_legacy *relocs = relocs_p;
401 int i;
402 if (!relocs_p)
403 return;
404 for (i = 0; i < crelocs; i++)
405 {
406 free(relocs[i].indices);
407 free(relocs[i].reloc_indices);
408 }
409 }
410
411 static int r600_cs_destroy(struct radeon_cs_int *csi)
412 {
413 r600_cs_free_reloc(csi->relocs, csi->crelocs);
414 free(csi->relocs);
415 free(csi->packets);
416 free(csi);
417 return 0;
418 }
419
420 static int r600_cs_erase(struct radeon_cs_int *csi)
421 {
422 r600_cs_free_reloc(csi->relocs, csi->crelocs);
423 free(csi->relocs);
424 csi->relocs_total_size = 0;
425 csi->relocs = NULL;
426 csi->crelocs = 0;
427 csi->cdw = 0;
428 return 0;
429 }
430
431 static int r600_cs_need_flush(struct radeon_cs_int *csi)
432 {
433 /* this function used to flush when the BO usage got to
434 * a certain size, now the higher levels handle this better */
435 return 0;
436 }
437
438 static void r600_cs_print(struct radeon_cs_int *csi, FILE *file)
439 {
440 }
441
442 static struct radeon_cs_funcs r600_cs_funcs = {
443 r600_cs_create,
444 r600_cs_write_reloc,
445 r600_cs_begin,
446 r600_cs_end,
447 r600_cs_emit,
448 r600_cs_destroy,
449 r600_cs_erase,
450 r600_cs_need_flush,
451 r600_cs_print
452 };
453
454 struct radeon_cs_manager * r600_radeon_cs_manager_legacy_ctor(struct radeon_context *ctx)
455 {
456 struct r600_cs_manager_legacy *csm;
457
458 csm = (struct r600_cs_manager_legacy*)
459 calloc(1, sizeof(struct r600_cs_manager_legacy));
460 if (csm == NULL) {
461 return NULL;
462 }
463 csm->base.funcs = &r600_cs_funcs;
464 csm->base.fd = ctx->dri.fd;
465 csm->ctx = ctx;
466 csm->pending_age = 1;
467 return (struct radeon_cs_manager*)csm;
468 }
469
470 void r600InitCmdBuf(context_t *r600) /* from rcommonInitCmdBuf */
471 {
472 radeonContextPtr rmesa = &r600->radeon;
473 GLuint size;
474
475 if(r600->radeon.radeonScreen->chip_family >= CHIP_FAMILY_CEDAR)
476 {
477 evergreenInitAtoms(r600);
478 }
479 else
480 {
481 r600InitAtoms(r600);
482 }
483
484 /* Initialize command buffer */
485 size = 256 * driQueryOptioni(&rmesa->optionCache,
486 "command_buffer_size");
487 if (size < 2 * rmesa->hw.max_state_size) {
488 size = 2 * rmesa->hw.max_state_size + 65535;
489 }
490 if (size > 64 * 256)
491 size = 64 * 256;
492
493 if (rmesa->radeonScreen->kernel_mm) {
494 int fd = rmesa->radeonScreen->driScreen->fd;
495 rmesa->cmdbuf.csm = radeon_cs_manager_gem_ctor(fd);
496 } else {
497 rmesa->cmdbuf.csm = r600_radeon_cs_manager_legacy_ctor(rmesa);
498 }
499 if (rmesa->cmdbuf.csm == NULL) {
500 /* FIXME: fatal error */
501 return;
502 }
503 rmesa->cmdbuf.cs = radeon_cs_create(rmesa->cmdbuf.csm, size);
504 assert(rmesa->cmdbuf.cs != NULL);
505 rmesa->cmdbuf.size = size;
506
507 radeon_cs_space_set_flush(rmesa->cmdbuf.cs,
508 (void (*)(void *))rmesa->glCtx->Driver.Flush, rmesa->glCtx);
509
510 if (!rmesa->radeonScreen->kernel_mm) {
511 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, rmesa->radeonScreen->texSize[0]);
512 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, rmesa->radeonScreen->gartTextures.size);
513 } else {
514 struct drm_radeon_gem_info mminfo;
515
516 if (!drmCommandWriteRead(rmesa->dri.fd, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)))
517 {
518 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, mminfo.vram_visible);
519 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, mminfo.gart_size);
520 }
521 }
522 }
523