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