1 #ifndef __NOUVEAU_STATEOBJ_H__
2 #define __NOUVEAU_STATEOBJ_H__
4 #include "util/u_debug.h"
7 #define DEBUG_NOUVEAU_STATEOBJ
10 struct nouveau_stateobj_reloc
{
11 struct nouveau_bo
*bo
;
13 struct nouveau_grobj
*gr
;
23 struct nouveau_stateobj_start
{
24 struct nouveau_grobj
*gr
;
30 struct nouveau_stateobj
{
31 struct pipe_reference reference
;
33 struct nouveau_stateobj_start
*start
;
34 struct nouveau_stateobj_reloc
*reloc
;
36 /* Common memory pool for data. */
40 #ifdef DEBUG_NOUVEAU_STATEOBJ
44 #endif /* DEBUG_NOUVEAU_STATEOBJ */
46 unsigned total
; /* includes begin_ring */
47 unsigned cur
; /* excludes begin_ring, offset from "cur_start" */
53 so_dump(struct nouveau_stateobj
*so
)
55 unsigned i
, nr
, total
= 0;
57 for (i
= 0; i
< so
->cur_start
; i
++) {
58 if (so
->start
[i
].gr
->subc
> -1)
59 debug_printf("+0x%04x: 0x%08x\n", total
++,
60 (so
->start
[i
].size
<< 18) | (so
->start
[i
].gr
->subc
<< 13)
63 debug_printf("+0x%04x: 0x%08x\n", total
++,
64 (so
->start
[i
].size
<< 18) | so
->start
[i
].mthd
);
65 for (nr
= 0; nr
< so
->start
[i
].size
; nr
++, total
++)
66 debug_printf("+0x%04x: 0x%08x\n", total
,
67 so
->pool
[so
->start
[i
].offset
+ nr
]);
71 static INLINE
struct nouveau_stateobj
*
72 so_new(unsigned start
, unsigned push
, unsigned reloc
)
74 struct nouveau_stateobj
*so
;
76 so
= MALLOC(sizeof(struct nouveau_stateobj
));
77 pipe_reference_init(&so
->reference
, 1);
78 so
->total
= so
->cur
= so
->cur_start
= so
->cur_reloc
= 0;
80 #ifdef DEBUG_NOUVEAU_STATEOBJ
81 so
->start_alloc
= start
;
82 so
->reloc_alloc
= reloc
;
83 so
->pool_alloc
= push
;
84 #endif /* DEBUG_NOUVEAU_STATEOBJ */
86 so
->start
= MALLOC(start
* sizeof(struct nouveau_stateobj_start
));
87 so
->reloc
= MALLOC(reloc
* sizeof(struct nouveau_stateobj_reloc
));
88 so
->pool
= MALLOC(push
* sizeof(uint32_t));
91 if (!so
->start
|| !so
->reloc
|| !so
->pool
) {
92 debug_printf("malloc failed\n");
100 so_ref(struct nouveau_stateobj
*ref
, struct nouveau_stateobj
**pso
)
102 struct nouveau_stateobj
*so
= *pso
;
105 if (pipe_reference(&(*pso
)->reference
, &ref
->reference
)) {
107 for (i
= 0; i
< so
->cur_reloc
; i
++)
108 nouveau_bo_ref(NULL
, &so
->reloc
[i
].bo
);
117 so_data(struct nouveau_stateobj
*so
, uint32_t data
)
119 #ifdef DEBUG_NOUVEAU_STATEOBJ
120 if (so
->cur
>= so
->start
[so
->cur_start
- 1].size
) {
121 debug_printf("exceeding specified size\n");
124 #endif /* DEBUG_NOUVEAU_STATEOBJ */
126 so
->pool
[so
->start
[so
->cur_start
- 1].offset
+ so
->cur
++] = data
;
130 so_datap(struct nouveau_stateobj
*so
, uint32_t *data
, unsigned size
)
132 #ifdef DEBUG_NOUVEAU_STATEOBJ
133 if ((so
->cur
+ size
) > so
->start
[so
->cur_start
- 1].size
) {
134 debug_printf("exceeding specified size\n");
137 #endif /* DEBUG_NOUVEAU_STATEOBJ */
140 so
->pool
[so
->start
[so
->cur_start
- 1].offset
+ so
->cur
++] =
145 so_method(struct nouveau_stateobj
*so
, struct nouveau_grobj
*gr
,
146 unsigned mthd
, unsigned size
)
148 struct nouveau_stateobj_start
*start
;
150 #ifdef DEBUG_NOUVEAU_STATEOBJ
151 if (so
->start_alloc
<= so
->cur_start
) {
152 debug_printf("exceeding num_start size\n");
155 #endif /* DEBUG_NOUVEAU_STATEOBJ */
158 #ifdef DEBUG_NOUVEAU_STATEOBJ
159 if (so
->cur_start
> 0 && start
[so
->cur_start
- 1].size
> so
->cur
) {
160 debug_printf("previous so_method was not filled\n");
163 #endif /* DEBUG_NOUVEAU_STATEOBJ */
165 start
[so
->cur_start
].gr
= gr
;
166 start
[so
->cur_start
].mthd
= mthd
;
167 start
[so
->cur_start
].size
= size
;
169 #ifdef DEBUG_NOUVEAU_STATEOBJ
170 if (so
->pool_alloc
< (size
+ so
->pool_cur
)) {
171 debug_printf("exceeding num_pool size\n");
174 #endif /* DEBUG_NOUVEAU_STATEOBJ */
176 start
[so
->cur_start
].offset
= so
->pool_cur
;
177 so
->pool_cur
+= size
;
180 /* The 1 is for *this* begin_ring. */
181 so
->total
+= so
->cur
+ 1;
186 so_reloc(struct nouveau_stateobj
*so
, struct nouveau_bo
*bo
,
187 unsigned data
, unsigned flags
, unsigned vor
, unsigned tor
)
189 struct nouveau_stateobj_reloc
*r
;
191 #ifdef DEBUG_NOUVEAU_STATEOBJ
192 if (so
->reloc_alloc
<= so
->cur_reloc
) {
193 debug_printf("exceeding num_reloc size\n");
196 #endif /* DEBUG_NOUVEAU_STATEOBJ */
199 r
[so
->cur_reloc
].bo
= NULL
;
200 nouveau_bo_ref(bo
, &(r
[so
->cur_reloc
].bo
));
201 r
[so
->cur_reloc
].gr
= so
->start
[so
->cur_start
-1].gr
;
202 r
[so
->cur_reloc
].push_offset
= so
->total
+ so
->cur
;
203 r
[so
->cur_reloc
].data
= data
;
204 r
[so
->cur_reloc
].flags
= flags
;
205 r
[so
->cur_reloc
].mthd
= so
->start
[so
->cur_start
-1].mthd
+
207 r
[so
->cur_reloc
].vor
= vor
;
208 r
[so
->cur_reloc
].tor
= tor
;
214 /* Determine if this buffer object is referenced by this state object. */
215 static INLINE boolean
216 so_bo_is_reloc(struct nouveau_stateobj
*so
, struct nouveau_bo
*bo
)
220 for (i
= 0; i
< so
->cur_reloc
; i
++)
221 if (so
->reloc
[i
].bo
== bo
)
228 so_emit(struct nouveau_channel
*chan
, struct nouveau_stateobj
*so
)
233 #ifdef DEBUG_NOUVEAU_STATEOBJ
234 if (so
->start
[so
->cur_start
- 1].size
> so
->cur
) {
235 debug_printf("emit: previous so_method was not filled\n");
238 #endif /* DEBUG_NOUVEAU_STATEOBJ */
240 /* We cannot update total in case we so_emit again. */
241 nr
= so
->total
+ so
->cur
;
243 /* This will flush if we need space.
244 * We don't actually need the marker.
246 if ((ret
= nouveau_pushbuf_marker_emit(chan
, nr
, so
->cur_reloc
))) {
247 debug_printf("so_emit failed marker emit with error %d\n", ret
);
251 /* Submit data. This will ensure proper binding of objects. */
252 for (i
= 0; i
< so
->cur_start
; i
++) {
253 BEGIN_RING(chan
, so
->start
[i
].gr
, so
->start
[i
].mthd
, so
->start
[i
].size
);
254 OUT_RINGp(chan
, &(so
->pool
[so
->start
[i
].offset
]), so
->start
[i
].size
);
257 for (i
= 0; i
< so
->cur_reloc
; i
++) {
258 struct nouveau_stateobj_reloc
*r
= &so
->reloc
[i
];
260 if ((ret
= nouveau_pushbuf_emit_reloc(chan
, chan
->cur
- nr
+
261 r
->push_offset
, r
->bo
, r
->data
,
262 0, r
->flags
, r
->vor
, r
->tor
))) {
263 debug_printf("so_emit failed reloc with error %d\n", ret
);
270 so_emit_reloc_markers(struct nouveau_channel
*chan
, struct nouveau_stateobj
*so
)
278 /* If we need to flush in flush notify, then we have a problem anyway. */
279 for (i
= 0; i
< so
->cur_reloc
; i
++) {
280 struct nouveau_stateobj_reloc
*r
= &so
->reloc
[i
];
282 #ifdef DEBUG_NOUVEAU_STATEOBJ
283 if (r
->mthd
& 0x40000000) {
284 debug_printf("error: NI mthd 0x%08X\n", r
->mthd
);
287 #endif /* DEBUG_NOUVEAU_STATEOBJ */
289 /* We don't need to autobind, since there are enough subchannels
290 * for all objects we use. If this is changed, account for the extra
291 * space in callers of this function.
293 assert(r
->gr
->bound
!= NOUVEAU_GROBJ_UNBOUND
);
295 /* Some relocs really don't like to be hammered,
296 * NOUVEAU_BO_DUMMY makes sure it only
297 * happens when needed.
299 ret
= OUT_RELOC(chan
, r
->bo
, (r
->gr
->subc
<< 13) | (1<< 18) |
300 r
->mthd
, (r
->flags
& (NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
301 | NOUVEAU_BO_RDWR
)) | NOUVEAU_BO_DUMMY
, 0, 0);
303 debug_printf("OUT_RELOC failed %d\n", ret
);
307 ret
= OUT_RELOC(chan
, r
->bo
, r
->data
, r
->flags
|
308 NOUVEAU_BO_DUMMY
, r
->vor
, r
->tor
);
310 debug_printf("OUT_RELOC failed %d\n", ret
);