/** * Apply all the per-fragment operations to a span. * This now includes texturing (_swrast_write_texture_span() is history). * This function may modify any of the array values in the span. * span->interpMask and span->arrayMask may be changed but will be restored * to their original values before returning. */ void _swrast_write_rgba_span( struct gl_context *ctx, SWspan *span) { const SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLuint colorMask = *((GLuint *)ctx->Color.ColorMask); const GLbitfield origInterpMask = span->interpMask; const GLbitfield origArrayMask = span->arrayMask; const GLbitfield64 origArrayAttribs = span->arrayAttribs; const GLenum origChanType = span->array->ChanType; void * const origRgba = span->array->rgba; const GLboolean texture = ctx->Texture._EnabledCoord; struct gl_framebuffer *fb = ctx->DrawBuffer; /* printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask); */ ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE || span->primitive == GL_POLYGON || span->primitive == GL_BITMAP); /* Fragment write masks */ if (span->arrayMask & SPAN_MASK) { /* mask was initialized by caller, probably glBitmap */ span->writeAll = GL_FALSE; } else { memset(span->array->mask, 1, span->end); span->writeAll = GL_TRUE; } /* Clip to window/scissor box */ if (!clip_span(ctx, span)) { return; } ASSERT(span->end <= MAX_WIDTH); /* Depth bounds test */ if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) { if (!_swrast_depth_bounds_test(ctx, span)) { return; } } #ifdef DEBUG /* Make sure all fragments are within window bounds */ if (span->arrayMask & SPAN_XY) { /* array of pixel locations */ GLuint i; for (i = 0; i < span->end; i++) { if (span->array->mask[i]) { assert(span->array->x[i] >= fb->_Xmin); assert(span->array->x[i] < fb->_Xmax); assert(span->array->y[i] >= fb->_Ymin); assert(span->array->y[i] < fb->_Ymax); } } } #endif /* Polygon Stippling */ if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { stipple_polygon_span(ctx, span); } /* This is the normal place to compute the fragment color/Z * from texturing or shading. */ if (texture && !swrast->_DeferredTexture) { shade_texture_span(ctx, span); } /* Do the alpha test */ if (ctx->Color.AlphaEnabled) { if (!_swrast_alpha_test(ctx, span)) { /* all fragments failed test */ goto end; } } /* Stencil and Z testing */ if (ctx->Stencil._Enabled || ctx->Depth.Test) { if (!(span->arrayMask & SPAN_Z)) _swrast_span_interpolate_z(ctx, span); if (ctx->Stencil._Enabled) { /* Combined Z/stencil tests */ if (!_swrast_stencil_and_ztest_span(ctx, span)) { /* all fragments failed test */ goto end; } } else if (fb->Visual.depthBits > 0) { /* Just regular depth testing */ ASSERT(ctx->Depth.Test); ASSERT(span->arrayMask & SPAN_Z); if (!_swrast_depth_test_span(ctx, span)) { /* all fragments failed test */ goto end; } } } /* We had to wait until now to check for glColorMask(0,0,0,0) because of * the occlusion test. */ if (colorMask == 0) { /* no colors to write */ goto end; } /* If we were able to defer fragment color computation to now, there's * a good chance that many fragments will have already been killed by * Z/stencil testing. */ if (texture && swrast->_DeferredTexture) { shade_texture_span(ctx, span); } #if CHAN_BITS == 32 if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) { interpolate_active_attribs(ctx, span, FRAG_BIT_COL0); } #else if ((span->arrayMask & SPAN_RGBA) == 0) { interpolate_int_colors(ctx, span); } #endif ASSERT(span->arrayMask & SPAN_RGBA); /* Fog */ if (swrast->_FogEnabled) { _swrast_fog_rgba_span(ctx, span); } /* Antialias coverage application */ if (span->arrayMask & SPAN_COVERAGE) { apply_aa_coverage(span); } /* * Write to renderbuffers. * Depending on glDrawBuffer() state and the which color outputs are * written by the fragment shader, we may either replicate one color to * all renderbuffers or write a different color to each renderbuffer. * multiFragOutputs=TRUE for the later case. */ { struct gl_renderbuffer *rb = fb->_ColorDrawBuffer; /* color[fragOutput] will be written to buffer */ if (rb) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); GLenum colorType = srb->ColorType; assert(colorType == GL_UNSIGNED_BYTE || colorType == GL_FLOAT); /* set span->array->rgba to colors for renderbuffer's datatype */ if (span->array->ChanType != colorType) { convert_color_type(span, colorType, 0); } else { if (span->array->ChanType == GL_UNSIGNED_BYTE) { span->array->rgba = span->array->rgba8; } else { span->array->rgba = (void *)span->array->attribs[FRAG_ATTRIB_COL]; } } ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RED || rb->_BaseFormat == GL_RG || rb->_BaseFormat == GL_ALPHA); if (ctx->Color.ColorLogicOpEnabled) { _swrast_logicop_rgba_span(ctx, rb, span); } else if (ctx->Color.BlendEnabled) { _swrast_blend_span(ctx, rb, span); } if (colorMask != 0xffffffff) { _swrast_mask_rgba_span(ctx, rb, span); } if (span->arrayMask & SPAN_XY) { /* array of pixel coords */ put_values(ctx, rb, span->array->ChanType, span->end, span->array->x, span->array->y, span->array->rgba, span->array->mask); } else { /* horizontal run of pixels */ _swrast_put_row(ctx, rb, span->array->ChanType, span->end, span->x, span->y, span->array->rgba, span->writeAll ? NULL: span->array->mask); } } /* if rb */ } end: /* restore these values before returning */ span->interpMask = origInterpMask; span->arrayMask = origArrayMask; span->arrayAttribs = origArrayAttribs; span->array->ChanType = origChanType; span->array->rgba = origRgba; }
/** * This isn't terribly efficient. If a driver really has combined * depth/stencil buffers the driver should implement an optimized * CopyPixels function. */ static void copy_depth_stencil_pixels(GLcontext *ctx, const GLint srcX, const GLint srcY, const GLint width, const GLint height, const GLint destX, const GLint destY) { struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb; GLint sy, dy, stepy; GLint j; GLstencil *tempStencilImage = NULL, *stencilPtr = NULL; GLfloat *tempDepthImage = NULL, *depthPtr = NULL; const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF; const GLuint stencilMask = ctx->Stencil.WriteMask[0]; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; const GLboolean shiftOrOffset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; const GLboolean scaleOrBias = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; GLint overlapping; depthDrawRb = ctx->DrawBuffer->_DepthBuffer; depthReadRb = ctx->ReadBuffer->_DepthBuffer; stencilReadRb = ctx->ReadBuffer->_StencilBuffer; ASSERT(depthDrawRb); ASSERT(depthReadRb); ASSERT(stencilReadRb); /* Determine if copy should be bottom-to-top or top-to-bottom */ if (srcY < destY) { /* top-down max-to-min */ sy = srcY + height - 1; dy = destY + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcY; dy = destY; stepy = 1; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcX, srcY, destX, destY, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } if (overlapping) { GLint ssy = sy; if (stencilMask != 0x0) { tempStencilImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); if (!tempStencilImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } /* get copy of stencil pixels */ stencilPtr = tempStencilImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_stencil_span(ctx, stencilReadRb, width, srcX, ssy, stencilPtr); stencilPtr += width; } stencilPtr = tempStencilImage; } if (ctx->Depth.Mask) { tempDepthImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); if (!tempDepthImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); _mesa_free(tempStencilImage); return; } /* get copy of depth pixels */ depthPtr = tempDepthImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_depth_span_float(ctx, depthReadRb, width, srcX, ssy, depthPtr); depthPtr += width; } depthPtr = tempDepthImage; } } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { if (stencilMask != 0x0) { GLstencil stencil[MAX_WIDTH]; /* Get stencil values */ if (overlapping) { _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil)); stencilPtr += width; } else { _swrast_read_stencil_span(ctx, stencilReadRb, width, srcX, sy, stencil); } /* Apply shift, offset, look-up table */ if (shiftOrOffset) { _mesa_shift_and_offset_stencil(ctx, width, stencil); } if (ctx->Pixel.MapStencilFlag) { _mesa_map_stencil(ctx, width, stencil); } /* Write values */ if (zoom) { _swrast_write_zoomed_stencil_span(ctx, destX, destY, width, destX, dy, stencil); } else { _swrast_write_stencil_span( ctx, width, destX, dy, stencil ); } } if (ctx->Depth.Mask) { GLfloat depth[MAX_WIDTH]; GLuint zVals32[MAX_WIDTH]; GLushort zVals16[MAX_WIDTH]; GLvoid *zVals; GLuint zBytes; /* get depth values */ if (overlapping) { _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat)); depthPtr += width; } else { _swrast_read_depth_span_float(ctx, depthReadRb, width, srcX, sy, depth); } /* scale & bias */ if (scaleOrBias) { _mesa_scale_and_bias_depth(ctx, width, depth); } /* convert to integer Z values */ if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) { GLint k; for (k = 0; k < width; k++) zVals16[k] = (GLushort) (depth[k] * depthScale); zVals = zVals16; zBytes = 2; } else { GLint k; for (k = 0; k < width; k++) zVals32[k] = (GLuint) (depth[k] * depthScale); zVals = zVals32; zBytes = 4; } /* Write values */ if (zoom) { _swrast_write_zoomed_z_span(ctx, destX, destY, width, destX, dy, zVals); } else { _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes); } } } if (tempStencilImage) _mesa_free(tempStencilImage); if (tempDepthImage) _mesa_free(tempDepthImage); }