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 "intel_batchbuffer.h"
37 #include "intel_blit.h"
38 #include "intel_buffers.h"
39 #include "intel_context.h"
40 #include "intel_fbo.h"
41 #include "intel_reg.h"
42 #include "intel_regions.h"
45 #define FILE_DEBUG_FLAG DEBUG_BLIT
48 * Copy the back color buffer to the front color buffer.
49 * Used for SwapBuffers().
52 intelCopyBuffer(const __DRIdrawablePrivate
* dPriv
,
53 const drm_clip_rect_t
* rect
)
56 struct intel_context
*intel
;
57 const intelScreenPrivate
*intelScreen
;
58 GLboolean missed_target
;
61 DBG("%s\n", __FUNCTION__
);
65 intel
= intelScreenContext(dPriv
->driScreenPriv
->private);
69 intelScreen
= intel
->intelScreen
;
71 if (!rect
&& !intel
->swap_scheduled
&& intelScreen
->drmMinor
>= 6 &&
72 !(intel
->vblank_flags
& VBLANK_FLAG_NO_IRQ
) &&
73 intelScreen
->current_rotation
== 0) {
74 unsigned int interval
= driGetVBlankInterval(dPriv
, intel
->vblank_flags
);
76 drm_i915_vblank_swap_t swap
;
78 swap
.drawable
= dPriv
->hHWDrawable
;
79 swap
.seqtype
= DRM_VBLANK_ABSOLUTE
;
80 target
= swap
.sequence
= intel
->vbl_seq
+ interval
;
82 if (intel
->vblank_flags
& VBLANK_FLAG_SYNC
) {
83 swap
.seqtype
|= DRM_VBLANK_NEXTONMISS
;
84 } else if (interval
== 0) {
88 if ( intel
->vblank_flags
& VBLANK_FLAG_SECONDARY
) {
89 swap
.seqtype
|= DRM_VBLANK_SECONDARY
;
92 intel_batchbuffer_flush(intel
->batch
);
94 if (!drmCommandWriteRead(intel
->driFd
, DRM_I915_VBLANK_SWAP
, &swap
,
96 intel
->swap_scheduled
= 1;
97 intel
->vbl_seq
= swap
.sequence
;
98 swap
.sequence
-= target
;
99 missed_target
= swap
.sequence
> 0 && swap
.sequence
<= (1 << 23);
102 intel
->swap_scheduled
= 0;
106 if (intel
->last_swap_fence
) {
107 driFenceFinish(intel
->last_swap_fence
, DRM_FENCE_TYPE_EXE
, GL_TRUE
);
108 driFenceUnReference(intel
->last_swap_fence
);
109 intel
->last_swap_fence
= NULL
;
111 intel
->last_swap_fence
= intel
->first_swap_fence
;
112 intel
->first_swap_fence
= NULL
;
114 if (!intel
->swap_scheduled
) {
116 driWaitForVBlank(dPriv
, &intel
->vbl_seq
, intel
->vblank_flags
,
121 /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
122 * should work regardless.
124 LOCK_HARDWARE(intel
);
126 if (intel
->driDrawable
&& intel
->driDrawable
->numClipRects
) {
127 const intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
128 struct gl_framebuffer
*fb
129 = (struct gl_framebuffer
*) dPriv
->driverPrivate
;
130 const struct intel_region
*frontRegion
131 = intel_get_rb_region(fb
, BUFFER_FRONT_LEFT
);
132 const struct intel_region
*backRegion
133 = intel_get_rb_region(fb
, BUFFER_BACK_LEFT
);
134 const int nbox
= dPriv
->numClipRects
;
135 const drm_clip_rect_t
*pbox
= dPriv
->pClipRects
;
136 const int pitch
= frontRegion
->pitch
;
137 const int cpp
= frontRegion
->cpp
;
142 ASSERT(fb
->Name
== 0); /* Not a user-created FBO */
145 ASSERT(frontRegion
->pitch
== backRegion
->pitch
);
146 ASSERT(frontRegion
->cpp
== backRegion
->cpp
);
149 BR13
= (pitch
* cpp
) | (0xCC << 16) | (1 << 24);
150 CMD
= XY_SRC_COPY_BLT_CMD
;
153 BR13
= (pitch
* cpp
) | (0xCC << 16) | (1 << 24) | (1 << 25);
154 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
155 XY_SRC_COPY_BLT_WRITE_RGB
);
158 for (i
= 0; i
< nbox
; i
++, pbox
++) {
161 if (pbox
->x1
> pbox
->x2
||
162 pbox
->y1
> pbox
->y2
||
163 pbox
->x2
> intelScreen
->width
|| pbox
->y2
> intelScreen
->height
)
169 if (rect
->x1
> box
.x1
)
171 if (rect
->y1
> box
.y1
)
173 if (rect
->x2
< box
.x2
)
175 if (rect
->y2
< box
.y2
)
178 if (box
.x1
> box
.x2
|| box
.y1
> box
.y2
)
182 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS
);
185 OUT_BATCH((pbox
->y1
<< 16) | pbox
->x1
);
186 OUT_BATCH((pbox
->y2
<< 16) | pbox
->x2
);
188 if (intel
->sarea
->pf_current_page
== 0)
189 OUT_RELOC(frontRegion
->buffer
,
190 DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_WRITE
,
191 DRM_BO_MASK_MEM
| DRM_BO_FLAG_WRITE
, 0);
193 OUT_RELOC(backRegion
->buffer
,
194 DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_WRITE
,
195 DRM_BO_MASK_MEM
| DRM_BO_FLAG_WRITE
, 0);
196 OUT_BATCH((pbox
->y1
<< 16) | pbox
->x1
);
197 OUT_BATCH(BR13
& 0xffff);
199 if (intel
->sarea
->pf_current_page
== 0)
200 OUT_RELOC(backRegion
->buffer
,
201 DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_READ
,
202 DRM_BO_MASK_MEM
| DRM_BO_FLAG_READ
, 0);
204 OUT_RELOC(frontRegion
->buffer
,
205 DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_READ
,
206 DRM_BO_MASK_MEM
| DRM_BO_FLAG_READ
, 0);
211 if (intel
->first_swap_fence
)
212 driFenceUnReference(intel
->first_swap_fence
);
213 intel
->first_swap_fence
= intel_batchbuffer_flush(intel
->batch
);
214 driFenceReference(intel
->first_swap_fence
);
217 UNLOCK_HARDWARE(intel
);
222 (*dri_interface
->getUST
) (&ust
);
224 intel
->swap_missed_count
++;
225 intel
->swap_missed_ust
= ust
- intel
->swap_ust
;
228 intel
->swap_ust
= ust
;
236 intelEmitFillBlit(struct intel_context
*intel
,
239 struct _DriBufferObject
*dst_buffer
,
241 GLshort x
, GLshort y
, GLshort w
, GLshort h
, GLuint color
)
252 BR13
= dst_pitch
| (0xF0 << 16) | (1 << 24);
253 CMD
= XY_COLOR_BLT_CMD
;
256 BR13
= dst_pitch
| (0xF0 << 16) | (1 << 24) | (1 << 25);
257 CMD
= (XY_COLOR_BLT_CMD
| XY_COLOR_BLT_WRITE_ALPHA
|
258 XY_COLOR_BLT_WRITE_RGB
);
264 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
265 __FUNCTION__
, dst_buffer
, dst_pitch
, dst_offset
, x
, y
, w
, h
);
268 BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS
);
271 OUT_BATCH((y
<< 16) | x
);
272 OUT_BATCH(((y
+ h
) << 16) | (x
+ w
));
273 OUT_RELOC(dst_buffer
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_WRITE
,
274 DRM_BO_MASK_MEM
| DRM_BO_FLAG_WRITE
, dst_offset
);
280 static GLuint
translate_raster_op(GLenum logicop
)
283 case GL_CLEAR
: return 0x00;
284 case GL_AND
: return 0x88;
285 case GL_AND_REVERSE
: return 0x44;
286 case GL_COPY
: return 0xCC;
287 case GL_AND_INVERTED
: return 0x22;
288 case GL_NOOP
: return 0xAA;
289 case GL_XOR
: return 0x66;
290 case GL_OR
: return 0xEE;
291 case GL_NOR
: return 0x11;
292 case GL_EQUIV
: return 0x99;
293 case GL_INVERT
: return 0x55;
294 case GL_OR_REVERSE
: return 0xDD;
295 case GL_COPY_INVERTED
: return 0x33;
296 case GL_OR_INVERTED
: return 0xBB;
297 case GL_NAND
: return 0x77;
298 case GL_SET
: return 0xFF;
307 intelEmitCopyBlit(struct intel_context
*intel
,
310 struct _DriBufferObject
*src_buffer
,
313 struct _DriBufferObject
*dst_buffer
,
315 GLshort src_x
, GLshort src_y
,
316 GLshort dst_x
, GLshort dst_y
,
317 GLshort w
, GLshort h
,
321 int dst_y2
= dst_y
+ h
;
322 int dst_x2
= dst_x
+ w
;
326 DBG("%s src:buf(%p)/%d+%d %d,%d dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
328 src_buffer
, src_pitch
, src_offset
, src_x
, src_y
,
329 dst_buffer
, dst_pitch
, dst_offset
, dst_x
, dst_y
, w
, h
);
338 BR13
= (((GLint
) dst_pitch
) & 0xffff) |
339 (translate_raster_op(logic_op
) << 16) | (1 << 24);
340 CMD
= XY_SRC_COPY_BLT_CMD
;
344 (((GLint
) dst_pitch
) & 0xffff) |
345 (translate_raster_op(logic_op
) << 16) | (1 << 24) | (1 << 25);
347 (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
348 XY_SRC_COPY_BLT_WRITE_RGB
);
354 if (dst_y2
< dst_y
|| dst_x2
< dst_x
) {
358 /* Initial y values don't seem to work with negative pitches. If
359 * we adjust the offsets manually (below), it seems to work fine.
361 * On the other hand, if we always adjust, the hardware doesn't
362 * know which blit directions to use, so overlapping copypixels get
365 if (dst_pitch
> 0 && src_pitch
> 0) {
366 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS
);
369 OUT_BATCH((dst_y
<< 16) | dst_x
);
370 OUT_BATCH((dst_y2
<< 16) | dst_x2
);
371 OUT_RELOC(dst_buffer
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_WRITE
,
372 DRM_BO_MASK_MEM
| DRM_BO_FLAG_WRITE
, dst_offset
);
373 OUT_BATCH((src_y
<< 16) | src_x
);
374 OUT_BATCH(((GLint
) src_pitch
& 0xffff));
375 OUT_RELOC(src_buffer
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_READ
,
376 DRM_BO_MASK_MEM
| DRM_BO_FLAG_READ
, src_offset
);
380 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS
);
383 OUT_BATCH((0 << 16) | dst_x
);
384 OUT_BATCH((h
<< 16) | dst_x2
);
385 OUT_RELOC(dst_buffer
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_WRITE
,
386 DRM_BO_MASK_MEM
| DRM_BO_FLAG_WRITE
,
387 dst_offset
+ dst_y
* dst_pitch
);
388 OUT_BATCH((0 << 16) | src_x
);
389 OUT_BATCH(((GLint
) src_pitch
& 0xffff));
390 OUT_RELOC(src_buffer
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_READ
,
391 DRM_BO_MASK_MEM
| DRM_BO_FLAG_READ
,
392 src_offset
+ src_y
* src_pitch
);
399 * Use blitting to clear the renderbuffers named by 'flags'.
400 * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferMask field
401 * since that might include software renderbuffers or renderbuffers
402 * which we're clearing with triangles.
403 * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear
406 intelClearWithBlit(GLcontext
* ctx
, GLbitfield mask
)
408 struct intel_context
*intel
= intel_context(ctx
);
410 GLbitfield skipBuffers
= 0;
413 DBG("%s %x\n", __FUNCTION__
, mask
);
416 * Compute values for clearing the buffers.
419 if (mask
& BUFFER_BIT_DEPTH
) {
420 clear_depth
= (GLuint
) (ctx
->DrawBuffer
->_DepthMax
* ctx
->Depth
.Clear
);
422 if (mask
& BUFFER_BIT_STENCIL
) {
423 clear_depth
|= (ctx
->Stencil
.Clear
& 0xff) << 24;
426 /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in
429 if ((mask
& BUFFER_BIT_DEPTH
) && (mask
& BUFFER_BIT_STENCIL
)) {
430 skipBuffers
= BUFFER_BIT_STENCIL
;
433 /* XXX Move this flush/lock into the following conditional? */
434 intelFlush(&intel
->ctx
);
435 LOCK_HARDWARE(intel
);
437 if (intel
->numClipRects
) {
438 GLint cx
, cy
, cw
, ch
;
439 drm_clip_rect_t clear
;
442 /* Get clear bounds after locking */
443 cx
= ctx
->DrawBuffer
->_Xmin
;
444 cy
= ctx
->DrawBuffer
->_Ymin
;
445 cw
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
446 ch
= ctx
->DrawBuffer
->_Ymax
- ctx
->DrawBuffer
->_Ymin
;
448 if (intel
->ctx
.DrawBuffer
->Name
== 0) {
449 /* clearing a window */
451 /* flip top to bottom */
452 clear
.x1
= cx
+ intel
->drawX
;
453 clear
.y1
= intel
->driDrawable
->y
+ intel
->driDrawable
->h
- cy
- ch
;
454 clear
.x2
= clear
.x1
+ cw
;
455 clear
.y2
= clear
.y1
+ ch
;
457 /* adjust for page flipping */
458 if (intel
->sarea
->pf_current_page
== 1) {
459 const GLuint tmp
= mask
;
460 mask
&= ~(BUFFER_BIT_FRONT_LEFT
| BUFFER_BIT_BACK_LEFT
);
461 if (tmp
& BUFFER_BIT_FRONT_LEFT
)
462 mask
|= BUFFER_BIT_BACK_LEFT
;
463 if (tmp
& BUFFER_BIT_BACK_LEFT
)
464 mask
|= BUFFER_BIT_FRONT_LEFT
;
469 assert(intel
->numClipRects
== 1);
470 assert(intel
->pClipRects
== &intel
->fboRect
);
473 clear
.x2
= clear
.x1
+ cw
;
474 clear
.y2
= clear
.y1
+ ch
;
475 /* no change to mask */
478 for (i
= 0; i
< intel
->numClipRects
; i
++) {
479 const drm_clip_rect_t
*box
= &intel
->pClipRects
[i
];
482 GLuint clearMask
= mask
; /* use copy, since we modify it below */
483 GLboolean all
= (cw
== ctx
->DrawBuffer
->Width
&&
484 ch
== ctx
->DrawBuffer
->Height
);
487 intel_intersect_cliprects(&b
, &clear
, box
);
494 _mesa_printf("clear %d,%d..%d,%d, mask %x\n",
495 b
.x1
, b
.y1
, b
.x2
, b
.y2
, mask
);
497 /* Loop over all renderbuffers */
498 for (buf
= 0; buf
< BUFFER_COUNT
&& clearMask
; buf
++) {
499 const GLbitfield bufBit
= 1 << buf
;
500 if ((clearMask
& bufBit
) && !(bufBit
& skipBuffers
)) {
501 /* OK, clear this renderbuffer */
502 const struct intel_renderbuffer
*irb
503 = intel_renderbuffer(ctx
->DrawBuffer
->
504 Attachment
[buf
].Renderbuffer
);
505 struct _DriBufferObject
*write_buffer
=
506 intel_region_buffer(intel
->intelScreen
, irb
->region
,
507 all
? INTEL_WRITE_FULL
:
517 pitch
= irb
->region
->pitch
;
518 cpp
= irb
->region
->cpp
;
520 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
522 irb
->region
->buffer
, (pitch
* cpp
),
523 irb
->region
->draw_offset
,
524 b
.x1
, b
.y1
, b
.x2
- b
.x1
, b
.y2
- b
.y1
);
527 /* Setup the blit command */
529 BR13
= (0xF0 << 16) | (pitch
* cpp
) | (1 << 24) | (1 << 25);
530 if (buf
== BUFFER_DEPTH
|| buf
== BUFFER_STENCIL
) {
531 CMD
= XY_COLOR_BLT_CMD
;
532 if (clearMask
& BUFFER_BIT_DEPTH
)
533 CMD
|= XY_COLOR_BLT_WRITE_RGB
;
534 if (clearMask
& BUFFER_BIT_STENCIL
)
535 CMD
|= XY_COLOR_BLT_WRITE_ALPHA
;
539 CMD
= (XY_COLOR_BLT_CMD
|
540 XY_COLOR_BLT_WRITE_ALPHA
|
541 XY_COLOR_BLT_WRITE_RGB
);
545 ASSERT(cpp
== 2 || cpp
== 0);
546 BR13
= (0xF0 << 16) | (pitch
* cpp
) | (1 << 24);
547 CMD
= XY_COLOR_BLT_CMD
;
550 if (buf
== BUFFER_DEPTH
|| buf
== BUFFER_STENCIL
) {
551 clearVal
= clear_depth
;
554 clearVal
= (cpp
== 4)
555 ? intel
->ClearColor8888
: intel
->ClearColor565
;
558 _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
559 buf, irb->Base.Name);
561 BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS
);
564 OUT_BATCH((b
.y1
<< 16) | b
.x1
);
565 OUT_BATCH((b
.y2
<< 16) | b
.x2
);
566 OUT_RELOC(write_buffer
, DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_WRITE
,
567 DRM_BO_MASK_MEM
| DRM_BO_FLAG_WRITE
,
568 irb
->region
->draw_offset
);
571 clearMask
&= ~bufBit
; /* turn off bit, for faster loop exit */
575 intel_batchbuffer_flush(intel
->batch
);
578 UNLOCK_HARDWARE(intel
);