texenvprogram: fix for ARB_draw_buffers.
[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 "main/glheader.h"
35 #include "main/enums.h"
36 #include "main/mtypes.h"
37 #include "main/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->radeon.radeonScreen->cpp;
55
56 if (R200_DEBUG & RADEON_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 & RADEON_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 & RADEON_PIXEL)
72 fprintf(stderr, "%s: passed 2\n", __FUNCTION__);
73 return GL_TRUE;
74 }
75
76 if (R200_DEBUG & RADEON_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][0] ||
92 !ctx->Color.ColorMask[0][1] ||
93 !ctx->Color.ColorMask[0][2] ||
94 !ctx->Color.ColorMask[0][3] ||
95 ctx->Color.ColorLogicOpEnabled ||
96 ctx->Texture._EnabledUnits
97 ) &&
98 ctx->Current.RasterPosValid);
99
100 return result;
101 }
102
103
104 #if 0
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->radeon.radeonScreen->frontPitch +
141 (*x + *width - 1) * rmesa->radeon.radeonScreen->cpp);
142
143 return GL_TRUE;
144 }
145 #endif
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 return GL_FALSE;
155 #if 0
156 r200ContextPtr rmesa = R200_CONTEXT(ctx);
157 GLint pitch = pack->RowLength ? pack->RowLength : width;
158 GLint blit_format;
159 GLuint cpp = rmesa->radeon.radeonScreen->cpp;
160 GLint size = width * height * cpp;
161
162 if (R200_DEBUG & RADEON_PIXEL)
163 fprintf(stderr, "%s\n", __FUNCTION__);
164
165 /* Only accelerate reading to GART buffers.
166 */
167 if ( !r200IsGartMemory(rmesa, pixels,
168 pitch * height * rmesa->radeon.radeonScreen->cpp ) ) {
169 if (R200_DEBUG & RADEON_PIXEL)
170 fprintf(stderr, "%s: dest not GART\n", __FUNCTION__);
171 }
172
173 /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from
174 * blitter:
175 */
176 if (!pack->Invert) {
177 if (R200_DEBUG & RADEON_PIXEL)
178 fprintf(stderr, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__);
179 return GL_FALSE;
180 }
181
182 if (!check_color(ctx, type, format, pack, pixels, size, pitch))
183 return GL_FALSE;
184
185 switch ( rmesa->radeon.radeonScreen->cpp ) {
186 case 4:
187 blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
188 break;
189 default:
190 return GL_FALSE;
191 }
192
193
194 /* Although the blits go on the command buffer, need to do this and
195 * fire with lock held to guarentee cliprects and drawOffset are
196 * correct.
197 *
198 * This is an unusual situation however, as the code which flushes
199 * a full command buffer expects to be called unlocked. As a
200 * workaround, immediately flush the buffer on aquiring the lock.
201 */
202 LOCK_HARDWARE( &rmesa->radeon );
203
204 if (rmesa->store.cmd_used)
205 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
206
207 if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height,
208 &size)) {
209 UNLOCK_HARDWARE( &rmesa->radeon );
210 if (R200_DEBUG & RADEON_PIXEL)
211 fprintf(stderr, "%s totally clipped -- nothing to do\n",
212 __FUNCTION__);
213 return GL_TRUE;
214 }
215
216 {
217 __DRIdrawable *dPriv = rmesa->radeon.dri.drawable;
218 driRenderbuffer *drb = (driRenderbuffer *) ctx->ReadBuffer->_ColorReadBuffer;
219 int nbox = dPriv->numClipRects;
220 int src_offset = drb->offset
221 + rmesa->radeon.radeonScreen->fbLocation;
222 int src_pitch = drb->pitch * drb->cpp;
223 int dst_offset = r200GartOffsetFromVirtual( rmesa, pixels );
224 int dst_pitch = pitch * rmesa->radeon.radeonScreen->cpp;
225 drm_clip_rect_t *box = dPriv->pClipRects;
226 int i;
227
228 r200EmitWait( rmesa, RADEON_WAIT_3D );
229
230 y = dPriv->h - y - height;
231 x += dPriv->x;
232 y += dPriv->y;
233
234
235 if (R200_DEBUG & RADEON_PIXEL)
236 fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n",
237 src_pitch, dst_pitch);
238
239 for (i = 0 ; i < nbox ; i++)
240 {
241 GLint bx = box[i].x1;
242 GLint by = box[i].y1;
243 GLint bw = box[i].x2 - bx;
244 GLint bh = box[i].y2 - by;
245
246 if (bx < x) bw -= x - bx, bx = x;
247 if (by < y) bh -= y - by, by = y;
248 if (bx + bw > x + width) bw = x + width - bx;
249 if (by + bh > y + height) bh = y + height - by;
250 if (bw <= 0) continue;
251 if (bh <= 0) continue;
252
253 r200EmitBlit( rmesa,
254 blit_format,
255 src_pitch, src_offset,
256 dst_pitch, dst_offset,
257 bx, by,
258 bx - x, by - y,
259 bw, bh );
260 }
261
262 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
263 }
264 UNLOCK_HARDWARE( &rmesa->radeon );
265
266 radeonFinish( ctx ); /* required by GL */
267 #endif
268 return GL_TRUE;
269 }
270
271 static void
272 r200ReadPixels( GLcontext *ctx,
273 GLint x, GLint y, GLsizei width, GLsizei height,
274 GLenum format, GLenum type,
275 const struct gl_pixelstore_attrib *pack,
276 GLvoid *pixels )
277 {
278 if (R200_DEBUG & RADEON_PIXEL)
279 fprintf(stderr, "%s\n", __FUNCTION__);
280
281 if (!r200TryReadPixels( ctx, x, y, width, height, format, type, pack,
282 pixels))
283 _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack,
284 pixels);
285 }
286
287
288
289
290 static void do_draw_pix( GLcontext *ctx,
291 GLint x, GLint y, GLsizei width, GLsizei height,
292 GLint pitch,
293 const void *pixels,
294 GLuint planemask)
295 {
296 if (R200_DEBUG & RADEON_PIXEL)
297 fprintf(stderr, "%s\n", __FUNCTION__);
298
299 #if 0
300 r200ContextPtr rmesa = R200_CONTEXT(ctx);
301 __DRIdrawable *dPriv = radeon_get_drawable(&rmesa->radeon);
302 drm_clip_rect_t *box = dPriv->pClipRects;
303 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorDrawBuffers[0];
304 driRenderbuffer *drb = (driRenderbuffer *) rb;
305 int nbox = dPriv->numClipRects;
306 int i;
307 int blit_format;
308 int size;
309 int src_offset = r200GartOffsetFromVirtual( rmesa, pixels );
310 int src_pitch = pitch * rmesa->radeon.radeonScreen->cpp;
311
312 switch ( rmesa->radeon.radeonScreen->cpp ) {
313 case 2:
314 blit_format = R200_CP_COLOR_FORMAT_RGB565;
315 break;
316 case 4:
317 blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
318 break;
319 default:
320 return;
321 }
322
323
324 LOCK_HARDWARE( &rmesa->radeon );
325
326 if (rmesa->store.cmd_used)
327 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
328
329 y -= height; /* cope with pixel zoom */
330
331 if (!clip_pixelrect(ctx, ctx->DrawBuffer,
332 &x, &y, &width, &height,
333 &size)) {
334 UNLOCK_HARDWARE( &rmesa->radeon );
335 return;
336 }
337
338 y = dPriv->h - y - height; /* convert from gl to hardware coords */
339 x += dPriv->x;
340 y += dPriv->y;
341
342
343 r200EmitWait( rmesa, RADEON_WAIT_3D );
344
345 for (i = 0 ; i < nbox ; i++ )
346 {
347 GLint bx = box[i].x1;
348 GLint by = box[i].y1;
349 GLint bw = box[i].x2 - bx;
350 GLint bh = box[i].y2 - by;
351
352 if (bx < x) bw -= x - bx, bx = x;
353 if (by < y) bh -= y - by, by = y;
354 if (bx + bw > x + width) bw = x + width - bx;
355 if (by + bh > y + height) bh = y + height - by;
356 if (bw <= 0) continue;
357 if (bh <= 0) continue;
358
359 r200EmitBlit( rmesa,
360 blit_format,
361 src_pitch, src_offset,
362 drb->pitch * drb->cpp,
363 drb->offset + rmesa->radeon.radeonScreen->fbLocation,
364 bx - x, by - y,
365 bx, by,
366 bw, bh );
367 }
368
369 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
370 radeonWaitForIdleLocked( &rmesa->radeon ); /* required by GL */
371 UNLOCK_HARDWARE( &rmesa->radeon );
372 #endif
373 }
374
375
376
377
378 static GLboolean
379 r200TryDrawPixels( GLcontext *ctx,
380 GLint x, GLint y, GLsizei width, GLsizei height,
381 GLenum format, GLenum type,
382 const struct gl_pixelstore_attrib *unpack,
383 const GLvoid *pixels )
384 {
385 r200ContextPtr rmesa = R200_CONTEXT(ctx);
386 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
387 GLuint planemask;
388 GLuint cpp = rmesa->radeon.radeonScreen->cpp;
389 GLint size = height * pitch * cpp;
390
391 if (R200_DEBUG & RADEON_PIXEL)
392 fprintf(stderr, "%s\n", __FUNCTION__);
393
394 /* check that we're drawing to exactly one color buffer */
395 if (ctx->DrawBuffer->_NumColorDrawBuffers != 1)
396 return GL_FALSE;
397
398 switch (format) {
399 case GL_RGB:
400 case GL_RGBA:
401 case GL_BGRA:
402 planemask = radeonPackColor(cpp,
403 ctx->Color.ColorMask[0][RCOMP],
404 ctx->Color.ColorMask[0][GCOMP],
405 ctx->Color.ColorMask[0][BCOMP],
406 ctx->Color.ColorMask[0][ACOMP]);
407
408 if (cpp == 2)
409 planemask |= planemask << 16;
410
411 if (planemask != ~0)
412 return GL_FALSE; /* fix me -- should be possible */
413
414 /* Can't do conversions on GART reads/draws.
415 */
416 if ( !r200IsGartMemory( rmesa, pixels, size ) ) {
417 if (R200_DEBUG & RADEON_PIXEL)
418 fprintf(stderr, "%s: not GART memory\n", __FUNCTION__);
419 return GL_FALSE;
420 }
421
422 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
423 return GL_FALSE;
424 }
425 if (!check_color_per_fragment_ops(ctx)) {
426 return GL_FALSE;
427 }
428
429 if (ctx->Pixel.ZoomX != 1.0F ||
430 ctx->Pixel.ZoomY != -1.0F)
431 return GL_FALSE;
432 break;
433
434 default:
435 return GL_FALSE;
436 }
437
438 if (0)// r200IsGartMemory(rmesa, pixels, size) )
439 {
440 do_draw_pix( ctx, x, y, width, height, pitch, pixels, planemask );
441 return GL_TRUE;
442 }
443 else if (0)
444 {
445 /* Pixels is in regular memory -- get dma buffers and perform
446 * upload through them.
447 */
448 }
449 else
450 return GL_FALSE;
451 }
452
453 static void
454 r200DrawPixels( GLcontext *ctx,
455 GLint x, GLint y, GLsizei width, GLsizei height,
456 GLenum format, GLenum type,
457 const struct gl_pixelstore_attrib *unpack,
458 const GLvoid *pixels )
459 {
460 if (R200_DEBUG & RADEON_PIXEL)
461 fprintf(stderr, "%s\n", __FUNCTION__);
462
463 if (!r200TryDrawPixels( ctx, x, y, width, height, format, type,
464 unpack, pixels ))
465 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
466 unpack, pixels );
467 }
468
469
470 static void
471 r200Bitmap( GLcontext *ctx, GLint px, GLint py,
472 GLsizei width, GLsizei height,
473 const struct gl_pixelstore_attrib *unpack,
474 const GLubyte *bitmap )
475 {
476 r200ContextPtr rmesa = R200_CONTEXT(ctx);
477
478 if (rmesa->radeon.Fallback)
479 _swrast_Bitmap( ctx, px, py, width, height, unpack, bitmap );
480 else
481 r200PointsBitmap( ctx, px, py, width, height, unpack, bitmap );
482 }
483
484
485
486 void r200InitPixelFuncs( GLcontext *ctx )
487 {
488 if (!getenv("R200_NO_BLITS")) {
489 ctx->Driver.ReadPixels = r200ReadPixels;
490 ctx->Driver.DrawPixels = r200DrawPixels;
491 if (getenv("R200_HW_BITMAP"))
492 ctx->Driver.Bitmap = r200Bitmap;
493 }
494 }