#include "glheader.h"
#include "enums.h"
#include "mtypes.h"
#include "macros.h"
#include "texutil.h"
#include "swrast/swrast.h"
#include "r200_context.h"
#include "r200_ioctl.h"
#include "r200_pixel.h"
#include "r200_swtcl.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 )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
GLuint cpp = rmesa->r200Screen->cpp;
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s\n", __FUNCTION__);
if ( (pitch & 63) ||
ctx->_ImageTransferState ||
packing->SwapBytes ||
packing->LsbFirst) {
if (R200_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 (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s: passed 2\n", __FUNCTION__);
return GL_TRUE;
}
if (R200_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 )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
if (*x < buffer->_Xmin) {
*width -= (buffer->_Xmin - *x);
*x = buffer->_Xmin;
}
if (*x + *width > buffer->_Xmax)
*width -= (*x + *width - buffer->_Xmax - 1);
if (*width <= 0)
return GL_FALSE;
if (*y < buffer->_Ymin) {
*height -= (buffer->_Ymin - *y);
*y = buffer->_Ymin;
}
if (*y + *height > buffer->_Ymax)
*height -= (*y + *height - buffer->_Ymax - 1);
if (*height <= 0)
return GL_FALSE;
*size = ((*y + *height - 1) * rmesa->r200Screen->frontPitch +
(*x + *width - 1) * rmesa->r200Screen->cpp);
return GL_TRUE;
}
static GLboolean
r200TryReadPixels( GLcontext *ctx,
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *pack,
GLvoid *pixels )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
GLint size;
GLint pitch = pack->RowLength ? pack->RowLength : width;
GLint blit_format;
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s\n", __FUNCTION__);
if ( !r200IsGartMemory(rmesa, pixels,
pitch * height * rmesa->r200Screen->cpp ) ) {
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s: dest not GART\n", __FUNCTION__);
return GL_FALSE;
}
if (!pack->Invert) {
if (R200_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 ( rmesa->r200Screen->cpp ) {
case 4:
blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
break;
default:
return GL_FALSE;
}
LOCK_HARDWARE( rmesa );
if (rmesa->store.cmd_used)
r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height,
&size)) {
UNLOCK_HARDWARE( rmesa );
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s totally clipped -- nothing to do\n",
__FUNCTION__);
return GL_TRUE;
}
{
__DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
int nbox = dPriv->numClipRects;
int src_offset = rmesa->state.color.drawOffset
+ rmesa->r200Screen->fbLocation;
int src_pitch = rmesa->state.color.drawPitch * rmesa->r200Screen->cpp;
int dst_offset = r200GartOffsetFromVirtual( rmesa, pixels );
int dst_pitch = pitch * rmesa->r200Screen->cpp;
XF86DRIClipRectRec *box = dPriv->pClipRects;
int i;
r200EmitWait( rmesa, RADEON_WAIT_3D );
y = dPriv->h - y - height;
x += dPriv->x;
y += dPriv->y;
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n",
src_pitch, dst_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;
r200EmitBlit( rmesa,
blit_format,
src_pitch, src_offset,
dst_pitch, dst_offset,
bx, by,
bx - x, by - y,
bw, bh );
}
r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
}
UNLOCK_HARDWARE( rmesa );
r200Finish( ctx );
return GL_TRUE;
}
static void
r200ReadPixels( GLcontext *ctx,
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *pack,
GLvoid *pixels )
{
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s\n", __FUNCTION__);
if (!r200TryReadPixels( 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 planemask)
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
__DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
XF86DRIClipRectPtr box = dPriv->pClipRects;
int nbox = dPriv->numClipRects;
int i;
int blit_format;
int size;
int src_offset = r200GartOffsetFromVirtual( rmesa, pixels );
int src_pitch = pitch * rmesa->r200Screen->cpp;
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s\n", __FUNCTION__);
switch ( rmesa->r200Screen->cpp ) {
case 2:
blit_format = R200_CP_COLOR_FORMAT_RGB565;
break;
case 4:
blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
break;
default:
return;
}
LOCK_HARDWARE( rmesa );
if (rmesa->store.cmd_used)
r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
y -= height;
if (!clip_pixelrect(ctx, ctx->DrawBuffer,
&x, &y, &width, &height,
&size)) {
UNLOCK_HARDWARE( rmesa );
return;
}
y = dPriv->h - y - height;
x += dPriv->x;
y += dPriv->y;
r200EmitWait( rmesa, RADEON_WAIT_3D );
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;
r200EmitBlit( rmesa,
blit_format,
src_pitch, src_offset,
rmesa->state.color.drawPitch * rmesa->r200Screen->cpp,
rmesa->state.color.drawOffset + rmesa->r200Screen->fbLocation,
bx - x, by - y,
bx, by,
bw, bh );
}
r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
r200WaitForIdleLocked( rmesa );
UNLOCK_HARDWARE( rmesa );
}
static GLboolean
r200TryDrawPixels( GLcontext *ctx,
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
GLint pitch = unpack->RowLength ? unpack->RowLength : width;
GLuint planemask;
GLuint cpp = rmesa->r200Screen->cpp;
GLint size = width * pitch * cpp;
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s\n", __FUNCTION__);
switch (format) {
case GL_RGB:
case GL_RGBA:
case GL_BGRA:
planemask = r200PackColor(cpp,
ctx->Color.ColorMask[RCOMP],
ctx->Color.ColorMask[GCOMP],
ctx->Color.ColorMask[BCOMP],
ctx->Color.ColorMask[ACOMP]);
if (cpp == 2)
planemask |= planemask << 16;
if (planemask != ~0)
return GL_FALSE;
if ( !r200IsGartMemory( rmesa, pixels, size ) ) {
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s: not GART 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 ( r200IsGartMemory(rmesa, pixels, size) )
{
do_draw_pix( ctx, x, y, width, height, pitch, pixels, planemask );
return GL_TRUE;
}
else if (0)
{
}
else
return GL_FALSE;
}
static void
r200DrawPixels( GLcontext *ctx,
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels )
{
if (R200_DEBUG & DEBUG_PIXEL)
fprintf(stderr, "%s\n", __FUNCTION__);
if (!r200TryDrawPixels( ctx, x, y, width, height, format, type,
unpack, pixels ))
_swrast_DrawPixels( ctx, x, y, width, height, format, type,
unpack, pixels );
}
static void
r200Bitmap( GLcontext *ctx, GLint px, GLint py,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
if (rmesa->Fallback)
_swrast_Bitmap( ctx, px, py, width, height, unpack, bitmap );
else
r200PointsBitmap( ctx, px, py, width, height, unpack, bitmap );
}
void r200InitPixelFuncs( GLcontext *ctx )
{
ctx->Driver.Accum = _swrast_Accum;
ctx->Driver.Bitmap = _swrast_Bitmap;
ctx->Driver.CopyPixels = _swrast_CopyPixels;
ctx->Driver.DrawPixels = _swrast_DrawPixels;
ctx->Driver.ReadPixels = _swrast_ReadPixels;
if (!getenv("R200_NO_BLITS") && R200_CONTEXT(ctx)->dri.drmMinor >= 6) {
ctx->Driver.ReadPixels = r200ReadPixels;
ctx->Driver.DrawPixels = r200DrawPixels;
if (getenv("R200_HW_BITMAP"))
ctx->Driver.Bitmap = r200Bitmap;
}
}