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
)
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;
387 fprintf(stderr
, "%s\n", __FUNCTION__
);
389 /* Take care of cliprects, which are handled differently for
392 intelFlush( &intel
->ctx
);
394 if (mask
& BUFFER_BIT_FRONT_LEFT
) {
395 if (colorMask
== ~0) {
396 blit_mask
|= BUFFER_BIT_FRONT_LEFT
;
399 tri_mask
|= BUFFER_BIT_FRONT_LEFT
;
403 if (mask
& BUFFER_BIT_BACK_LEFT
) {
404 if (colorMask
== ~0) {
405 blit_mask
|= BUFFER_BIT_BACK_LEFT
;
408 tri_mask
|= BUFFER_BIT_BACK_LEFT
;
412 if (mask
& BUFFER_BIT_DEPTH
) {
413 blit_mask
|= BUFFER_BIT_DEPTH
;
416 if (mask
& BUFFER_BIT_STENCIL
) {
417 if (!intel
->hw_stencil
) {
418 swrast_mask
|= BUFFER_BIT_STENCIL
;
420 else if ((ctx
->Stencil
.WriteMask
[0] & 0xff) != 0xff) {
421 tri_mask
|= BUFFER_BIT_STENCIL
;
424 blit_mask
|= BUFFER_BIT_STENCIL
;
428 swrast_mask
|= (mask
& BUFFER_BIT_ACCUM
);
431 intelClearWithBlit( ctx
, blit_mask
, 0, 0, 0, 0, 0);
434 intel
->vtbl
.clear_with_tris( intel
, tri_mask
, 0, 0, 0, 0, 0);
437 _swrast_Clear( ctx
, swrast_mask
);
442 intelRotateWindow(intelContextPtr intel
, __DRIdrawablePrivate
*dPriv
,
445 if (intel
->vtbl
.rotate_window
) {
446 intel
->vtbl
.rotate_window(intel
, dPriv
, srcBuffer
);
451 void *intelAllocateAGP( intelContextPtr intel
, GLsizei size
)
454 drmI830MemAlloc alloc
;
458 fprintf(stderr
, "%s: %d bytes\n", __FUNCTION__
, size
);
460 alloc
.region
= I830_MEM_REGION_AGP
;
463 alloc
.region_offset
= ®ion_offset
;
465 LOCK_HARDWARE(intel
);
467 /* Make sure the global heap is initialized
469 if (intel
->texture_heaps
[0])
470 driAgeTextures( intel
->texture_heaps
[0] );
473 ret
= drmCommandWriteRead( intel
->driFd
,
475 &alloc
, sizeof(alloc
));
478 fprintf(stderr
, "%s: DRM_I830_ALLOC ret %d\n", __FUNCTION__
, ret
);
479 UNLOCK_HARDWARE(intel
);
484 fprintf(stderr
, "%s: allocated %d bytes\n", __FUNCTION__
, size
);
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.
491 if (intel
->texture_heaps
[0])
492 driAgeTextures( intel
->texture_heaps
[0] );
494 UNLOCK_HARDWARE(intel
);
496 return (void *)((char *)intel
->intelScreen
->tex
.map
+ region_offset
);
499 void intelFreeAGP( intelContextPtr intel
, void *pointer
)
502 drmI830MemFree memfree
;
505 region_offset
= (char *)pointer
- (char *)intel
->intelScreen
->tex
.map
;
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
);
514 memfree
.region
= I830_MEM_REGION_AGP
;
515 memfree
.region_offset
= region_offset
;
517 ret
= drmCommandWrite( intel
->driFd
,
519 &memfree
, sizeof(memfree
));
522 fprintf(stderr
, "%s: DRM_I830_FREE ret %d\n", __FUNCTION__
, ret
);
525 /* This version of AllocateMemoryMESA allocates only agp memory, and
526 * only does so after the point at which the driver has been
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
534 void *intelAllocateMemoryMESA(__DRInativeDisplay
*dpy
, int scrn
,
535 GLsizei size
, GLfloat readfreq
,
536 GLfloat writefreq
, GLfloat priority
)
538 GET_CURRENT_CONTEXT(ctx
);
540 if (INTEL_DEBUG
& DEBUG_IOCTL
)
541 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
542 writefreq
, priority
);
544 if (getenv("INTEL_NO_ALLOC"))
547 if (!ctx
|| INTEL_CONTEXT(ctx
) == 0)
550 return intelAllocateAGP( INTEL_CONTEXT(ctx
), size
);
554 /* Called via glXFreeMemoryMESA() */
555 void intelFreeMemoryMESA(__DRInativeDisplay
*dpy
, int scrn
, GLvoid
*pointer
)
557 GET_CURRENT_CONTEXT(ctx
);
558 if (INTEL_DEBUG
& DEBUG_IOCTL
)
559 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
561 if (!ctx
|| INTEL_CONTEXT(ctx
) == 0) {
562 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
566 intelFreeAGP( INTEL_CONTEXT(ctx
), pointer
);
569 /* Called via glXGetMemoryOffsetMESA()
571 * Returns offset of pointer from the start of agp aperture.
573 GLuint
intelGetMemoryOffsetMESA(__DRInativeDisplay
*dpy
, int scrn
,
574 const GLvoid
*pointer
)
576 GET_CURRENT_CONTEXT(ctx
);
577 intelContextPtr intel
;
579 if (!ctx
|| !(intel
= INTEL_CONTEXT(ctx
)) ) {
580 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
584 if (!intelIsAgpMemory( intel
, pointer
, 0 ))
587 return intelAgpOffsetFromVirtual( intel
, pointer
);
591 GLboolean
intelIsAgpMemory( intelContextPtr intel
, const GLvoid
*pointer
,
594 int offset
= (char *)pointer
- (char *)intel
->intelScreen
->tex
.map
;
595 int valid
= (size
>= 0 &&
597 offset
+ size
< intel
->intelScreen
->tex
.size
);
599 if (INTEL_DEBUG
& DEBUG_IOCTL
)
600 fprintf(stderr
, "intelIsAgpMemory( %p ) : %d\n", pointer
, valid
);
606 GLuint
intelAgpOffsetFromVirtual( intelContextPtr intel
, const GLvoid
*pointer
)
608 int offset
= (char *)pointer
- (char *)intel
->intelScreen
->tex
.map
;
610 if (offset
< 0 || offset
> intel
->intelScreen
->tex
.size
)
613 return intel
->intelScreen
->tex
.offset
+ offset
;
620 /* Flip the front & back buffes
622 void intelPageFlip( const __DRIdrawablePrivate
*dPriv
)
625 intelContextPtr intel
;
628 if (INTEL_DEBUG
& DEBUG_IOCTL
)
629 fprintf(stderr
, "%s\n", __FUNCTION__
);
632 assert(dPriv
->driContextPriv
);
633 assert(dPriv
->driContextPriv
->driverPrivate
);
635 intel
= (intelContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
637 intelFlush( &intel
->ctx
);
638 LOCK_HARDWARE( intel
);
640 if (dPriv
->pClipRects
) {
641 *(drm_clip_rect_t
*)intel
->sarea
->boxes
= dPriv
->pClipRects
[0];
642 intel
->sarea
->nbox
= 1;
645 ret
= drmCommandNone(intel
->driFd
, DRM_I830_FLIP
);
647 fprintf(stderr
, "%s: %d\n", __FUNCTION__
, ret
);
648 UNLOCK_HARDWARE( intel
);
652 tmp
= intel
->sarea
->last_enqueue
;
653 intelRefillBatchLocked( intel
);
654 UNLOCK_HARDWARE( intel
);
657 intelSetDrawBuffer( &intel
->ctx
, intel
->ctx
.Color
.DriverDrawBuffer
);