/** * Try to do a fast and simple RGB(a) glDrawPixels. * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead */ static GLboolean fast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *userUnpack, const GLvoid *pixels) { const GLint imgX = x, imgY = y; struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; GLenum rbType; SWcontext *swrast = SWRAST_CONTEXT(ctx); SWspan span; GLboolean simpleZoom; GLint yStep; /* +1 or -1 */ struct gl_pixelstore_attrib unpack; GLint destX, destY, drawWidth, drawHeight; /* post clipping */ if (!rb) return GL_TRUE; /* no-op */ rbType = rb->DataType; if ((swrast->_RasterMask & ~CLIP_BIT) || ctx->Texture._EnabledCoordUnits || userUnpack->SwapBytes || ctx->_ImageTransferState) { /* can't handle any of those conditions */ return GL_FALSE; } INIT_SPAN(span, GL_BITMAP); span.arrayMask = SPAN_RGBA; span.arrayAttribs = FRAG_BIT_COL0; _swrast_span_default_attribs(ctx, &span); /* copy input params since clipping may change them */ unpack = *userUnpack; destX = x; destY = y; drawWidth = width; drawHeight = height; /* check for simple zooming and clipping */ if (ctx->Pixel.ZoomX == 1.0F && (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F)) { if (!_mesa_clip_drawpixels(ctx, &destX, &destY, &drawWidth, &drawHeight, &unpack)) { /* image was completely clipped: no-op, all done */ return GL_TRUE; } simpleZoom = GL_TRUE; yStep = (GLint) ctx->Pixel.ZoomY; ASSERT(yStep == 1 || yStep == -1); } else { /* non-simple zooming */ simpleZoom = GL_FALSE; yStep = 1; if (unpack.RowLength == 0) unpack.RowLength = width; } /* * Ready to draw! */ if (format == GL_RGBA && type == rbType) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, height, format, type, 0, 0); const GLint srcStride = _mesa_image_row_stride(&unpack, width, format, type); if (simpleZoom) { GLint row; for (row = 0; row < drawHeight; row++) { rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL); src += srcStride; destY += yStep; } } else { /* with zooming */ GLint row; for (row = 0; row < drawHeight; row++) { span.x = destX; span.y = destY + row; span.end = drawWidth; span.array->ChanType = rbType; _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src); src += srcStride; } span.array->ChanType = CHAN_TYPE; } return GL_TRUE; } if (format == GL_RGB && type == rbType) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, height, format, type, 0, 0); const GLint srcStride = _mesa_image_row_stride(&unpack, width, format, type); if (simpleZoom) { GLint row; for (row = 0; row < drawHeight; row++) { rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL); src += srcStride; destY += yStep; } } else { /* with zooming */ GLint row; for (row = 0; row < drawHeight; row++) { span.x = destX; span.y = destY; span.end = drawWidth; span.array->ChanType = rbType; _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src); src += srcStride; destY++; } span.array->ChanType = CHAN_TYPE; } return GL_TRUE; } /* Remaining cases haven't been tested with alignment != 1 */ if (userUnpack->Alignment != 1) return GL_FALSE; if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) { const GLchan *src = (const GLchan *) pixels + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels); if (simpleZoom) { /* no zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { GLchan rgb[MAX_WIDTH][3]; GLint i; for (i = 0;i<drawWidth;i++) { rgb[i][0] = src[i]; rgb[i][1] = src[i]; rgb[i][2] = src[i]; } rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, rgb, NULL); src += unpack.RowLength; destY += yStep; } } else { /* with zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { GLchan rgb[MAX_WIDTH][3]; GLint i; for (i = 0;i<drawWidth;i++) { rgb[i][0] = src[i]; rgb[i][1] = src[i]; rgb[i][2] = src[i]; } span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, rgb); src += unpack.RowLength; destY++; } } return GL_TRUE; } if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE && rbType == CHAN_TYPE) { const GLchan *src = (const GLchan *) pixels + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels)*2; if (simpleZoom) { GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { GLint i; const GLchan *ptr = src; for (i = 0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } rb->PutRow(ctx, rb, drawWidth, destX, destY, span.array->rgba, NULL); src += unpack.RowLength*2; destY += yStep; } } else { /* with zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { const GLchan *ptr = src; GLint i; for (i = 0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, span.array->rgba); src += unpack.RowLength*2; destY++; } } return GL_TRUE; } if (format == GL_COLOR_INDEX && type == GL_UNSIGNED_BYTE) { const GLubyte *src = (const GLubyte *) pixels + unpack.SkipRows * unpack.RowLength + unpack.SkipPixels; if (rbType == GL_UNSIGNED_BYTE) { /* convert ubyte/CI data to ubyte/RGBA */ if (simpleZoom) { GLint row; for (row = 0; row < drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, span.array->rgba8); rb->PutRow(ctx, rb, drawWidth, destX, destY, span.array->rgba8, NULL); src += unpack.RowLength; destY += yStep; } } else { /* ubyte/CI to ubyte/RGBA with zooming */ GLint row; for (row = 0; row < drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, span.array->rgba8); span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, span.array->rgba8); src += unpack.RowLength; destY++; } } return GL_TRUE; } } /* can't handle this pixel format and/or data type */ return GL_FALSE; }
/* * Try to do a fast and simple RGB(a) glDrawPixels. * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead */ static GLboolean fast_draw_pixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { SWcontext *swrast = SWRAST_CONTEXT(ctx); struct sw_span span; INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); if (!ctx->Current.RasterPosValid) { return GL_TRUE; /* no-op */ } if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (ctx->Fog.Enabled) _swrast_span_default_fog(ctx, &span); if (ctx->Texture._EnabledCoordUnits) _swrast_span_default_texcoords(ctx, &span); if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0 && ctx->Texture._EnabledCoordUnits == 0 && unpack->Alignment == 1 && !unpack->SwapBytes && !unpack->LsbFirst) { GLint destX = x; GLint destY = y; GLint drawWidth = width; /* actual width drawn */ GLint drawHeight = height; /* actual height drawn */ GLint skipPixels = unpack->SkipPixels; GLint skipRows = unpack->SkipRows; GLint rowLength; GLint zoomY0 = 0; if (unpack->RowLength > 0) rowLength = unpack->RowLength; else rowLength = width; /* If we're not using pixel zoom then do all clipping calculations * now. Otherwise, we'll let the _swrast_write_zoomed_*_span() functions * handle the clipping. */ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { /* horizontal clipping */ if (destX < ctx->DrawBuffer->_Xmin) { skipPixels += (ctx->DrawBuffer->_Xmin - destX); drawWidth -= (ctx->DrawBuffer->_Xmin - destX); destX = ctx->DrawBuffer->_Xmin; } if (destX + drawWidth > ctx->DrawBuffer->_Xmax) drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); if (drawWidth <= 0) return GL_TRUE; /* vertical clipping */ if (destY < ctx->DrawBuffer->_Ymin) { skipRows += (ctx->DrawBuffer->_Ymin - destY); drawHeight -= (ctx->DrawBuffer->_Ymin - destY); destY = ctx->DrawBuffer->_Ymin; } if (destY + drawHeight > ctx->DrawBuffer->_Ymax) drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax); if (drawHeight <= 0) return GL_TRUE; } else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { /* upside-down image */ /* horizontal clipping */ if (destX < ctx->DrawBuffer->_Xmin) { skipPixels += (ctx->DrawBuffer->_Xmin - destX); drawWidth -= (ctx->DrawBuffer->_Xmin - destX); destX = ctx->DrawBuffer->_Xmin; } if (destX + drawWidth > ctx->DrawBuffer->_Xmax) drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); if (drawWidth <= 0) return GL_TRUE; /* vertical clipping */ if (destY > ctx->DrawBuffer->_Ymax) { skipRows += (destY - ctx->DrawBuffer->_Ymax); drawHeight -= (destY - ctx->DrawBuffer->_Ymax); destY = ctx->DrawBuffer->_Ymax; } if (destY - drawHeight < ctx->DrawBuffer->_Ymin) drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight)); if (drawHeight <= 0) return GL_TRUE; } else { if (drawWidth > MAX_WIDTH) return GL_FALSE; /* fall back to general case path */ /* save Y value of first row */ zoomY0 = IROUND(ctx->Current.RasterPos[1]); } /* * Ready to draw! * The window region at (destX, destY) of size (drawWidth, drawHeight) * will be written to. * We'll take pixel data from buffer pointed to by "pixels" but we'll * skip "skipRows" rows and skip "skipPixels" pixels/row. */ if (format == GL_RGBA && type == CHAN_TYPE && ctx->_ImageTransferState==0) { if (ctx->Visual.rgbMode) { GLchan *src = (GLchan *) pixels + (skipRows * rowLength + skipPixels) * 4; if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { /* no zooming */ GLint row; for (row=0; row<drawHeight; row++) { (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[4]) src, NULL); src += rowLength * 4; destY++; } } else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { /* upside-down */ GLint row; for (row=0; row<drawHeight; row++) { destY--; (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[4]) src, NULL); src += rowLength * 4; } } else { /* with zooming */ GLint row; for (row=0; row<drawHeight; row++) { span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, &span, (CONST GLchan (*)[4]) src, zoomY0, 0); src += rowLength * 4; destY++; } } } return GL_TRUE; } else if (format == GL_RGB && type == CHAN_TYPE && ctx->_ImageTransferState == 0) { if (ctx->Visual.rgbMode) { GLchan *src = (GLchan *) pixels + (skipRows * rowLength + skipPixels) * 3; if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { GLint row; for (row=0; row<drawHeight; row++) { (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[3]) src, NULL); src += rowLength * 3; destY++; } } else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { /* upside-down */ GLint row; for (row=0; row<drawHeight; row++) { destY--; (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[3]) src, NULL); src += rowLength * 3; } } else { /* with zooming */ GLint row; for (row=0; row<drawHeight; row++) { span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgb_span(ctx, &span, (CONST GLchan (*)[3]) src, zoomY0, 0); src += rowLength * 3; destY++; } } } return GL_TRUE; } else if (format == GL_LUMINANCE && type == CHAN_TYPE && ctx->_ImageTransferState==0) { if (ctx->Visual.rgbMode) { GLchan *src = (GLchan *) pixels + (skipRows * rowLength + skipPixels); if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { /* no zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row=0; row<drawHeight; row++) { GLint i; for (i=0;i<drawWidth;i++) { span.array->rgb[i][0] = src[i]; span.array->rgb[i][1] = src[i]; span.array->rgb[i][2] = src[i]; } (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[3]) span.array->rgb, NULL); src += rowLength; destY++; } } else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { /* upside-down */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row=0; row<drawHeight; row++) { GLint i; for (i=0;i<drawWidth;i++) { span.array->rgb[i][0] = src[i]; span.array->rgb[i][1] = src[i]; span.array->rgb[i][2] = src[i]; } destY--; (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[3]) span.array->rgb, NULL); src += rowLength; } } else { /* with zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row=0; row<drawHeight; row++) { GLint i; for (i=0;i<drawWidth;i++) { span.array->rgb[i][0] = src[i]; span.array->rgb[i][1] = src[i]; span.array->rgb[i][2] = src[i]; } span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgb_span(ctx, &span, (CONST GLchan (*)[3]) span.array->rgb, zoomY0, 0); src += rowLength; destY++; } } } return GL_TRUE; } else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE && ctx->_ImageTransferState == 0) { if (ctx->Visual.rgbMode) { GLchan *src = (GLchan *) pixels + (skipRows * rowLength + skipPixels)*2; if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { /* no zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row=0; row<drawHeight; row++) { GLint i; GLchan *ptr = src; for (i=0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[4]) span.array->rgba, NULL); src += rowLength*2; destY++; } } else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { /* upside-down */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row=0; row<drawHeight; row++) { GLint i; GLchan *ptr = src; for (i=0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } destY--; (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[4]) span.array->rgba, NULL); src += rowLength*2; } } else { /* with zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row=0; row<drawHeight; row++) { GLchan *ptr = src; GLint i; for (i=0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, &span, (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0); src += rowLength*2; destY++; } } } return GL_TRUE; } else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) { GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels; if (ctx->Visual.rgbMode) { /* convert CI data to RGBA */ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { /* no zooming */ GLint row; for (row=0; row<drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba); (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, (const GLchan (*)[4]) span.array->rgba, NULL); src += rowLength; destY++; } return GL_TRUE; } else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { /* upside-down */ GLint row; for (row=0; row<drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba); destY--; (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, (CONST GLchan (*)[4]) span.array->rgba, NULL); src += rowLength; } return GL_TRUE; } else { /* with zooming */ GLint row; for (row=0; row<drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba); span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, &span, (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0); src += rowLength; destY++; } return GL_TRUE; } } else if (ctx->_ImageTransferState==0) { /* write CI data to CI frame buffer */ GLint row; if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { /* no zooming */ for (row=0; row<drawHeight; row++) { (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY, src, NULL); src += rowLength; destY++; } return GL_TRUE; } else { /* with zooming */ return GL_FALSE; } } } else { /* can't handle this pixel format and/or data type here */ return GL_FALSE; } } /* can't do a simple draw, have to use slow path */ return GL_FALSE; }