Merge branch 'gallium-vertex-linear' into gallium-0.1
[mesa.git] / src / mesa / drivers / dri / i915 / intel_ioctl.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sched.h>
33
34 #include "mtypes.h"
35 #include "context.h"
36 #include "swrast/swrast.h"
37
38 #include "intel_context.h"
39 #include "intel_ioctl.h"
40 #include "intel_batchbuffer.h"
41 #include "drm.h"
42
43 u_int32_t intelGetLastFrame (intelContextPtr intel)
44 {
45 int ret;
46 u_int32_t frame;
47 drm_i915_getparam_t gp;
48
49 gp.param = I915_PARAM_LAST_DISPATCH;
50 gp.value = (int *)&frame;
51 ret = drmCommandWriteRead( intel->driFd, DRM_I915_GETPARAM,
52 &gp, sizeof(gp) );
53 return frame;
54 }
55
56 int intelEmitIrqLocked( intelContextPtr intel )
57 {
58 drmI830IrqEmit ie;
59 int ret, seq;
60
61 assert(((*(int *)intel->driHwLock) & ~DRM_LOCK_CONT) ==
62 (DRM_LOCK_HELD|intel->hHWContext));
63
64 ie.irq_seq = &seq;
65
66 ret = drmCommandWriteRead( intel->driFd, DRM_I830_IRQ_EMIT,
67 &ie, sizeof(ie) );
68 if ( ret ) {
69 fprintf( stderr, "%s: drmI830IrqEmit: %d\n", __FUNCTION__, ret );
70 exit(1);
71 }
72
73 if (0)
74 fprintf(stderr, "%s --> %d\n", __FUNCTION__, seq );
75
76 return seq;
77 }
78
79 void intelWaitIrq( intelContextPtr intel, int seq )
80 {
81 int ret;
82
83 if (0)
84 fprintf(stderr, "%s %d\n", __FUNCTION__, seq );
85
86 intel->iw.irq_seq = seq;
87
88 do {
89 ret = drmCommandWrite( intel->driFd, DRM_I830_IRQ_WAIT, &intel->iw, sizeof(intel->iw) );
90 } while (ret == -EAGAIN || ret == -EINTR);
91
92 if ( ret ) {
93 fprintf( stderr, "%s: drmI830IrqWait: %d\n", __FUNCTION__, ret );
94 if (0)
95 intel_dump_batchbuffer( intel->alloc.offset,
96 intel->alloc.ptr,
97 intel->alloc.size );
98 exit(1);
99 }
100 }
101
102
103
104 static void age_intel( intelContextPtr intel, int age )
105 {
106 GLuint i;
107
108 for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
109 if (intel->CurrentTexObj[i])
110 intel->CurrentTexObj[i]->age = age;
111 }
112
113 void intel_dump_batchbuffer( long offset,
114 int *ptr,
115 int count )
116 {
117 int i;
118 fprintf(stderr, "\n\n\nSTART BATCH (%d dwords):\n", count);
119 for (i = 0; i < count/4; i += 4)
120 fprintf(stderr, "\t0x%x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
121 (unsigned int)offset + i*4, ptr[i], ptr[i+1], ptr[i+2], ptr[i+3]);
122 fprintf(stderr, "END BATCH\n\n\n");
123 }
124
125 void intelRefillBatchLocked( intelContextPtr intel, GLboolean allow_unlock )
126 {
127 GLuint last_irq = intel->alloc.irq_emitted;
128 GLuint half = intel->alloc.size / 2;
129 GLuint buf = (intel->alloc.active_buf ^= 1);
130
131 intel->alloc.irq_emitted = intelEmitIrqLocked( intel );
132
133 if (last_irq) {
134 if (allow_unlock) UNLOCK_HARDWARE( intel );
135 intelWaitIrq( intel, last_irq );
136 if (allow_unlock) LOCK_HARDWARE( intel );
137 }
138
139 if (0)
140 fprintf(stderr, "%s: now using half %d\n", __FUNCTION__, buf);
141
142 intel->batch.start_offset = intel->alloc.offset + buf * half;
143 intel->batch.ptr = (unsigned char *)intel->alloc.ptr + buf * half;
144 intel->batch.size = half - 8;
145 intel->batch.space = half - 8;
146 assert(intel->batch.space >= 0);
147 }
148
149 #define MI_BATCH_BUFFER_END (0xA<<23)
150
151
152 void intelFlushBatchLocked( intelContextPtr intel,
153 GLboolean ignore_cliprects,
154 GLboolean refill,
155 GLboolean allow_unlock)
156 {
157 drmI830BatchBuffer batch;
158
159 assert(intel->locked);
160
161 if (0)
162 fprintf(stderr, "%s used %d of %d offset %x..%x refill %d (started in %s)\n",
163 __FUNCTION__,
164 (intel->batch.size - intel->batch.space),
165 intel->batch.size,
166 intel->batch.start_offset,
167 intel->batch.start_offset +
168 (intel->batch.size - intel->batch.space),
169 refill,
170 intel->batch.func);
171
172 /* Throw away non-effective packets. Won't work once we have
173 * hardware contexts which would preserve statechanges beyond a
174 * single buffer.
175 */
176 if (intel->numClipRects == 0 && !ignore_cliprects) {
177
178 /* Without this yeild, an application with no cliprects can hog
179 * the hardware. Without unlocking, the effect is much worse -
180 * effectively a lock-out of other contexts.
181 */
182 if (allow_unlock) {
183 UNLOCK_HARDWARE( intel );
184 sched_yield();
185 LOCK_HARDWARE( intel );
186 }
187
188 /* Note that any state thought to have been emitted actually
189 * hasn't:
190 */
191 intel->batch.ptr -= (intel->batch.size - intel->batch.space);
192 intel->batch.space = intel->batch.size;
193 intel->vtbl.lost_hardware( intel );
194 }
195
196 if (intel->batch.space != intel->batch.size) {
197
198 if (intel->sarea->ctxOwner != intel->hHWContext) {
199 intel->perf_boxes |= I830_BOX_LOST_CONTEXT;
200 intel->sarea->ctxOwner = intel->hHWContext;
201 }
202
203 batch.start = intel->batch.start_offset;
204 batch.used = intel->batch.size - intel->batch.space;
205 batch.cliprects = intel->pClipRects;
206 batch.num_cliprects = ignore_cliprects ? 0 : intel->numClipRects;
207 batch.DR1 = 0;
208 batch.DR4 = ((((GLuint)intel->drawX) & 0xffff) |
209 (((GLuint)intel->drawY) << 16));
210
211 if (intel->alloc.offset) {
212 if ((batch.used & 0x4) == 0) {
213 ((int *)intel->batch.ptr)[0] = 0;
214 ((int *)intel->batch.ptr)[1] = MI_BATCH_BUFFER_END;
215 batch.used += 0x8;
216 intel->batch.ptr += 0x8;
217 }
218 else {
219 ((int *)intel->batch.ptr)[0] = MI_BATCH_BUFFER_END;
220 batch.used += 0x4;
221 intel->batch.ptr += 0x4;
222 }
223 }
224
225 if (0)
226 intel_dump_batchbuffer( batch.start,
227 (int *)(intel->batch.ptr - batch.used),
228 batch.used );
229
230 intel->batch.start_offset += batch.used;
231 intel->batch.size -= batch.used;
232
233 if (intel->batch.size < 8) {
234 refill = GL_TRUE;
235 intel->batch.space = intel->batch.size = 0;
236 }
237 else {
238 intel->batch.size -= 8;
239 intel->batch.space = intel->batch.size;
240 }
241
242
243 assert(intel->batch.space >= 0);
244 assert(batch.start >= intel->alloc.offset);
245 assert(batch.start < intel->alloc.offset + intel->alloc.size);
246 assert(batch.start + batch.used > intel->alloc.offset);
247 assert(batch.start + batch.used <=
248 intel->alloc.offset + intel->alloc.size);
249
250
251 if (intel->alloc.offset) {
252 if (drmCommandWrite (intel->driFd, DRM_I830_BATCHBUFFER, &batch,
253 sizeof(batch))) {
254 fprintf(stderr, "DRM_I830_BATCHBUFFER: %d\n", -errno);
255 UNLOCK_HARDWARE(intel);
256 exit(1);
257 }
258 } else {
259 drmI830CmdBuffer cmd;
260 cmd.buf = (char *)intel->alloc.ptr + batch.start;
261 cmd.sz = batch.used;
262 cmd.DR1 = batch.DR1;
263 cmd.DR4 = batch.DR4;
264 cmd.num_cliprects = batch.num_cliprects;
265 cmd.cliprects = batch.cliprects;
266
267 if (drmCommandWrite (intel->driFd, DRM_I830_CMDBUFFER, &cmd,
268 sizeof(cmd))) {
269 fprintf(stderr, "DRM_I830_CMDBUFFER: %d\n", -errno);
270 UNLOCK_HARDWARE(intel);
271 exit(1);
272 }
273 }
274
275
276 age_intel(intel, intel->sarea->last_enqueue);
277
278 /* FIXME: use hardware contexts to avoid 'losing' hardware after
279 * each buffer flush.
280 */
281 if (intel->batch.contains_geometry)
282 assert(intel->batch.last_emit_state == intel->batch.counter);
283
284 intel->batch.counter++;
285 intel->batch.contains_geometry = 0;
286 intel->batch.func = 0;
287 intel->vtbl.lost_hardware( intel );
288 }
289
290 if (refill)
291 intelRefillBatchLocked( intel, allow_unlock );
292 }
293
294 void intelFlushBatch( intelContextPtr intel, GLboolean refill )
295 {
296 if (intel->locked) {
297 intelFlushBatchLocked( intel, GL_FALSE, refill, GL_FALSE );
298 }
299 else {
300 LOCK_HARDWARE(intel);
301 intelFlushBatchLocked( intel, GL_FALSE, refill, GL_TRUE );
302 UNLOCK_HARDWARE(intel);
303 }
304 }
305
306
307 void intelWaitForIdle( intelContextPtr intel )
308 {
309 if (0)
310 fprintf(stderr, "%s\n", __FUNCTION__);
311
312 intel->vtbl.emit_flush( intel );
313 intelFlushBatch( intel, GL_TRUE );
314
315 /* Use an irq to wait for dma idle -- Need to track lost contexts
316 * to shortcircuit consecutive calls to this function:
317 */
318 intelWaitIrq( intel, intel->alloc.irq_emitted );
319 intel->alloc.irq_emitted = 0;
320 }
321
322
323 /**
324 * Check if we need to rotate/warp the front color buffer to the
325 * rotated screen. We generally need to do this when we get a glFlush
326 * or glFinish after drawing to the front color buffer.
327 */
328 static void
329 intelCheckFrontRotate(GLcontext *ctx)
330 {
331 intelContextPtr intel = INTEL_CONTEXT( ctx );
332 if (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT) {
333 intelScreenPrivate *screen = intel->intelScreen;
334 if (screen->current_rotation != 0) {
335 __DRIdrawablePrivate *dPriv = intel->driDrawable;
336 intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
337 }
338 }
339 }
340
341
342 /**
343 * NOT directly called via glFlush.
344 */
345 void intelFlush( GLcontext *ctx )
346 {
347 intelContextPtr intel = INTEL_CONTEXT( ctx );
348
349 if (intel->Fallback)
350 _swrast_flush( ctx );
351
352 INTEL_FIREVERTICES( intel );
353
354 if (intel->batch.size != intel->batch.space)
355 intelFlushBatch( intel, GL_FALSE );
356 }
357
358
359 /**
360 * Called via glFlush.
361 */
362 void intelglFlush( GLcontext *ctx )
363 {
364 intelFlush(ctx);
365 intelCheckFrontRotate(ctx);
366 }
367
368
369 void intelFinish( GLcontext *ctx )
370 {
371 intelContextPtr intel = INTEL_CONTEXT( ctx );
372 intelFlush( ctx );
373 intelWaitForIdle( intel );
374 intelCheckFrontRotate(ctx);
375 }
376
377
378 void intelClear(GLcontext *ctx, GLbitfield mask)
379 {
380 intelContextPtr intel = INTEL_CONTEXT( ctx );
381 const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
382 GLbitfield tri_mask = 0;
383 GLbitfield blit_mask = 0;
384 GLbitfield swrast_mask = 0;
385
386 if (0)
387 fprintf(stderr, "%s\n", __FUNCTION__);
388
389 /* Take care of cliprects, which are handled differently for
390 * clears, etc.
391 */
392 intelFlush( &intel->ctx );
393
394 if (mask & BUFFER_BIT_FRONT_LEFT) {
395 if (colorMask == ~0) {
396 blit_mask |= BUFFER_BIT_FRONT_LEFT;
397 }
398 else {
399 tri_mask |= BUFFER_BIT_FRONT_LEFT;
400 }
401 }
402
403 if (mask & BUFFER_BIT_BACK_LEFT) {
404 if (colorMask == ~0) {
405 blit_mask |= BUFFER_BIT_BACK_LEFT;
406 }
407 else {
408 tri_mask |= BUFFER_BIT_BACK_LEFT;
409 }
410 }
411
412 if (mask & BUFFER_BIT_DEPTH) {
413 blit_mask |= BUFFER_BIT_DEPTH;
414 }
415
416 if (mask & BUFFER_BIT_STENCIL) {
417 if (!intel->hw_stencil) {
418 swrast_mask |= BUFFER_BIT_STENCIL;
419 }
420 else if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
421 tri_mask |= BUFFER_BIT_STENCIL;
422 }
423 else {
424 blit_mask |= BUFFER_BIT_STENCIL;
425 }
426 }
427
428 swrast_mask |= (mask & BUFFER_BIT_ACCUM);
429
430 if (blit_mask)
431 intelClearWithBlit( ctx, blit_mask, 0, 0, 0, 0, 0);
432
433 if (tri_mask)
434 intel->vtbl.clear_with_tris( intel, tri_mask, 0, 0, 0, 0, 0);
435
436 if (swrast_mask)
437 _swrast_Clear( ctx, swrast_mask );
438 }
439
440
441 void
442 intelRotateWindow(intelContextPtr intel, __DRIdrawablePrivate *dPriv,
443 GLuint srcBuffer)
444 {
445 if (intel->vtbl.rotate_window) {
446 intel->vtbl.rotate_window(intel, dPriv, srcBuffer);
447 }
448 }
449
450
451 void *intelAllocateAGP( intelContextPtr intel, GLsizei size )
452 {
453 int region_offset;
454 drmI830MemAlloc alloc;
455 int ret;
456
457 if (0)
458 fprintf(stderr, "%s: %d bytes\n", __FUNCTION__, size);
459
460 alloc.region = I830_MEM_REGION_AGP;
461 alloc.alignment = 0;
462 alloc.size = size;
463 alloc.region_offset = &region_offset;
464
465 LOCK_HARDWARE(intel);
466
467 /* Make sure the global heap is initialized
468 */
469 if (intel->texture_heaps[0])
470 driAgeTextures( intel->texture_heaps[0] );
471
472
473 ret = drmCommandWriteRead( intel->driFd,
474 DRM_I830_ALLOC,
475 &alloc, sizeof(alloc));
476
477 if (ret) {
478 fprintf(stderr, "%s: DRM_I830_ALLOC ret %d\n", __FUNCTION__, ret);
479 UNLOCK_HARDWARE(intel);
480 return NULL;
481 }
482
483 if (0)
484 fprintf(stderr, "%s: allocated %d bytes\n", __FUNCTION__, size);
485
486 /* Need to propogate this information (agp memory in use) to our
487 * local texture lru. The kernel has already updated the global
488 * lru. An alternative would have been to allocate memory the
489 * usual way and then notify the kernel to pin the allocation.
490 */
491 if (intel->texture_heaps[0])
492 driAgeTextures( intel->texture_heaps[0] );
493
494 UNLOCK_HARDWARE(intel);
495
496 return (void *)((char *)intel->intelScreen->tex.map + region_offset);
497 }
498
499 void intelFreeAGP( intelContextPtr intel, void *pointer )
500 {
501 int region_offset;
502 drmI830MemFree memfree;
503 int ret;
504
505 region_offset = (char *)pointer - (char *)intel->intelScreen->tex.map;
506
507 if (region_offset < 0 ||
508 region_offset > intel->intelScreen->tex.size) {
509 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
510 intel->intelScreen->tex.size);
511 return;
512 }
513
514 memfree.region = I830_MEM_REGION_AGP;
515 memfree.region_offset = region_offset;
516
517 ret = drmCommandWrite( intel->driFd,
518 DRM_I830_FREE,
519 &memfree, sizeof(memfree));
520
521 if (ret)
522 fprintf(stderr, "%s: DRM_I830_FREE ret %d\n", __FUNCTION__, ret);
523 }
524
525 /* This version of AllocateMemoryMESA allocates only agp memory, and
526 * only does so after the point at which the driver has been
527 * initialized.
528 *
529 * Theoretically a valid context isn't required. However, in this
530 * implementation, it is, as I'm using the hardware lock to protect
531 * the kernel data structures, and the current context to get the
532 * device fd.
533 */
534 void *intelAllocateMemoryMESA(__DRInativeDisplay *dpy, int scrn,
535 GLsizei size, GLfloat readfreq,
536 GLfloat writefreq, GLfloat priority)
537 {
538 GET_CURRENT_CONTEXT(ctx);
539
540 if (INTEL_DEBUG & DEBUG_IOCTL)
541 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
542 writefreq, priority);
543
544 if (getenv("INTEL_NO_ALLOC"))
545 return NULL;
546
547 if (!ctx || INTEL_CONTEXT(ctx) == 0)
548 return NULL;
549
550 return intelAllocateAGP( INTEL_CONTEXT(ctx), size );
551 }
552
553
554 /* Called via glXFreeMemoryMESA() */
555 void intelFreeMemoryMESA(__DRInativeDisplay *dpy, int scrn, GLvoid *pointer)
556 {
557 GET_CURRENT_CONTEXT(ctx);
558 if (INTEL_DEBUG & DEBUG_IOCTL)
559 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
560
561 if (!ctx || INTEL_CONTEXT(ctx) == 0) {
562 fprintf(stderr, "%s: no context\n", __FUNCTION__);
563 return;
564 }
565
566 intelFreeAGP( INTEL_CONTEXT(ctx), pointer );
567 }
568
569 /* Called via glXGetMemoryOffsetMESA()
570 *
571 * Returns offset of pointer from the start of agp aperture.
572 */
573 GLuint intelGetMemoryOffsetMESA(__DRInativeDisplay *dpy, int scrn,
574 const GLvoid *pointer)
575 {
576 GET_CURRENT_CONTEXT(ctx);
577 intelContextPtr intel;
578
579 if (!ctx || !(intel = INTEL_CONTEXT(ctx)) ) {
580 fprintf(stderr, "%s: no context\n", __FUNCTION__);
581 return ~0;
582 }
583
584 if (!intelIsAgpMemory( intel, pointer, 0 ))
585 return ~0;
586
587 return intelAgpOffsetFromVirtual( intel, pointer );
588 }
589
590
591 GLboolean intelIsAgpMemory( intelContextPtr intel, const GLvoid *pointer,
592 GLint size )
593 {
594 int offset = (char *)pointer - (char *)intel->intelScreen->tex.map;
595 int valid = (size >= 0 &&
596 offset >= 0 &&
597 offset + size < intel->intelScreen->tex.size);
598
599 if (INTEL_DEBUG & DEBUG_IOCTL)
600 fprintf(stderr, "intelIsAgpMemory( %p ) : %d\n", pointer, valid );
601
602 return valid;
603 }
604
605
606 GLuint intelAgpOffsetFromVirtual( intelContextPtr intel, const GLvoid *pointer )
607 {
608 int offset = (char *)pointer - (char *)intel->intelScreen->tex.map;
609
610 if (offset < 0 || offset > intel->intelScreen->tex.size)
611 return ~0;
612 else
613 return intel->intelScreen->tex.offset + offset;
614 }
615
616
617
618
619
620 /* Flip the front & back buffes
621 */
622 void intelPageFlip( const __DRIdrawablePrivate *dPriv )
623 {
624 #if 0
625 intelContextPtr intel;
626 int tmp, ret;
627
628 if (INTEL_DEBUG & DEBUG_IOCTL)
629 fprintf(stderr, "%s\n", __FUNCTION__);
630
631 assert(dPriv);
632 assert(dPriv->driContextPriv);
633 assert(dPriv->driContextPriv->driverPrivate);
634
635 intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate;
636
637 intelFlush( &intel->ctx );
638 LOCK_HARDWARE( intel );
639
640 if (dPriv->pClipRects) {
641 *(drm_clip_rect_t *)intel->sarea->boxes = dPriv->pClipRects[0];
642 intel->sarea->nbox = 1;
643 }
644
645 ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
646 if (ret) {
647 fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
648 UNLOCK_HARDWARE( intel );
649 exit(1);
650 }
651
652 tmp = intel->sarea->last_enqueue;
653 intelRefillBatchLocked( intel );
654 UNLOCK_HARDWARE( intel );
655
656
657 intelSetDrawBuffer( &intel->ctx, intel->ctx.Color.DriverDrawBuffer );
658 #endif
659 }