bumpmap sample is correct now
[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 ) &&
91 ctx->Current.RasterPosValid);
92
93 return result;
94 }
95
96
97 /**
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.
101 *
102 * XXX Replace this with _mesa_clip_drawpixels() and _mesa_clip_readpixels()
103 * from Mesa 6.4. We shouldn't apply scissor for ReadPixels.
104 */
105 static GLboolean
106 clip_pixelrect( const GLcontext *ctx,
107 const GLframebuffer *buffer,
108 GLint *x, GLint *y,
109 GLsizei *width, GLsizei *height)
110 {
111 /* left clipping */
112 if (*x < buffer->_Xmin) {
113 *width -= (buffer->_Xmin - *x);
114 *x = buffer->_Xmin;
115 }
116
117 /* right clipping */
118 if (*x + *width > buffer->_Xmax)
119 *width -= (*x + *width - buffer->_Xmax - 1);
120
121 if (*width <= 0)
122 return GL_FALSE;
123
124 /* bottom clipping */
125 if (*y < buffer->_Ymin) {
126 *height -= (buffer->_Ymin - *y);
127 *y = buffer->_Ymin;
128 }
129
130 /* top clipping */
131 if (*y + *height > buffer->_Ymax)
132 *height -= (*y + *height - buffer->_Ymax - 1);
133
134 if (*height <= 0)
135 return GL_FALSE;
136
137 return GL_TRUE;
138 }
139
140
141 /**
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.
145 */
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)
150 {
151 GLint bx = box->x1;
152 GLint by = box->y1;
153 GLint bw = box->x2 - bx;
154 GLint bh = box->y2 - by;
155
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
161 *xOut = bx;
162 *yOut = by;
163 *wOut = bw;
164 *hOut = bh;
165
166 if (bw <= 0) return GL_FALSE;
167 if (bh <= 0) return GL_FALSE;
168
169 return GL_TRUE;
170 }
171
172
173
174 static GLboolean
175 intelTryReadPixels( GLcontext *ctx,
176 GLint x, GLint y, GLsizei width, GLsizei height,
177 GLenum format, GLenum type,
178 const struct gl_pixelstore_attrib *pack,
179 GLvoid *pixels )
180 {
181 intelContextPtr intel = INTEL_CONTEXT(ctx);
182 GLint size = 0; /* not really used */
183 GLint pitch = pack->RowLength ? pack->RowLength : width;
184
185 if (INTEL_DEBUG & DEBUG_PIXEL)
186 fprintf(stderr, "%s\n", __FUNCTION__);
187
188 /* Only accelerate reading to agp buffers.
189 */
190 if ( !intelIsAgpMemory(intel, pixels,
191 pitch * height * intel->intelScreen->cpp ) ) {
192 if (INTEL_DEBUG & DEBUG_PIXEL)
193 fprintf(stderr, "%s: dest not agp\n", __FUNCTION__);
194 return GL_FALSE;
195 }
196
197 /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from
198 * blitter:
199 */
200 if (!pack->Invert) {
201 if (INTEL_DEBUG & DEBUG_PIXEL)
202 fprintf(stderr, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__);
203 return GL_FALSE;
204 }
205
206 if (!check_color(ctx, type, format, pack, pixels, size, pitch))
207 return GL_FALSE;
208
209 switch ( intel->intelScreen->cpp ) {
210 case 4:
211 break;
212 default:
213 return GL_FALSE;
214 }
215
216
217 /* Although the blits go on the command buffer, need to do this and
218 * fire with lock held to guarentee cliprects and drawing offset are
219 * correct.
220 *
221 * This is an unusual situation however, as the code which flushes
222 * a full command buffer expects to be called unlocked. As a
223 * workaround, immediately flush the buffer on aquiring the lock.
224 */
225 intelFlush( &intel->ctx );
226 LOCK_HARDWARE( intel );
227 {
228 __DRIdrawablePrivate *dPriv = intel->driDrawable;
229 int nbox = dPriv->numClipRects;
230 int src_offset = intel->readRegion->offset;
231 int src_pitch = intel->intelScreen->front.pitch;
232 int dst_offset = intelAgpOffsetFromVirtual( intel, pixels);
233 drm_clip_rect_t *box = dPriv->pClipRects;
234 int i;
235
236 assert(dst_offset != ~0); /* should have been caught above */
237
238 if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height)) {
239 UNLOCK_HARDWARE( intel );
240 if (INTEL_DEBUG & DEBUG_PIXEL)
241 fprintf(stderr, "%s totally clipped -- nothing to do\n",
242 __FUNCTION__);
243 return GL_TRUE;
244 }
245
246 /* convert to screen coords (y=0=top) */
247 y = dPriv->h - y - height;
248 x += dPriv->x;
249 y += dPriv->y;
250
251 if (INTEL_DEBUG & DEBUG_PIXEL)
252 fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n",
253 src_pitch, pitch);
254
255 /* We don't really have to do window clipping for readpixels.
256 * The OpenGL spec says that pixels read from outside the
257 * visible window region (pixel ownership) have undefined value.
258 */
259 for (i = 0 ; i < nbox ; i++)
260 {
261 GLint bx, by, bw, bh;
262 if (intersect_region(box+i, x, y, width, height,
263 &bx, &by, &bw, &bh)) {
264 intelEmitCopyBlitLocked( intel,
265 intel->intelScreen->cpp,
266 src_pitch, src_offset,
267 pitch, dst_offset,
268 bx, by,
269 bx - x, by - y,
270 bw, bh );
271 }
272 }
273 }
274 UNLOCK_HARDWARE( intel );
275 intelFinish( &intel->ctx );
276
277 return GL_TRUE;
278 }
279
280 static void
281 intelReadPixels( GLcontext *ctx,
282 GLint x, GLint y, GLsizei width, GLsizei height,
283 GLenum format, GLenum type,
284 const struct gl_pixelstore_attrib *pack,
285 GLvoid *pixels )
286 {
287 if (INTEL_DEBUG & DEBUG_PIXEL)
288 fprintf(stderr, "%s\n", __FUNCTION__);
289
290 if (!intelTryReadPixels( ctx, x, y, width, height, format, type, pack,
291 pixels))
292 _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack,
293 pixels);
294 }
295
296
297
298
299 static void do_draw_pix( GLcontext *ctx,
300 GLint x, GLint y, GLsizei width, GLsizei height,
301 GLint pitch,
302 const void *pixels,
303 GLuint dest )
304 {
305 intelContextPtr intel = INTEL_CONTEXT(ctx);
306 __DRIdrawablePrivate *dPriv = intel->driDrawable;
307 drm_clip_rect_t *box = dPriv->pClipRects;
308 int nbox = dPriv->numClipRects;
309 int i;
310 int src_offset = intelAgpOffsetFromVirtual( intel, pixels);
311 int src_pitch = pitch;
312
313 assert(src_offset != ~0); /* should be caught earlier */
314
315 if (INTEL_DEBUG & DEBUG_PIXEL)
316 fprintf(stderr, "%s\n", __FUNCTION__);
317
318 intelFlush( &intel->ctx );
319 LOCK_HARDWARE( intel );
320 if (ctx->DrawBuffer)
321 {
322 y -= height; /* cope with pixel zoom */
323
324 if (!clip_pixelrect(ctx, ctx->DrawBuffer,
325 &x, &y, &width, &height)) {
326 UNLOCK_HARDWARE( intel );
327 return;
328 }
329
330 y = dPriv->h - y - height; /* convert from gl to hardware coords */
331 x += dPriv->x;
332 y += dPriv->y;
333
334 for (i = 0 ; i < nbox ; i++ )
335 {
336 GLint bx, by, bw, bh;
337 if (intersect_region(box + i, x, y, width, height,
338 &bx, &by, &bw, &bh)) {
339 intelEmitCopyBlitLocked( intel,
340 intel->intelScreen->cpp,
341 src_pitch, src_offset,
342 intel->intelScreen->front.pitch,
343 intel->drawRegion->offset,
344 bx - x, by - y,
345 bx, by,
346 bw, bh );
347 }
348 }
349 }
350 UNLOCK_HARDWARE( intel );
351 intelFinish( &intel->ctx );
352 }
353
354
355
356 static GLboolean
357 intelTryDrawPixels( GLcontext *ctx,
358 GLint x, GLint y, GLsizei width, GLsizei height,
359 GLenum format, GLenum type,
360 const struct gl_pixelstore_attrib *unpack,
361 const GLvoid *pixels )
362 {
363 intelContextPtr intel = INTEL_CONTEXT(ctx);
364 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
365 GLuint dest;
366 GLuint cpp = intel->intelScreen->cpp;
367 GLint size = width * pitch * cpp;
368
369 if (INTEL_DEBUG & DEBUG_PIXEL)
370 fprintf(stderr, "%s\n", __FUNCTION__);
371
372 switch (format) {
373 case GL_RGB:
374 case GL_RGBA:
375 case GL_BGRA:
376 dest = intel->drawRegion->offset;
377
378 /* Planemask doesn't have full support in blits.
379 */
380 if (!ctx->Color.ColorMask[RCOMP] ||
381 !ctx->Color.ColorMask[GCOMP] ||
382 !ctx->Color.ColorMask[BCOMP] ||
383 !ctx->Color.ColorMask[ACOMP]) {
384 if (INTEL_DEBUG & DEBUG_PIXEL)
385 fprintf(stderr, "%s: planemask\n", __FUNCTION__);
386 return GL_FALSE;
387 }
388
389 /* Can't do conversions on agp reads/draws.
390 */
391 if ( !intelIsAgpMemory( intel, pixels, size ) ) {
392 if (INTEL_DEBUG & DEBUG_PIXEL)
393 fprintf(stderr, "%s: not agp memory\n", __FUNCTION__);
394 return GL_FALSE;
395 }
396
397 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
398 return GL_FALSE;
399 }
400 if (!check_color_per_fragment_ops(ctx)) {
401 return GL_FALSE;
402 }
403
404 if (ctx->Pixel.ZoomX != 1.0F ||
405 ctx->Pixel.ZoomY != -1.0F)
406 return GL_FALSE;
407 break;
408
409 default:
410 return GL_FALSE;
411 }
412
413 if ( intelIsAgpMemory(intel, pixels, size) )
414 {
415 do_draw_pix( ctx, x, y, width, height, pitch, pixels, dest );
416 return GL_TRUE;
417 }
418 else if (0)
419 {
420 /* Pixels is in regular memory -- get dma buffers and perform
421 * upload through them. No point doing this for regular uploads
422 * but once we remove some of the restrictions above (colormask,
423 * pixelformat conversion, zoom?, etc), this could be a win.
424 */
425 }
426 else
427 return GL_FALSE;
428
429 return GL_FALSE;
430 }
431
432 static void
433 intelDrawPixels( GLcontext *ctx,
434 GLint x, GLint y, GLsizei width, GLsizei height,
435 GLenum format, GLenum type,
436 const struct gl_pixelstore_attrib *unpack,
437 const GLvoid *pixels )
438 {
439 if (INTEL_DEBUG & DEBUG_PIXEL)
440 fprintf(stderr, "%s\n", __FUNCTION__);
441
442 if (intelTryDrawPixels( ctx, x, y, width, height, format, type,
443 unpack, pixels ))
444 return;
445
446 if (ctx->FragmentProgram._Current == ctx->FragmentProgram._TexEnvProgram) {
447 /*
448 * We don't want the i915 texenv program to be applied to DrawPixels.
449 * This is really just a performance optimization (mesa will other-
450 * wise happily run the fragment program on each pixel in the image).
451 */
452 struct gl_fragment_program *fpSave = ctx->FragmentProgram._Current;
453 ctx->FragmentProgram._Current = NULL;
454 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
455 unpack, pixels );
456 ctx->FragmentProgram._Current = fpSave;
457 }
458 else {
459 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
460 unpack, pixels );
461 }
462 }
463
464
465
466
467 /**
468 * Implement glCopyPixels for the front color buffer (or back buffer Pixmap)
469 * for the color buffer. Don't support zooming, pixel transfer, etc.
470 * We do support copying from one window to another, ala glXMakeCurrentRead.
471 */
472 static void
473 intelCopyPixels( GLcontext *ctx,
474 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
475 GLint destx, GLint desty, GLenum type )
476 {
477 #if 0
478 const XMesaContext xmesa = XMESA_CONTEXT(ctx);
479 const SWcontext *swrast = SWRAST_CONTEXT( ctx );
480 XMesaDisplay *dpy = xmesa->xm_visual->display;
481 const XMesaDrawable drawBuffer = xmesa->xm_draw_buffer->buffer;
482 const XMesaDrawable readBuffer = xmesa->xm_read_buffer->buffer;
483 const XMesaGC gc = xmesa->xm_draw_buffer->gc;
484
485 ASSERT(dpy);
486 ASSERT(gc);
487
488 if (drawBuffer && /* buffer != 0 means it's a Window or Pixmap */
489 readBuffer &&
490 type == GL_COLOR &&
491 (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */
492 ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */
493 ctx->Pixel.ZoomX == 1.0 && /* no zooming */
494 ctx->Pixel.ZoomY == 1.0) {
495 /* Note: we don't do any special clipping work here. We could,
496 * but X will do it for us.
497 */
498 srcy = FLIP(xmesa->xm_read_buffer, srcy) - height + 1;
499 desty = FLIP(xmesa->xm_draw_buffer, desty) - height + 1;
500 XCopyArea(dpy, readBuffer, drawBuffer, gc,
501 srcx, srcy, width, height, destx, desty);
502 }
503 #else
504 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type );
505 #endif
506 }
507
508
509
510
511 void intelInitPixelFuncs( struct dd_function_table *functions )
512 {
513 functions->CopyPixels = intelCopyPixels;
514 if (!getenv("INTEL_NO_BLITS")) {
515 functions->ReadPixels = intelReadPixels;
516 functions->DrawPixels = intelDrawPixels;
517 }
518 }