[965] Use shared intel_regions.c.
[mesa.git] / src / mesa / drivers / dri / i965 / intel_buffers.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 #include "intel_screen.h"
29 #include "intel_context.h"
30 #include "intel_blit.h"
31 #include "intel_regions.h"
32 #include "intel_batchbuffer.h"
33 #include "context.h"
34 #include "framebuffer.h"
35 #include "macros.h"
36 #include "utils.h"
37 #include "vblank.h"
38 #include "swrast/swrast.h"
39
40 GLboolean intel_intersect_cliprects( drm_clip_rect_t *dst,
41 const drm_clip_rect_t *a,
42 const drm_clip_rect_t *b )
43 {
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);
48
49 return (dst->x1 <= dst->x2 &&
50 dst->y1 <= dst->y2);
51 }
52
53 struct intel_region *intel_drawbuf_region( struct intel_context *intel )
54 {
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;
60 default:
61 /* Not necessary to fallback - could handle either NONE or
62 * FRONT_AND_BACK cases below.
63 */
64 return NULL;
65 }
66 }
67
68 struct intel_region *intel_readbuf_region( struct intel_context *intel )
69 {
70 GLcontext *ctx = &intel->ctx;
71
72 /* This will have to change to support EXT_fbo's, but is correct
73 * for now:
74 */
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;
80 default:
81 assert(0);
82 return NULL;
83 }
84 }
85
86
87
88 static void intelBufferSize(GLframebuffer *buffer,
89 GLuint *width,
90 GLuint *height)
91 {
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
96 * to be correct.
97 */
98 LOCK_HARDWARE(intel);
99 if (intel->driDrawable) {
100 *width = intel->driDrawable->w;
101 *height = intel->driDrawable->h;
102 }
103 else {
104 *width = 0;
105 *height = 0;
106 }
107 UNLOCK_HARDWARE(intel);
108 }
109
110
111 static void intelSetFrontClipRects( struct intel_context *intel )
112 {
113 __DRIdrawablePrivate *dPriv = intel->driDrawable;
114
115 if (!dPriv) return;
116
117 intel->numClipRects = dPriv->numClipRects;
118 intel->pClipRects = dPriv->pClipRects;
119 intel->drawX = dPriv->x;
120 intel->drawY = dPriv->y;
121 }
122
123
124 static void intelSetBackClipRects( struct intel_context *intel )
125 {
126 __DRIdrawablePrivate *dPriv = intel->driDrawable;
127
128 if (!dPriv) return;
129
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;
135 } else {
136 intel->numClipRects = dPriv->numBackClipRects;
137 intel->pClipRects = dPriv->pBackClipRects;
138 intel->drawX = dPriv->backX;
139 intel->drawY = dPriv->backY;
140
141 if (dPriv->numBackClipRects == 1 &&
142 dPriv->x == dPriv->backX &&
143 dPriv->y == dPriv->backY) {
144
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.
149 */
150 int x1, y1;
151 int x2, y2;
152
153 x1 = dPriv->x;
154 y1 = dPriv->y;
155 x2 = dPriv->x + dPriv->w;
156 y2 = dPriv->y + dPriv->h;
157
158 if (x1 < 0) x1 = 0;
159 if (y1 < 0) y1 = 0;
160 if (x2 > intel->intelScreen->width) x2 = intel->intelScreen->width;
161 if (y2 > intel->intelScreen->height) y2 = intel->intelScreen->height;
162
163 if (x1 == dPriv->pBackClipRects[0].x1 &&
164 y1 == dPriv->pBackClipRects[0].y1) {
165
166 dPriv->pBackClipRects[0].x2 = x2;
167 dPriv->pBackClipRects[0].y2 = y2;
168 }
169 }
170 }
171 }
172
173
174 void intelWindowMoved( struct intel_context *intel )
175 {
176 __DRIdrawablePrivate *dPriv = intel->driDrawable;
177
178 if (!intel->ctx.DrawBuffer) {
179 intelSetFrontClipRects( intel );
180 }
181 else {
182 switch (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0]) {
183 case BUFFER_BIT_FRONT_LEFT:
184 intelSetFrontClipRects( intel );
185 break;
186 case BUFFER_BIT_BACK_LEFT:
187 intelSetBackClipRects( intel );
188 break;
189 default:
190 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
191 intelSetFrontClipRects( intel );
192 }
193 }
194
195 /* Get updated plane info so we sync against the right vblank counter */
196 if (intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
197 volatile 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;
209
210 /* Update vblank info
211 */
212 if (areaB > areaA || (areaA == areaB && areaB > 0)) {
213 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY;
214 } else {
215 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
216 }
217
218 /* Check to see if we changed pipes */
219 if (flags != dPriv->vblFlags && dPriv->vblFlags &&
220 !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) {
221 int64_t count;
222
223 /*
224 * Update msc_base from old pipe
225 */
226 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count);
227 dPriv->msc_base = count;
228 /*
229 * Then get new vblank_base and vblSeq values
230 */
231 dPriv->vblFlags = flags;
232 driGetCurrentVBlank(dPriv);
233 dPriv->vblank_base = dPriv->vblSeq;
234 }
235 } else {
236 dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY;
237 }
238
239 _mesa_resize_framebuffer(&intel->ctx,
240 (GLframebuffer*)dPriv->driverPrivate,
241 dPriv->w, dPriv->h);
242
243 /* Set state we know depends on drawable parameters:
244 */
245 {
246 GLcontext *ctx = &intel->ctx;
247
248 if (ctx->Driver.Scissor)
249 ctx->Driver.Scissor( ctx, ctx->Scissor.X, ctx->Scissor.Y,
250 ctx->Scissor.Width, ctx->Scissor.Height );
251
252 if (ctx->Driver.DepthRange)
253 ctx->Driver.DepthRange( ctx,
254 ctx->Viewport.Near,
255 ctx->Viewport.Far );
256
257 intel->NewGLState |= _NEW_SCISSOR;
258 }
259
260 /* This works because the lock is always grabbed before emitting
261 * commands and commands are always flushed prior to releasing
262 * the lock.
263 */
264 intel->NewGLState |= _NEW_WINDOW_POS;
265 }
266
267
268
269 /* A true meta version of this would be very simple and additionally
270 * machine independent. Maybe we'll get there one day.
271 */
272 static void intelClearWithTris(struct intel_context *intel,
273 GLbitfield mask)
274 {
275 GLcontext *ctx = &intel->ctx;
276 drm_clip_rect_t clear;
277 GLint cx, cy, cw, ch;
278
279 if (INTEL_DEBUG & DEBUG_DRI)
280 _mesa_printf("%s %x\n", __FUNCTION__, mask);
281
282 {
283
284 intel->vtbl.install_meta_state(intel);
285
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;
291
292 clear.x1 = cx;
293 clear.y1 = cy;
294 clear.x2 = cx + cw;
295 clear.y2 = cy + ch;
296
297 /* Back and stencil cliprects are the same. Try and do both
298 * buffers at once:
299 */
300 if (mask & (BUFFER_BIT_BACK_LEFT|BUFFER_BIT_STENCIL|BUFFER_BIT_DEPTH)) {
301 intel->vtbl.meta_draw_region(intel,
302 intel->back_region,
303 intel->depth_region );
304
305 if (mask & BUFFER_BIT_BACK_LEFT)
306 intel->vtbl.meta_color_mask(intel, GL_TRUE );
307 else
308 intel->vtbl.meta_color_mask(intel, GL_FALSE );
309
310 if (mask & BUFFER_BIT_STENCIL)
311 intel->vtbl.meta_stencil_replace( intel,
312 intel->ctx.Stencil.WriteMask[0],
313 intel->ctx.Stencil.Clear);
314 else
315 intel->vtbl.meta_no_stencil_write(intel);
316
317 if (mask & BUFFER_BIT_DEPTH)
318 intel->vtbl.meta_depth_replace( intel );
319 else
320 intel->vtbl.meta_no_depth_write(intel);
321
322 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
323 * drawing origin may not be correctly emitted.
324 */
325 intel->vtbl.meta_draw_quad(intel,
326 clear.x1, clear.x2,
327 clear.y1, clear.y2,
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],
333 0, 0, 0, 0);
334 }
335
336 /* Front may have different cliprects:
337 */
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,
343 intel->front_region,
344 intel->depth_region);
345
346 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
347 * drawing origin may not be correctly emitted.
348 */
349 intel->vtbl.meta_draw_quad(intel,
350 clear.x1, clear.x2,
351 clear.y1, clear.y2,
352 0,
353 intel->clear_chan[0],
354 intel->clear_chan[1],
355 intel->clear_chan[2],
356 intel->clear_chan[3],
357 0, 0, 0, 0);
358 }
359
360 intel->vtbl.leave_meta_state( intel );
361 }
362 }
363
364
365
366
367
368 static void intelClear(GLcontext *ctx, GLbitfield mask)
369 {
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;
375
376 if (INTEL_DEBUG & DEBUG_DRI)
377 fprintf(stderr, "%s %x\n", __FUNCTION__, mask);
378
379
380 if (mask & BUFFER_BIT_FRONT_LEFT) {
381 if (colorMask == ~0) {
382 blit_mask |= BUFFER_BIT_FRONT_LEFT;
383 }
384 else {
385 tri_mask |= BUFFER_BIT_FRONT_LEFT;
386 }
387 }
388
389 if (mask & BUFFER_BIT_BACK_LEFT) {
390 if (colorMask == ~0) {
391 blit_mask |= BUFFER_BIT_BACK_LEFT;
392 }
393 else {
394 tri_mask |= BUFFER_BIT_BACK_LEFT;
395 }
396 }
397
398
399 if (mask & BUFFER_BIT_STENCIL) {
400 if (!intel->hw_stencil) {
401 swrast_mask |= BUFFER_BIT_STENCIL;
402 }
403 else if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff ||
404 intel->depth_region->tiled) {
405 tri_mask |= BUFFER_BIT_STENCIL;
406 }
407 else {
408 blit_mask |= BUFFER_BIT_STENCIL;
409 }
410 }
411
412 /* Do depth with stencil if possible to avoid 2nd pass over the
413 * same buffer.
414 */
415 if (mask & BUFFER_BIT_DEPTH) {
416 if ((tri_mask & BUFFER_BIT_STENCIL) ||
417 intel->depth_region->tiled)
418 tri_mask |= BUFFER_BIT_DEPTH;
419 else
420 blit_mask |= BUFFER_BIT_DEPTH;
421 }
422
423 swrast_mask |= (mask & BUFFER_BIT_ACCUM);
424
425 intelFlush( ctx );
426
427 if (blit_mask)
428 intelClearWithBlit( ctx, blit_mask );
429
430 if (tri_mask)
431 intelClearWithTris( intel, tri_mask );
432
433 if (swrast_mask)
434 _swrast_Clear( ctx, swrast_mask );
435 }
436
437
438
439
440
441
442
443 /* Flip the front & back buffers
444 */
445 static void intelPageFlip( const __DRIdrawablePrivate *dPriv )
446 {
447 #if 0
448 struct intel_context *intel;
449 int tmp, ret;
450
451 if (INTEL_DEBUG & DEBUG_IOCTL)
452 fprintf(stderr, "%s\n", __FUNCTION__);
453
454 assert(dPriv);
455 assert(dPriv->driContextPriv);
456 assert(dPriv->driContextPriv->driverPrivate);
457
458 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
459
460 intelFlush( &intel->ctx );
461 LOCK_HARDWARE( intel );
462
463 if (dPriv->pClipRects) {
464 *(drm_clip_rect_t *)intel->sarea->boxes = dPriv->pClipRects[0];
465 intel->sarea->nbox = 1;
466 }
467
468 ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
469 if (ret) {
470 fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
471 UNLOCK_HARDWARE( intel );
472 exit(1);
473 }
474
475 tmp = intel->sarea->last_enqueue;
476 intelRefillBatchLocked( intel );
477 UNLOCK_HARDWARE( intel );
478
479
480 intelSetDrawBuffer( &intel->ctx, intel->ctx.Color.DriverDrawBuffer );
481 #endif
482 }
483
484
485 void intelSwapBuffers( __DRIdrawablePrivate *dPriv )
486 {
487 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
488 struct intel_context *intel;
489 GLcontext *ctx;
490 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
491 ctx = &intel->ctx;
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 );
496 } else {
497 intelCopyBuffer( dPriv, NULL );
498 }
499 }
500 } else {
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__);
503 }
504 }
505
506 void intelCopySubBuffer( __DRIdrawablePrivate *dPriv,
507 int x, int y, int w, int h )
508 {
509 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
510 struct intel_context *intel = dPriv->driContextPriv->driverPrivate;
511 GLcontext *ctx = &intel->ctx;
512
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 );
521 }
522 } else {
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__);
525 }
526 }
527
528
529 static void intelDrawBuffer(GLcontext *ctx, GLenum mode )
530 {
531 struct intel_context *intel = intel_context(ctx);
532 int front = 0;
533
534 if (!ctx->DrawBuffer)
535 return;
536
537 switch ( ctx->DrawBuffer->_ColorDrawBufferMask[0] ) {
538 case BUFFER_BIT_FRONT_LEFT:
539 front = 1;
540 FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE );
541 break;
542 case BUFFER_BIT_BACK_LEFT:
543 front = 0;
544 FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE );
545 break;
546 default:
547 FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE );
548 return;
549 }
550
551 if ( intel->sarea->pf_current_page == 1 )
552 front ^= 1;
553
554 intelSetFrontClipRects( intel );
555
556
557 if (front) {
558 if (intel->draw_region != intel->front_region) {
559 intel_region_release(&intel->draw_region);
560 intel_region_reference(&intel->draw_region, intel->front_region);
561 }
562 } else {
563 if (intel->draw_region != intel->back_region) {
564 intel_region_release(&intel->draw_region);
565 intel_region_reference(&intel->draw_region, intel->back_region);
566 }
567 }
568
569 intel->vtbl.set_draw_region( intel,
570 intel->draw_region,
571 intel->depth_region);
572 }
573
574 static void intelReadBuffer( GLcontext *ctx, GLenum mode )
575 {
576 /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
577 }
578
579
580
581 void intelInitBufferFuncs( struct dd_function_table *functions )
582 {
583 functions->Clear = intelClear;
584 functions->GetBufferSize = intelBufferSize;
585 functions->DrawBuffer = intelDrawBuffer;
586 functions->ReadBuffer = intelReadBuffer;
587 }