check for null DrawBuffer values
[mesa.git] / src / mesa / drivers / dri / i915 / intel_pixel.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 "glheader.h"
29 #include "enums.h"
30 #include "mtypes.h"
31 #include "macros.h"
32 #include "swrast/swrast.h"
33
34 #include "intel_screen.h"
35 #include "intel_context.h"
36 #include "intel_ioctl.h"
37 #include "intel_batchbuffer.h"
38
39
40
41 static GLboolean
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 )
45 {
46 intelContextPtr intel = INTEL_CONTEXT(ctx);
47 GLuint cpp = intel->intelScreen->cpp;
48
49 if (INTEL_DEBUG & DEBUG_PIXEL)
50 fprintf(stderr, "%s\n", __FUNCTION__);
51
52 if ( (pitch & 63) ||
53 ctx->_ImageTransferState ||
54 packing->SwapBytes ||
55 packing->LsbFirst) {
56 if (INTEL_DEBUG & DEBUG_PIXEL)
57 fprintf(stderr, "%s: failed 1\n", __FUNCTION__);
58 return GL_FALSE;
59 }
60
61 if ( type == GL_UNSIGNED_INT_8_8_8_8_REV &&
62 cpp == 4 &&
63 format == GL_BGRA ) {
64 if (INTEL_DEBUG & DEBUG_PIXEL)
65 fprintf(stderr, "%s: passed 2\n", __FUNCTION__);
66 return GL_TRUE;
67 }
68
69 if (INTEL_DEBUG & DEBUG_PIXEL)
70 fprintf(stderr, "%s: failed\n", __FUNCTION__);
71
72 return GL_FALSE;
73 }
74
75 static GLboolean
76 check_color_per_fragment_ops( const GLcontext *ctx )
77 {
78 int result;
79 result = (!( ctx->Color.AlphaEnabled ||
80 ctx->Depth.Test ||
81 ctx->Fog.Enabled ||
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 ||
90 ctx->Depth.OcclusionTest
91 ) &&
92 ctx->Current.RasterPosValid);
93
94 return result;
95 }
96
97
98
99 static GLboolean
100 clip_pixelrect( const GLcontext *ctx,
101 const GLframebuffer *buffer,
102 GLint *x, GLint *y,
103 GLsizei *width, GLsizei *height,
104 GLint *size )
105 {
106 intelContextPtr intel = INTEL_CONTEXT(ctx);
107
108 /* left clipping */
109 if (*x < buffer->_Xmin) {
110 *width -= (buffer->_Xmin - *x);
111 *x = buffer->_Xmin;
112 }
113
114 /* right clipping */
115 if (*x + *width > buffer->_Xmax)
116 *width -= (*x + *width - buffer->_Xmax - 1);
117
118 if (*width <= 0)
119 return GL_FALSE;
120
121 /* bottom clipping */
122 if (*y < buffer->_Ymin) {
123 *height -= (buffer->_Ymin - *y);
124 *y = buffer->_Ymin;
125 }
126
127 /* top clipping */
128 if (*y + *height > buffer->_Ymax)
129 *height -= (*y + *height - buffer->_Ymax - 1);
130
131 if (*height <= 0)
132 return GL_FALSE;
133
134 *size = ((*y + *height - 1) * intel->intelScreen->frontPitch +
135 (*x + *width - 1) * intel->intelScreen->cpp);
136
137 return GL_TRUE;
138 }
139
140 static GLboolean
141 intelTryReadPixels( GLcontext *ctx,
142 GLint x, GLint y, GLsizei width, GLsizei height,
143 GLenum format, GLenum type,
144 const struct gl_pixelstore_attrib *pack,
145 GLvoid *pixels )
146 {
147 intelContextPtr intel = INTEL_CONTEXT(ctx);
148 GLint size = 0;
149 GLint pitch = pack->RowLength ? pack->RowLength : width;
150
151 if (INTEL_DEBUG & DEBUG_PIXEL)
152 fprintf(stderr, "%s\n", __FUNCTION__);
153
154 /* Only accelerate reading to agp buffers.
155 */
156 if ( !intelIsAgpMemory(intel, pixels,
157 pitch * height * intel->intelScreen->cpp ) ) {
158 if (INTEL_DEBUG & DEBUG_PIXEL)
159 fprintf(stderr, "%s: dest not agp\n", __FUNCTION__);
160 return GL_FALSE;
161 }
162
163 /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from
164 * blitter:
165 */
166 if (!pack->Invert) {
167 if (INTEL_DEBUG & DEBUG_PIXEL)
168 fprintf(stderr, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__);
169 return GL_FALSE;
170 }
171
172 if (!check_color(ctx, type, format, pack, pixels, size, pitch))
173 return GL_FALSE;
174
175 switch ( intel->intelScreen->cpp ) {
176 case 4:
177 break;
178 default:
179 return GL_FALSE;
180 }
181
182
183 /* Although the blits go on the command buffer, need to do this and
184 * fire with lock held to guarentee cliprects and drawOffset are
185 * correct.
186 *
187 * This is an unusual situation however, as the code which flushes
188 * a full command buffer expects to be called unlocked. As a
189 * workaround, immediately flush the buffer on aquiring the lock.
190 */
191 intelFlush( &intel->ctx );
192 LOCK_HARDWARE( intel );
193 {
194 __DRIdrawablePrivate *dPriv = intel->driDrawable;
195 int nbox = dPriv->numClipRects;
196 int src_offset = intel->drawOffset;
197 int src_pitch = intel->intelScreen->frontPitch;
198 int dst_offset = intelAgpOffsetFromVirtual( intel, pixels);
199 drm_clip_rect_t *box = dPriv->pClipRects;
200 int i;
201
202 if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height,
203 &size)) {
204 UNLOCK_HARDWARE( intel );
205 if (INTEL_DEBUG & DEBUG_PIXEL)
206 fprintf(stderr, "%s totally clipped -- nothing to do\n",
207 __FUNCTION__);
208 return GL_TRUE;
209 }
210
211
212 y = dPriv->h - y - height;
213 x += dPriv->x;
214 y += dPriv->y;
215
216
217 if (INTEL_DEBUG & DEBUG_PIXEL)
218 fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n",
219 src_pitch, pitch);
220
221 for (i = 0 ; i < nbox ; i++)
222 {
223 GLint bx = box[i].x1;
224 GLint by = box[i].y1;
225 GLint bw = box[i].x2 - bx;
226 GLint bh = box[i].y2 - by;
227
228 if (bx < x) bw -= x - bx, bx = x;
229 if (by < y) bh -= y - by, by = y;
230 if (bx + bw > x + width) bw = x + width - bx;
231 if (by + bh > y + height) bh = y + height - by;
232 if (bw <= 0) continue;
233 if (bh <= 0) continue;
234
235 intelEmitCopyBlitLocked( intel,
236 intel->intelScreen->cpp,
237 src_pitch, src_offset,
238 pitch, dst_offset,
239 bx, by,
240 bx - x, by - y,
241 bw, bh );
242 }
243 }
244 UNLOCK_HARDWARE( intel );
245 intelFinish( &intel->ctx );
246
247 return GL_TRUE;
248 }
249
250 static void
251 intelReadPixels( GLcontext *ctx,
252 GLint x, GLint y, GLsizei width, GLsizei height,
253 GLenum format, GLenum type,
254 const struct gl_pixelstore_attrib *pack,
255 GLvoid *pixels )
256 {
257 if (INTEL_DEBUG & DEBUG_PIXEL)
258 fprintf(stderr, "%s\n", __FUNCTION__);
259
260 if (!intelTryReadPixels( ctx, x, y, width, height, format, type, pack,
261 pixels))
262 _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack,
263 pixels);
264 }
265
266
267
268
269 static void do_draw_pix( GLcontext *ctx,
270 GLint x, GLint y, GLsizei width, GLsizei height,
271 GLint pitch,
272 const void *pixels,
273 GLuint dest )
274 {
275 intelContextPtr intel = INTEL_CONTEXT(ctx);
276 __DRIdrawablePrivate *dPriv = intel->driDrawable;
277 drm_clip_rect_t *box = dPriv->pClipRects;
278 int nbox = dPriv->numClipRects;
279 int i;
280 int size;
281 int src_offset = intelAgpOffsetFromVirtual( intel, pixels);
282 int src_pitch = pitch;
283
284 if (INTEL_DEBUG & DEBUG_PIXEL)
285 fprintf(stderr, "%s\n", __FUNCTION__);
286
287 intelFlush( &intel->ctx );
288 LOCK_HARDWARE( intel );
289 if (ctx->DrawBuffer)
290 {
291 y -= height; /* cope with pixel zoom */
292
293 if (!clip_pixelrect(ctx, ctx->DrawBuffer,
294 &x, &y, &width, &height,
295 &size)) {
296 UNLOCK_HARDWARE( intel );
297 return;
298 }
299
300 y = dPriv->h - y - height; /* convert from gl to hardware coords */
301 x += dPriv->x;
302 y += dPriv->y;
303
304
305 for (i = 0 ; i < nbox ; i++ )
306 {
307 GLint bx = box[i].x1;
308 GLint by = box[i].y1;
309 GLint bw = box[i].x2 - bx;
310 GLint bh = box[i].y2 - by;
311
312 if (bx < x) bw -= x - bx, bx = x;
313 if (by < y) bh -= y - by, by = y;
314 if (bx + bw > x + width) bw = x + width - bx;
315 if (by + bh > y + height) bh = y + height - by;
316 if (bw <= 0) continue;
317 if (bh <= 0) continue;
318
319 intelEmitCopyBlitLocked( intel,
320 intel->intelScreen->cpp,
321 src_pitch, src_offset,
322 intel->intelScreen->frontPitch,
323 intel->drawOffset,
324 bx - x, by - y,
325 bx, by,
326 bw, bh );
327 }
328 }
329 UNLOCK_HARDWARE( intel );
330 intelFinish( &intel->ctx );
331 }
332
333
334
335
336 static GLboolean
337 intelTryDrawPixels( GLcontext *ctx,
338 GLint x, GLint y, GLsizei width, GLsizei height,
339 GLenum format, GLenum type,
340 const struct gl_pixelstore_attrib *unpack,
341 const GLvoid *pixels )
342 {
343 intelContextPtr intel = INTEL_CONTEXT(ctx);
344 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
345 GLuint dest;
346 GLuint cpp = intel->intelScreen->cpp;
347 GLint size = width * pitch * cpp;
348
349 if (INTEL_DEBUG & DEBUG_PIXEL)
350 fprintf(stderr, "%s\n", __FUNCTION__);
351
352 switch (format) {
353 case GL_RGB:
354 case GL_RGBA:
355 case GL_BGRA:
356 dest = intel->drawOffset;
357
358 /* Planemask doesn't have full support in blits.
359 */
360 if (!ctx->Color.ColorMask[RCOMP] ||
361 !ctx->Color.ColorMask[GCOMP] ||
362 !ctx->Color.ColorMask[BCOMP] ||
363 !ctx->Color.ColorMask[ACOMP]) {
364 if (INTEL_DEBUG & DEBUG_PIXEL)
365 fprintf(stderr, "%s: planemask\n", __FUNCTION__);
366 return GL_FALSE;
367 }
368
369 /* Can't do conversions on agp reads/draws.
370 */
371 if ( !intelIsAgpMemory( intel, pixels, size ) ) {
372 if (INTEL_DEBUG & DEBUG_PIXEL)
373 fprintf(stderr, "%s: not agp memory\n", __FUNCTION__);
374 return GL_FALSE;
375 }
376
377 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
378 return GL_FALSE;
379 }
380 if (!check_color_per_fragment_ops(ctx)) {
381 return GL_FALSE;
382 }
383
384 if (ctx->Pixel.ZoomX != 1.0F ||
385 ctx->Pixel.ZoomY != -1.0F)
386 return GL_FALSE;
387 break;
388
389 default:
390 return GL_FALSE;
391 }
392
393 if ( intelIsAgpMemory(intel, pixels, size) )
394 {
395 do_draw_pix( ctx, x, y, width, height, pitch, pixels,
396 dest );
397 return GL_TRUE;
398 }
399 else if (0)
400 {
401 /* Pixels is in regular memory -- get dma buffers and perform
402 * upload through them. No point doing this for regular uploads
403 * but once we remove some of the restrictions above (colormask,
404 * pixelformat conversion, zoom?, etc), this could be a win.
405 */
406 }
407 else
408 return GL_FALSE;
409 }
410
411 static void
412 intelDrawPixels( GLcontext *ctx,
413 GLint x, GLint y, GLsizei width, GLsizei height,
414 GLenum format, GLenum type,
415 const struct gl_pixelstore_attrib *unpack,
416 const GLvoid *pixels )
417 {
418 if (INTEL_DEBUG & DEBUG_PIXEL)
419 fprintf(stderr, "%s\n", __FUNCTION__);
420
421 if (!intelTryDrawPixels( ctx, x, y, width, height, format, type,
422 unpack, pixels ))
423 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
424 unpack, pixels );
425 }
426
427
428
429
430 /**
431 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap)
432 * for the color buffer. Don't support zooming, pixel transfer, etc.
433 * We do support copying from one window to another, ala glXMakeCurrentRead.
434 */
435 static void
436 intelCopyPixels( GLcontext *ctx,
437 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
438 GLint destx, GLint desty, GLenum type )
439 {
440 #if 0
441 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
442 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
443 XMesaDisplay *dpy = xmesa->xm_visual->display;
444 const XMesaDrawable drawBuffer = xmesa->xm_draw_buffer->buffer;
445 const XMesaDrawable readBuffer = xmesa->xm_read_buffer->buffer;
446 const XMesaGC gc = xmesa->xm_draw_buffer->gc;
447
448 ASSERT(dpy);
449 ASSERT(gc);
450
451 if (drawBuffer && /* buffer != 0 means it's a Window or Pixmap */
452 readBuffer &&
453 type == GL_COLOR &&
454 (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */
455 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */
456 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
457 ctx->Pixel.ZoomY == 1.0) {
458 /* Note: we don't do any special clipping work here. We could,
459 * but X will do it for us.
460 */
461 srcy = FLIP(xmesa->xm_read_buffer, srcy) - height + 1;
462 desty = FLIP(xmesa->xm_draw_buffer, desty) - height + 1;
463 XCopyArea(dpy, readBuffer, drawBuffer, gc,
464 srcx, srcy, width, height, destx, desty);
465 }
466 #else
467 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type );
468 #endif
469 }
470
471
472
473
474 void intelInitPixelFuncs( struct dd_function_table *functions )
475 {
476 /* Pixel path fallbacks.
477 */
478 functions->Accum = _swrast_Accum;
479 functions->Bitmap = _swrast_Bitmap;
480 functions->CopyPixels = intelCopyPixels;
481
482 if (!getenv("INTEL_NO_BLITS")) {
483 functions->ReadPixels = intelReadPixels;
484 functions->DrawPixels = intelDrawPixels;
485 }
486 else {
487 functions->ReadPixels = _swrast_ReadPixels;
488 functions->DrawPixels = _swrast_DrawPixels;
489 }
490 }