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 **************************************************************************/
28 #include "intel_screen.h"
29 #include "intel_context.h"
30 #include "intel_blit.h"
31 #include "intel_regions.h"
32 #include "intel_batchbuffer.h"
34 #include "framebuffer.h"
38 #include "swrast/swrast.h"
40 GLboolean
intel_intersect_cliprects( drm_clip_rect_t
*dst
,
41 const drm_clip_rect_t
*a
,
42 const drm_clip_rect_t
*b
)
44 dst
->x1
= MAX2(a
->x1
, b
->x1
);
45 dst
->x2
= MIN2(a
->x2
, b
->x2
);
46 dst
->y1
= MAX2(a
->y1
, b
->y1
);
47 dst
->y2
= MIN2(a
->y2
, b
->y2
);
49 return (dst
->x1
<= dst
->x2
&&
53 struct intel_region
*intel_drawbuf_region( struct intel_context
*intel
)
55 switch (intel
->ctx
.DrawBuffer
->_ColorDrawBufferMask
[0]) {
56 case BUFFER_BIT_FRONT_LEFT
:
57 return intel
->front_region
;
58 case BUFFER_BIT_BACK_LEFT
:
59 return intel
->back_region
;
61 /* Not necessary to fallback - could handle either NONE or
62 * FRONT_AND_BACK cases below.
68 struct intel_region
*intel_readbuf_region( struct intel_context
*intel
)
70 GLcontext
*ctx
= &intel
->ctx
;
72 /* This will have to change to support EXT_fbo's, but is correct
75 switch (ctx
->ReadBuffer
->_ColorReadBufferIndex
) {
76 case BUFFER_FRONT_LEFT
:
77 return intel
->front_region
;
78 case BUFFER_BACK_LEFT
:
79 return intel
->back_region
;
88 static void intelBufferSize(GLframebuffer
*buffer
,
92 GET_CURRENT_CONTEXT(ctx
);
93 struct intel_context
*intel
= intel_context(ctx
);
94 /* Need to lock to make sure the driDrawable is uptodate. This
95 * information is used to resize Mesa's software buffers, so it has
99 if (intel
->driDrawable
) {
100 *width
= intel
->driDrawable
->w
;
101 *height
= intel
->driDrawable
->h
;
107 UNLOCK_HARDWARE(intel
);
111 static void intelSetFrontClipRects( struct intel_context
*intel
)
113 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
117 intel
->numClipRects
= dPriv
->numClipRects
;
118 intel
->pClipRects
= dPriv
->pClipRects
;
119 intel
->drawX
= dPriv
->x
;
120 intel
->drawY
= dPriv
->y
;
124 static void intelSetBackClipRects( struct intel_context
*intel
)
126 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
130 if (intel
->sarea
->pf_enabled
== 0 && dPriv
->numBackClipRects
== 0) {
131 intel
->numClipRects
= dPriv
->numClipRects
;
132 intel
->pClipRects
= dPriv
->pClipRects
;
133 intel
->drawX
= dPriv
->x
;
134 intel
->drawY
= dPriv
->y
;
136 intel
->numClipRects
= dPriv
->numBackClipRects
;
137 intel
->pClipRects
= dPriv
->pBackClipRects
;
138 intel
->drawX
= dPriv
->backX
;
139 intel
->drawY
= dPriv
->backY
;
141 if (dPriv
->numBackClipRects
== 1 &&
142 dPriv
->x
== dPriv
->backX
&&
143 dPriv
->y
== dPriv
->backY
) {
145 /* Repeat the calculation of the back cliprect dimensions here
146 * as early versions of dri.a in the Xserver are incorrect. Try
147 * very hard not to restrict future versions of dri.a which
148 * might eg. allocate truly private back buffers.
155 x2
= dPriv
->x
+ dPriv
->w
;
156 y2
= dPriv
->y
+ dPriv
->h
;
160 if (x2
> intel
->intelScreen
->width
) x2
= intel
->intelScreen
->width
;
161 if (y2
> intel
->intelScreen
->height
) y2
= intel
->intelScreen
->height
;
163 if (x1
== dPriv
->pBackClipRects
[0].x1
&&
164 y1
== dPriv
->pBackClipRects
[0].y1
) {
166 dPriv
->pBackClipRects
[0].x2
= x2
;
167 dPriv
->pBackClipRects
[0].y2
= y2
;
174 void intelWindowMoved( struct intel_context
*intel
)
176 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
178 if (!intel
->ctx
.DrawBuffer
) {
179 intelSetFrontClipRects( intel
);
182 switch (intel
->ctx
.DrawBuffer
->_ColorDrawBufferMask
[0]) {
183 case BUFFER_BIT_FRONT_LEFT
:
184 intelSetFrontClipRects( intel
);
186 case BUFFER_BIT_BACK_LEFT
:
187 intelSetBackClipRects( intel
);
190 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
191 intelSetFrontClipRects( intel
);
195 /* Get updated plane info so we sync against the right vblank counter */
196 if (intel
->intelScreen
->driScrnPriv
->ddx_version
.minor
>= 7) {
197 drmI830Sarea
*sarea
= intel
->sarea
;
198 drm_clip_rect_t drw_rect
= { .x1
= dPriv
->x
, .x2
= dPriv
->x
+ dPriv
->w
,
199 .y1
= dPriv
->y
, .y2
= dPriv
->y
+ dPriv
->h
};
200 drm_clip_rect_t planeA_rect
= { .x1
= sarea
->planeA_x
, .y1
= sarea
->planeA_y
,
201 .x2
= sarea
->planeA_x
+ sarea
->planeA_w
,
202 .y2
= sarea
->planeA_y
+ sarea
->planeA_h
};
203 drm_clip_rect_t planeB_rect
= { .x1
= sarea
->planeB_x
, .y1
= sarea
->planeB_y
,
204 .x2
= sarea
->planeB_x
+ sarea
->planeB_w
,
205 .y2
= sarea
->planeB_y
+ sarea
->planeB_h
};
206 GLint areaA
= driIntersectArea( drw_rect
, planeA_rect
);
207 GLint areaB
= driIntersectArea( drw_rect
, planeB_rect
);
208 GLuint flags
= dPriv
->vblFlags
;
210 /* Update vblank info
212 if (areaB
> areaA
|| (areaA
== areaB
&& areaB
> 0)) {
213 flags
= dPriv
->vblFlags
| VBLANK_FLAG_SECONDARY
;
215 flags
= dPriv
->vblFlags
& ~VBLANK_FLAG_SECONDARY
;
218 /* Check to see if we changed pipes */
219 if (flags
!= dPriv
->vblFlags
&& dPriv
->vblFlags
&&
220 !(dPriv
->vblFlags
& VBLANK_FLAG_NO_IRQ
)) {
224 * Update msc_base from old pipe
226 driDrawableGetMSC32(dPriv
->driScreenPriv
, dPriv
, &count
);
227 dPriv
->msc_base
= count
;
229 * Then get new vblank_base and vblSeq values
231 dPriv
->vblFlags
= flags
;
232 driGetCurrentVBlank(dPriv
, dPriv
->vblFlags
, &dPriv
->vblSeq
);
233 dPriv
->vblank_base
= dPriv
->vblSeq
;
236 dPriv
->vblFlags
&= ~VBLANK_FLAG_SECONDARY
;
239 _mesa_resize_framebuffer(&intel
->ctx
,
240 (GLframebuffer
*)dPriv
->driverPrivate
,
243 /* Set state we know depends on drawable parameters:
246 GLcontext
*ctx
= &intel
->ctx
;
248 if (ctx
->Driver
.Scissor
)
249 ctx
->Driver
.Scissor( ctx
, ctx
->Scissor
.X
, ctx
->Scissor
.Y
,
250 ctx
->Scissor
.Width
, ctx
->Scissor
.Height
);
252 if (ctx
->Driver
.DepthRange
)
253 ctx
->Driver
.DepthRange( ctx
,
257 intel
->NewGLState
|= _NEW_SCISSOR
;
260 /* This works because the lock is always grabbed before emitting
261 * commands and commands are always flushed prior to releasing
264 intel
->NewGLState
|= _NEW_WINDOW_POS
;
269 /* A true meta version of this would be very simple and additionally
270 * machine independent. Maybe we'll get there one day.
272 static void intelClearWithTris(struct intel_context
*intel
,
275 GLcontext
*ctx
= &intel
->ctx
;
276 drm_clip_rect_t clear
;
277 GLint cx
, cy
, cw
, ch
;
279 if (INTEL_DEBUG
& DEBUG_DRI
)
280 _mesa_printf("%s %x\n", __FUNCTION__
, mask
);
284 intel
->vtbl
.install_meta_state(intel
);
286 /* Get clear bounds after locking */
287 cx
= ctx
->DrawBuffer
->_Xmin
;
288 cy
= ctx
->DrawBuffer
->_Ymin
;
289 cw
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
290 ch
= ctx
->DrawBuffer
->_Ymax
- ctx
->DrawBuffer
->_Ymin
;
297 /* Back and stencil cliprects are the same. Try and do both
300 if (mask
& (BUFFER_BIT_BACK_LEFT
|BUFFER_BIT_STENCIL
|BUFFER_BIT_DEPTH
)) {
301 intel
->vtbl
.meta_draw_region(intel
,
303 intel
->depth_region
);
305 if (mask
& BUFFER_BIT_BACK_LEFT
)
306 intel
->vtbl
.meta_color_mask(intel
, GL_TRUE
);
308 intel
->vtbl
.meta_color_mask(intel
, GL_FALSE
);
310 if (mask
& BUFFER_BIT_STENCIL
)
311 intel
->vtbl
.meta_stencil_replace( intel
,
312 intel
->ctx
.Stencil
.WriteMask
[0],
313 intel
->ctx
.Stencil
.Clear
);
315 intel
->vtbl
.meta_no_stencil_write(intel
);
317 if (mask
& BUFFER_BIT_DEPTH
)
318 intel
->vtbl
.meta_depth_replace( intel
);
320 intel
->vtbl
.meta_no_depth_write(intel
);
322 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
323 * drawing origin may not be correctly emitted.
325 intel
->vtbl
.meta_draw_quad(intel
,
328 intel
->ctx
.Depth
.Clear
,
329 intel
->clear_chan
[0],
330 intel
->clear_chan
[1],
331 intel
->clear_chan
[2],
332 intel
->clear_chan
[3],
336 /* Front may have different cliprects:
338 if (mask
& BUFFER_BIT_FRONT_LEFT
) {
339 intel
->vtbl
.meta_no_depth_write(intel
);
340 intel
->vtbl
.meta_no_stencil_write(intel
);
341 intel
->vtbl
.meta_color_mask(intel
, GL_TRUE
);
342 intel
->vtbl
.meta_draw_region(intel
,
344 intel
->depth_region
);
346 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
347 * drawing origin may not be correctly emitted.
349 intel
->vtbl
.meta_draw_quad(intel
,
353 intel
->clear_chan
[0],
354 intel
->clear_chan
[1],
355 intel
->clear_chan
[2],
356 intel
->clear_chan
[3],
360 intel
->vtbl
.leave_meta_state( intel
);
368 static void intelClear(GLcontext
*ctx
, GLbitfield mask
)
370 struct intel_context
*intel
= intel_context( ctx
);
371 const GLuint colorMask
= *((GLuint
*) &ctx
->Color
.ColorMask
);
372 GLbitfield tri_mask
= 0;
373 GLbitfield blit_mask
= 0;
374 GLbitfield swrast_mask
= 0;
376 if (INTEL_DEBUG
& DEBUG_DRI
)
377 fprintf(stderr
, "%s %x\n", __FUNCTION__
, mask
);
380 if (mask
& BUFFER_BIT_FRONT_LEFT
) {
381 if (colorMask
== ~0) {
382 blit_mask
|= BUFFER_BIT_FRONT_LEFT
;
385 tri_mask
|= BUFFER_BIT_FRONT_LEFT
;
389 if (mask
& BUFFER_BIT_BACK_LEFT
) {
390 if (colorMask
== ~0) {
391 blit_mask
|= BUFFER_BIT_BACK_LEFT
;
394 tri_mask
|= BUFFER_BIT_BACK_LEFT
;
399 if (mask
& BUFFER_BIT_STENCIL
) {
400 if (!intel
->hw_stencil
) {
401 swrast_mask
|= BUFFER_BIT_STENCIL
;
403 else if ((ctx
->Stencil
.WriteMask
[0] & 0xff) != 0xff ||
404 intel
->depth_region
->tiled
) {
405 tri_mask
|= BUFFER_BIT_STENCIL
;
408 blit_mask
|= BUFFER_BIT_STENCIL
;
412 /* Do depth with stencil if possible to avoid 2nd pass over the
415 if (mask
& BUFFER_BIT_DEPTH
) {
416 if ((tri_mask
& BUFFER_BIT_STENCIL
) ||
417 intel
->depth_region
->tiled
)
418 tri_mask
|= BUFFER_BIT_DEPTH
;
420 blit_mask
|= BUFFER_BIT_DEPTH
;
423 swrast_mask
|= (mask
& BUFFER_BIT_ACCUM
);
428 intelClearWithBlit( ctx
, blit_mask
);
431 intelClearWithTris( intel
, tri_mask
);
434 _swrast_Clear( ctx
, swrast_mask
);
443 /* Flip the front & back buffers
445 static void intelPageFlip( const __DRIdrawablePrivate
*dPriv
)
448 struct intel_context
*intel
;
451 if (INTEL_DEBUG
& DEBUG_IOCTL
)
452 fprintf(stderr
, "%s\n", __FUNCTION__
);
455 assert(dPriv
->driContextPriv
);
456 assert(dPriv
->driContextPriv
->driverPrivate
);
458 intel
= (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
460 intelFlush( &intel
->ctx
);
461 LOCK_HARDWARE( intel
);
463 if (dPriv
->pClipRects
) {
464 *(drm_clip_rect_t
*)intel
->sarea
->boxes
= dPriv
->pClipRects
[0];
465 intel
->sarea
->nbox
= 1;
468 ret
= drmCommandNone(intel
->driFd
, DRM_I830_FLIP
);
470 fprintf(stderr
, "%s: %d\n", __FUNCTION__
, ret
);
471 UNLOCK_HARDWARE( intel
);
475 tmp
= intel
->sarea
->last_enqueue
;
476 intelRefillBatchLocked( intel
);
477 UNLOCK_HARDWARE( intel
);
480 intelSetDrawBuffer( &intel
->ctx
, intel
->ctx
.Color
.DriverDrawBuffer
);
485 void intelSwapBuffers( __DRIdrawablePrivate
*dPriv
)
487 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
488 struct intel_context
*intel
;
490 intel
= (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
492 if (ctx
->Visual
.doubleBufferMode
) {
493 _mesa_notifySwapBuffers( ctx
); /* flush pending rendering comands */
494 if ( 0 /*intel->doPageFlip*/ ) { /* doPageFlip is never set !!! */
495 intelPageFlip( dPriv
);
497 intelCopyBuffer( dPriv
, NULL
);
501 /* XXX this shouldn't be an error but we can't handle it for now */
502 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
506 void intelCopySubBuffer( __DRIdrawablePrivate
*dPriv
,
507 int x
, int y
, int w
, int h
)
509 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
510 struct intel_context
*intel
= dPriv
->driContextPriv
->driverPrivate
;
511 GLcontext
*ctx
= &intel
->ctx
;
513 if (ctx
->Visual
.doubleBufferMode
) {
514 drm_clip_rect_t rect
;
515 rect
.x1
= x
+ dPriv
->x
;
516 rect
.y1
= (dPriv
->h
- y
- h
) + dPriv
->y
;
517 rect
.x2
= rect
.x1
+ w
;
518 rect
.y2
= rect
.y1
+ h
;
519 _mesa_notifySwapBuffers( ctx
); /* flush pending rendering comands */
520 intelCopyBuffer( dPriv
, &rect
);
523 /* XXX this shouldn't be an error but we can't handle it for now */
524 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
529 static void intelDrawBuffer(GLcontext
*ctx
, GLenum mode
)
531 struct intel_context
*intel
= intel_context(ctx
);
534 if (!ctx
->DrawBuffer
)
537 switch ( ctx
->DrawBuffer
->_ColorDrawBufferMask
[0] ) {
538 case BUFFER_BIT_FRONT_LEFT
:
540 FALLBACK( intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_FALSE
);
542 case BUFFER_BIT_BACK_LEFT
:
544 FALLBACK( intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_FALSE
);
547 FALLBACK( intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_TRUE
);
551 if ( intel
->sarea
->pf_current_page
== 1 )
554 intelSetFrontClipRects( intel
);
558 if (intel
->draw_region
!= intel
->front_region
) {
559 intel_region_release(intel
, &intel
->draw_region
);
560 intel_region_reference(&intel
->draw_region
, intel
->front_region
);
563 if (intel
->draw_region
!= intel
->back_region
) {
564 intel_region_release(intel
, &intel
->draw_region
);
565 intel_region_reference(&intel
->draw_region
, intel
->back_region
);
569 intel
->vtbl
.set_draw_region( intel
,
571 intel
->depth_region
);
574 static void intelReadBuffer( GLcontext
*ctx
, GLenum mode
)
576 /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
581 void intelInitBufferFuncs( struct dd_function_table
*functions
)
583 functions
->Clear
= intelClear
;
584 functions
->GetBufferSize
= intelBufferSize
;
585 functions
->DrawBuffer
= intelDrawBuffer
;
586 functions
->ReadBuffer
= intelReadBuffer
;