Merge remote branch 'main/master' into radeon-rewrite
[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 & 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->radeon.radeonScreen->frontPitch +
141 (*x + *width - 1) * rmesa->radeon.radeonScreen->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->radeon.radeonScreen->cpp;
157 GLint size = width * height * cpp;
158
159 return GL_FALSE;
160 #if 0
161 if (R200_DEBUG & DEBUG_PIXEL)
162 fprintf(stderr, "%s\n", __FUNCTION__);
163
164 /* Only accelerate reading to GART buffers.
165 */
166 if ( !r200IsGartMemory(rmesa, pixels,
167 pitch * height * rmesa->radeon.radeonScreen->cpp ) ) {
168 if (R200_DEBUG & DEBUG_PIXEL)
169 fprintf(stderr, "%s: dest not GART\n", __FUNCTION__);
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->radeon.radeonScreen->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->radeon );
202
203 if (rmesa->store.cmd_used)
204 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
205
206 if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height,
207 &size)) {
208 UNLOCK_HARDWARE( &rmesa->radeon );
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->radeon.dri.drawable;
217 driRenderbuffer *drb = (driRenderbuffer *) ctx->ReadBuffer->_ColorReadBuffer;
218 int nbox = dPriv->numClipRects;
219 int src_offset = drb->offset
220 + rmesa->radeon.radeonScreen->fbLocation;
221 int src_pitch = drb->pitch * drb->cpp;
222 int dst_offset = r200GartOffsetFromVirtual( rmesa, pixels );
223 int dst_pitch = pitch * rmesa->radeon.radeonScreen->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 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
262 }
263 UNLOCK_HARDWARE( &rmesa->radeon );
264
265 radeonFinish( ctx ); /* required by GL */
266 #endif
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->radeon.dri.drawable;
297 drm_clip_rect_t *box = dPriv->pClipRects;
298 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorDrawBuffers[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->radeon.radeonScreen->cpp;
306
307 if (R200_DEBUG & DEBUG_PIXEL)
308 fprintf(stderr, "%s\n", __FUNCTION__);
309 #if 0
310 switch ( rmesa->radeon.radeonScreen->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->radeon );
323
324 if (rmesa->store.cmd_used)
325 rcommonFlushCmdBufLocked( &rmesa->radeon, __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->radeon );
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->radeon.radeonScreen->fbLocation,
362 bx - x, by - y,
363 bx, by,
364 bw, bh );
365 }
366
367 rcommonFlushCmdBufLocked( &rmesa->radeon, __FUNCTION__ );
368 radeonWaitForIdleLocked( &rmesa->radeon ); /* required by GL */
369 UNLOCK_HARDWARE( &rmesa->radeon );
370 #endif
371 }
372
373
374
375
376 static GLboolean
377 r200TryDrawPixels( GLcontext *ctx,
378 GLint x, GLint y, GLsizei width, GLsizei height,
379 GLenum format, GLenum type,
380 const struct gl_pixelstore_attrib *unpack,
381 const GLvoid *pixels )
382 {
383 r200ContextPtr rmesa = R200_CONTEXT(ctx);
384 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
385 GLuint planemask;
386 GLuint cpp = rmesa->radeon.radeonScreen->cpp;
387 GLint size = height * pitch * cpp;
388
389 if (R200_DEBUG & DEBUG_PIXEL)
390 fprintf(stderr, "%s\n", __FUNCTION__);
391
392 /* check that we're drawing to exactly one color buffer */
393 if (ctx->DrawBuffer->_NumColorDrawBuffers != 1)
394 return GL_FALSE;
395
396 switch (format) {
397 case GL_RGB:
398 case GL_RGBA:
399 case GL_BGRA:
400 planemask = radeonPackColor(cpp,
401 ctx->Color.ColorMask[RCOMP],
402 ctx->Color.ColorMask[GCOMP],
403 ctx->Color.ColorMask[BCOMP],
404 ctx->Color.ColorMask[ACOMP]);
405
406 if (cpp == 2)
407 planemask |= planemask << 16;
408
409 if (planemask != ~0)
410 return GL_FALSE; /* fix me -- should be possible */
411
412 /* Can't do conversions on GART reads/draws.
413 */
414 if ( !r200IsGartMemory( rmesa, pixels, size ) ) {
415 if (R200_DEBUG & DEBUG_PIXEL)
416 fprintf(stderr, "%s: not GART memory\n", __FUNCTION__);
417 return GL_FALSE;
418 }
419
420 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
421 return GL_FALSE;
422 }
423 if (!check_color_per_fragment_ops(ctx)) {
424 return GL_FALSE;
425 }
426
427 if (ctx->Pixel.ZoomX != 1.0F ||
428 ctx->Pixel.ZoomY != -1.0F)
429 return GL_FALSE;
430 break;
431
432 default:
433 return GL_FALSE;
434 }
435
436 if (0)// r200IsGartMemory(rmesa, pixels, size) )
437 {
438 do_draw_pix( ctx, x, y, width, height, pitch, pixels, planemask );
439 return GL_TRUE;
440 }
441 else if (0)
442 {
443 /* Pixels is in regular memory -- get dma buffers and perform
444 * upload through them.
445 */
446 }
447 else
448 return GL_FALSE;
449 }
450
451 static void
452 r200DrawPixels( GLcontext *ctx,
453 GLint x, GLint y, GLsizei width, GLsizei height,
454 GLenum format, GLenum type,
455 const struct gl_pixelstore_attrib *unpack,
456 const GLvoid *pixels )
457 {
458 if (R200_DEBUG & DEBUG_PIXEL)
459 fprintf(stderr, "%s\n", __FUNCTION__);
460
461 if (!r200TryDrawPixels( ctx, x, y, width, height, format, type,
462 unpack, pixels ))
463 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
464 unpack, pixels );
465 }
466
467
468 static void
469 r200Bitmap( GLcontext *ctx, GLint px, GLint py,
470 GLsizei width, GLsizei height,
471 const struct gl_pixelstore_attrib *unpack,
472 const GLubyte *bitmap )
473 {
474 r200ContextPtr rmesa = R200_CONTEXT(ctx);
475
476 if (rmesa->radeon.Fallback)
477 _swrast_Bitmap( ctx, px, py, width, height, unpack, bitmap );
478 else
479 r200PointsBitmap( ctx, px, py, width, height, unpack, bitmap );
480 }
481
482
483
484 void r200InitPixelFuncs( GLcontext *ctx )
485 {
486 if (!getenv("R200_NO_BLITS")) {
487 ctx->Driver.ReadPixels = r200ReadPixels;
488 ctx->Driver.DrawPixels = r200DrawPixels;
489 if (getenv("R200_HW_BITMAP"))
490 ctx->Driver.Bitmap = r200Bitmap;
491 }
492 }