fix up radeon span functions using latest r200 code from Brian,
[mesa.git] / src / mesa / drivers / dri / r200 / r200_pixel.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/r200/r200_pixel.c,v 1.2 2002/12/16 16:18:54 dawes Exp $ */
2 /*
3 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
4
5 The Weather Channel (TM) funded Tungsten Graphics to develop the
6 initial release of the Radeon 8500 driver under the XFree86 license.
7 This notice must be preserved.
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30 /*
31 * Authors:
32 * Keith Whitwell <keith@tungstengraphics.com>
33 */
34
35 #include "glheader.h"
36 #include "enums.h"
37 #include "mtypes.h"
38 #include "macros.h"
39 #include "swrast/swrast.h"
40
41 #include "r200_context.h"
42 #include "r200_ioctl.h"
43 #include "r200_pixel.h"
44 #include "r200_swtcl.h"
45
46 #include "drirenderbuffer.h"
47
48
49 static GLboolean
50 check_color( const GLcontext *ctx, GLenum type, GLenum format,
51 const struct gl_pixelstore_attrib *packing,
52 const void *pixels, GLint sz, GLint pitch )
53 {
54 r200ContextPtr rmesa = R200_CONTEXT(ctx);
55 GLuint cpp = rmesa->r200Screen->cpp;
56
57 if (R200_DEBUG & DEBUG_PIXEL)
58 fprintf(stderr, "%s\n", __FUNCTION__);
59
60 if ( (pitch & 63) ||
61 ctx->_ImageTransferState ||
62 packing->SwapBytes ||
63 packing->LsbFirst) {
64 if (R200_DEBUG & DEBUG_PIXEL)
65 fprintf(stderr, "%s: failed 1\n", __FUNCTION__);
66 return GL_FALSE;
67 }
68
69 if ( type == GL_UNSIGNED_INT_8_8_8_8_REV &&
70 cpp == 4 &&
71 format == GL_BGRA ) {
72 if (R200_DEBUG & DEBUG_PIXEL)
73 fprintf(stderr, "%s: passed 2\n", __FUNCTION__);
74 return GL_TRUE;
75 }
76
77 if (R200_DEBUG & DEBUG_PIXEL)
78 fprintf(stderr, "%s: failed\n", __FUNCTION__);
79
80 return GL_FALSE;
81 }
82
83 static GLboolean
84 check_color_per_fragment_ops( const GLcontext *ctx )
85 {
86 int result;
87 result = (!( ctx->Color.AlphaEnabled ||
88 ctx->Depth.Test ||
89 ctx->Fog.Enabled ||
90 ctx->Scissor.Enabled ||
91 ctx->Stencil.Enabled ||
92 !ctx->Color.ColorMask[0] ||
93 !ctx->Color.ColorMask[1] ||
94 !ctx->Color.ColorMask[2] ||
95 !ctx->Color.ColorMask[3] ||
96 ctx->Color.ColorLogicOpEnabled ||
97 ctx->Texture._EnabledUnits
98 ) &&
99 ctx->Current.RasterPosValid);
100
101 return result;
102 }
103
104
105
106 static GLboolean
107 clip_pixelrect( const GLcontext *ctx,
108 const GLframebuffer *buffer,
109 GLint *x, GLint *y,
110 GLsizei *width, GLsizei *height,
111 GLint *size )
112 {
113 r200ContextPtr rmesa = R200_CONTEXT(ctx);
114
115 /* left clipping */
116 if (*x < buffer->_Xmin) {
117 *width -= (buffer->_Xmin - *x);
118 *x = buffer->_Xmin;
119 }
120
121 /* right clipping */
122 if (*x + *width > buffer->_Xmax)
123 *width -= (*x + *width - buffer->_Xmax - 1);
124
125 if (*width <= 0)
126 return GL_FALSE;
127
128 /* bottom clipping */
129 if (*y < buffer->_Ymin) {
130 *height -= (buffer->_Ymin - *y);
131 *y = buffer->_Ymin;
132 }
133
134 /* top clipping */
135 if (*y + *height > buffer->_Ymax)
136 *height -= (*y + *height - buffer->_Ymax - 1);
137
138 if (*height <= 0)
139 return GL_FALSE;
140
141 *size = ((*y + *height - 1) * rmesa->r200Screen->frontPitch +
142 (*x + *width - 1) * rmesa->r200Screen->cpp);
143
144 return GL_TRUE;
145 }
146
147 static GLboolean
148 r200TryReadPixels( GLcontext *ctx,
149 GLint x, GLint y, GLsizei width, GLsizei height,
150 GLenum format, GLenum type,
151 const struct gl_pixelstore_attrib *pack,
152 GLvoid *pixels )
153 {
154 r200ContextPtr rmesa = R200_CONTEXT(ctx);
155 GLint pitch = pack->RowLength ? pack->RowLength : width;
156 GLint blit_format;
157 GLuint cpp = rmesa->r200Screen->cpp;
158 GLint size = width * height * cpp;
159
160 if (R200_DEBUG & DEBUG_PIXEL)
161 fprintf(stderr, "%s\n", __FUNCTION__);
162
163 /* Only accelerate reading to GART buffers.
164 */
165 if ( !r200IsGartMemory(rmesa, pixels,
166 pitch * height * rmesa->r200Screen->cpp ) ) {
167 if (R200_DEBUG & DEBUG_PIXEL)
168 fprintf(stderr, "%s: dest not GART\n", __FUNCTION__);
169 return GL_FALSE;
170 }
171
172 /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from
173 * blitter:
174 */
175 if (!pack->Invert) {
176 if (R200_DEBUG & DEBUG_PIXEL)
177 fprintf(stderr, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__);
178 return GL_FALSE;
179 }
180
181 if (!check_color(ctx, type, format, pack, pixels, size, pitch))
182 return GL_FALSE;
183
184 switch ( rmesa->r200Screen->cpp ) {
185 case 4:
186 blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
187 break;
188 default:
189 return GL_FALSE;
190 }
191
192
193 /* Although the blits go on the command buffer, need to do this and
194 * fire with lock held to guarentee cliprects and drawOffset are
195 * correct.
196 *
197 * This is an unusual situation however, as the code which flushes
198 * a full command buffer expects to be called unlocked. As a
199 * workaround, immediately flush the buffer on aquiring the lock.
200 */
201 LOCK_HARDWARE( rmesa );
202
203 if (rmesa->store.cmd_used)
204 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
205
206 if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height,
207 &size)) {
208 UNLOCK_HARDWARE( rmesa );
209 if (R200_DEBUG & DEBUG_PIXEL)
210 fprintf(stderr, "%s totally clipped -- nothing to do\n",
211 __FUNCTION__);
212 return GL_TRUE;
213 }
214
215 {
216 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
217 driRenderbuffer *drb = (driRenderbuffer *) ctx->ReadBuffer->_ColorReadBuffer;
218 int nbox = dPriv->numClipRects;
219 int src_offset = drb->offset
220 + rmesa->r200Screen->fbLocation;
221 int src_pitch = drb->pitch * drb->cpp;
222 int dst_offset = r200GartOffsetFromVirtual( rmesa, pixels );
223 int dst_pitch = pitch * rmesa->r200Screen->cpp;
224 drm_clip_rect_t *box = dPriv->pClipRects;
225 int i;
226
227 r200EmitWait( rmesa, RADEON_WAIT_3D );
228
229 y = dPriv->h - y - height;
230 x += dPriv->x;
231 y += dPriv->y;
232
233
234 if (R200_DEBUG & DEBUG_PIXEL)
235 fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n",
236 src_pitch, dst_pitch);
237
238 for (i = 0 ; i < nbox ; i++)
239 {
240 GLint bx = box[i].x1;
241 GLint by = box[i].y1;
242 GLint bw = box[i].x2 - bx;
243 GLint bh = box[i].y2 - by;
244
245 if (bx < x) bw -= x - bx, bx = x;
246 if (by < y) bh -= y - by, by = y;
247 if (bx + bw > x + width) bw = x + width - bx;
248 if (by + bh > y + height) bh = y + height - by;
249 if (bw <= 0) continue;
250 if (bh <= 0) continue;
251
252 r200EmitBlit( rmesa,
253 blit_format,
254 src_pitch, src_offset,
255 dst_pitch, dst_offset,
256 bx, by,
257 bx - x, by - y,
258 bw, bh );
259 }
260
261 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
262 }
263 UNLOCK_HARDWARE( rmesa );
264
265 r200Finish( ctx ); /* required by GL */
266
267 return GL_TRUE;
268 }
269
270 static void
271 r200ReadPixels( GLcontext *ctx,
272 GLint x, GLint y, GLsizei width, GLsizei height,
273 GLenum format, GLenum type,
274 const struct gl_pixelstore_attrib *pack,
275 GLvoid *pixels )
276 {
277 if (R200_DEBUG & DEBUG_PIXEL)
278 fprintf(stderr, "%s\n", __FUNCTION__);
279
280 if (!r200TryReadPixels( ctx, x, y, width, height, format, type, pack,
281 pixels))
282 _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack,
283 pixels);
284 }
285
286
287
288
289 static void do_draw_pix( GLcontext *ctx,
290 GLint x, GLint y, GLsizei width, GLsizei height,
291 GLint pitch,
292 const void *pixels,
293 GLuint planemask)
294 {
295 r200ContextPtr rmesa = R200_CONTEXT(ctx);
296 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
297 drm_clip_rect_t *box = dPriv->pClipRects;
298 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorDrawBuffers[0][0];
299 driRenderbuffer *drb = (driRenderbuffer *) rb;
300 int nbox = dPriv->numClipRects;
301 int i;
302 int blit_format;
303 int size;
304 int src_offset = r200GartOffsetFromVirtual( rmesa, pixels );
305 int src_pitch = pitch * rmesa->r200Screen->cpp;
306
307 if (R200_DEBUG & DEBUG_PIXEL)
308 fprintf(stderr, "%s\n", __FUNCTION__);
309
310 switch ( rmesa->r200Screen->cpp ) {
311 case 2:
312 blit_format = R200_CP_COLOR_FORMAT_RGB565;
313 break;
314 case 4:
315 blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
316 break;
317 default:
318 return;
319 }
320
321
322 LOCK_HARDWARE( rmesa );
323
324 if (rmesa->store.cmd_used)
325 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
326
327 y -= height; /* cope with pixel zoom */
328
329 if (!clip_pixelrect(ctx, ctx->DrawBuffer,
330 &x, &y, &width, &height,
331 &size)) {
332 UNLOCK_HARDWARE( rmesa );
333 return;
334 }
335
336 y = dPriv->h - y - height; /* convert from gl to hardware coords */
337 x += dPriv->x;
338 y += dPriv->y;
339
340
341 r200EmitWait( rmesa, RADEON_WAIT_3D );
342
343 for (i = 0 ; i < nbox ; i++ )
344 {
345 GLint bx = box[i].x1;
346 GLint by = box[i].y1;
347 GLint bw = box[i].x2 - bx;
348 GLint bh = box[i].y2 - by;
349
350 if (bx < x) bw -= x - bx, bx = x;
351 if (by < y) bh -= y - by, by = y;
352 if (bx + bw > x + width) bw = x + width - bx;
353 if (by + bh > y + height) bh = y + height - by;
354 if (bw <= 0) continue;
355 if (bh <= 0) continue;
356
357 r200EmitBlit( rmesa,
358 blit_format,
359 src_pitch, src_offset,
360 drb->pitch * drb->cpp,
361 drb->offset + rmesa->r200Screen->fbLocation,
362 bx - x, by - y,
363 bx, by,
364 bw, bh );
365 }
366
367 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
368 r200WaitForIdleLocked( rmesa ); /* required by GL */
369 UNLOCK_HARDWARE( rmesa );
370 }
371
372
373
374
375 static GLboolean
376 r200TryDrawPixels( GLcontext *ctx,
377 GLint x, GLint y, GLsizei width, GLsizei height,
378 GLenum format, GLenum type,
379 const struct gl_pixelstore_attrib *unpack,
380 const GLvoid *pixels )
381 {
382 r200ContextPtr rmesa = R200_CONTEXT(ctx);
383 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
384 GLuint planemask;
385 GLuint cpp = rmesa->r200Screen->cpp;
386 GLint size = width * pitch * cpp;
387
388 if (R200_DEBUG & DEBUG_PIXEL)
389 fprintf(stderr, "%s\n", __FUNCTION__);
390
391 /* check that we're drawing to exactly one color buffer */
392 if (ctx->DrawBuffer->_NumColorDrawBuffers[0] != 1)
393 return GL_FALSE;
394
395 switch (format) {
396 case GL_RGB:
397 case GL_RGBA:
398 case GL_BGRA:
399 planemask = r200PackColor(cpp,
400 ctx->Color.ColorMask[RCOMP],
401 ctx->Color.ColorMask[GCOMP],
402 ctx->Color.ColorMask[BCOMP],
403 ctx->Color.ColorMask[ACOMP]);
404
405 if (cpp == 2)
406 planemask |= planemask << 16;
407
408 if (planemask != ~0)
409 return GL_FALSE; /* fix me -- should be possible */
410
411 /* Can't do conversions on GART reads/draws.
412 */
413 if ( !r200IsGartMemory( rmesa, pixels, size ) ) {
414 if (R200_DEBUG & DEBUG_PIXEL)
415 fprintf(stderr, "%s: not GART memory\n", __FUNCTION__);
416 return GL_FALSE;
417 }
418
419 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
420 return GL_FALSE;
421 }
422 if (!check_color_per_fragment_ops(ctx)) {
423 return GL_FALSE;
424 }
425
426 if (ctx->Pixel.ZoomX != 1.0F ||
427 ctx->Pixel.ZoomY != -1.0F)
428 return GL_FALSE;
429 break;
430
431 default:
432 return GL_FALSE;
433 }
434
435 if ( r200IsGartMemory(rmesa, pixels, size) )
436 {
437 do_draw_pix( ctx, x, y, width, height, pitch, pixels, planemask );
438 return GL_TRUE;
439 }
440 else if (0)
441 {
442 /* Pixels is in regular memory -- get dma buffers and perform
443 * upload through them.
444 */
445 }
446 else
447 return GL_FALSE;
448 }
449
450 static void
451 r200DrawPixels( GLcontext *ctx,
452 GLint x, GLint y, GLsizei width, GLsizei height,
453 GLenum format, GLenum type,
454 const struct gl_pixelstore_attrib *unpack,
455 const GLvoid *pixels )
456 {
457 if (R200_DEBUG & DEBUG_PIXEL)
458 fprintf(stderr, "%s\n", __FUNCTION__);
459
460 if (!r200TryDrawPixels( ctx, x, y, width, height, format, type,
461 unpack, pixels ))
462 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
463 unpack, pixels );
464 }
465
466
467 static void
468 r200Bitmap( GLcontext *ctx, GLint px, GLint py,
469 GLsizei width, GLsizei height,
470 const struct gl_pixelstore_attrib *unpack,
471 const GLubyte *bitmap )
472 {
473 r200ContextPtr rmesa = R200_CONTEXT(ctx);
474
475 if (rmesa->Fallback)
476 _swrast_Bitmap( ctx, px, py, width, height, unpack, bitmap );
477 else
478 r200PointsBitmap( ctx, px, py, width, height, unpack, bitmap );
479 }
480
481
482
483 void r200InitPixelFuncs( GLcontext *ctx )
484 {
485 /* Pixel path fallbacks.
486 */
487 ctx->Driver.Accum = _swrast_Accum;
488 ctx->Driver.Bitmap = _swrast_Bitmap;
489 ctx->Driver.CopyPixels = _swrast_CopyPixels;
490 ctx->Driver.DrawPixels = _swrast_DrawPixels;
491 ctx->Driver.ReadPixels = _swrast_ReadPixels;
492
493 if (!getenv("R200_NO_BLITS") && R200_CONTEXT(ctx)->dri.drmMinor >= 6) {
494 ctx->Driver.ReadPixels = r200ReadPixels;
495 ctx->Driver.DrawPixels = r200DrawPixels;
496 if (getenv("R200_HW_BITMAP"))
497 ctx->Driver.Bitmap = r200Bitmap;
498 }
499 }