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 **************************************************************************/
32 #include "swrast/swrast.h"
34 #include "intel_screen.h"
35 #include "intel_context.h"
36 #include "intel_ioctl.h"
37 #include "intel_batchbuffer.h"
42 check_color( const GLcontext
*ctx
, GLenum type
, GLenum format
,
43 const struct gl_pixelstore_attrib
*packing
,
44 const void *pixels
, GLint sz
, GLint pitch
)
46 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
47 GLuint cpp
= intel
->intelScreen
->cpp
;
49 if (INTEL_DEBUG
& DEBUG_PIXEL
)
50 fprintf(stderr
, "%s\n", __FUNCTION__
);
53 ctx
->_ImageTransferState
||
56 if (INTEL_DEBUG
& DEBUG_PIXEL
)
57 fprintf(stderr
, "%s: failed 1\n", __FUNCTION__
);
61 if ( type
== GL_UNSIGNED_INT_8_8_8_8_REV
&&
64 if (INTEL_DEBUG
& DEBUG_PIXEL
)
65 fprintf(stderr
, "%s: passed 2\n", __FUNCTION__
);
69 if (INTEL_DEBUG
& DEBUG_PIXEL
)
70 fprintf(stderr
, "%s: failed\n", __FUNCTION__
);
76 check_color_per_fragment_ops( const GLcontext
*ctx
)
79 result
= (!( ctx
->Color
.AlphaEnabled
||
82 ctx
->Scissor
.Enabled
||
83 ctx
->Stencil
.Enabled
||
84 !ctx
->Color
.ColorMask
[0] ||
85 !ctx
->Color
.ColorMask
[1] ||
86 !ctx
->Color
.ColorMask
[2] ||
87 !ctx
->Color
.ColorMask
[3] ||
88 ctx
->Color
.ColorLogicOpEnabled
||
89 ctx
->Texture
._EnabledUnits
91 ctx
->Current
.RasterPosValid
);
98 * Clip the given rectangle against the buffer's bounds (including scissor).
99 * \param size returns the
100 * \return GL_TRUE if any pixels remain, GL_FALSE if totally clipped.
102 * XXX Replace this with _mesa_clip_drawpixels() and _mesa_clip_readpixels()
103 * from Mesa 6.4. We shouldn't apply scissor for ReadPixels.
106 clip_pixelrect( const GLcontext
*ctx
,
107 const GLframebuffer
*buffer
,
109 GLsizei
*width
, GLsizei
*height
)
112 if (*x
< buffer
->_Xmin
) {
113 *width
-= (buffer
->_Xmin
- *x
);
118 if (*x
+ *width
> buffer
->_Xmax
)
119 *width
-= (*x
+ *width
- buffer
->_Xmax
- 1);
124 /* bottom clipping */
125 if (*y
< buffer
->_Ymin
) {
126 *height
-= (buffer
->_Ymin
- *y
);
131 if (*y
+ *height
> buffer
->_Ymax
)
132 *height
-= (*y
+ *height
- buffer
->_Ymax
- 1);
142 * Compute intersection of a clipping rectangle and pixel rectangle,
143 * returning results in x/y/w/hOut vars.
144 * \return GL_TRUE if there's intersection, GL_FALSE if disjoint.
146 static INLINE GLboolean
147 intersect_region(const drm_clip_rect_t
*box
,
148 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
149 GLint
*xOut
, GLint
*yOut
, GLint
*wOut
, GLint
*hOut
)
153 GLint bw
= box
->x2
- bx
;
154 GLint bh
= box
->y2
- by
;
156 if (bx
< x
) bw
-= x
- bx
, bx
= x
;
157 if (by
< y
) bh
-= y
- by
, by
= y
;
158 if (bx
+ bw
> x
+ width
) bw
= x
+ width
- bx
;
159 if (by
+ bh
> y
+ height
) bh
= y
+ height
- by
;
160 if (bw
<= 0) return GL_FALSE
;
161 if (bh
<= 0) return GL_FALSE
;
173 intelTryReadPixels( GLcontext
*ctx
,
174 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
175 GLenum format
, GLenum type
,
176 const struct gl_pixelstore_attrib
*pack
,
179 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
180 GLint size
= 0; /* not really used */
181 GLint pitch
= pack
->RowLength
? pack
->RowLength
: width
;
183 if (INTEL_DEBUG
& DEBUG_PIXEL
)
184 fprintf(stderr
, "%s\n", __FUNCTION__
);
186 /* Only accelerate reading to agp buffers.
188 if ( !intelIsAgpMemory(intel
, pixels
,
189 pitch
* height
* intel
->intelScreen
->cpp
) ) {
190 if (INTEL_DEBUG
& DEBUG_PIXEL
)
191 fprintf(stderr
, "%s: dest not agp\n", __FUNCTION__
);
195 /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from
199 if (INTEL_DEBUG
& DEBUG_PIXEL
)
200 fprintf(stderr
, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__
);
204 if (!check_color(ctx
, type
, format
, pack
, pixels
, size
, pitch
))
207 switch ( intel
->intelScreen
->cpp
) {
215 /* Although the blits go on the command buffer, need to do this and
216 * fire with lock held to guarentee cliprects and drawing offset are
219 * This is an unusual situation however, as the code which flushes
220 * a full command buffer expects to be called unlocked. As a
221 * workaround, immediately flush the buffer on aquiring the lock.
223 intelFlush( &intel
->ctx
);
224 LOCK_HARDWARE( intel
);
226 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
227 int nbox
= dPriv
->numClipRects
;
228 int src_offset
= intel
->readRegion
->offset
;
229 int src_pitch
= intel
->intelScreen
->front
.pitch
;
230 int dst_offset
= intelAgpOffsetFromVirtual( intel
, pixels
);
231 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
234 assert(dst_offset
!= ~0); /* should have been caught above */
236 if (!clip_pixelrect(ctx
, ctx
->ReadBuffer
, &x
, &y
, &width
, &height
)) {
237 UNLOCK_HARDWARE( intel
);
238 if (INTEL_DEBUG
& DEBUG_PIXEL
)
239 fprintf(stderr
, "%s totally clipped -- nothing to do\n",
244 /* convert to screen coords (y=0=top) */
245 y
= dPriv
->h
- y
- height
;
249 if (INTEL_DEBUG
& DEBUG_PIXEL
)
250 fprintf(stderr
, "readpixel blit src_pitch %d dst_pitch %d\n",
253 /* We don't really have to do window clipping for readpixels.
254 * The OpenGL spec says that pixels read from outside the
255 * visible window region (pixel ownership) have undefined value.
257 for (i
= 0 ; i
< nbox
; i
++)
259 GLint bx
, by
, bw
, bh
;
260 if (intersect_region(box
+i
, x
, y
, width
, height
,
261 &bx
, &by
, &bw
, &bh
)) {
262 intelEmitCopyBlitLocked( intel
,
263 intel
->intelScreen
->cpp
,
264 src_pitch
, src_offset
,
272 UNLOCK_HARDWARE( intel
);
273 intelFinish( &intel
->ctx
);
279 intelReadPixels( GLcontext
*ctx
,
280 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
281 GLenum format
, GLenum type
,
282 const struct gl_pixelstore_attrib
*pack
,
285 if (INTEL_DEBUG
& DEBUG_PIXEL
)
286 fprintf(stderr
, "%s\n", __FUNCTION__
);
288 if (!intelTryReadPixels( ctx
, x
, y
, width
, height
, format
, type
, pack
,
290 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, pack
,
297 static void do_draw_pix( GLcontext
*ctx
,
298 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
303 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
304 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
305 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
306 int nbox
= dPriv
->numClipRects
;
308 int src_offset
= intelAgpOffsetFromVirtual( intel
, pixels
);
309 int src_pitch
= pitch
;
311 assert(src_offset
!= ~0); /* should be caught earlier */
313 if (INTEL_DEBUG
& DEBUG_PIXEL
)
314 fprintf(stderr
, "%s\n", __FUNCTION__
);
316 intelFlush( &intel
->ctx
);
317 LOCK_HARDWARE( intel
);
320 y
-= height
; /* cope with pixel zoom */
322 if (!clip_pixelrect(ctx
, ctx
->DrawBuffer
,
323 &x
, &y
, &width
, &height
)) {
324 UNLOCK_HARDWARE( intel
);
328 y
= dPriv
->h
- y
- height
; /* convert from gl to hardware coords */
332 for (i
= 0 ; i
< nbox
; i
++ )
334 GLint bx
, by
, bw
, bh
;
335 if (intersect_region(box
+ i
, x
, y
, width
, height
,
336 &bx
, &by
, &bw
, &bh
)) {
337 intelEmitCopyBlitLocked( intel
,
338 intel
->intelScreen
->cpp
,
339 src_pitch
, src_offset
,
340 intel
->intelScreen
->front
.pitch
,
341 intel
->drawRegion
->offset
,
348 UNLOCK_HARDWARE( intel
);
349 intelFinish( &intel
->ctx
);
355 intelTryDrawPixels( GLcontext
*ctx
,
356 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
357 GLenum format
, GLenum type
,
358 const struct gl_pixelstore_attrib
*unpack
,
359 const GLvoid
*pixels
)
361 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
362 GLint pitch
= unpack
->RowLength
? unpack
->RowLength
: width
;
364 GLuint cpp
= intel
->intelScreen
->cpp
;
365 GLint size
= width
* pitch
* cpp
;
367 if (INTEL_DEBUG
& DEBUG_PIXEL
)
368 fprintf(stderr
, "%s\n", __FUNCTION__
);
374 dest
= intel
->drawRegion
->offset
;
376 /* Planemask doesn't have full support in blits.
378 if (!ctx
->Color
.ColorMask
[RCOMP
] ||
379 !ctx
->Color
.ColorMask
[GCOMP
] ||
380 !ctx
->Color
.ColorMask
[BCOMP
] ||
381 !ctx
->Color
.ColorMask
[ACOMP
]) {
382 if (INTEL_DEBUG
& DEBUG_PIXEL
)
383 fprintf(stderr
, "%s: planemask\n", __FUNCTION__
);
387 /* Can't do conversions on agp reads/draws.
389 if ( !intelIsAgpMemory( intel
, pixels
, size
) ) {
390 if (INTEL_DEBUG
& DEBUG_PIXEL
)
391 fprintf(stderr
, "%s: not agp memory\n", __FUNCTION__
);
395 if (!check_color(ctx
, type
, format
, unpack
, pixels
, size
, pitch
)) {
398 if (!check_color_per_fragment_ops(ctx
)) {
402 if (ctx
->Pixel
.ZoomX
!= 1.0F
||
403 ctx
->Pixel
.ZoomY
!= -1.0F
)
411 if ( intelIsAgpMemory(intel
, pixels
, size
) )
413 do_draw_pix( ctx
, x
, y
, width
, height
, pitch
, pixels
, dest
);
418 /* Pixels is in regular memory -- get dma buffers and perform
419 * upload through them. No point doing this for regular uploads
420 * but once we remove some of the restrictions above (colormask,
421 * pixelformat conversion, zoom?, etc), this could be a win.
429 intelDrawPixels( GLcontext
*ctx
,
430 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
431 GLenum format
, GLenum type
,
432 const struct gl_pixelstore_attrib
*unpack
,
433 const GLvoid
*pixels
)
435 if (INTEL_DEBUG
& DEBUG_PIXEL
)
436 fprintf(stderr
, "%s\n", __FUNCTION__
);
438 if (!intelTryDrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
440 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
448 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap)
449 * for the color buffer. Don't support zooming, pixel transfer, etc.
450 * We do support copying from one window to another, ala glXMakeCurrentRead.
453 intelCopyPixels( GLcontext
*ctx
,
454 GLint srcx
, GLint srcy
, GLsizei width
, GLsizei height
,
455 GLint destx
, GLint desty
, GLenum type
)
458 const XMesaContext xmesa
= XMESA_CONTEXT(ctx
);
459 const SWcontext
*swrast
= SWRAST_CONTEXT( ctx
);
460 XMesaDisplay
*dpy
= xmesa
->xm_visual
->display
;
461 const XMesaDrawable drawBuffer
= xmesa
->xm_draw_buffer
->buffer
;
462 const XMesaDrawable readBuffer
= xmesa
->xm_read_buffer
->buffer
;
463 const XMesaGC gc
= xmesa
->xm_draw_buffer
->gc
;
468 if (drawBuffer
&& /* buffer != 0 means it's a Window or Pixmap */
471 (swrast
->_RasterMask
& ~CLIP_BIT
) == 0 && /* no blend, z-test, etc */
472 ctx
->_ImageTransferState
== 0 && /* no color tables, scale/bias, etc */
473 ctx
->Pixel
.ZoomX
== 1.0 && /* no zooming */
474 ctx
->Pixel
.ZoomY
== 1.0) {
475 /* Note: we don't do any special clipping work here. We could,
476 * but X will do it for us.
478 srcy
= FLIP(xmesa
->xm_read_buffer
, srcy
) - height
+ 1;
479 desty
= FLIP(xmesa
->xm_draw_buffer
, desty
) - height
+ 1;
480 XCopyArea(dpy
, readBuffer
, drawBuffer
, gc
,
481 srcx
, srcy
, width
, height
, destx
, desty
);
484 _swrast_CopyPixels(ctx
, srcx
, srcy
, width
, height
, destx
, desty
, type
);
491 void intelInitPixelFuncs( struct dd_function_table
*functions
)
493 /* Pixel path fallbacks.
495 functions
->Accum
= _swrast_Accum
;
496 functions
->Bitmap
= _swrast_Bitmap
;
497 functions
->CopyPixels
= intelCopyPixels
;
499 if (!getenv("INTEL_NO_BLITS")) {
500 functions
->ReadPixels
= intelReadPixels
;
501 functions
->DrawPixels
= intelDrawPixels
;
504 functions
->ReadPixels
= _swrast_ReadPixels
;
505 functions
->DrawPixels
= _swrast_DrawPixels
;