Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / gallium / winsys / drm / intel / common / intel_be_batchbuffer.c
1
2 #include "intel_be_batchbuffer.h"
3 #include "intel_be_context.h"
4 #include "intel_be_device.h"
5 #include <errno.h>
6
7 #include "xf86drm.h"
8
9 static void
10 intel_realloc_relocs(struct intel_be_batchbuffer *batch, int num_relocs)
11 {
12 unsigned long size = num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER;
13
14 size *= sizeof(uint32_t);
15 batch->reloc = realloc(batch->reloc, size);
16 batch->reloc_size = num_relocs;
17 }
18
19
20 void
21 intel_be_batchbuffer_reset(struct intel_be_batchbuffer *batch)
22 {
23 /*
24 * Get a new, free batchbuffer.
25 */
26 drmBO *bo;
27 struct drm_bo_info_req *req;
28
29 driBOUnrefUserList(batch->list);
30 driBOResetList(batch->list);
31
32 /* base.size is the size available to the i915simple driver */
33 batch->base.size = batch->device->max_batch_size - BATCH_RESERVED;
34 batch->base.actual_size = batch->device->max_batch_size;
35 driBOData(batch->buffer, batch->base.actual_size, NULL, NULL, 0);
36
37 /*
38 * Add the batchbuffer to the validate list.
39 */
40
41 driBOAddListItem(batch->list, batch->buffer,
42 DRM_BO_FLAG_EXE | DRM_BO_FLAG_MEM_TT,
43 DRM_BO_FLAG_EXE | DRM_BO_MASK_MEM,
44 &batch->dest_location, &batch->node);
45
46 req = &batch->node->bo_arg.d.req.bo_req;
47
48 /*
49 * Set up information needed for us to make relocations
50 * relative to the underlying drm buffer objects.
51 */
52
53 driReadLockKernelBO();
54 bo = driBOKernel(batch->buffer);
55 req->presumed_offset = (uint64_t) bo->offset;
56 req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
57 batch->drmBOVirtual = (uint8_t *) bo->virtual;
58 driReadUnlockKernelBO();
59
60 /*
61 * Adjust the relocation buffer size.
62 */
63
64 if (batch->reloc_size > INTEL_MAX_RELOCS ||
65 batch->reloc == NULL)
66 intel_realloc_relocs(batch, INTEL_DEFAULT_RELOCS);
67
68 assert(batch->reloc != NULL);
69 batch->reloc[0] = 0; /* No relocs yet. */
70 batch->reloc[1] = 1; /* Reloc type 1 */
71 batch->reloc[2] = 0; /* Only a single relocation list. */
72 batch->reloc[3] = 0; /* Only a single relocation list. */
73
74 batch->base.map = driBOMap(batch->buffer, DRM_BO_FLAG_WRITE, 0);
75 batch->poolOffset = driBOPoolOffset(batch->buffer);
76 batch->base.ptr = batch->base.map;
77 batch->dirty_state = ~0;
78 batch->nr_relocs = 0;
79 batch->flags = 0;
80 batch->id = 0;//batch->intel->intelScreen->batch_id++;
81 }
82
83 /*======================================================================
84 * Public functions
85 */
86 struct intel_be_batchbuffer *
87 intel_be_batchbuffer_alloc(struct intel_be_context *intel)
88 {
89 struct intel_be_batchbuffer *batch = calloc(sizeof(*batch), 1);
90
91 batch->intel = intel;
92 batch->device = intel->device;
93
94 driGenBuffers(intel->device->batchPool, "batchbuffer", 1,
95 &batch->buffer, 4096,
96 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE, 0);
97 batch->last_fence = NULL;
98 batch->list = driBOCreateList(20);
99 batch->reloc = NULL;
100 intel_be_batchbuffer_reset(batch);
101 return batch;
102 }
103
104 void
105 intel_be_batchbuffer_free(struct intel_be_batchbuffer *batch)
106 {
107 if (batch->last_fence) {
108 driFenceFinish(batch->last_fence,
109 DRM_FENCE_TYPE_EXE, FALSE);
110 driFenceUnReference(&batch->last_fence);
111 }
112 if (batch->base.map) {
113 driBOUnmap(batch->buffer);
114 batch->base.map = NULL;
115 }
116 driBOUnReference(batch->buffer);
117 driBOFreeList(batch->list);
118 if (batch->reloc)
119 free(batch->reloc);
120 batch->buffer = NULL;
121 free(batch);
122 }
123
124 void
125 intel_be_offset_relocation(struct intel_be_batchbuffer *batch,
126 unsigned pre_add,
127 struct _DriBufferObject *driBO,
128 uint64_t val_flags,
129 uint64_t val_mask)
130 {
131 int itemLoc;
132 struct _drmBONode *node;
133 uint32_t *reloc;
134 struct drm_bo_info_req *req;
135
136 driBOAddListItem(batch->list, driBO, val_flags, val_mask,
137 &itemLoc, &node);
138 req = &node->bo_arg.d.req.bo_req;
139
140 if (!(req->hint & DRM_BO_HINT_PRESUMED_OFFSET)) {
141
142 /*
143 * Stop other threads from tampering with the underlying
144 * drmBO while we're reading its offset.
145 */
146
147 driReadLockKernelBO();
148 req->presumed_offset = (uint64_t) driBOKernel(driBO)->offset;
149 driReadUnlockKernelBO();
150 req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
151 }
152
153 pre_add += driBOPoolOffset(driBO);
154
155 if (batch->nr_relocs == batch->reloc_size)
156 intel_realloc_relocs(batch, batch->reloc_size * 2);
157
158 reloc = batch->reloc +
159 (I915_RELOC_HEADER + batch->nr_relocs * I915_RELOC0_STRIDE);
160
161 reloc[0] = ((uint8_t *)batch->base.ptr - batch->drmBOVirtual);
162 i915_batchbuffer_dword(&batch->base, req->presumed_offset + pre_add);
163 reloc[1] = pre_add;
164 reloc[2] = itemLoc;
165 reloc[3] = batch->dest_location;
166 batch->nr_relocs++;
167 }
168
169 static void
170 i915_drm_copy_reply(const struct drm_bo_info_rep * rep, drmBO * buf)
171 {
172 buf->handle = rep->handle;
173 buf->flags = rep->flags;
174 buf->size = rep->size;
175 buf->offset = rep->offset;
176 buf->mapHandle = rep->arg_handle;
177 buf->proposedFlags = rep->proposed_flags;
178 buf->start = rep->buffer_start;
179 buf->fenceFlags = rep->fence_flags;
180 buf->replyFlags = rep->rep_flags;
181 buf->pageAlignment = rep->page_alignment;
182 }
183
184 static int
185 i915_execbuf(struct intel_be_batchbuffer *batch,
186 unsigned int used,
187 boolean ignore_cliprects,
188 drmBOList *list,
189 struct drm_i915_execbuffer *ea)
190 {
191 // struct intel_be_context *intel = batch->intel;
192 drmBONode *node;
193 drmMMListHead *l;
194 struct drm_i915_op_arg *arg, *first;
195 struct drm_bo_op_req *req;
196 struct drm_bo_info_rep *rep;
197 uint64_t *prevNext = NULL;
198 drmBO *buf;
199 int ret = 0;
200 uint32_t count = 0;
201
202 first = NULL;
203 for (l = list->list.next; l != &list->list; l = l->next) {
204 node = DRMLISTENTRY(drmBONode, l, head);
205
206 arg = &node->bo_arg;
207 req = &arg->d.req;
208
209 if (!first)
210 first = arg;
211
212 if (prevNext)
213 *prevNext = (unsigned long)arg;
214
215 prevNext = &arg->next;
216 req->bo_req.handle = node->buf->handle;
217 req->op = drm_bo_validate;
218 req->bo_req.flags = node->arg0;
219 req->bo_req.mask = node->arg1;
220 req->bo_req.hint |= 0;
221 count++;
222 }
223
224 memset(ea, 0, sizeof(*ea));
225 ea->num_buffers = count;
226 ea->batch.start = batch->poolOffset;
227 ea->batch.used = used;
228 #if 0 /* ZZZ JB: no cliprects used */
229 ea->batch.cliprects = intel->pClipRects;
230 ea->batch.num_cliprects = ignore_cliprects ? 0 : intel->numClipRects;
231 ea->batch.DR1 = 0;
232 ea->batch.DR4 = 0;((((GLuint) intel->drawX) & 0xffff) |
233 (((GLuint) intel->drawY) << 16));
234 #else
235 ea->batch.cliprects = NULL;
236 ea->batch.num_cliprects = 0;
237 ea->batch.DR1 = 0;
238 ea->batch.DR4 = 0;
239 #endif
240 ea->fence_arg.flags = DRM_I915_FENCE_FLAG_FLUSHED;
241 ea->ops_list = (unsigned long) first;
242 first->reloc_ptr = (unsigned long) batch->reloc;
243 batch->reloc[0] = batch->nr_relocs;
244
245 //return -EFAULT;
246 do {
247 ret = drmCommandWriteRead(batch->device->fd, DRM_I915_EXECBUFFER, ea,
248 sizeof(*ea));
249 } while (ret == -EAGAIN);
250
251 if (ret != 0)
252 return ret;
253
254 for (l = list->list.next; l != &list->list; l = l->next) {
255 node = DRMLISTENTRY(drmBONode, l, head);
256 arg = &node->bo_arg;
257 rep = &arg->d.rep.bo_info;
258
259 if (!arg->handled) {
260 return -EFAULT;
261 }
262 if (arg->d.rep.ret)
263 return arg->d.rep.ret;
264
265 buf = node->buf;
266 i915_drm_copy_reply(rep, buf);
267 }
268 return 0;
269 }
270
271 /* TODO: Push this whole function into bufmgr.
272 */
273 static struct _DriFenceObject *
274 do_flush_locked(struct intel_be_batchbuffer *batch,
275 unsigned int used,
276 boolean ignore_cliprects, boolean allow_unlock)
277 {
278 struct intel_be_context *intel = batch->intel;
279 struct _DriFenceObject *fo;
280 drmFence fence;
281 drmBOList *boList;
282 struct drm_i915_execbuffer ea;
283 int ret = 0;
284
285 driBOValidateUserList(batch->list);
286 boList = driGetdrmBOList(batch->list);
287
288 #if 0 /* ZZZ JB Allways run */
289 if (!(intel->numClipRects == 0 && !ignore_cliprects)) {
290 #else
291 if (1) {
292 #endif
293 ret = i915_execbuf(batch, used, ignore_cliprects, boList, &ea);
294 } else {
295 driPutdrmBOList(batch->list);
296 fo = NULL;
297 goto out;
298 }
299 driPutdrmBOList(batch->list);
300 if (ret)
301 abort();
302
303 if (ea.fence_arg.error != 0) {
304
305 /*
306 * The hardware has been idled by the kernel.
307 * Don't fence the driBOs.
308 */
309
310 if (batch->last_fence)
311 driFenceUnReference(&batch->last_fence);
312 #if 0 /* ZZZ JB: no _mesa_* funcs in gallium */
313 _mesa_printf("fence error\n");
314 #endif
315 batch->last_fence = NULL;
316 fo = NULL;
317 goto out;
318 }
319
320 fence.handle = ea.fence_arg.handle;
321 fence.fence_class = ea.fence_arg.fence_class;
322 fence.type = ea.fence_arg.type;
323 fence.flags = ea.fence_arg.flags;
324 fence.signaled = ea.fence_arg.signaled;
325
326 fo = driBOFenceUserList(batch->device->fenceMgr, batch->list,
327 "SuperFence", &fence);
328
329 if (driFenceType(fo) & DRM_I915_FENCE_TYPE_RW) {
330 if (batch->last_fence)
331 driFenceUnReference(&batch->last_fence);
332 /*
333 * FIXME: Context last fence??
334 */
335 batch->last_fence = fo;
336 driFenceReference(fo);
337 }
338 out:
339 #if 0 /* ZZZ JB: fix this */
340 intel->vtbl.lost_hardware(intel);
341 #else
342 (void)intel;
343 #endif
344 return fo;
345 }
346
347
348 struct _DriFenceObject *
349 intel_be_batchbuffer_flush(struct intel_be_batchbuffer *batch)
350 {
351 struct intel_be_context *intel = batch->intel;
352 unsigned int used = batch->base.ptr - batch->base.map;
353 boolean was_locked = batch->intel->hardware_locked(intel);
354 struct _DriFenceObject *fence;
355
356 if (used == 0) {
357 driFenceReference(batch->last_fence);
358 return batch->last_fence;
359 }
360
361 /* Add the MI_BATCH_BUFFER_END. Always add an MI_FLUSH - this is a
362 * performance drain that we would like to avoid.
363 */
364 #if 0 /* ZZZ JB: what should we do here? */
365 if (used & 4) {
366 ((int *) batch->base.ptr)[0] = intel->vtbl.flush_cmd();
367 ((int *) batch->base.ptr)[1] = 0;
368 ((int *) batch->base.ptr)[2] = MI_BATCH_BUFFER_END;
369 used += 12;
370 }
371 else {
372 ((int *) batch->base.ptr)[0] = intel->vtbl.flush_cmd();
373 ((int *) batch->base.ptr)[1] = MI_BATCH_BUFFER_END;
374 used += 8;
375 }
376 #else
377 if (used & 4) {
378 ((int *) batch->base.ptr)[0] = ((0<<29)|(4<<23)); // MI_FLUSH;
379 ((int *) batch->base.ptr)[1] = 0;
380 ((int *) batch->base.ptr)[2] = (0xA<<23); // MI_BATCH_BUFFER_END;
381 used += 12;
382 }
383 else {
384 ((int *) batch->base.ptr)[0] = ((0<<29)|(4<<23)); // MI_FLUSH;
385 ((int *) batch->base.ptr)[1] = (0xA<<23); // MI_BATCH_BUFFER_END;
386 used += 8;
387 }
388 #endif
389 driBOUnmap(batch->buffer);
390 batch->base.ptr = NULL;
391 batch->base.map = NULL;
392
393 /* TODO: Just pass the relocation list and dma buffer up to the
394 * kernel.
395 */
396 if (!was_locked)
397 intel->hardware_lock(intel);
398
399 fence = do_flush_locked(batch, used, !(batch->flags & INTEL_BATCH_CLIPRECTS),
400 FALSE);
401
402 if (!was_locked)
403 intel->hardware_unlock(intel);
404
405 /* Reset the buffer:
406 */
407 intel_be_batchbuffer_reset(batch);
408 return fence;
409 }
410
411 void
412 intel_be_batchbuffer_finish(struct intel_be_batchbuffer *batch)
413 {
414 struct _DriFenceObject *fence = intel_be_batchbuffer_flush(batch);
415 driFenceFinish(fence, driFenceType(fence), FALSE);
416 driFenceUnReference(&fence);
417 }
418
419 #if 0
420 void
421 intel_be_batchbuffer_data(struct intel_be_batchbuffer *batch,
422 const void *data, unsigned int bytes, unsigned int flags)
423 {
424 assert((bytes & 3) == 0);
425 intel_batchbuffer_require_space(batch, bytes, flags);
426 memcpy(batch->base.ptr, data, bytes);
427 batch->base.ptr += bytes;
428 }
429 #endif