Beispiel #1
0
/**
 * Write a span of stencil values to the stencil buffer.  This function
 * applies the stencil write mask when needed.
 * Used for glDraw/CopyPixels
 * Input:  n - how many pixels
 *         x, y - location of first pixel
 *         stencil - the array of stencil values
 */
void
_swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y,
                           const GLubyte stencil[] )
{
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
   const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1;
   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
   GLubyte *stencilBuf;

   if (y < 0 || y >= (GLint) rb->Height ||
       x + n <= 0 || x >= (GLint) rb->Width) {
      /* span is completely outside framebuffer */
      return; /* undefined values OK */
   }
   if (x < 0) {
      GLint dx = -x;
      x = 0;
      n -= dx;
      stencil += dx;
   }
   if (x + n > (GLint) rb->Width) {
      GLint dx = x + n - rb->Width;
      n -= dx;
   }
   if (n <= 0) {
      return;
   }

   stencilBuf = _swrast_pixel_address(rb, x, y);

   if ((stencilMask & stencilMax) != stencilMax) {
      /* need to apply writemask */
      GLubyte *destVals = swrast->stencil_temp.buf1;
      GLubyte *newVals = swrast->stencil_temp.buf2;
      GLint i;

      _mesa_unpack_ubyte_stencil_row(rb->Format, n, stencilBuf, destVals);
      for (i = 0; i < n; i++) {
         newVals[i]
            = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask);
      }
      _mesa_pack_ubyte_stencil_row(rb->Format, n, newVals, stencilBuf);
   }
   else {
      _mesa_pack_ubyte_stencil_row(rb->Format, n, stencil, stencilBuf);
   }
}
Beispiel #2
0
/**
 * Compute/return the offset of the stencil value in a pixel.
 * For example, if the format is Z24+S8, the position of the stencil bits
 * within the 4-byte pixel will be either 0 or 3.
 */
static GLint
get_stencil_offset(gl_format format)
{
   const GLubyte one = 1;
   GLubyte pixel[MAX_PIXEL_BYTES];
   GLint bpp = _mesa_get_format_bytes(format);
   GLint i;

   assert(_mesa_get_format_bits(format, GL_STENCIL_BITS) == 8);
   memset(pixel, 0, sizeof(pixel));
   _mesa_pack_ubyte_stencil_row(format, 1, &one, pixel);

   for (i = 0; i < bpp; i++) {
      if (pixel[i])
         return i;
   }

   _mesa_problem(NULL, "get_stencil_offset() failed\n");
   return 0;
}
Beispiel #3
0
/**
 * Blit color, depth or stencil with GL_NEAREST filtering.
 */
static void
blit_nearest(struct gl_context *ctx,
             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
             GLbitfield buffer)
{
   struct gl_renderbuffer *readRb, *drawRb;

   const GLint srcWidth = ABS(srcX1 - srcX0);
   const GLint dstWidth = ABS(dstX1 - dstX0);
   const GLint srcHeight = ABS(srcY1 - srcY0);
   const GLint dstHeight = ABS(dstY1 - dstY0);

   const GLint srcXpos = MIN2(srcX0, srcX1);
   const GLint srcYpos = MIN2(srcY0, srcY1);
   const GLint dstXpos = MIN2(dstX0, dstX1);
   const GLint dstYpos = MIN2(dstY0, dstY1);

   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
   enum mode {
      DIRECT,
      UNPACK_RGBA_FLOAT,
      UNPACK_Z_FLOAT,
      UNPACK_Z_INT,
      UNPACK_S,
   } mode;
   GLubyte *srcMap, *dstMap;
   GLint srcRowStride, dstRowStride;
   GLint dstRow;

   GLint pixelSize;
   GLvoid *srcBuffer, *dstBuffer;
   GLint prevY = -1;

   typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
                                 const GLvoid *srcBuffer, GLvoid *dstBuffer,
                                 GLboolean flip);
   resample_func resampleRow;

   switch (buffer) {
   case GL_COLOR_BUFFER_BIT:
      readRb = ctx->ReadBuffer->_ColorReadBuffer;
      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];

      if (readRb->Format == drawRb->Format) {
	 mode = DIRECT;
	 pixelSize = _mesa_get_format_bytes(readRb->Format);
      } else {
	 mode = UNPACK_RGBA_FLOAT;
	 pixelSize = 16;
      }

      break;
   case GL_DEPTH_BUFFER_BIT:
      readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
      drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;

      /* Note that for depth/stencil, the formats of src/dst must match.  By
       * using the core helpers for pack/unpack, we avoid needing to handle
       * masking for things like DEPTH copies of Z24S8.
       */
      if (readRb->Format == MESA_FORMAT_Z32_FLOAT ||
	  readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) {
	 mode = UNPACK_Z_FLOAT;
      } else {
	 mode = UNPACK_Z_INT;
      }
      pixelSize = 4;
      break;
   case GL_STENCIL_BUFFER_BIT:
      readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
      drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
      mode = UNPACK_S;
      pixelSize = 1;
      break;
   default:
      _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
      return;
   }

   /* choose row resampler */
   switch (pixelSize) {
   case 1:
      resampleRow = resample_row_1;
      break;
   case 2:
      resampleRow = resample_row_2;
      break;
   case 4:
      resampleRow = resample_row_4;
      break;
   case 8:
      resampleRow = resample_row_8;
      break;
   case 16:
      resampleRow = resample_row_16;
      break;
   default:
      _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
                    pixelSize);
      return;
   }

   if (readRb == drawRb) {
      /* map whole buffer for read/write */
      /* XXX we could be clever and just map the union region of the
       * source and dest rects.
       */
      GLubyte *map;
      GLint rowStride;
      GLint formatSize = _mesa_get_format_bytes(readRb->Format);

      ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
                                  readRb->Width, readRb->Height,
                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
                                  &map, &rowStride);
      if (!map) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
         return;
      }

      srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
      dstMap = map + dstYpos * rowStride + dstXpos * formatSize;

      /* this handles overlapping copies */
      if (srcY0 < dstY0) {
         /* copy in reverse (top->down) order */
         srcMap += rowStride * (readRb->Height - 1);
         dstMap += rowStride * (readRb->Height - 1);
         srcRowStride = -rowStride;
         dstRowStride = -rowStride;
      }
      else {
         /* copy in normal (bottom->up) order */
         srcRowStride = rowStride;
         dstRowStride = rowStride;
      }
   }
   else {
      /* different src/dst buffers */
      ctx->Driver.MapRenderbuffer(ctx, readRb,
				  srcXpos, srcYpos,
                                  srcWidth, srcHeight,
                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
      if (!srcMap) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
         return;
      }
      ctx->Driver.MapRenderbuffer(ctx, drawRb,
				  dstXpos, dstYpos,
                                  dstWidth, dstHeight,
                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
      if (!dstMap) {
         ctx->Driver.UnmapRenderbuffer(ctx, readRb);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
         return;
      }
   }

   /* allocate the src/dst row buffers */
   srcBuffer = malloc(pixelSize * srcWidth);
   if (!srcBuffer) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }
   dstBuffer = malloc(pixelSize * dstWidth);
   if (!dstBuffer) {
      free(srcBuffer);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }

   for (dstRow = 0; dstRow < dstHeight; dstRow++) {
      GLint srcRow = (dstRow * srcHeight) / dstHeight;
      GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;

      ASSERT(srcRow >= 0);
      ASSERT(srcRow < srcHeight);

      if (invertY) {
         srcRow = srcHeight - 1 - srcRow;
      }

      /* get pixel row from source and resample to match dest width */
      if (prevY != srcRow) {
	 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;

	 switch (mode) {
	 case DIRECT:
	    memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
	    break;
	 case UNPACK_RGBA_FLOAT:
	    _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
				  srcBuffer);
	    break;
	 case UNPACK_Z_FLOAT:
	    _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
				     srcBuffer);
	    break;
	 case UNPACK_Z_INT:
	    _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
				    srcBuffer);
	    break;
	 case UNPACK_S:
	    _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
					   srcRowStart, srcBuffer);
	    break;
	 }

         (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
         prevY = srcRow;
      }

      /* store pixel row in destination */
      switch (mode) {
      case DIRECT:
	 memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth);
	 break;
      case UNPACK_RGBA_FLOAT:
	 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
				   dstRowStart);
	 break;
      case UNPACK_Z_FLOAT:
	 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
				dstRowStart);
	 break;
      case UNPACK_Z_INT:
	 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
			       dstRowStart);
	 break;
      case UNPACK_S:
	 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
				      dstRowStart);
	 break;
      }
   }

   free(srcBuffer);
   free(dstBuffer);

   ctx->Driver.UnmapRenderbuffer(ctx, readRb);
   if (drawRb != readRb) {
      ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
   }
}