d155c039d77872017e943b20df8ce262e5ed0249
[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 "swrast/swrast.h"
37
38 GLboolean intel_intersect_cliprects( drm_clip_rect_t *dst,
39 const drm_clip_rect_t *a,
40 const drm_clip_rect_t *b )
41 {
42 dst->x1 = MAX2(a->x1, b->x1);
43 dst->x2 = MIN2(a->x2, b->x2);
44 dst->y1 = MAX2(a->y1, b->y1);
45 dst->y2 = MIN2(a->y2, b->y2);
46
47 return (dst->x1 <= dst->x2 &&
48 dst->y1 <= dst->y2);
49 }
50
51 struct intel_region *intel_drawbuf_region( struct intel_context *intel )
52 {
53 switch (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0]) {
54 case BUFFER_BIT_FRONT_LEFT:
55 return intel->front_region;
56 case BUFFER_BIT_BACK_LEFT:
57 return intel->back_region;
58 default:
59 /* Not necessary to fallback - could handle either NONE or
60 * FRONT_AND_BACK cases below.
61 */
62 return NULL;
63 }
64 }
65
66 struct intel_region *intel_readbuf_region( struct intel_context *intel )
67 {
68 GLcontext *ctx = &intel->ctx;
69
70 /* This will have to change to support EXT_fbo's, but is correct
71 * for now:
72 */
73 switch (ctx->ReadBuffer->_ColorReadBufferIndex) {
74 case BUFFER_FRONT_LEFT:
75 return intel->front_region;
76 case BUFFER_BACK_LEFT:
77 return intel->back_region;
78 default:
79 assert(0);
80 return NULL;
81 }
82 }
83
84
85
86 static void intelBufferSize(GLframebuffer *buffer,
87 GLuint *width,
88 GLuint *height)
89 {
90 GET_CURRENT_CONTEXT(ctx);
91 struct intel_context *intel = intel_context(ctx);
92 /* Need to lock to make sure the driDrawable is uptodate. This
93 * information is used to resize Mesa's software buffers, so it has
94 * to be correct.
95 */
96 LOCK_HARDWARE(intel);
97 if (intel->driDrawable) {
98 *width = intel->driDrawable->w;
99 *height = intel->driDrawable->h;
100 }
101 else {
102 *width = 0;
103 *height = 0;
104 }
105 UNLOCK_HARDWARE(intel);
106 }
107
108
109 static void intelSetFrontClipRects( struct intel_context *intel )
110 {
111 __DRIdrawablePrivate *dPriv = intel->driDrawable;
112
113 if (!dPriv) return;
114
115 intel->numClipRects = dPriv->numClipRects;
116 intel->pClipRects = dPriv->pClipRects;
117 intel->drawX = dPriv->x;
118 intel->drawY = dPriv->y;
119 }
120
121
122 static void intelSetBackClipRects( struct intel_context *intel )
123 {
124 __DRIdrawablePrivate *dPriv = intel->driDrawable;
125
126 if (!dPriv) return;
127
128 if (intel->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0) {
129 intel->numClipRects = dPriv->numClipRects;
130 intel->pClipRects = dPriv->pClipRects;
131 intel->drawX = dPriv->x;
132 intel->drawY = dPriv->y;
133 } else {
134 intel->numClipRects = dPriv->numBackClipRects;
135 intel->pClipRects = dPriv->pBackClipRects;
136 intel->drawX = dPriv->backX;
137 intel->drawY = dPriv->backY;
138
139 if (dPriv->numBackClipRects == 1 &&
140 dPriv->x == dPriv->backX &&
141 dPriv->y == dPriv->backY) {
142
143 /* Repeat the calculation of the back cliprect dimensions here
144 * as early versions of dri.a in the Xserver are incorrect. Try
145 * very hard not to restrict future versions of dri.a which
146 * might eg. allocate truly private back buffers.
147 */
148 int x1, y1;
149 int x2, y2;
150
151 x1 = dPriv->x;
152 y1 = dPriv->y;
153 x2 = dPriv->x + dPriv->w;
154 y2 = dPriv->y + dPriv->h;
155
156 if (x1 < 0) x1 = 0;
157 if (y1 < 0) y1 = 0;
158 if (x2 > intel->intelScreen->width) x2 = intel->intelScreen->width;
159 if (y2 > intel->intelScreen->height) y2 = intel->intelScreen->height;
160
161 if (x1 == dPriv->pBackClipRects[0].x1 &&
162 y1 == dPriv->pBackClipRects[0].y1) {
163
164 dPriv->pBackClipRects[0].x2 = x2;
165 dPriv->pBackClipRects[0].y2 = y2;
166 }
167 }
168 }
169 }
170
171
172 void intelWindowMoved( struct intel_context *intel )
173 {
174 __DRIdrawablePrivate *dPriv = intel->driDrawable;
175
176 if (!intel->ctx.DrawBuffer) {
177 intelSetFrontClipRects( intel );
178 }
179 else {
180 switch (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0]) {
181 case BUFFER_BIT_FRONT_LEFT:
182 intelSetFrontClipRects( intel );
183 break;
184 case BUFFER_BIT_BACK_LEFT:
185 intelSetBackClipRects( intel );
186 break;
187 default:
188 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
189 intelSetFrontClipRects( intel );
190 }
191 }
192
193 _mesa_resize_framebuffer(&intel->ctx,
194 (GLframebuffer*)dPriv->driverPrivate,
195 dPriv->w, dPriv->h);
196
197 /* Set state we know depends on drawable parameters:
198 */
199 {
200 GLcontext *ctx = &intel->ctx;
201
202 if (ctx->Driver.Scissor)
203 ctx->Driver.Scissor( ctx, ctx->Scissor.X, ctx->Scissor.Y,
204 ctx->Scissor.Width, ctx->Scissor.Height );
205
206 if (ctx->Driver.DepthRange)
207 ctx->Driver.DepthRange( ctx,
208 ctx->Viewport.Near,
209 ctx->Viewport.Far );
210
211 intel->NewGLState |= _NEW_SCISSOR;
212 }
213
214 /* This works because the lock is always grabbed before emitting
215 * commands and commands are always flushed prior to releasing
216 * the lock.
217 */
218 intel->NewGLState |= _NEW_WINDOW_POS;
219 }
220
221
222
223 /* A true meta version of this would be very simple and additionally
224 * machine independent. Maybe we'll get there one day.
225 */
226 static void intelClearWithTris(struct intel_context *intel,
227 GLbitfield mask)
228 {
229 GLcontext *ctx = &intel->ctx;
230 drm_clip_rect_t clear;
231 GLint cx, cy, cw, ch;
232
233 if (INTEL_DEBUG & DEBUG_DRI)
234 _mesa_printf("%s %x\n", __FUNCTION__, mask);
235
236 {
237
238 intel->vtbl.install_meta_state(intel);
239
240 /* Get clear bounds after locking */
241 cx = ctx->DrawBuffer->_Xmin;
242 cy = ctx->DrawBuffer->_Ymin;
243 cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
244 ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
245
246 clear.x1 = cx;
247 clear.y1 = cy;
248 clear.x2 = cx + cw;
249 clear.y2 = cy + ch;
250
251 /* Back and stencil cliprects are the same. Try and do both
252 * buffers at once:
253 */
254 if (mask & (BUFFER_BIT_BACK_LEFT|BUFFER_BIT_STENCIL|BUFFER_BIT_DEPTH)) {
255 intel->vtbl.meta_draw_region(intel,
256 intel->back_region,
257 intel->depth_region );
258
259 if (mask & BUFFER_BIT_BACK_LEFT)
260 intel->vtbl.meta_color_mask(intel, GL_TRUE );
261 else
262 intel->vtbl.meta_color_mask(intel, GL_FALSE );
263
264 if (mask & BUFFER_BIT_STENCIL)
265 intel->vtbl.meta_stencil_replace( intel,
266 intel->ctx.Stencil.WriteMask[0],
267 intel->ctx.Stencil.Clear);
268 else
269 intel->vtbl.meta_no_stencil_write(intel);
270
271 if (mask & BUFFER_BIT_DEPTH)
272 intel->vtbl.meta_depth_replace( intel );
273 else
274 intel->vtbl.meta_no_depth_write(intel);
275
276 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
277 * drawing origin may not be correctly emitted.
278 */
279 intel->vtbl.meta_draw_quad(intel,
280 clear.x1, clear.x2,
281 clear.y1, clear.y2,
282 intel->ctx.Depth.Clear,
283 intel->clear_chan[0],
284 intel->clear_chan[1],
285 intel->clear_chan[2],
286 intel->clear_chan[3],
287 0, 0, 0, 0);
288 }
289
290 /* Front may have different cliprects:
291 */
292 if (mask & BUFFER_BIT_FRONT_LEFT) {
293 intel->vtbl.meta_no_depth_write(intel);
294 intel->vtbl.meta_no_stencil_write(intel);
295 intel->vtbl.meta_color_mask(intel, GL_TRUE );
296 intel->vtbl.meta_draw_region(intel,
297 intel->front_region,
298 intel->depth_region);
299
300 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
301 * drawing origin may not be correctly emitted.
302 */
303 intel->vtbl.meta_draw_quad(intel,
304 clear.x1, clear.x2,
305 clear.y1, clear.y2,
306 0,
307 intel->clear_chan[0],
308 intel->clear_chan[1],
309 intel->clear_chan[2],
310 intel->clear_chan[3],
311 0, 0, 0, 0);
312 }
313
314 intel->vtbl.leave_meta_state( intel );
315 }
316 }
317
318
319
320
321
322 static void intelClear(GLcontext *ctx, GLbitfield mask)
323 {
324 struct intel_context *intel = intel_context( ctx );
325 const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
326 GLbitfield tri_mask = 0;
327 GLbitfield blit_mask = 0;
328 GLbitfield swrast_mask = 0;
329
330 if (INTEL_DEBUG & DEBUG_DRI)
331 fprintf(stderr, "%s %x\n", __FUNCTION__, mask);
332
333
334 if (mask & BUFFER_BIT_FRONT_LEFT) {
335 if (colorMask == ~0) {
336 blit_mask |= BUFFER_BIT_FRONT_LEFT;
337 }
338 else {
339 tri_mask |= BUFFER_BIT_FRONT_LEFT;
340 }
341 }
342
343 if (mask & BUFFER_BIT_BACK_LEFT) {
344 if (colorMask == ~0) {
345 blit_mask |= BUFFER_BIT_BACK_LEFT;
346 }
347 else {
348 tri_mask |= BUFFER_BIT_BACK_LEFT;
349 }
350 }
351
352
353 if (mask & BUFFER_BIT_STENCIL) {
354 if (!intel->hw_stencil) {
355 swrast_mask |= BUFFER_BIT_STENCIL;
356 }
357 else if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff ||
358 intel->depth_region->tiled) {
359 tri_mask |= BUFFER_BIT_STENCIL;
360 }
361 else {
362 blit_mask |= BUFFER_BIT_STENCIL;
363 }
364 }
365
366 /* Do depth with stencil if possible to avoid 2nd pass over the
367 * same buffer.
368 */
369 if (mask & BUFFER_BIT_DEPTH) {
370 if ((tri_mask & BUFFER_BIT_STENCIL) ||
371 intel->depth_region->tiled)
372 tri_mask |= BUFFER_BIT_DEPTH;
373 else
374 blit_mask |= BUFFER_BIT_DEPTH;
375 }
376
377 swrast_mask |= (mask & BUFFER_BIT_ACCUM);
378
379 intelFlush( ctx );
380
381 if (blit_mask)
382 intelClearWithBlit( ctx, blit_mask );
383
384 if (tri_mask)
385 intelClearWithTris( intel, tri_mask );
386
387 if (swrast_mask)
388 _swrast_Clear( ctx, swrast_mask );
389 }
390
391
392
393
394
395
396
397 /* Flip the front & back buffers
398 */
399 static void intelPageFlip( const __DRIdrawablePrivate *dPriv )
400 {
401 #if 0
402 struct intel_context *intel;
403 int tmp, ret;
404
405 if (INTEL_DEBUG & DEBUG_IOCTL)
406 fprintf(stderr, "%s\n", __FUNCTION__);
407
408 assert(dPriv);
409 assert(dPriv->driContextPriv);
410 assert(dPriv->driContextPriv->driverPrivate);
411
412 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
413
414 intelFlush( &intel->ctx );
415 LOCK_HARDWARE( intel );
416
417 if (dPriv->pClipRects) {
418 *(drm_clip_rect_t *)intel->sarea->boxes = dPriv->pClipRects[0];
419 intel->sarea->nbox = 1;
420 }
421
422 ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
423 if (ret) {
424 fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
425 UNLOCK_HARDWARE( intel );
426 exit(1);
427 }
428
429 tmp = intel->sarea->last_enqueue;
430 intelRefillBatchLocked( intel );
431 UNLOCK_HARDWARE( intel );
432
433
434 intelSetDrawBuffer( &intel->ctx, intel->ctx.Color.DriverDrawBuffer );
435 #endif
436 }
437
438
439 void intelSwapBuffers( __DRIdrawablePrivate *dPriv )
440 {
441 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
442 struct intel_context *intel;
443 GLcontext *ctx;
444 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
445 ctx = &intel->ctx;
446 if (ctx->Visual.doubleBufferMode) {
447 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
448 if ( 0 /*intel->doPageFlip*/ ) { /* doPageFlip is never set !!! */
449 intelPageFlip( dPriv );
450 } else {
451 intelCopyBuffer( dPriv, NULL );
452 }
453 if (intel->aub_file) {
454 intelFlush(ctx);
455 intel->vtbl.aub_dump_bmp( intel, 1 );
456
457 intel->aub_wrap = 1;
458 }
459 }
460 } else {
461 /* XXX this shouldn't be an error but we can't handle it for now */
462 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
463 }
464 }
465
466 void intelCopySubBuffer( __DRIdrawablePrivate *dPriv,
467 int x, int y, int w, int h )
468 {
469 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
470 struct intel_context *intel = dPriv->driContextPriv->driverPrivate;
471 GLcontext *ctx = &intel->ctx;
472
473 if (ctx->Visual.doubleBufferMode) {
474 drm_clip_rect_t rect;
475 rect.x1 = x + dPriv->x;
476 rect.y1 = (dPriv->h - y - h) + dPriv->y;
477 rect.x2 = rect.x1 + w;
478 rect.y2 = rect.y1 + h;
479 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
480 intelCopyBuffer( dPriv, &rect );
481 }
482 } else {
483 /* XXX this shouldn't be an error but we can't handle it for now */
484 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
485 }
486 }
487
488
489 static void intelDrawBuffer(GLcontext *ctx, GLenum mode )
490 {
491 struct intel_context *intel = intel_context(ctx);
492 int front = 0;
493
494 if (!ctx->DrawBuffer)
495 return;
496
497 switch ( ctx->DrawBuffer->_ColorDrawBufferMask[0] ) {
498 case BUFFER_BIT_FRONT_LEFT:
499 front = 1;
500 FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE );
501 break;
502 case BUFFER_BIT_BACK_LEFT:
503 front = 0;
504 FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE );
505 break;
506 default:
507 FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE );
508 return;
509 }
510
511 if ( intel->sarea->pf_current_page == 1 )
512 front ^= 1;
513
514 intelSetFrontClipRects( intel );
515
516
517 if (front) {
518 if (intel->draw_region != intel->front_region) {
519 intel_region_release(intel, &intel->draw_region);
520 intel_region_reference(&intel->draw_region, intel->front_region);
521 }
522 } else {
523 if (intel->draw_region != intel->back_region) {
524 intel_region_release(intel, &intel->draw_region);
525 intel_region_reference(&intel->draw_region, intel->back_region);
526 }
527 }
528
529 intel->vtbl.set_draw_region( intel,
530 intel->draw_region,
531 intel->depth_region);
532 }
533
534 static void intelReadBuffer( GLcontext *ctx, GLenum mode )
535 {
536 /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
537 }
538
539
540
541 void intelInitBufferFuncs( struct dd_function_table *functions )
542 {
543 functions->Clear = intelClear;
544 functions->GetBufferSize = intelBufferSize;
545 functions->DrawBuffer = intelDrawBuffer;
546 functions->ReadBuffer = intelReadBuffer;
547 }