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.
30 #include "radeon_priv.h"
31 #include "radeon_drm.h"
34 static int radeon_ctx_set_bo_new(struct radeon_ctx
*ctx
, struct radeon_bo
*bo
, unsigned state_id
)
36 ctx
->bo
[ctx
->nbo
].bo
= bo
;
37 ctx
->bo
[ctx
->nbo
].bo_flushed
= 0;
38 ctx
->bo
[ctx
->nbo
].state_id
= state_id
;
43 void radeon_ctx_clear(struct radeon_ctx
*ctx
)
47 /* FIXME somethings is wrong, it should be safe to
48 * delete bo here, kernel should postpone bo deletion
49 * until bo is no longer referenced by cs (through the
52 for (i
= 0; i
< 50; i
++) {
55 for (i
= 0; i
< ctx
->nbo
; i
++) {
56 ctx
->bo
[i
].bo
= radeon_bo_decref(ctx
->radeon
, ctx
->bo
[i
].bo
);
59 ctx
->npm4
= RADEON_CTX_MAX_PM4
;
62 memset(ctx
->state_crc32
, 0, ctx
->radeon
->nstate
* 4);
65 struct radeon_ctx
*radeon_ctx(struct radeon
*radeon
)
67 struct radeon_ctx
*ctx
;
71 ctx
= calloc(1, sizeof(*ctx
));
74 ctx
->radeon
= radeon_incref(radeon
);
76 ctx
->max_reloc
= 4096;
77 ctx
->pm4
= malloc(RADEON_CTX_MAX_PM4
* 4);
78 if (ctx
->pm4
== NULL
) {
79 return radeon_ctx_decref(ctx
);
81 ctx
->state_crc32
= malloc(ctx
->radeon
->nstate
* 4);
82 if (ctx
->state_crc32
== NULL
) {
83 return radeon_ctx_decref(ctx
);
85 ctx
->bo
= malloc(ctx
->max_bo
* sizeof(struct radeon_ctx_bo
));
86 if (ctx
->bo
== NULL
) {
87 return radeon_ctx_decref(ctx
);
89 ctx
->reloc
= malloc(ctx
->max_reloc
* sizeof(struct radeon_cs_reloc
));
90 if (ctx
->reloc
== NULL
) {
91 return radeon_ctx_decref(ctx
);
93 radeon_ctx_clear(ctx
);
97 struct radeon_ctx
*radeon_ctx_incref(struct radeon_ctx
*ctx
)
103 struct radeon_ctx
*radeon_ctx_decref(struct radeon_ctx
*ctx
)
107 if (--ctx
->refcount
> 0) {
111 ctx
->radeon
= radeon_decref(ctx
->radeon
);
115 free(ctx
->state_crc32
);
116 memset(ctx
, 0, sizeof(*ctx
));
121 static int radeon_ctx_bo_id(struct radeon_ctx
*ctx
, struct radeon_bo
*bo
)
125 for (i
= 0; i
< ctx
->nbo
; i
++) {
126 if (bo
== ctx
->bo
[i
].bo
)
132 static int radeon_ctx_state_bo(struct radeon_ctx
*ctx
, struct radeon_state
*state
)
139 for (i
= 0; i
< state
->nbo
; i
++) {
140 for (j
= 0; j
< ctx
->nbo
; j
++) {
141 if (state
->bo
[i
] == ctx
->bo
[j
].bo
)
145 if (ctx
->nbo
>= ctx
->max_bo
) {
148 radeon_bo_incref(ctx
->radeon
, state
->bo
[i
]);
149 r
= radeon_ctx_set_bo_new(ctx
, state
->bo
[i
], state
->id
);
157 int radeon_ctx_submit(struct radeon_ctx
*ctx
)
159 struct drm_radeon_cs drmib
;
160 struct drm_radeon_cs_chunk chunks
[2];
161 uint64_t chunk_array
[2];
167 for (r
= 0; r
< ctx
->id
; r
++) {
168 fprintf(stderr
, "0x%08X\n", ctx
->pm4
[r
]);
171 drmib
.num_chunks
= 2;
172 drmib
.chunks
= (uint64_t)(uintptr_t)chunk_array
;
173 chunks
[0].chunk_id
= RADEON_CHUNK_ID_IB
;
174 chunks
[0].length_dw
= ctx
->id
;
175 chunks
[0].chunk_data
= (uint64_t)(uintptr_t)ctx
->pm4
;
176 chunks
[1].chunk_id
= RADEON_CHUNK_ID_RELOCS
;
177 chunks
[1].length_dw
= ctx
->nreloc
* sizeof(struct radeon_cs_reloc
) / 4;
178 chunks
[1].chunk_data
= (uint64_t)(uintptr_t)ctx
->reloc
;
179 chunk_array
[0] = (uint64_t)(uintptr_t)&chunks
[0];
180 chunk_array
[1] = (uint64_t)(uintptr_t)&chunks
[1];
182 r
= drmCommandWriteRead(ctx
->radeon
->fd
, DRM_RADEON_CS
, &drmib
,
183 sizeof(struct drm_radeon_cs
));
188 int radeon_ctx_reloc(struct radeon_ctx
*ctx
, struct radeon_bo
*bo
,
189 unsigned id
, unsigned *placement
)
193 for (i
= 0; i
< ctx
->nreloc
; i
++) {
194 if (ctx
->reloc
[i
].handle
== bo
->handle
) {
195 ctx
->pm4
[id
] = i
* sizeof(struct radeon_cs_reloc
) / 4;
199 if (ctx
->nreloc
>= ctx
->max_reloc
) {
202 ctx
->reloc
[ctx
->nreloc
].handle
= bo
->handle
;
203 ctx
->reloc
[ctx
->nreloc
].read_domain
= placement
[0] | placement
[1];
204 ctx
->reloc
[ctx
->nreloc
].write_domain
= placement
[0] | placement
[1];
205 ctx
->reloc
[ctx
->nreloc
].flags
= 0;
206 ctx
->pm4
[id
] = ctx
->nreloc
* sizeof(struct radeon_cs_reloc
) / 4;
211 static int radeon_ctx_state_schedule(struct radeon_ctx
*ctx
, struct radeon_state
*state
)
213 unsigned i
, rid
, cid
;
219 for (i
= 0; i
< state
->nbo
; i
++) {
220 bo_id
[i
] = radeon_ctx_bo_id(ctx
, state
->bo
[i
]);
224 flags
= (~ctx
->bo
[bo_id
[i
]].bo_flushed
) & ctx
->radeon
->type
[state
->id
].flush_flags
;
226 r
= ctx
->radeon
->bo_flush(ctx
, state
->bo
[i
], flags
, &state
->placement
[i
* 2]);
231 ctx
->bo
[bo_id
[i
]].bo_flushed
|= ctx
->radeon
->type
[state
->id
].flush_flags
;
233 if ((ctx
->radeon
->type
[state
->id
].header_cpm4
+ state
->cpm4
) > ctx
->npm4
) {
237 memcpy(&ctx
->pm4
[ctx
->id
], ctx
->radeon
->type
[state
->id
].header_pm4
, ctx
->radeon
->type
[state
->id
].header_cpm4
* 4);
238 ctx
->id
+= ctx
->radeon
->type
[state
->id
].header_cpm4
;
239 ctx
->npm4
-= ctx
->radeon
->type
[state
->id
].header_cpm4
;
240 memcpy(&ctx
->pm4
[ctx
->id
], state
->states
, state
->cpm4
* 4);
241 for (i
= 0; i
< state
->nbo
; i
++) {
242 rid
= state
->reloc_pm4_id
[i
];
244 r
= radeon_ctx_reloc(ctx
, state
->bo
[i
], cid
,
245 &state
->placement
[i
* 2]);
247 fprintf(stderr
, "%s state %d failed to reloc\n", __func__
, state
->id
);
251 ctx
->id
+= state
->cpm4
;
252 ctx
->npm4
-= state
->cpm4
;
253 for (i
= 0; i
< state
->nbo
; i
++) {
254 ctx
->bo
[bo_id
[i
]].bo_flushed
&= ~ctx
->radeon
->type
[state
->id
].dirty_flags
;
259 int radeon_ctx_set_query_state(struct radeon_ctx
*ctx
, struct radeon_state
*state
)
264 r
= radeon_state_pm4(state
);
268 /* !!! ONLY ACCEPT QUERY STATE HERE !!! */
269 ndw
= state
->cpm4
+ ctx
->radeon
->type
[state
->id
].header_cpm4
;
271 case R600_QUERY_BEGIN
:
272 /* account QUERY_END at same time of QUERY_BEGIN so we know we
273 * have room left for QUERY_END
275 if ((ndw
* 2) > ctx
->npm4
) {
282 /* add again ndw from previous accounting */
289 return radeon_ctx_state_schedule(ctx
, state
);
292 int radeon_ctx_set_draw(struct radeon_ctx
*ctx
, struct radeon_draw
*draw
)
294 unsigned i
, previous_id
;
297 for (i
= 0; i
< draw
->nstate
; i
++) {
298 r
= radeon_ctx_state_bo(ctx
, draw
->state
[i
]);
302 r
= radeon_draw_check(draw
);
305 if (draw
->cpm4
>= RADEON_CTX_MAX_PM4
) {
306 fprintf(stderr
, "%s single draw too big %d, max %d\n",
307 __func__
, draw
->cpm4
, RADEON_CTX_MAX_PM4
);
310 previous_id
= ctx
->id
;
311 for (i
= 0; i
< draw
->nstate
; i
++) {
312 /* FIXME always force draw state to schedule */
313 if (draw
->state
[i
] && draw
->state
[i
]->pm4_crc
!= ctx
->state_crc32
[draw
->state
[i
]->id
]) {
314 r
= radeon_ctx_state_schedule(ctx
, draw
->state
[i
]);
316 ctx
->id
= previous_id
;
324 void radeon_ctx_dump_bof(struct radeon_ctx
*ctx
, const char *file
)
326 bof_t
*bcs
, *blob
, *array
, *bo
, *size
, *handle
, *device_id
, *root
;
329 root
= device_id
= bcs
= blob
= array
= bo
= size
= handle
= NULL
;
333 device_id
= bof_int32(ctx
->radeon
->device
);
334 if (device_id
== NULL
)
336 if (bof_object_set(root
, "device_id", device_id
))
338 bof_decref(device_id
);
341 printf("%d relocs\n", ctx
->nreloc
);
342 blob
= bof_blob(ctx
->nreloc
* 16, ctx
->reloc
);
345 if (bof_object_set(root
, "reloc", blob
))
350 printf("%d pm4\n", ctx
->id
);
351 blob
= bof_blob(ctx
->id
* 4, ctx
->pm4
);
354 if (bof_object_set(root
, "pm4", blob
))
362 for (i
= 0; i
< ctx
->nbo
; i
++) {
366 size
= bof_int32(ctx
->bo
[i
].bo
->size
);
369 if (bof_object_set(bo
, "size", size
))
373 handle
= bof_int32(ctx
->bo
[i
].bo
->handle
);
376 if (bof_object_set(bo
, "handle", handle
))
380 radeon_bo_map(ctx
->radeon
, ctx
->bo
[i
].bo
);
381 blob
= bof_blob(ctx
->bo
[i
].bo
->size
, ctx
->bo
[i
].bo
->data
);
382 radeon_bo_unmap(ctx
->radeon
, ctx
->bo
[i
].bo
);
385 if (bof_object_set(bo
, "data", blob
))
389 if (bof_array_append(array
, bo
))
394 if (bof_object_set(root
, "bo", array
))
396 bof_dump_file(root
, file
);
397 printf("done dump\n");
404 bof_decref(device_id
);