diff options
Diffstat (limited to 'src/mesa/drivers/dri/i915/intel_pixel.c')
-rw-r--r-- | src/mesa/drivers/dri/i915/intel_pixel.c | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915/intel_pixel.c b/src/mesa/drivers/dri/i915/intel_pixel.c new file mode 100644 index 0000000000..6ffc33aa6b --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_pixel.c @@ -0,0 +1,469 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "mtypes.h" +#include "macros.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" + + + +static GLboolean +check_color( const GLcontext *ctx, GLenum type, GLenum format, + const struct gl_pixelstore_attrib *packing, + const void *pixels, GLint sz, GLint pitch ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLuint cpp = intel->intelScreen->cpp; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if ( (pitch & 63) || + ctx->_ImageTransferState || + packing->SwapBytes || + packing->LsbFirst) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: failed 1\n", __FUNCTION__); + return GL_FALSE; + } + + if ( type == GL_UNSIGNED_INT_8_8_8_8_REV && + cpp == 4 && + format == GL_BGRA ) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: passed 2\n", __FUNCTION__); + return GL_TRUE; + } + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: failed\n", __FUNCTION__); + + return GL_FALSE; +} + +static GLboolean +check_color_per_fragment_ops( const GLcontext *ctx ) +{ + int result; + result = (!( ctx->Color.AlphaEnabled || + ctx->Depth.Test || + ctx->Fog.Enabled || + ctx->Scissor.Enabled || + ctx->Stencil.Enabled || + !ctx->Color.ColorMask[0] || + !ctx->Color.ColorMask[1] || + !ctx->Color.ColorMask[2] || + !ctx->Color.ColorMask[3] || + ctx->Color.ColorLogicOpEnabled || + ctx->Texture._EnabledUnits || + ctx->Depth.OcclusionTest + ) && + ctx->Current.RasterPosValid); + + return result; +} + + + +static GLboolean +clip_pixelrect( const GLcontext *ctx, + const GLframebuffer *buffer, + GLint *x, GLint *y, + GLsizei *width, GLsizei *height, + GLint *size ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + /* left clipping */ + if (*x < buffer->_Xmin) { + *width -= (buffer->_Xmin - *x); + *x = buffer->_Xmin; + } + + /* right clipping */ + if (*x + *width > buffer->_Xmax) + *width -= (*x + *width - buffer->_Xmax - 1); + + if (*width <= 0) + return GL_FALSE; + + /* bottom clipping */ + if (*y < buffer->_Ymin) { + *height -= (buffer->_Ymin - *y); + *y = buffer->_Ymin; + } + + /* top clipping */ + if (*y + *height > buffer->_Ymax) + *height -= (*y + *height - buffer->_Ymax - 1); + + if (*height <= 0) + return GL_FALSE; + + *size = ((*y + *height - 1) * intel->intelScreen->frontPitch + + (*x + *width - 1) * intel->intelScreen->cpp); + + return GL_TRUE; +} + +static GLboolean +intelTryReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLint size; + GLint pitch = pack->RowLength ? pack->RowLength : width; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* Only accelerate reading to agp buffers. + */ + if ( !intelIsAgpMemory(intel, pixels, + pitch * height * intel->intelScreen->cpp ) ) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: dest not agp\n", __FUNCTION__); + return GL_FALSE; + } + + /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from + * blitter: + */ + if (!pack->Invert) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__); + return GL_FALSE; + } + + if (!check_color(ctx, type, format, pack, pixels, size, pitch)) + return GL_FALSE; + + switch ( intel->intelScreen->cpp ) { + case 4: + break; + default: + return GL_FALSE; + } + + + /* Although the blits go on the command buffer, need to do this and + * fire with lock held to guarentee cliprects and drawOffset are + * correct. + * + * This is an unusual situation however, as the code which flushes + * a full command buffer expects to be called unlocked. As a + * workaround, immediately flush the buffer on aquiring the lock. + */ + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + { + __DRIdrawablePrivate *dPriv = intel->driDrawable; + int nbox = dPriv->numClipRects; + int src_offset = intel->drawOffset; + int src_pitch = intel->intelScreen->frontPitch; + int dst_offset = intelAgpOffsetFromVirtual( intel, pixels); + drm_clip_rect_t *box = dPriv->pClipRects; + int i; + + if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height, + &size)) { + UNLOCK_HARDWARE( intel ); + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s totally clipped -- nothing to do\n", + __FUNCTION__); + return GL_TRUE; + } + + + y = dPriv->h - y - height; + x += dPriv->x; + y += dPriv->y; + + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n", + src_pitch, pitch); + + for (i = 0 ; i < nbox ; i++) + { + GLint bx = box[i].x1; + GLint by = box[i].y1; + GLint bw = box[i].x2 - bx; + GLint bh = box[i].y2 - by; + + if (bx < x) bw -= x - bx, bx = x; + if (by < y) bh -= y - by, by = y; + if (bx + bw > x + width) bw = x + width - bx; + if (by + bh > y + height) bh = y + height - by; + if (bw <= 0) continue; + if (bh <= 0) continue; + + intelEmitCopyBlitLocked( intel, + intel->intelScreen->cpp, + src_pitch, src_offset, + pitch, dst_offset, + bx, by, + bx - x, by - y, + bw, bh ); + } + } + UNLOCK_HARDWARE( intel ); + intelFinish( &intel->ctx ); + + return GL_TRUE; +} + +static void +intelReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ) +{ + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (!intelTryReadPixels( ctx, x, y, width, height, format, type, pack, + pixels)) + _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack, + pixels); +} + + + + +static void do_draw_pix( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint pitch, + const void *pixels, + GLuint dest ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = intel->driDrawable; + drm_clip_rect_t *box = dPriv->pClipRects; + int nbox = dPriv->numClipRects; + int i; + int size; + int src_offset = intelAgpOffsetFromVirtual( intel, pixels); + int src_pitch = pitch; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + { + y -= height; /* cope with pixel zoom */ + + if (!clip_pixelrect(ctx, ctx->DrawBuffer, + &x, &y, &width, &height, + &size)) { + UNLOCK_HARDWARE( intel ); + return; + } + + y = dPriv->h - y - height; /* convert from gl to hardware coords */ + x += dPriv->x; + y += dPriv->y; + + + for (i = 0 ; i < nbox ; i++ ) + { + GLint bx = box[i].x1; + GLint by = box[i].y1; + GLint bw = box[i].x2 - bx; + GLint bh = box[i].y2 - by; + + if (bx < x) bw -= x - bx, bx = x; + if (by < y) bh -= y - by, by = y; + if (bx + bw > x + width) bw = x + width - bx; + if (by + bh > y + height) bh = y + height - by; + if (bw <= 0) continue; + if (bh <= 0) continue; + + intelEmitCopyBlitLocked( intel, + intel->intelScreen->cpp, + src_pitch, src_offset, + intel->intelScreen->frontPitch, + intel->drawOffset, + bx - x, by - y, + bx, by, + bw, bh ); + } + } + UNLOCK_HARDWARE( intel ); + intelFinish( &intel->ctx ); +} + + + + +static GLboolean +intelTryDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLint pitch = unpack->RowLength ? unpack->RowLength : width; + GLuint dest; + GLuint cpp = intel->intelScreen->cpp; + GLint size = width * pitch * cpp; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + switch (format) { + case GL_RGB: + case GL_RGBA: + case GL_BGRA: + dest = intel->drawOffset; + + /* Planemask doesn't have full support in blits. + */ + if (!ctx->Color.ColorMask[RCOMP] || + !ctx->Color.ColorMask[GCOMP] || + !ctx->Color.ColorMask[BCOMP] || + !ctx->Color.ColorMask[ACOMP]) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: planemask\n", __FUNCTION__); + return GL_FALSE; + } + + /* Can't do conversions on agp reads/draws. + */ + if ( !intelIsAgpMemory( intel, pixels, size ) ) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: not agp memory\n", __FUNCTION__); + return GL_FALSE; + } + + if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) { + return GL_FALSE; + } + if (!check_color_per_fragment_ops(ctx)) { + return GL_FALSE; + } + + if (ctx->Pixel.ZoomX != 1.0F || + ctx->Pixel.ZoomY != -1.0F) + return GL_FALSE; + break; + + default: + return GL_FALSE; + } + + if ( intelIsAgpMemory(intel, pixels, size) ) + { + do_draw_pix( ctx, x, y, width, height, pitch, pixels, + dest ); + return GL_TRUE; + } + else if (0) + { + /* Pixels is in regular memory -- get dma buffers and perform + * upload through them. No point doing this for regular uploads + * but once we remove some of the restrictions above (colormask, + * pixelformat conversion, zoom?, etc), this could be a win. + */ + } + else + return GL_FALSE; +} + +static void +intelDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (!intelTryDrawPixels( ctx, x, y, width, height, format, type, + unpack, pixels )) + _swrast_DrawPixels( ctx, x, y, width, height, format, type, + unpack, pixels ); +} + + + + +/** + * Implement glCopyPixels for the front color buffer (or back buffer Pixmap) + * for the color buffer. Don't support zooming, pixel transfer, etc. + * We do support copying from one window to another, ala glXMakeCurrentRead. + */ +static void +intelCopyPixels( GLcontext *ctx, + GLint srcx, GLint srcy, GLsizei width, GLsizei height, + GLint destx, GLint desty, GLenum type ) +{ +#if 0 + const XMesaContext xmesa = XMESA_CONTEXT(ctx); + const SWcontext *swrast = SWRAST_CONTEXT( ctx ); + XMesaDisplay *dpy = xmesa->xm_visual->display; + const XMesaDrawable drawBuffer = xmesa->xm_draw_buffer->buffer; + const XMesaDrawable readBuffer = xmesa->xm_read_buffer->buffer; + const XMesaGC gc = xmesa->xm_draw_buffer->gc; + + ASSERT(dpy); + ASSERT(gc); + + if (drawBuffer && /* buffer != 0 means it's a Window or Pixmap */ + readBuffer && + type == GL_COLOR && + (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */ + ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */ + ctx->Pixel.ZoomX == 1.0 && /* no zooming */ + ctx->Pixel.ZoomY == 1.0) { + /* Note: we don't do any special clipping work here. We could, + * but X will do it for us. + */ + srcy = FLIP(xmesa->xm_read_buffer, srcy) - height + 1; + desty = FLIP(xmesa->xm_draw_buffer, desty) - height + 1; + XCopyArea(dpy, readBuffer, drawBuffer, gc, + srcx, srcy, width, height, destx, desty); + } +#else + _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type ); +#endif +} + + + + +void intelInitPixelFuncs( struct dd_function_table *functions ) +{ + /* Pixel path fallbacks. + */ + functions->Accum = _swrast_Accum; + functions->Bitmap = _swrast_Bitmap; + functions->CopyPixels = intelCopyPixels; + + if (!getenv("INTEL_NO_BLITS")) { + functions->ReadPixels = intelReadPixels; + functions->DrawPixels = intelDrawPixels; + } + else { + functions->ReadPixels = _swrast_ReadPixels; + functions->DrawPixels = _swrast_DrawPixels; + } +} |