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