2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
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:
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
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.
29 #include "radeon_priv.h"
30 #include "radeon_drm.h"
33 static int radeon_ctx_set_bo_new(struct radeon_ctx
*ctx
, struct radeon_ws_bo
*bo
)
35 if (ctx
->nbo
>= RADEON_CTX_MAX_PM4
)
37 radeon_ws_bo_reference(ctx
->radeon
, &ctx
->bo
[ctx
->nbo
], bo
);
42 static struct radeon_ws_bo
*radeon_ctx_get_bo(struct radeon_ctx
*ctx
, unsigned reloc
)
44 struct radeon_cs_reloc
*greloc
;
46 struct radeon_ws_bo
*bo
;
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
]);
55 fprintf(stderr
, "%s no bo for reloc[%d 0x%08X] %d\n", __func__
, reloc
, greloc
->handle
, ctx
->nbo
);
59 static void radeon_ctx_get_placement(struct radeon_ctx
*ctx
, unsigned reloc
, u32
*placement
)
61 struct radeon_cs_reloc
*greloc
;
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];
76 void radeon_ctx_clear(struct radeon_ctx
*ctx
)
78 for (int i
= 0; i
< ctx
->nbo
; i
++) {
79 radeon_ws_bo_reference(ctx
->radeon
, &ctx
->bo
[i
], NULL
);
81 ctx
->ndwords
= RADEON_CTX_MAX_PM4
;
87 struct radeon_ctx
*radeon_ctx_init(struct radeon
*radeon
)
89 struct radeon_ctx
*ctx
;
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
) {
100 ctx
->reloc
= malloc(sizeof(struct radeon_cs_reloc
) * RADEON_CTX_MAX_PM4
);
101 if (ctx
->reloc
== NULL
) {
102 radeon_ctx_fini(ctx
);
105 ctx
->bo
= malloc(sizeof(void *) * RADEON_CTX_MAX_PM4
);
106 if (ctx
->bo
== NULL
) {
107 radeon_ctx_fini(ctx
);
113 void radeon_ctx_fini(struct radeon_ctx
*ctx
)
120 for (i
= 0; i
< ctx
->nbo
; i
++) {
121 radeon_ws_bo_reference(ctx
->radeon
, &ctx
->bo
[i
], NULL
);
123 ctx
->radeon
= radeon_decref(ctx
->radeon
);
130 static int radeon_ctx_state_bo(struct radeon_ctx
*ctx
, struct radeon_state
*state
)
137 for (i
= 0; i
< state
->nbo
; i
++) {
138 for (j
= 0; j
< ctx
->nbo
; j
++) {
139 if (state
->bo
[i
] == ctx
->bo
[j
])
143 r
= radeon_ctx_set_bo_new(ctx
, state
->bo
[i
]);
152 int radeon_ctx_submit(struct radeon_ctx
*ctx
)
154 struct drm_radeon_cs drmib
;
155 struct drm_radeon_cs_chunk chunks
[2];
156 uint64_t chunk_array
[2];
162 for (r
= 0; r
< ctx
->cdwords
; r
++) {
163 fprintf(stderr
, "0x%08X\n", ctx
->pm4
[r
]);
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];
177 r
= drmCommandWriteRead(ctx
->radeon
->fd
, DRM_RADEON_CS
, &drmib
,
178 sizeof(struct drm_radeon_cs
));
183 static int radeon_ctx_reloc(struct radeon_ctx
*ctx
, struct radeon_ws_bo
*bo
,
184 unsigned id
, unsigned *placement
)
187 unsigned bo_handle
= radeon_ws_bo_get_handle(bo
);
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;
195 if (ctx
->nreloc
>= RADEON_CTX_MAX_PM4
) {
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;
207 static int radeon_ctx_state_schedule(struct radeon_ctx
*ctx
, struct radeon_state
*state
)
209 unsigned i
, rid
, bid
, cid
;
214 if (state
->cpm4
> ctx
->ndwords
) {
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]);
225 fprintf(stderr
, "%s state %d failed to reloc\n", __func__
, state
->stype
->stype
);
229 ctx
->cdwords
+= state
->cpm4
;
230 ctx
->ndwords
-= state
->cpm4
;
234 int radeon_ctx_set_query_state(struct radeon_ctx
*ctx
, struct radeon_state
*state
)
238 /* !!! ONLY ACCEPT QUERY STATE HERE !!! */
239 r
= radeon_state_pm4(state
);
242 /* BEGIN/END query are balanced in the same cs so account for END
243 * END query when scheduling BEGIN query
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
)
250 ctx
->ndwords
-= state
->cpm4
;
252 case R600_STATE_QUERY_END
:
253 ctx
->ndwords
+= state
->cpm4
;
258 return radeon_ctx_state_schedule(ctx
, state
);
261 int radeon_ctx_set_draw(struct radeon_ctx
*ctx
, struct radeon_draw
*draw
)
263 unsigned previous_cdwords
;
267 for (i
= 0; i
< ctx
->radeon
->max_states
; i
++) {
268 r
= radeon_ctx_state_bo(ctx
, draw
->state
[i
]);
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
]);
277 ctx
->cdwords
= previous_cdwords
;
287 int radeon_ctx_pm4(struct radeon_ctx
*ctx
)
294 ctx
->pm4
= malloc(ctx
->draw_cpm4
* 4);
295 if (ctx
->pm4
== NULL
)
297 for (i
= 0, ctx
->id
= 0; i
< ctx
->nstate
; i
++) {
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
);
304 ctx
->cpm4
= ctx
->draw_cpm4
;
309 void radeon_ctx_dump_bof(struct radeon_ctx
*ctx
, const char *file
)
311 bof_t
*bcs
, *blob
, *array
, *bo
, *size
, *handle
, *device_id
, *root
;
315 root
= device_id
= bcs
= blob
= array
= bo
= size
= handle
= NULL
;
319 device_id
= bof_int32(ctx
->radeon
->device
);
320 if (device_id
== NULL
)
322 if (bof_object_set(root
, "device_id", device_id
))
324 bof_decref(device_id
);
327 blob
= bof_blob(ctx
->nreloc
* 16, ctx
->reloc
);
330 if (bof_object_set(root
, "reloc", blob
))
335 blob
= bof_blob(ctx
->cdwords
* 4, ctx
->pm4
);
338 if (bof_object_set(root
, "pm4", blob
))
346 for (i
= 0; i
< ctx
->nbo
; i
++) {
350 bo_size
= radeon_ws_bo_get_size(ctx
->bo
[i
]);
351 size
= bof_int32(bo_size
);
354 if (bof_object_set(bo
, "size", size
))
358 handle
= bof_int32(radeon_ws_bo_get_handle(ctx
->bo
[i
]));
361 if (bof_object_set(bo
, "handle", handle
))
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
]);
370 if (bof_object_set(bo
, "data", blob
))
374 if (bof_array_append(array
, bo
))
379 if (bof_object_set(root
, "bo", array
))
381 bof_dump_file(root
, file
);
388 bof_decref(device_id
);