1 /**************************************************************************
3 * Copyright 2003 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 **************************************************************************/
36 #include "swrast/swrast.h"
38 #include "intel_context.h"
39 #include "intel_ioctl.h"
40 #include "intel_batchbuffer.h"
43 u_int32_t
intelGetLastFrame (intelContextPtr intel
)
47 drm_i915_getparam_t gp
;
49 gp
.param
= I915_PARAM_LAST_DISPATCH
;
50 gp
.value
= (int *)&frame
;
51 ret
= drmCommandWriteRead( intel
->driFd
, DRM_I915_GETPARAM
,
56 int intelEmitIrqLocked( intelContextPtr intel
)
61 assert(((*(int *)intel
->driHwLock
) & ~DRM_LOCK_CONT
) ==
62 (DRM_LOCK_HELD
|intel
->hHWContext
));
66 ret
= drmCommandWriteRead( intel
->driFd
, DRM_I830_IRQ_EMIT
,
69 fprintf( stderr
, "%s: drmI830IrqEmit: %d\n", __FUNCTION__
, ret
);
74 fprintf(stderr
, "%s --> %d\n", __FUNCTION__
, seq
);
79 void intelWaitIrq( intelContextPtr intel
, int seq
)
84 fprintf(stderr
, "%s %d\n", __FUNCTION__
, seq
);
86 intel
->iw
.irq_seq
= seq
;
89 ret
= drmCommandWrite( intel
->driFd
, DRM_I830_IRQ_WAIT
, &intel
->iw
, sizeof(intel
->iw
) );
90 } while (ret
== -EAGAIN
|| ret
== -EINTR
);
93 fprintf( stderr
, "%s: drmI830IrqWait: %d\n", __FUNCTION__
, ret
);
95 intel_dump_batchbuffer( intel
->alloc
.offset
,
104 static void age_intel( intelContextPtr intel
, int age
)
108 for (i
= 0 ; i
< MAX_TEXTURE_UNITS
; i
++)
109 if (intel
->CurrentTexObj
[i
])
110 intel
->CurrentTexObj
[i
]->age
= age
;
113 void intel_dump_batchbuffer( long offset
,
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");
125 void intelRefillBatchLocked( intelContextPtr intel
, GLboolean allow_unlock
)
127 GLuint last_irq
= intel
->alloc
.irq_emitted
;
128 GLuint half
= intel
->alloc
.size
/ 2;
129 GLuint buf
= (intel
->alloc
.active_buf
^= 1);
131 intel
->alloc
.irq_emitted
= intelEmitIrqLocked( intel
);
134 if (allow_unlock
) UNLOCK_HARDWARE( intel
);
135 intelWaitIrq( intel
, last_irq
);
136 if (allow_unlock
) LOCK_HARDWARE( intel
);
140 fprintf(stderr
, "%s: now using half %d\n", __FUNCTION__
, buf
);
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);
149 #define MI_BATCH_BUFFER_END (0xA<<23)
152 void intelFlushBatchLocked( intelContextPtr intel
,
153 GLboolean ignore_cliprects
,
155 GLboolean allow_unlock
)
157 drmI830BatchBuffer batch
;
159 assert(intel
->locked
);
162 fprintf(stderr
, "%s used %d of %d offset %x..%x refill %d (started in %s)\n",
164 (intel
->batch
.size
- intel
->batch
.space
),
166 intel
->batch
.start_offset
,
167 intel
->batch
.start_offset
+
168 (intel
->batch
.size
- intel
->batch
.space
),
172 /* Throw away non-effective packets. Won't work once we have
173 * hardware contexts which would preserve statechanges beyond a
176 if (intel
->numClipRects
== 0 && !ignore_cliprects
) {
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.
183 UNLOCK_HARDWARE( intel
);
185 LOCK_HARDWARE( intel
);
188 /* Note that any state thought to have been emitted actually
191 intel
->batch
.ptr
-= (intel
->batch
.size
- intel
->batch
.space
);
192 intel
->batch
.space
= intel
->batch
.size
;
193 intel
->vtbl
.lost_hardware( intel
);
196 if (intel
->batch
.space
!= intel
->batch
.size
) {
198 if (intel
->sarea
->ctxOwner
!= intel
->hHWContext
) {
199 intel
->perf_boxes
|= I830_BOX_LOST_CONTEXT
;
200 intel
->sarea
->ctxOwner
= intel
->hHWContext
;
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
;
208 batch
.DR4
= ((((GLuint
)intel
->drawX
) & 0xffff) |
209 (((GLuint
)intel
->drawY
) << 16));
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
;
216 intel
->batch
.ptr
+= 0x8;
219 ((int *)intel
->batch
.ptr
)[0] = MI_BATCH_BUFFER_END
;
221 intel
->batch
.ptr
+= 0x4;
226 intel_dump_batchbuffer( batch
.start
,
227 (int *)(intel
->batch
.ptr
- batch
.used
),
230 intel
->batch
.start_offset
+= batch
.used
;
231 intel
->batch
.size
-= batch
.used
;
233 if (intel
->batch
.size
< 8) {
235 intel
->batch
.space
= intel
->batch
.size
= 0;
238 intel
->batch
.size
-= 8;
239 intel
->batch
.space
= intel
->batch
.size
;
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
);
251 if (intel
->alloc
.offset
) {
252 if (drmCommandWrite (intel
->driFd
, DRM_I830_BATCHBUFFER
, &batch
,
254 fprintf(stderr
, "DRM_I830_BATCHBUFFER: %d\n", -errno
);
255 UNLOCK_HARDWARE(intel
);
259 drmI830CmdBuffer cmd
;
260 cmd
.buf
= (char *)intel
->alloc
.ptr
+ batch
.start
;
264 cmd
.num_cliprects
= batch
.num_cliprects
;
265 cmd
.cliprects
= batch
.cliprects
;
267 if (drmCommandWrite (intel
->driFd
, DRM_I830_CMDBUFFER
, &cmd
,
269 fprintf(stderr
, "DRM_I830_CMDBUFFER: %d\n", -errno
);
270 UNLOCK_HARDWARE(intel
);
276 age_intel(intel
, intel
->sarea
->last_enqueue
);
278 /* FIXME: use hardware contexts to avoid 'losing' hardware after
281 if (intel
->batch
.contains_geometry
)
282 assert(intel
->batch
.last_emit_state
== intel
->batch
.counter
);
284 intel
->batch
.counter
++;
285 intel
->batch
.contains_geometry
= 0;
286 intel
->batch
.func
= 0;
287 intel
->vtbl
.lost_hardware( intel
);
291 intelRefillBatchLocked( intel
, allow_unlock
);
294 void intelFlushBatch( intelContextPtr intel
, GLboolean refill
)
297 intelFlushBatchLocked( intel
, GL_FALSE
, refill
, GL_FALSE
);
300 LOCK_HARDWARE(intel
);
301 intelFlushBatchLocked( intel
, GL_FALSE
, refill
, GL_TRUE
);
302 UNLOCK_HARDWARE(intel
);
307 void intelWaitForIdle( intelContextPtr intel
)
310 fprintf(stderr
, "%s\n", __FUNCTION__
);
312 intel
->vtbl
.emit_flush( intel
);
313 intelFlushBatch( intel
, GL_TRUE
);
315 /* Use an irq to wait for dma idle -- Need to track lost contexts
316 * to shortcircuit consecutive calls to this function:
318 intelWaitIrq( intel
, intel
->alloc
.irq_emitted
);
319 intel
->alloc
.irq_emitted
= 0;
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.
329 intelCheckFrontRotate(GLcontext
*ctx
)
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
);
343 * NOT directly called via glFlush.
345 void intelFlush( GLcontext
*ctx
)
347 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
350 _swrast_flush( ctx
);
352 INTEL_FIREVERTICES( intel
);
354 if (intel
->batch
.size
!= intel
->batch
.space
)
355 intelFlushBatch( intel
, GL_FALSE
);
360 * Called via glFlush.
362 void intelglFlush( GLcontext
*ctx
)
365 intelCheckFrontRotate(ctx
);
369 void intelFinish( GLcontext
*ctx
)
371 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
373 intelWaitForIdle( intel
);
374 intelCheckFrontRotate(ctx
);
378 void intelClear(GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
379 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
381 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
382 const GLuint colorMask
= *((GLuint
*) &ctx
->Color
.ColorMask
);
383 GLbitfield tri_mask
= 0;
384 GLbitfield blit_mask
= 0;
385 GLbitfield swrast_mask
= 0;
388 fprintf(stderr
, "%s\n", __FUNCTION__
);
390 /* Take care of cliprects, which are handled differently for
393 intelFlush( &intel
->ctx
);
395 if (mask
& BUFFER_BIT_FRONT_LEFT
) {
396 if (colorMask
== ~0) {
397 blit_mask
|= BUFFER_BIT_FRONT_LEFT
;
400 tri_mask
|= BUFFER_BIT_FRONT_LEFT
;
404 if (mask
& BUFFER_BIT_BACK_LEFT
) {
405 if (colorMask
== ~0) {
406 blit_mask
|= BUFFER_BIT_BACK_LEFT
;
409 tri_mask
|= BUFFER_BIT_BACK_LEFT
;
413 if (mask
& BUFFER_BIT_DEPTH
) {
414 blit_mask
|= BUFFER_BIT_DEPTH
;
417 if (mask
& BUFFER_BIT_STENCIL
) {
418 if (!intel
->hw_stencil
) {
419 swrast_mask
|= BUFFER_BIT_STENCIL
;
421 else if (ctx
->Stencil
.WriteMask
[0] != 0xff) {
422 tri_mask
|= BUFFER_BIT_STENCIL
;
425 blit_mask
|= BUFFER_BIT_STENCIL
;
429 swrast_mask
|= (mask
& BUFFER_BIT_ACCUM
);
432 intelClearWithBlit( ctx
, blit_mask
, all
, cx
, cy
, cw
, ch
);
435 intel
->vtbl
.clear_with_tris( intel
, tri_mask
, all
, cx
, cy
, cw
, ch
);
438 _swrast_Clear( ctx
, swrast_mask
, all
, cx
, cy
, cw
, ch
);
443 intelRotateWindow(intelContextPtr intel
, __DRIdrawablePrivate
*dPriv
,
446 if (intel
->vtbl
.rotate_window
) {
447 intel
->vtbl
.rotate_window(intel
, dPriv
, srcBuffer
);
452 void *intelAllocateAGP( intelContextPtr intel
, GLsizei size
)
455 drmI830MemAlloc alloc
;
459 fprintf(stderr
, "%s: %d bytes\n", __FUNCTION__
, size
);
461 alloc
.region
= I830_MEM_REGION_AGP
;
464 alloc
.region_offset
= ®ion_offset
;
466 LOCK_HARDWARE(intel
);
468 /* Make sure the global heap is initialized
470 if (intel
->texture_heaps
[0])
471 driAgeTextures( intel
->texture_heaps
[0] );
474 ret
= drmCommandWriteRead( intel
->driFd
,
476 &alloc
, sizeof(alloc
));
479 fprintf(stderr
, "%s: DRM_I830_ALLOC ret %d\n", __FUNCTION__
, ret
);
480 UNLOCK_HARDWARE(intel
);
485 fprintf(stderr
, "%s: allocated %d bytes\n", __FUNCTION__
, size
);
487 /* Need to propogate this information (agp memory in use) to our
488 * local texture lru. The kernel has already updated the global
489 * lru. An alternative would have been to allocate memory the
490 * usual way and then notify the kernel to pin the allocation.
492 if (intel
->texture_heaps
[0])
493 driAgeTextures( intel
->texture_heaps
[0] );
495 UNLOCK_HARDWARE(intel
);
497 return (void *)((char *)intel
->intelScreen
->tex
.map
+ region_offset
);
500 void intelFreeAGP( intelContextPtr intel
, void *pointer
)
503 drmI830MemFree memfree
;
506 region_offset
= (char *)pointer
- (char *)intel
->intelScreen
->tex
.map
;
508 if (region_offset
< 0 ||
509 region_offset
> intel
->intelScreen
->tex
.size
) {
510 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
511 intel
->intelScreen
->tex
.size
);
515 memfree
.region
= I830_MEM_REGION_AGP
;
516 memfree
.region_offset
= region_offset
;
518 ret
= drmCommandWrite( intel
->driFd
,
520 &memfree
, sizeof(memfree
));
523 fprintf(stderr
, "%s: DRM_I830_FREE ret %d\n", __FUNCTION__
, ret
);
526 /* This version of AllocateMemoryMESA allocates only agp memory, and
527 * only does so after the point at which the driver has been
530 * Theoretically a valid context isn't required. However, in this
531 * implementation, it is, as I'm using the hardware lock to protect
532 * the kernel data structures, and the current context to get the
535 void *intelAllocateMemoryMESA(__DRInativeDisplay
*dpy
, int scrn
,
536 GLsizei size
, GLfloat readfreq
,
537 GLfloat writefreq
, GLfloat priority
)
539 GET_CURRENT_CONTEXT(ctx
);
541 if (INTEL_DEBUG
& DEBUG_IOCTL
)
542 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
543 writefreq
, priority
);
545 if (getenv("INTEL_NO_ALLOC"))
548 if (!ctx
|| INTEL_CONTEXT(ctx
) == 0)
551 return intelAllocateAGP( INTEL_CONTEXT(ctx
), size
);
555 /* Called via glXFreeMemoryMESA() */
556 void intelFreeMemoryMESA(__DRInativeDisplay
*dpy
, int scrn
, GLvoid
*pointer
)
558 GET_CURRENT_CONTEXT(ctx
);
559 if (INTEL_DEBUG
& DEBUG_IOCTL
)
560 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
562 if (!ctx
|| INTEL_CONTEXT(ctx
) == 0) {
563 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
567 intelFreeAGP( INTEL_CONTEXT(ctx
), pointer
);
570 /* Called via glXGetMemoryOffsetMESA()
572 * Returns offset of pointer from the start of agp aperture.
574 GLuint
intelGetMemoryOffsetMESA(__DRInativeDisplay
*dpy
, int scrn
,
575 const GLvoid
*pointer
)
577 GET_CURRENT_CONTEXT(ctx
);
578 intelContextPtr intel
;
580 if (!ctx
|| !(intel
= INTEL_CONTEXT(ctx
)) ) {
581 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
585 if (!intelIsAgpMemory( intel
, pointer
, 0 ))
588 return intelAgpOffsetFromVirtual( intel
, pointer
);
592 GLboolean
intelIsAgpMemory( intelContextPtr intel
, const GLvoid
*pointer
,
595 int offset
= (char *)pointer
- (char *)intel
->intelScreen
->tex
.map
;
596 int valid
= (size
>= 0 &&
598 offset
+ size
< intel
->intelScreen
->tex
.size
);
600 if (INTEL_DEBUG
& DEBUG_IOCTL
)
601 fprintf(stderr
, "intelIsAgpMemory( %p ) : %d\n", pointer
, valid
);
607 GLuint
intelAgpOffsetFromVirtual( intelContextPtr intel
, const GLvoid
*pointer
)
609 int offset
= (char *)pointer
- (char *)intel
->intelScreen
->tex
.map
;
611 if (offset
< 0 || offset
> intel
->intelScreen
->tex
.size
)
614 return intel
->intelScreen
->tex
.offset
+ offset
;
621 /* Flip the front & back buffes
623 void intelPageFlip( const __DRIdrawablePrivate
*dPriv
)
626 intelContextPtr intel
;
629 if (INTEL_DEBUG
& DEBUG_IOCTL
)
630 fprintf(stderr
, "%s\n", __FUNCTION__
);
633 assert(dPriv
->driContextPriv
);
634 assert(dPriv
->driContextPriv
->driverPrivate
);
636 intel
= (intelContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
638 intelFlush( &intel
->ctx
);
639 LOCK_HARDWARE( intel
);
641 if (dPriv
->pClipRects
) {
642 *(drm_clip_rect_t
*)intel
->sarea
->boxes
= dPriv
->pClipRects
[0];
643 intel
->sarea
->nbox
= 1;
646 ret
= drmCommandNone(intel
->driFd
, DRM_I830_FLIP
);
648 fprintf(stderr
, "%s: %d\n", __FUNCTION__
, ret
);
649 UNLOCK_HARDWARE( intel
);
653 tmp
= intel
->sarea
->last_enqueue
;
654 intelRefillBatchLocked( intel
);
655 UNLOCK_HARDWARE( intel
);
658 intelSetDrawBuffer( &intel
->ctx
, intel
->ctx
.Color
.DriverDrawBuffer
);