2 * Copyright © 2008 Nicolai Haehnle
3 * Copyright © 2008 Jérôme Glisse
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
28 * Aapo Tahkola <aet@rasterburn.org>
29 * Nicolai Haehnle <prefect_@gmx.net>
30 * Jérôme Glisse <glisse@freedesktop.org>
35 #include "common_context.h"
36 #include "radeon_cs.h"
37 #include "radeon_cs_legacy.h"
38 #include "radeon_bo_legacy.h"
41 struct cs_manager_legacy
{
42 struct radeon_cs_manager base
;
43 struct radeon_context
*ctx
;
44 /* hack for scratch stuff */
46 uint32_t pending_count
;
51 struct cs_reloc_legacy
{
52 struct radeon_cs_reloc base
;
58 static struct radeon_cs
*cs_create(struct radeon_cs_manager
*csm
,
63 cs
= (struct radeon_cs
*)calloc(1, sizeof(struct radeon_cs
));
68 cs
->ndw
= (ndw
+ 0x3FF) & (~0x3FF);
69 cs
->packets
= (uint32_t*)malloc(4*cs
->ndw
);
70 if (cs
->packets
== NULL
) {
74 cs
->relocs_total_size
= 0;
78 static int cs_write_reloc(struct radeon_cs
*cs
,
81 uint32_t write_domain
,
84 struct cs_reloc_legacy
*relocs
;
87 relocs
= (struct cs_reloc_legacy
*)cs
->relocs
;
89 if ((read_domain
&& write_domain
) || (!read_domain
&& !write_domain
)) {
90 /* in one CS a bo can only be in read or write domain but not
91 * in read & write domain at the same sime
95 if (read_domain
== RADEON_GEM_DOMAIN_CPU
) {
98 if (write_domain
== RADEON_GEM_DOMAIN_CPU
) {
101 /* check if bo is already referenced */
102 for(i
= 0; i
< cs
->crelocs
; i
++) {
105 if (relocs
[i
].base
.bo
->handle
== bo
->handle
) {
106 /* Check domains must be in read or write. As we check already
107 * checked that in argument one of the read or write domain was
108 * set we only need to check that if previous reloc as the read
109 * domain set then the read_domain should also be set for this
112 if (relocs
[i
].base
.read_domain
&& !read_domain
) {
115 if (relocs
[i
].base
.write_domain
&& !write_domain
) {
118 relocs
[i
].base
.read_domain
|= read_domain
;
119 relocs
[i
].base
.write_domain
|= write_domain
;
121 relocs
[i
].cindices
++;
122 indices
= (uint32_t*)realloc(relocs
[i
].indices
,
123 relocs
[i
].cindices
* 4);
124 if (indices
== NULL
) {
125 relocs
[i
].cindices
-= 1;
128 relocs
[i
].indices
= indices
;
129 relocs
[i
].indices
[relocs
[i
].cindices
- 1] = cs
->cdw
- 1;
133 /* add bo to reloc */
134 relocs
= (struct cs_reloc_legacy
*)
136 sizeof(struct cs_reloc_legacy
) * (cs
->crelocs
+ 1));
137 if (relocs
== NULL
) {
141 relocs
[cs
->crelocs
].base
.bo
= bo
;
142 relocs
[cs
->crelocs
].base
.read_domain
= read_domain
;
143 relocs
[cs
->crelocs
].base
.write_domain
= write_domain
;
144 relocs
[cs
->crelocs
].base
.flags
= flags
;
145 relocs
[cs
->crelocs
].indices
= (uint32_t*)malloc(4);
146 if (relocs
[cs
->crelocs
].indices
== NULL
) {
149 relocs
[cs
->crelocs
].indices
[0] = cs
->cdw
- 1;
150 relocs
[cs
->crelocs
].cindices
= 1;
151 cs
->relocs_total_size
+= radeon_bo_legacy_relocs_size(bo
);
157 static int cs_begin(struct radeon_cs
*cs
,
164 fprintf(stderr
, "CS already in a section(%s,%s,%d)\n",
165 cs
->section_file
, cs
->section_func
, cs
->section_line
);
166 fprintf(stderr
, "CS can't start section(%s,%s,%d)\n",
171 cs
->section_ndw
= ndw
;
173 cs
->section_file
= file
;
174 cs
->section_func
= func
;
175 cs
->section_line
= line
;
178 if (cs
->cdw
+ ndw
> cs
->ndw
) {
180 int num
= (ndw
> 0x3FF) ? ndw
: 0x3FF;
182 tmp
= (cs
->cdw
+ 1 + num
) & (~num
);
183 ptr
= (uint32_t*)realloc(cs
->packets
, 4 * tmp
);
194 static int cs_end(struct radeon_cs
*cs
,
201 fprintf(stderr
, "CS no section to end at (%s,%s,%d)\n",
206 if (cs
->section_ndw
!= cs
->section_cdw
) {
207 fprintf(stderr
, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
208 cs
->section_file
, cs
->section_func
, cs
->section_line
, cs
->section_ndw
, cs
->section_cdw
);
209 fprintf(stderr
, "CS section end at (%s,%s,%d)\n",
216 static int cs_process_relocs(struct radeon_cs
*cs
)
218 struct cs_manager_legacy
*csm
= (struct cs_manager_legacy
*)cs
->csm
;
219 struct cs_reloc_legacy
*relocs
;
222 csm
= (struct cs_manager_legacy
*)cs
->csm
;
223 relocs
= (struct cs_reloc_legacy
*)cs
->relocs
;
224 for (i
= 0; i
< cs
->crelocs
; i
++) {
225 for (j
= 0; j
< relocs
[i
].cindices
; j
++) {
226 uint32_t soffset
, eoffset
;
228 r
= radeon_bo_legacy_validate(relocs
[i
].base
.bo
,
231 fprintf(stderr
, "validated %p [0x%08X, 0x%08X]\n",
232 relocs
[i
].base
.bo
, soffset
, eoffset
);
235 cs
->packets
[relocs
[i
].indices
[j
]] += soffset
;
236 if (cs
->packets
[relocs
[i
].indices
[j
]] >= eoffset
) {
237 radeon_bo_debug(relocs
[i
].base
.bo
, 12);
238 fprintf(stderr
, "validated %p [0x%08X, 0x%08X]\n",
239 relocs
[i
].base
.bo
, soffset
, eoffset
);
240 fprintf(stderr
, "above end: %p 0x%08X 0x%08X\n",
242 cs
->packets
[relocs
[i
].indices
[j
]],
252 static int cs_set_age(struct radeon_cs
*cs
)
254 struct cs_manager_legacy
*csm
= (struct cs_manager_legacy
*)cs
->csm
;
255 struct cs_reloc_legacy
*relocs
;
258 relocs
= (struct cs_reloc_legacy
*)cs
->relocs
;
259 for (i
= 0; i
< cs
->crelocs
; i
++) {
260 radeon_bo_legacy_pending(relocs
[i
].base
.bo
, csm
->pending_age
);
261 radeon_bo_unref(relocs
[i
].base
.bo
);
266 static void dump_cmdbuf(struct radeon_cs
*cs
)
269 for (i
= 0; i
< cs
->cdw
; i
++){
270 fprintf(stderr
,"%x: %08x\n", i
, cs
->packets
[i
]);
274 static int cs_emit(struct radeon_cs
*cs
)
276 struct cs_manager_legacy
*csm
= (struct cs_manager_legacy
*)cs
->csm
;
277 drm_radeon_cmd_buffer_t cmd
;
278 drm_r300_cmd_header_t age
;
282 csm
->ctx
->vtbl
.emit_cs_header(cs
, csm
->ctx
);
285 /* append buffer age */
286 if (IS_R300_CLASS(csm
->ctx
->radeonScreen
)) {
287 age
.scratch
.cmd_type
= R300_CMD_SCRATCH
;
288 /* Scratch register 2 corresponds to what radeonGetAge polls */
289 csm
->pending_age
= 0;
290 csm
->pending_count
= 1;
291 ull
= (uint64_t) (intptr_t) &csm
->pending_age
;
293 age
.scratch
.n_bufs
= 1;
294 age
.scratch
.flags
= 0;
295 radeon_cs_write_dword(cs
, age
.u
);
296 radeon_cs_write_dword(cs
, ull
& 0xffffffff);
297 radeon_cs_write_dword(cs
, ull
>> 32);
298 radeon_cs_write_dword(cs
, 0);
301 r
= cs_process_relocs(cs
);
306 cmd
.buf
= (char *)cs
->packets
;
307 cmd
.bufsz
= cs
->cdw
* 4;
308 if (csm
->ctx
->state
.scissor
.enabled
) {
309 cmd
.nbox
= csm
->ctx
->state
.scissor
.numClipRects
;
310 cmd
.boxes
= (drm_clip_rect_t
*) csm
->ctx
->state
.scissor
.pClipRects
;
312 cmd
.nbox
= csm
->ctx
->numClipRects
;
313 cmd
.boxes
= (drm_clip_rect_t
*) csm
->ctx
->pClipRects
;
318 r
= drmCommandWrite(cs
->csm
->fd
, DRM_RADEON_CMDBUF
, &cmd
, sizeof(cmd
));
322 if (!IS_R300_CLASS(csm
->ctx
->radeonScreen
)) {
323 drm_radeon_irq_emit_t emit_cmd
;
324 emit_cmd
.irq_seq
= &csm
->pending_age
;
325 r
= drmCommandWrite(cs
->csm
->fd
, DRM_RADEON_IRQ_EMIT
, &emit_cmd
, sizeof(emit_cmd
));
332 cs
->csm
->read_used
= 0;
333 cs
->csm
->vram_write_used
= 0;
334 cs
->csm
->gart_write_used
= 0;
338 static void inline cs_free_reloc(void *relocs_p
, int crelocs
)
340 struct cs_reloc_legacy
*relocs
= relocs_p
;
344 for (i
= 0; i
< crelocs
; i
++)
345 free(relocs
[i
].indices
);
348 static int cs_destroy(struct radeon_cs
*cs
)
350 cs_free_reloc(cs
->relocs
, cs
->crelocs
);
357 static int cs_erase(struct radeon_cs
*cs
)
359 cs_free_reloc(cs
->relocs
, cs
->crelocs
);
361 cs
->relocs_total_size
= 0;
369 static int cs_need_flush(struct radeon_cs
*cs
)
371 /* FIXME: we should get the texture heap size */
372 return (cs
->relocs_total_size
> (7*1024*1024));
375 static void cs_print(struct radeon_cs
*cs
, FILE *file
)
379 static int cs_check_space(struct radeon_cs
*cs
, struct radeon_cs_space_check
*bos
, int num_bo
)
381 struct radeon_cs_manager
*csm
= cs
->csm
;
382 int this_op_read
= 0, this_op_gart_write
= 0, this_op_vram_write
= 0;
383 uint32_t read_domains
, write_domain
;
385 struct radeon_bo
*bo
;
387 /* check the totals for this operation */
393 for (i
= 0; i
< num_bo
; i
++) {
396 bos
[i
].new_accounted
= 0;
397 read_domains
= bos
[i
].read_domains
;
398 write_domain
= bos
[i
].write_domain
;
400 /* pinned bos don't count */
401 if (radeon_legacy_bo_is_static(bo
))
404 /* already accounted this bo */
405 if (write_domain
&& (write_domain
== bo
->space_accounted
))
408 if (read_domains
&& ((read_domains
<< 16) == bo
->space_accounted
))
411 if (bo
->space_accounted
== 0) {
412 if (write_domain
== RADEON_GEM_DOMAIN_VRAM
)
413 this_op_vram_write
+= bo
->size
;
414 else if (write_domain
== RADEON_GEM_DOMAIN_GTT
)
415 this_op_gart_write
+= bo
->size
;
417 this_op_read
+= bo
->size
;
418 bos
[i
].new_accounted
= (read_domains
<< 16) | write_domain
;
420 uint16_t old_read
, old_write
;
422 old_read
= bo
->space_accounted
>> 16;
423 old_write
= bo
->space_accounted
& 0xffff;
425 if (write_domain
&& (old_read
& write_domain
)) {
426 bos
[i
].new_accounted
= write_domain
;
427 /* moving from read to a write domain */
428 if (write_domain
== RADEON_GEM_DOMAIN_VRAM
) {
429 this_op_read
-= bo
->size
;
430 this_op_vram_write
+= bo
->size
;
431 } else if (write_domain
== RADEON_GEM_DOMAIN_VRAM
) {
432 this_op_read
-= bo
->size
;
433 this_op_gart_write
+= bo
->size
;
435 } else if (read_domains
& old_write
) {
436 bos
[i
].new_accounted
= bo
->space_accounted
& 0xffff;
438 /* rewrite the domains */
439 if (write_domain
!= old_write
)
440 fprintf(stderr
,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo
->handle
, write_domain
, old_write
);
441 if (read_domains
!= old_read
)
442 fprintf(stderr
,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo
->handle
, read_domains
, old_read
);
443 return RADEON_CS_SPACE_FLUSH
;
448 if (this_op_read
< 0)
451 /* check sizes - operation first */
452 if ((this_op_read
+ this_op_gart_write
> csm
->gart_limit
) ||
453 (this_op_vram_write
> csm
->vram_limit
)) {
454 return RADEON_CS_SPACE_OP_TO_BIG
;
457 if (((csm
->vram_write_used
+ this_op_vram_write
) > csm
->vram_limit
) ||
458 ((csm
->read_used
+ csm
->gart_write_used
+ this_op_gart_write
+ this_op_read
) > csm
->gart_limit
)) {
459 return RADEON_CS_SPACE_FLUSH
;
462 csm
->gart_write_used
+= this_op_gart_write
;
463 csm
->vram_write_used
+= this_op_vram_write
;
464 csm
->read_used
+= this_op_read
;
466 for (i
= 0; i
< num_bo
; i
++) {
468 bo
->space_accounted
= bos
[i
].new_accounted
;
471 return RADEON_CS_SPACE_OK
;
474 static struct radeon_cs_funcs radeon_cs_legacy_funcs
= {
487 struct radeon_cs_manager
*radeon_cs_manager_legacy_ctor(struct radeon_context
*ctx
)
489 struct cs_manager_legacy
*csm
;
491 csm
= (struct cs_manager_legacy
*)
492 calloc(1, sizeof(struct cs_manager_legacy
));
496 csm
->base
.funcs
= &radeon_cs_legacy_funcs
;
497 csm
->base
.fd
= ctx
->dri
.fd
;
499 csm
->pending_age
= 1;
500 return (struct radeon_cs_manager
*)csm
;
503 void radeon_cs_manager_legacy_dtor(struct radeon_cs_manager
*csm
)