Exemple #1
0
static void
slow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
					GLint x, GLint y,
					GLsizei width, GLsizei height,
					GLenum type,
					const struct gl_pixelstore_attrib *packing,
					GLubyte *dst, int dstStride)
{
   struct gl_framebuffer *fb = ctx->ReadBuffer;
   struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
   GLubyte *depthMap, *stencilMap;
   int depthStride, stencilStride, j;

   /* The depth and stencil buffers might be separate, or a single buffer.
    * If one buffer, only map it once.
    */
   ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
			       GL_MAP_READ_BIT, &depthMap, &depthStride);
   if (!depthMap) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return;
   }

   if (stencilRb != depthRb) {
      ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
                                  GL_MAP_READ_BIT, &stencilMap,
                                  &stencilStride);
      if (!stencilMap) {
         ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
         return;
      }
   }
   else {
      stencilMap = depthMap;
      stencilStride = depthStride;
   }

   for (j = 0; j < height; j++) {
      GLubyte stencilVals[MAX_WIDTH];
      GLfloat depthVals[MAX_WIDTH];

      _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
      _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
				     stencilMap, stencilVals);

      _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
				    depthVals, stencilVals, packing);

      depthMap += depthStride;
      stencilMap += stencilStride;
      dst += dstStride;
   }

   ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
   if (stencilRb != depthRb) {
      ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
   }
}
Exemple #2
0
/**
 * Read pixels for format=GL_DEPTH_COMPONENT.
 */
static void
read_depth_pixels( struct gl_context *ctx,
                   GLint x, GLint y,
                   GLsizei width, GLsizei height,
                   GLenum type, GLvoid *pixels,
                   const struct gl_pixelstore_attrib *packing )
{
   struct gl_framebuffer *fb = ctx->ReadBuffer;
   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
   GLint j;
   GLubyte *dst, *map;
   int dstStride, stride;
   GLfloat *depthValues;

   if (!rb)
      return;

   /* clipping should have been done already */
   ASSERT(x >= 0);
   ASSERT(y >= 0);
   ASSERT(x + width <= (GLint) rb->Width);
   ASSERT(y + height <= (GLint) rb->Height);

   if (type == GL_UNSIGNED_INT &&
       read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) {
      return;
   }

   dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
					   GL_DEPTH_COMPONENT, type, 0, 0);

   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
			       &map, &stride);
   if (!map) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return;
   }

   depthValues = malloc(width * sizeof(GLfloat));

   if (depthValues) {
      /* General case (slower) */
      for (j = 0; j < height; j++, y++) {
         _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
         _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);

         dst += dstStride;
         map += stride;
      }
   }
   else {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
   }

   free(depthValues);

   ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
/**
 * glGetTexImage for depth/Z pixels.
 */
static void
get_tex_depth(struct gl_context *ctx, GLuint dimensions,
              GLenum format, GLenum type, GLvoid *pixels,
              struct gl_texture_image *texImage)
{
   const GLint width = texImage->Width;
   const GLint height = texImage->Height;
   const GLint depth = texImage->Depth;
   GLint img, row;
   GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));

   if (!depthRow) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
      return;
   }

   for (img = 0; img < depth; img++) {
      GLubyte *srcMap;
      GLint srcRowStride;

      /* map src texture buffer */
      ctx->Driver.MapTextureImage(ctx, texImage, img,
                                  0, 0, width, height, GL_MAP_READ_BIT,
                                  &srcMap, &srcRowStride);

      if (srcMap) {
         for (row = 0; row < height; row++) {
            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
                                             width, height, format, type,
                                             img, row, 0);
            const GLubyte *src = srcMap + row * srcRowStride;
            _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow);
            _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
         }

         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
      }
      else {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
         break;
      }
   }

   free(depthRow);
}
Exemple #4
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);
   }
}