disable under _SOLO build
[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 "texutil.h"
40 #include "swrast/swrast.h"
41
42 #include "r200_context.h"
43 #include "r200_ioctl.h"
44 #include "r200_pixel.h"
45 #include "r200_swtcl.h"
46
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 ctx->Depth.OcclusionTest
99 ) &&
100 ctx->Current.RasterPosValid);
101
102 return result;
103 }
104
105
106
107 static GLboolean
108 clip_pixelrect( const GLcontext *ctx,
109 const GLframebuffer *buffer,
110 GLint *x, GLint *y,
111 GLsizei *width, GLsizei *height,
112 GLint *size )
113 {
114 r200ContextPtr rmesa = R200_CONTEXT(ctx);
115
116 /* left clipping */
117 if (*x < buffer->_Xmin) {
118 *width -= (buffer->_Xmin - *x);
119 *x = buffer->_Xmin;
120 }
121
122 /* right clipping */
123 if (*x + *width > buffer->_Xmax)
124 *width -= (*x + *width - buffer->_Xmax - 1);
125
126 if (*width <= 0)
127 return GL_FALSE;
128
129 /* bottom clipping */
130 if (*y < buffer->_Ymin) {
131 *height -= (buffer->_Ymin - *y);
132 *y = buffer->_Ymin;
133 }
134
135 /* top clipping */
136 if (*y + *height > buffer->_Ymax)
137 *height -= (*y + *height - buffer->_Ymax - 1);
138
139 if (*height <= 0)
140 return GL_FALSE;
141
142 *size = ((*y + *height - 1) * rmesa->r200Screen->frontPitch +
143 (*x + *width - 1) * rmesa->r200Screen->cpp);
144
145 return GL_TRUE;
146 }
147
148 static GLboolean
149 r200TryReadPixels( GLcontext *ctx,
150 GLint x, GLint y, GLsizei width, GLsizei height,
151 GLenum format, GLenum type,
152 const struct gl_pixelstore_attrib *pack,
153 GLvoid *pixels )
154 {
155 r200ContextPtr rmesa = R200_CONTEXT(ctx);
156 GLint size;
157 GLint pitch = pack->RowLength ? pack->RowLength : width;
158 GLint blit_format;
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 int nbox = dPriv->numClipRects;
218 int src_offset = rmesa->state.color.drawOffset
219 + rmesa->r200Screen->fbLocation;
220 int src_pitch = rmesa->state.color.drawPitch * rmesa->r200Screen->cpp;
221 int dst_offset = r200GartOffsetFromVirtual( rmesa, pixels );
222 int dst_pitch = pitch * rmesa->r200Screen->cpp;
223 drm_clip_rect_t *box = dPriv->pClipRects;
224 int i;
225
226 r200EmitWait( rmesa, RADEON_WAIT_3D );
227
228 y = dPriv->h - y - height;
229 x += dPriv->x;
230 y += dPriv->y;
231
232
233 if (R200_DEBUG & DEBUG_PIXEL)
234 fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n",
235 src_pitch, dst_pitch);
236
237 for (i = 0 ; i < nbox ; i++)
238 {
239 GLint bx = box[i].x1;
240 GLint by = box[i].y1;
241 GLint bw = box[i].x2 - bx;
242 GLint bh = box[i].y2 - by;
243
244 if (bx < x) bw -= x - bx, bx = x;
245 if (by < y) bh -= y - by, by = y;
246 if (bx + bw > x + width) bw = x + width - bx;
247 if (by + bh > y + height) bh = y + height - by;
248 if (bw <= 0) continue;
249 if (bh <= 0) continue;
250
251 r200EmitBlit( rmesa,
252 blit_format,
253 src_pitch, src_offset,
254 dst_pitch, dst_offset,
255 bx, by,
256 bx - x, by - y,
257 bw, bh );
258 }
259
260 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
261 }
262 UNLOCK_HARDWARE( rmesa );
263
264 r200Finish( ctx ); /* required by GL */
265
266 return GL_TRUE;
267 }
268
269 static void
270 r200ReadPixels( GLcontext *ctx,
271 GLint x, GLint y, GLsizei width, GLsizei height,
272 GLenum format, GLenum type,
273 const struct gl_pixelstore_attrib *pack,
274 GLvoid *pixels )
275 {
276 if (R200_DEBUG & DEBUG_PIXEL)
277 fprintf(stderr, "%s\n", __FUNCTION__);
278
279 if (!r200TryReadPixels( ctx, x, y, width, height, format, type, pack,
280 pixels))
281 _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack,
282 pixels);
283 }
284
285
286
287
288 static void do_draw_pix( GLcontext *ctx,
289 GLint x, GLint y, GLsizei width, GLsizei height,
290 GLint pitch,
291 const void *pixels,
292 GLuint planemask)
293 {
294 r200ContextPtr rmesa = R200_CONTEXT(ctx);
295 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
296 drm_clip_rect_t *box = dPriv->pClipRects;
297 int nbox = dPriv->numClipRects;
298 int i;
299 int blit_format;
300 int size;
301 int src_offset = r200GartOffsetFromVirtual( rmesa, pixels );
302 int src_pitch = pitch * rmesa->r200Screen->cpp;
303
304 if (R200_DEBUG & DEBUG_PIXEL)
305 fprintf(stderr, "%s\n", __FUNCTION__);
306
307 switch ( rmesa->r200Screen->cpp ) {
308 case 2:
309 blit_format = R200_CP_COLOR_FORMAT_RGB565;
310 break;
311 case 4:
312 blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
313 break;
314 default:
315 return;
316 }
317
318
319 LOCK_HARDWARE( rmesa );
320
321 if (rmesa->store.cmd_used)
322 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
323
324 y -= height; /* cope with pixel zoom */
325
326 if (!clip_pixelrect(ctx, ctx->DrawBuffer,
327 &x, &y, &width, &height,
328 &size)) {
329 UNLOCK_HARDWARE( rmesa );
330 return;
331 }
332
333 y = dPriv->h - y - height; /* convert from gl to hardware coords */
334 x += dPriv->x;
335 y += dPriv->y;
336
337
338 r200EmitWait( rmesa, RADEON_WAIT_3D );
339
340 for (i = 0 ; i < nbox ; i++ )
341 {
342 GLint bx = box[i].x1;
343 GLint by = box[i].y1;
344 GLint bw = box[i].x2 - bx;
345 GLint bh = box[i].y2 - by;
346
347 if (bx < x) bw -= x - bx, bx = x;
348 if (by < y) bh -= y - by, by = y;
349 if (bx + bw > x + width) bw = x + width - bx;
350 if (by + bh > y + height) bh = y + height - by;
351 if (bw <= 0) continue;
352 if (bh <= 0) continue;
353
354 r200EmitBlit( rmesa,
355 blit_format,
356 src_pitch, src_offset,
357 rmesa->state.color.drawPitch * rmesa->r200Screen->cpp,
358 rmesa->state.color.drawOffset + rmesa->r200Screen->fbLocation,
359 bx - x, by - y,
360 bx, by,
361 bw, bh );
362 }
363
364 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
365 r200WaitForIdleLocked( rmesa ); /* required by GL */
366 UNLOCK_HARDWARE( rmesa );
367 }
368
369
370
371
372 static GLboolean
373 r200TryDrawPixels( GLcontext *ctx,
374 GLint x, GLint y, GLsizei width, GLsizei height,
375 GLenum format, GLenum type,
376 const struct gl_pixelstore_attrib *unpack,
377 const GLvoid *pixels )
378 {
379 r200ContextPtr rmesa = R200_CONTEXT(ctx);
380 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
381 GLuint planemask;
382 GLuint cpp = rmesa->r200Screen->cpp;
383 GLint size = width * pitch * cpp;
384
385 if (R200_DEBUG & DEBUG_PIXEL)
386 fprintf(stderr, "%s\n", __FUNCTION__);
387
388 switch (format) {
389 case GL_RGB:
390 case GL_RGBA:
391 case GL_BGRA:
392 planemask = r200PackColor(cpp,
393 ctx->Color.ColorMask[RCOMP],
394 ctx->Color.ColorMask[GCOMP],
395 ctx->Color.ColorMask[BCOMP],
396 ctx->Color.ColorMask[ACOMP]);
397
398 if (cpp == 2)
399 planemask |= planemask << 16;
400
401 if (planemask != ~0)
402 return GL_FALSE; /* fix me -- should be possible */
403
404 /* Can't do conversions on GART reads/draws.
405 */
406 if ( !r200IsGartMemory( rmesa, pixels, size ) ) {
407 if (R200_DEBUG & DEBUG_PIXEL)
408 fprintf(stderr, "%s: not GART memory\n", __FUNCTION__);
409 return GL_FALSE;
410 }
411
412 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
413 return GL_FALSE;
414 }
415 if (!check_color_per_fragment_ops(ctx)) {
416 return GL_FALSE;
417 }
418
419 if (ctx->Pixel.ZoomX != 1.0F ||
420 ctx->Pixel.ZoomY != -1.0F)
421 return GL_FALSE;
422 break;
423
424 default:
425 return GL_FALSE;
426 }
427
428 if ( r200IsGartMemory(rmesa, pixels, size) )
429 {
430 do_draw_pix( ctx, x, y, width, height, pitch, pixels, planemask );
431 return GL_TRUE;
432 }
433 else if (0)
434 {
435 /* Pixels is in regular memory -- get dma buffers and perform
436 * upload through them.
437 */
438 }
439 else
440 return GL_FALSE;
441 }
442
443 static void
444 r200DrawPixels( GLcontext *ctx,
445 GLint x, GLint y, GLsizei width, GLsizei height,
446 GLenum format, GLenum type,
447 const struct gl_pixelstore_attrib *unpack,
448 const GLvoid *pixels )
449 {
450 if (R200_DEBUG & DEBUG_PIXEL)
451 fprintf(stderr, "%s\n", __FUNCTION__);
452
453 if (!r200TryDrawPixels( ctx, x, y, width, height, format, type,
454 unpack, pixels ))
455 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
456 unpack, pixels );
457 }
458
459
460 static void
461 r200Bitmap( GLcontext *ctx, GLint px, GLint py,
462 GLsizei width, GLsizei height,
463 const struct gl_pixelstore_attrib *unpack,
464 const GLubyte *bitmap )
465 {
466 r200ContextPtr rmesa = R200_CONTEXT(ctx);
467
468 if (rmesa->Fallback)
469 _swrast_Bitmap( ctx, px, py, width, height, unpack, bitmap );
470 else
471 r200PointsBitmap( ctx, px, py, width, height, unpack, bitmap );
472 }
473
474
475
476 void r200InitPixelFuncs( GLcontext *ctx )
477 {
478 /* Pixel path fallbacks.
479 */
480 ctx->Driver.Accum = _swrast_Accum;
481 ctx->Driver.Bitmap = _swrast_Bitmap;
482 ctx->Driver.CopyPixels = _swrast_CopyPixels;
483 ctx->Driver.DrawPixels = _swrast_DrawPixels;
484 ctx->Driver.ReadPixels = _swrast_ReadPixels;
485
486 if (!getenv("R200_NO_BLITS") && R200_CONTEXT(ctx)->dri.drmMinor >= 6) {
487 ctx->Driver.ReadPixels = r200ReadPixels;
488 ctx->Driver.DrawPixels = r200DrawPixels;
489 if (getenv("R200_HW_BITMAP"))
490 ctx->Driver.Bitmap = r200Bitmap;
491 }
492 }