1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
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 above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 #include "intel_batchbuffer.h"
29 #include "intel_ioctl.h"
31 /* Relocations in kernel space:
32 * - pass dma buffer seperately
33 * - memory manager knows how to patch
34 * - pass list of dependent buffers
35 * - pass relocation list
38 * - get back an offset for buffer to fire
39 * - memory manager knows how to fire buffer
41 * Really want the buffer to be AGP and pinned.
45 /* Cliprect fence: The highest fence protecting a dma buffer
46 * containing explicit cliprect information. Like the old drawable
47 * lock but irq-driven. X server must wait for this fence to expire
48 * before changing cliprects [and then doing sw rendering?]. For
49 * other dma buffers, the scheduler will grab current cliprect info
50 * and mix into buffer. X server must hold the lock while changing
51 * cliprects??? Make per-drawable. Need cliprects in shared memory
52 * -- beats storing them with every cmd buffer in the queue.
54 * ==> X server must wait for this fence to expire before touching the
55 * framebuffer with new cliprects.
57 * ==> Cliprect-dependent buffers associated with a
58 * cliprect-timestamp. All of the buffers associated with a timestamp
59 * must go to hardware before any buffer with a newer timestamp.
61 * ==> Dma should be queued per-drawable for correct X/GL
62 * synchronization. Or can fences be used for this?
64 * Applies to: Blit operations, metaops, X server operations -- X
65 * server automatically waits on its own dma to complete before
66 * modifying cliprects ???
70 intel_dump_batchbuffer(GLuint offset
, GLuint
* ptr
, GLuint count
)
73 fprintf(stderr
, "\n\n\nSTART BATCH (%d dwords):\n", count
/ 4);
74 for (i
= 0; i
< count
/ 4; i
+= 4)
75 fprintf(stderr
, "0x%x:\t0x%08x 0x%08x 0x%08x 0x%08x\n",
76 offset
+ i
* 4, ptr
[i
], ptr
[i
+ 1], ptr
[i
+ 2], ptr
[i
+ 3]);
77 fprintf(stderr
, "END BATCH\n\n\n");
80 /*======================================================================
83 struct intel_batchbuffer
*
84 intel_batchbuffer_alloc(struct intel_context
*intel
)
86 struct intel_batchbuffer
*batch
= calloc(sizeof(*batch
), 1);
89 batch
->buf
= dri_bo_alloc(intel
->intelScreen
->bufmgr
, "batchbuffer",
90 intel
->intelScreen
->maxBatchSize
, 4096,
93 dri_bo_map(batch
->buf
, GL_TRUE
);
94 batch
->map
= batch
->buf
->virtual;
95 batch
->size
= intel
->intelScreen
->maxBatchSize
;
96 batch
->ptr
= batch
->map
;
98 batch
->last_fence
= NULL
;
99 intel_batchbuffer_reset(batch
);
104 intel_batchbuffer_free(struct intel_batchbuffer
*batch
)
106 if (batch
->last_fence
) {
107 dri_fence_wait(batch
->last_fence
);
108 dri_fence_unreference(batch
->last_fence
);
109 batch
->last_fence
= NULL
;
112 dri_bo_unmap(batch
->buf
);
115 dri_bo_unreference(batch
->buf
);
120 /* TODO: Push this whole function into bufmgr.
123 do_flush_locked(struct intel_batchbuffer
*batch
,
125 GLboolean ignore_cliprects
, GLboolean allow_unlock
)
129 struct intel_context
*intel
= batch
->intel
;
131 GLboolean performed_rendering
= GL_FALSE
;
133 assert(batch
->buf
->virtual != NULL
);
134 ptr
= batch
->buf
->virtual;
136 for (i
= 0; i
< batch
->nr_relocs
; i
++) {
137 struct buffer_reloc
*r
= &batch
->reloc
[i
];
139 if (r
->validate_flags
& DRM_BO_FLAG_WRITE
)
140 performed_rendering
= GL_TRUE
;
142 dri_bo_validate(r
->buf
, r
->validate_flags
);
143 ptr
[r
->offset
/ 4] = r
->buf
->offset
+ r
->delta
;
144 dri_bo_unreference(r
->buf
);
147 if (INTEL_DEBUG
& DEBUG_BATCH
)
148 intel_dump_batchbuffer(0, ptr
, used
);
150 dri_bo_unmap(batch
->buf
);
154 dri_bo_validate(batch
->buf
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_EXE
);
156 batch
->list_count
= 0;
157 batch
->nr_relocs
= 0;
160 /* Throw away non-effective packets. Won't work once we have
161 * hardware contexts which would preserve statechanges beyond a
165 if (!(intel
->numClipRects
== 0 && !ignore_cliprects
)) {
166 intel_batch_ioctl(batch
->intel
,
168 used
, ignore_cliprects
, allow_unlock
);
171 /* Associate a fence with the validated buffers, and note that we included
172 * a flush at the end.
174 fo
= dri_fence_validated(intel
->intelScreen
->bufmgr
,
175 "Batch fence", GL_TRUE
);
177 if (performed_rendering
) {
178 dri_fence_unreference(batch
->last_fence
);
179 batch
->last_fence
= fo
;
181 /* If we didn't validate any buffers for writing by the card, we don't
182 * need to track the fence for glFinish().
184 dri_fence_unreference(fo
);
187 if (intel
->numClipRects
== 0 && !ignore_cliprects
) {
189 /* If we are not doing any actual user-visible rendering,
190 * do a sched_yield to keep the app from pegging the cpu while
193 UNLOCK_HARDWARE(intel
);
195 LOCK_HARDWARE(intel
);
197 intel
->vtbl
.lost_hardware(intel
);
203 intel_batchbuffer_flush(struct intel_batchbuffer
*batch
)
205 struct intel_context
*intel
= batch
->intel
;
206 GLuint used
= batch
->ptr
- batch
->map
;
207 GLboolean was_locked
= intel
->locked
;
212 /* Add the MI_BATCH_BUFFER_END. Always add an MI_FLUSH - this is a
213 * performance drain that we would like to avoid.
216 ((int *) batch
->ptr
)[0] = intel
->vtbl
.flush_cmd();
217 ((int *) batch
->ptr
)[1] = 0;
218 ((int *) batch
->ptr
)[2] = MI_BATCH_BUFFER_END
;
222 ((int *) batch
->ptr
)[0] = intel
->vtbl
.flush_cmd();
223 ((int *) batch
->ptr
)[1] = MI_BATCH_BUFFER_END
;
227 /* TODO: Just pass the relocation list and dma buffer up to the
231 LOCK_HARDWARE(intel
);
233 do_flush_locked(batch
, used
, !(batch
->flags
& INTEL_BATCH_CLIPRECTS
),
237 UNLOCK_HARDWARE(intel
);
241 intel_batchbuffer_reset(batch
);
245 intel_batchbuffer_finish(struct intel_batchbuffer
*batch
)
247 intel_batchbuffer_flush(batch
);
248 if (batch
->last_fence
!= NULL
)
249 dri_fence_wait(batch
->last_fence
);
253 /* This is the only way buffers get added to the validate list.
256 intel_batchbuffer_emit_reloc(struct intel_batchbuffer
*batch
,
258 GLuint flags
, GLuint delta
)
260 struct buffer_reloc
*r
= &batch
->reloc
[batch
->nr_relocs
++];
262 assert(batch
->nr_relocs
<= MAX_RELOCS
);
264 dri_bo_reference(buffer
);
266 r
->offset
= batch
->ptr
- batch
->map
;
268 r
->validate_flags
= flags
;
277 intel_batchbuffer_data(struct intel_batchbuffer
*batch
,
278 const void *data
, GLuint bytes
, GLuint flags
)
280 assert((bytes
& 3) == 0);
281 intel_batchbuffer_require_space(batch
, bytes
, flags
);
282 __memcpy(batch
->ptr
, data
, bytes
);