Пример #1
0
static GLboolean
readpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum type,
                          const struct gl_pixelstore_attrib *packing)
{
   struct gl_renderbuffer *rb =
         _mesa_get_read_renderbuffer_for_format(ctx, format);

   ASSERT(rb);

   if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_FALSE)) {
      return GL_FALSE;
   }

   /* The base internal format and the base Mesa format must match. */
   if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) {
      return GL_FALSE;
   }

   /* The Mesa format must match the input format and type. */
   if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
                                             packing->SwapBytes)) {
      return GL_FALSE;
   }

   return GL_TRUE;
}
Пример #2
0
static GLboolean
fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
			      GLint x, GLint y,
			      GLsizei width, GLsizei height,
			      GLenum format, GLenum type,
			      GLvoid *pixels,
			      const struct gl_pixelstore_attrib *packing,
			      GLbitfield transferOps )
{
   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
   GLubyte *dst, *map;
   int dstStride, stride, j, texelBytes;

   if (!_mesa_format_matches_format_and_type(rb->Format, format, type))
      return GL_FALSE;

   /* check for things we can't handle here */
   if (packing->SwapBytes ||
       packing->LsbFirst) {
      return GL_FALSE;
   }

   dstStride = _mesa_image_row_stride(packing, width, format, type);
   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
					   format, 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 GL_TRUE;  /* don't bother trying the slow path */
   }

   texelBytes = _mesa_get_format_bytes(rb->Format);
   for (j = 0; j < height; j++) {
      memcpy(dst, map, width * texelBytes);
      dst += dstStride;
      map += stride;
   }

   ctx->Driver.UnmapRenderbuffer(ctx, rb);

   return GL_TRUE;
}
Пример #3
0
GLboolean
_mesa_texstore_can_use_memcpy(struct gl_context *ctx,
                              GLenum baseInternalFormat, mesa_format dstFormat,
                              GLenum srcFormat, GLenum srcType,
                              const struct gl_pixelstore_attrib *srcPacking)
{
   if (_mesa_texstore_needs_transfer_ops(ctx, baseInternalFormat, dstFormat)) {
      return GL_FALSE;
   }

   /* The base internal format and the base Mesa format must match. */
   if (baseInternalFormat != _mesa_get_format_base_format(dstFormat)) {
      return GL_FALSE;
   }

   /* The Mesa format must match the input format and type. */
   if (!_mesa_format_matches_format_and_type(dstFormat, srcFormat, srcType,
                                             srcPacking->SwapBytes)) {
      return GL_FALSE;
   }

   /* Depth texture data needs clamping in following cases:
    * - Floating point dstFormat with signed srcType: clamp to [0.0, 1.0].
    * - Fixed point dstFormat with signed srcType: clamp to [0, 2^n -1].
    *
    * All the cases except one (float dstFormat with float srcType) are ruled
    * out by _mesa_format_matches_format_and_type() check above. Handle the
    * remaining case here.
    */
   if ((baseInternalFormat == GL_DEPTH_COMPONENT ||
        baseInternalFormat == GL_DEPTH_STENCIL) &&
       (srcType == GL_FLOAT ||
        srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV)) {
      return GL_FALSE;
   }

   return GL_TRUE;
}
Пример #4
0
/**
 * This uses a blit to copy the read buffer to a texture format which matches
 * the format and type combo and then a fast read-back is done using memcpy.
 * We can do arbitrary X/Y/Z/W/0/1 swizzling here as long as there is
 * a format which matches the swizzling.
 *
 * If such a format isn't available, we fall back to _mesa_readpixels.
 *
 * NOTE: Some drivers use a blit to convert between tiled and linear
 *       texture layouts during texture uploads/downloads, so the blit
 *       we do here should be free in such cases.
 */
static void
st_readpixels(struct gl_context *ctx, GLint x, GLint y,
              GLsizei width, GLsizei height,
              GLenum format, GLenum type,
              const struct gl_pixelstore_attrib *pack,
              GLvoid *pixels)
{
   struct st_context *st = st_context(ctx);
   struct gl_renderbuffer *rb =
         _mesa_get_read_renderbuffer_for_format(ctx, format);
   struct st_renderbuffer *strb = st_renderbuffer(rb);
   struct pipe_context *pipe = st->pipe;
   struct pipe_screen *screen = pipe->screen;
   struct pipe_resource *src;
   struct pipe_resource *dst = NULL;
   struct pipe_resource dst_templ;
   enum pipe_format dst_format, src_format;
   struct pipe_blit_info blit;
   unsigned bind = PIPE_BIND_TRANSFER_READ;
   struct pipe_transfer *tex_xfer;
   ubyte *map = NULL;

   /* Validate state (to be sure we have up-to-date framebuffer surfaces)
    * and flush the bitmap cache prior to reading. */
   st_validate_state(st);
   st_flush_bitmap_cache(st);

   if (!st->prefer_blit_based_texture_transfer) {
      goto fallback;
   }

   /* This must be done after state validation. */
   src = strb->texture;

   /* XXX Fallback for depth-stencil formats due to an incomplete
    * stencil blit implementation in some drivers. */
   if (format == GL_DEPTH_STENCIL) {
      goto fallback;
   }

   /* We are creating a texture of the size of the region being read back.
    * Need to check for NPOT texture support. */
   if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) &&
       (!util_is_power_of_two(width) ||
        !util_is_power_of_two(height))) {
      goto fallback;
   }

   /* If the base internal format and the texture format don't match, we have
    * to use the slow path. */
   if (rb->_BaseFormat !=
       _mesa_get_format_base_format(rb->Format)) {
      goto fallback;
   }

   /* See if the texture format already matches the format and type,
    * in which case the memcpy-based fast path will likely be used and
    * we don't have to blit. */
   if (_mesa_format_matches_format_and_type(rb->Format, format,
                                            type, pack->SwapBytes)) {
      goto fallback;
   }

   if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) {
      goto fallback;
   }

   /* Convert the source format to what is expected by ReadPixels
    * and see if it's supported. */
   src_format = util_format_linear(src->format);
   src_format = util_format_luminance_to_red(src_format);
   src_format = util_format_intensity_to_red(src_format);

   if (!src_format ||
       !screen->is_format_supported(screen, src_format, src->target,
                                    src->nr_samples,
                                    PIPE_BIND_SAMPLER_VIEW)) {
      goto fallback;
   }

   if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)
      bind |= PIPE_BIND_DEPTH_STENCIL;
   else
      bind |= PIPE_BIND_RENDER_TARGET;

   /* Choose the destination format by finding the best match
    * for the format+type combo. */
   dst_format = st_choose_matching_format(screen, bind, format, type,
                                          pack->SwapBytes);
   if (dst_format == PIPE_FORMAT_NONE) {
      goto fallback;
   }

   /* create the destination texture */
   memset(&dst_templ, 0, sizeof(dst_templ));
   dst_templ.target = PIPE_TEXTURE_2D;
   dst_templ.format = dst_format;
   dst_templ.bind = bind;
   dst_templ.usage = PIPE_USAGE_STAGING;

   st_gl_texture_dims_to_pipe_dims(GL_TEXTURE_2D, width, height, 1,
                                   &dst_templ.width0, &dst_templ.height0,
                                   &dst_templ.depth0, &dst_templ.array_size);

   dst = screen->resource_create(screen, &dst_templ);
   if (!dst) {
      goto fallback;
   }

   memset(&blit, 0, sizeof(blit));
   blit.src.resource = src;
   blit.src.level = strb->surface->u.tex.level;
   blit.src.format = src_format;
   blit.dst.resource = dst;
   blit.dst.level = 0;
   blit.dst.format = dst->format;
   blit.src.box.x = x;
   blit.dst.box.x = 0;
   blit.src.box.y = y;
   blit.dst.box.y = 0;
   blit.src.box.z = strb->surface->u.tex.first_layer;
   blit.dst.box.z = 0;
   blit.src.box.width = blit.dst.box.width = width;
   blit.src.box.height = blit.dst.box.height = height;
   blit.src.box.depth = blit.dst.box.depth = 1;
   blit.mask = st_get_blit_mask(rb->_BaseFormat, format);
   blit.filter = PIPE_TEX_FILTER_NEAREST;
   blit.scissor_enable = FALSE;

   if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
      blit.src.box.y = rb->Height - blit.src.box.y;
      blit.src.box.height = -blit.src.box.height;
   }

   /* blit */
   st->pipe->blit(st->pipe, &blit);

   /* map resources */
   pixels = _mesa_map_pbo_dest(ctx, pack, pixels);

   map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_TRANSFER_READ,
                              0, 0, 0, width, height, 1, &tex_xfer);
   if (!map) {
      _mesa_unmap_pbo_dest(ctx, pack);
      pipe_resource_reference(&dst, NULL);
      goto fallback;
   }

   /* memcpy data into a user buffer */
   {
      const uint bytesPerRow = width * util_format_get_blocksize(dst_format);
      GLuint row;

      for (row = 0; row < (unsigned) height; row++) {
         GLvoid *dest = _mesa_image_address3d(pack, pixels,
                                              width, height, format,
                                              type, 0, row, 0);
         memcpy(dest, map, bytesPerRow);
         map += tex_xfer->stride;
      }
   }

   pipe_transfer_unmap(pipe, tex_xfer);
   _mesa_unmap_pbo_dest(ctx, pack);
   pipe_resource_reference(&dst, NULL);
   return;

fallback:
   _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels);
}
Пример #5
0
/* XXX: Do this for TexSubImage also:
 */
static bool
try_pbo_upload(struct gl_context *ctx,
               struct gl_texture_image *image,
               const struct gl_pixelstore_attrib *unpack,
	       GLenum format, GLenum type, const void *pixels)
{
   struct intel_texture_image *intelImage = intel_texture_image(image);
   struct intel_context *intel = intel_context(ctx);
   struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
   GLuint src_offset;
   drm_intel_bo *src_buffer;

   if (!_mesa_is_bufferobj(unpack->BufferObj))
      return false;

   DBG("trying pbo upload\n");

   if (intel->ctx._ImageTransferState ||
       unpack->SkipPixels || unpack->SkipRows) {
      DBG("%s: image transfer\n", __FUNCTION__);
      return false;
   }

   ctx->Driver.AllocTextureImageBuffer(ctx, image);

   if (!intelImage->mt) {
      DBG("%s: no miptree\n", __FUNCTION__);
      return false;
   }

   if (!_mesa_format_matches_format_and_type(intelImage->mt->format,
                                             format, type, false)) {
      DBG("%s: format mismatch (upload to %s with format 0x%x, type 0x%x)\n",
	  __FUNCTION__, _mesa_get_format_name(intelImage->mt->format),
	  format, type);
      return false;
   }

   if (image->TexObject->Target == GL_TEXTURE_1D_ARRAY ||
       image->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
      DBG("%s: no support for array textures\n", __FUNCTION__);
      return false;
   }

   src_buffer = intel_bufferobj_source(intel, pbo, 64, &src_offset);
   /* note: potential 64-bit ptr to 32-bit int cast */
   src_offset += (GLuint) (unsigned long) pixels;

   int src_stride =
      _mesa_image_row_stride(unpack, image->Width, format, type);

   struct intel_mipmap_tree *pbo_mt =
      intel_miptree_create_for_bo(intel,
                                  src_buffer,
                                  intelImage->mt->format,
                                  src_offset,
                                  image->Width, image->Height,
                                  src_stride, I915_TILING_NONE);
   if (!pbo_mt)
      return false;

   if (!intel_miptree_blit(intel,
                           pbo_mt, 0, 0,
                           0, 0, false,
                           intelImage->mt, image->Level, image->Face,
                           0, 0, false,
                           image->Width, image->Height, GL_COPY)) {
      DBG("%s: blit failed\n", __FUNCTION__);
      intel_miptree_release(&pbo_mt);
      return false;
   }

   intel_miptree_release(&pbo_mt);

   DBG("%s: success\n", __FUNCTION__);
   return true;
}
Пример #6
0
/**
 * 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)
{
   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   struct gl_pixelstore_attrib unpack;

   if (!rb)
      return GL_TRUE; /* no-op */

   if (ctx->DrawBuffer->_NumColorDrawBuffers > 1 ||
       (swrast->_RasterMask & ~CLIP_BIT) ||
       ctx->Texture._EnabledCoordUnits ||
       userUnpack->SwapBytes ||
       ctx->Pixel.ZoomX != 1.0f ||
       fabsf(ctx->Pixel.ZoomY) != 1.0f ||
       ctx->_ImageTransferState) {
      /* can't handle any of those conditions */
      return GL_FALSE;
   }

   unpack = *userUnpack;

   /* clipping */
   if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, &unpack)) {
      /* image was completely clipped: no-op, all done */
      return GL_TRUE;
   }

   if (format == GL_RGB &&
       type == GL_UNSIGNED_BYTE &&
       (rb->Format == MESA_FORMAT_XRGB8888 ||
        rb->Format == MESA_FORMAT_ARGB8888)) {
      fast_draw_rgb_ubyte_pixels(ctx, rb, x, y, width, height,
                                 &unpack, pixels);
      return GL_TRUE;
   }

   if (format == GL_RGBA &&
       type == GL_UNSIGNED_BYTE &&
       (rb->Format == MESA_FORMAT_XRGB8888 ||
        rb->Format == MESA_FORMAT_ARGB8888)) {
      fast_draw_rgba_ubyte_pixels(ctx, rb, x, y, width, height,
                                  &unpack, pixels);
      return GL_TRUE;
   }

   if (_mesa_format_matches_format_and_type(rb->Format, format, type,
                                            ctx->Unpack.SwapBytes)) {
      fast_draw_generic_pixels(ctx, rb, x, y, width, height,
                               format, type, &unpack, pixels);
      return GL_TRUE;
   }

   /* can't handle this pixel format and/or data type */
   return GL_FALSE;
}
static bool
do_blit_drawpixels(struct gl_context * ctx,
		   GLint x, GLint y, GLsizei width, GLsizei height,
		   GLenum format, GLenum type,
		   const struct gl_pixelstore_attrib *unpack,
		   const GLvoid * pixels)
{
   struct brw_context *brw = brw_context(ctx);
   struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj);
   GLuint src_offset;
   drm_intel_bo *src_buffer;

   DBG("%s\n", __FUNCTION__);

   if (!intel_check_blit_fragment_ops(ctx, false))
      return false;

   if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) {
      DBG("%s: fallback due to MRT\n", __FUNCTION__);
      return false;
   }

   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);

   if (!_mesa_format_matches_format_and_type(irb->mt->format, format, type,
                                             false)) {
      DBG("%s: bad format for blit\n", __FUNCTION__);
      return false;
   }

   if (unpack->SwapBytes || unpack->LsbFirst ||
       unpack->SkipPixels || unpack->SkipRows) {
      DBG("%s: bad packing params\n", __FUNCTION__);
      return false;
   }

   int src_stride = _mesa_image_row_stride(unpack, width, format, type);
   bool src_flip = false;
   /* Mesa flips the src_stride for unpack->Invert, but we want our mt to have
    * a normal src_stride.
    */
   if (unpack->Invert) {
      src_stride = -src_stride;
      src_flip = true;
   }

   src_offset = (GLintptr)pixels;
   src_offset += _mesa_image_offset(2, unpack, width, height,
				    format, type, 0, 0, 0);

   intel_prepare_render(brw);

   src_buffer = intel_bufferobj_buffer(brw, src,
				       src_offset, width * height *
                                       irb->mt->cpp);

   struct intel_mipmap_tree *pbo_mt =
      intel_miptree_create_for_bo(brw,
                                  src_buffer,
                                  irb->mt->format,
                                  src_offset,
                                  width, height,
                                  src_stride, I915_TILING_NONE);
   if (!pbo_mt)
      return false;

   if (!intel_miptree_blit(brw,
                           pbo_mt, 0, 0,
                           0, 0, src_flip,
                           irb->mt, irb->mt_level, irb->mt_layer,
                           x, y, _mesa_is_winsys_fbo(ctx->DrawBuffer),
                           width, height, GL_COPY)) {
      DBG("%s: blit failed\n", __FUNCTION__);
      intel_miptree_release(&pbo_mt);
      return false;
   }

   intel_miptree_release(&pbo_mt);

   if (ctx->Query.CurrentOcclusionObject)
      ctx->Query.CurrentOcclusionObject->Result += width * height;

   intel_check_front_buffer_rendering(brw);

   DBG("%s: success\n", __FUNCTION__);
   return true;
}
Пример #8
0
/* XXX: Do this for TexSubImage also:
 */
static bool
try_pbo_upload(struct gl_context *ctx,
               struct gl_texture_image *image,
               const struct gl_pixelstore_attrib *unpack,
	       GLenum format, GLenum type, const void *pixels)
{
   struct intel_texture_image *intelImage = intel_texture_image(image);
   struct intel_context *intel = intel_context(ctx);
   struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
   GLuint src_offset, src_stride;
   GLuint dst_x, dst_y;
   drm_intel_bo *dst_buffer, *src_buffer;

   if (!_mesa_is_bufferobj(unpack->BufferObj))
      return false;

   DBG("trying pbo upload\n");

   if (intel->ctx._ImageTransferState ||
       unpack->SkipPixels || unpack->SkipRows) {
      DBG("%s: image transfer\n", __FUNCTION__);
      return false;
   }

   if (!_mesa_format_matches_format_and_type(image->TexFormat,
                                             format, type, false)) {
      DBG("%s: format mismatch (upload to %s with format 0x%x, type 0x%x)\n",
	  __FUNCTION__, _mesa_get_format_name(image->TexFormat),
	  format, type);
      return false;
   }

   ctx->Driver.AllocTextureImageBuffer(ctx, image);

   if (!intelImage->mt) {
      DBG("%s: no miptree\n", __FUNCTION__);
      return false;
   }

   if (image->TexObject->Target == GL_TEXTURE_1D_ARRAY ||
       image->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
      DBG("%s: no support for array textures\n", __FUNCTION__);
      return false;
   }

   dst_buffer = intelImage->mt->region->bo;
   src_buffer = intel_bufferobj_source(intel, pbo, 64, &src_offset);
   /* note: potential 64-bit ptr to 32-bit int cast */
   src_offset += (GLuint) (unsigned long) pixels;

   if (unpack->RowLength > 0)
      src_stride = unpack->RowLength;
   else
      src_stride = image->Width;
   src_stride *= intelImage->mt->region->cpp;

   intel_miptree_get_image_offset(intelImage->mt, intelImage->base.Base.Level,
				  intelImage->base.Base.Face,
				  &dst_x, &dst_y);

   if (!intelEmitCopyBlit(intel,
			  intelImage->mt->cpp,
			  src_stride, src_buffer,
			  src_offset, false,
			  intelImage->mt->region->pitch, dst_buffer, 0,
			  intelImage->mt->region->tiling,
			  0, 0, dst_x, dst_y, image->Width, image->Height,
			  GL_COPY)) {
      DBG("%s: blit failed\n", __FUNCTION__);
      return false;
   }

   DBG("%s: success\n", __FUNCTION__);
   return true;
}
Пример #9
0
/**
 * glGetTexImage() helper: decompress a compressed texture by rendering
 * a textured quad.  Store the results in the user's buffer.
 */
static void
decompress_with_blit(struct gl_context * ctx,
                     GLenum format, GLenum type, GLvoid *pixels,
                     struct gl_texture_image *texImage)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;
   struct st_texture_image *stImage = st_texture_image(texImage);
   struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
   const GLuint width = texImage->Width;
   const GLuint height = texImage->Height;
   struct pipe_resource *dst_texture;
   struct pipe_blit_info blit;
   unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ);
   struct pipe_transfer *tex_xfer;
   ubyte *map;

   /* create temp / dest surface */
   if (!util_create_rgba_texture(pipe, width, height, bind,
                                 &dst_texture)) {
      _mesa_problem(ctx, "util_create_rgba_texture() failed "
                    "in decompress_with_blit()");
      return;
   }

   blit.src.resource = stObj->pt;
   blit.src.level = texImage->Level;
   blit.src.format = util_format_linear(stObj->pt->format);
   blit.dst.resource = dst_texture;
   blit.dst.level = 0;
   blit.dst.format = dst_texture->format;
   blit.src.box.x = blit.dst.box.x = 0;
   blit.src.box.y = blit.dst.box.y = 0;
   blit.src.box.z = 0; /* XXX compressed array textures? */
   blit.dst.box.z = 0;
   blit.src.box.width = blit.dst.box.width = width;
   blit.src.box.height = blit.dst.box.height = height;
   blit.src.box.depth = blit.dst.box.depth = 1;
   blit.mask = PIPE_MASK_RGBA;
   blit.filter = PIPE_TEX_FILTER_NEAREST;
   blit.scissor_enable = FALSE;

   /* blit/render/decompress */
   st->pipe->blit(st->pipe, &blit);

   pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);

   map = pipe_transfer_map(pipe, dst_texture, 0, 0,
                           PIPE_TRANSFER_READ,
                           0, 0, width, height, &tex_xfer);
   if (!map) {
      goto end;
   }

   /* copy/pack data into user buffer */
   if (_mesa_format_matches_format_and_type(stImage->base.TexFormat,
                                            format, type,
                                            ctx->Pack.SwapBytes)) {
      /* memcpy */
      const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format);
      /* map the dst_surface so we can read from it */
      GLuint row;
      for (row = 0; row < height; row++) {
         GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
                                              height, format, type, row, 0);
         memcpy(dest, map, bytesPerRow);
         map += tex_xfer->stride;
      }
      pipe_transfer_unmap(pipe, tex_xfer);
   }
   else {
      /* format translation via floats */
      GLuint row;
      enum pipe_format pformat = util_format_linear(dst_texture->format);
      GLfloat *rgba;

      rgba = malloc(width * 4 * sizeof(GLfloat));
      if (!rgba) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
         goto end;
      }

      for (row = 0; row < height; row++) {
         const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */
         GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
                                              height, format, type, row, 0);

         if (ST_DEBUG & DEBUG_FALLBACK)
            debug_printf("%s: fallback format translation\n", __FUNCTION__);

         /* get float[4] rgba row from surface */
         pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1,
                                   pformat, rgba);

         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
                                    type, dest, &ctx->Pack, transferOps);
      }

      free(rgba);
   }

end:
   if (map)
      pipe_transfer_unmap(pipe, tex_xfer);

   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
   pipe_resource_reference(&dst_texture, NULL);
}
Пример #10
0
/**
 * glGetTexImage() helper: decompress a compressed texture by rendering
 * a textured quad.  Store the results in the user's buffer.
 */
static void
decompress_with_blit(struct gl_context * ctx,
                     GLenum format, GLenum type, GLvoid *pixels,
                     struct gl_texture_image *texImage)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;
   struct st_texture_image *stImage = st_texture_image(texImage);
   struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
   struct pipe_sampler_view *src_view;
   const GLuint width = texImage->Width;
   const GLuint height = texImage->Height;
   struct pipe_surface *dst_surface;
   struct pipe_resource *dst_texture;
   struct pipe_transfer *tex_xfer;
   unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */
		    PIPE_BIND_TRANSFER_READ);

   /* create temp / dest surface */
   if (!util_create_rgba_surface(pipe, width, height, bind,
                                 &dst_texture, &dst_surface)) {
      _mesa_problem(ctx, "util_create_rgba_surface() failed "
                    "in decompress_with_blit()");
      return;
   }

   /* Disable conditional rendering. */
   if (st->render_condition) {
      pipe->render_condition(pipe, NULL, 0);
   }

   /* Create sampler view that limits fetches to the source mipmap level */
   {
      struct pipe_sampler_view sv_temp;

      u_sampler_view_default_template(&sv_temp, stObj->pt, stObj->pt->format);

      sv_temp.format = util_format_linear(sv_temp.format);
      sv_temp.u.tex.first_level =
      sv_temp.u.tex.last_level = texImage->Level;

      src_view = pipe->create_sampler_view(pipe, stObj->pt, &sv_temp);
      if (!src_view) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
         return;
      }
   }

   /* blit/render/decompress */
   util_blit_pixels_tex(st->blit,
                        src_view,      /* pipe_resource (src) */
                        0, 0,             /* src x0, y0 */
                        width, height,    /* src x1, y1 */
                        dst_surface,      /* pipe_surface (dst) */
                        0, 0,             /* dst x0, y0 */
                        width, height,    /* dst x1, y1 */
                        0.0,              /* z */
                        PIPE_TEX_MIPFILTER_NEAREST);

   /* Restore conditional rendering state. */
   if (st->render_condition) {
      pipe->render_condition(pipe, st->render_condition,
                             st->condition_mode);
   }

   /* map the dst_surface so we can read from it */
   tex_xfer = pipe_get_transfer(pipe,
                                dst_texture, 0, 0,
                                PIPE_TRANSFER_READ,
                                0, 0, width, height);

   pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);

   /* copy/pack data into user buffer */
   if (_mesa_format_matches_format_and_type(stImage->base.TexFormat,
                                            format, type,
                                            ctx->Pack.SwapBytes)) {
      /* memcpy */
      const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format);
      ubyte *map = pipe_transfer_map(pipe, tex_xfer);
      GLuint row;
      for (row = 0; row < height; row++) {
         GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
                                              height, format, type, row, 0);
         memcpy(dest, map, bytesPerRow);
         map += tex_xfer->stride;
      }
      pipe_transfer_unmap(pipe, tex_xfer);
   }
   else {
      /* format translation via floats */
      GLuint row;
      enum pipe_format pformat = util_format_linear(dst_texture->format);
      GLfloat *rgba;

      rgba = (GLfloat *) malloc(width * 4 * sizeof(GLfloat));
      if (!rgba) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
         goto end;
      }

      for (row = 0; row < height; row++) {
         const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */
         GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
                                              height, format, type, row, 0);

         if (ST_DEBUG & DEBUG_FALLBACK)
            debug_printf("%s: fallback format translation\n", __FUNCTION__);

         /* get float[4] rgba row from surface */
         pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1,
                                   pformat, rgba);

         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
                                    type, dest, &ctx->Pack, transferOps);
      }

      free(rgba);
   }

end:
   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);

   pipe->transfer_destroy(pipe, tex_xfer);

   /* destroy the temp / dest surface */
   util_destroy_rgba_surface(dst_texture, dst_surface);

   pipe_sampler_view_release(pipe, &src_view);
}
/**
 * Try to do glGetTexImage() with simple memcpy().
 * \return GL_TRUE if done, GL_FALSE otherwise
 */
static GLboolean
get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
               GLvoid *pixels,
               struct gl_texture_image *texImage)
{
   const GLenum target = texImage->TexObject->Target;
   GLboolean memCopy = GL_FALSE;

   /*
    * Check if we can use memcpy to copy from the hardware texture
    * format to the user's format/type.
    * Note that GL's pixel transfer ops don't apply to glGetTexImage()
    */
   if (target == GL_TEXTURE_1D ||
       target == GL_TEXTURE_2D ||
       target == GL_TEXTURE_RECTANGLE ||
       _mesa_is_cube_face(target)) {
      memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat,
                                                     format, type,
                                                     ctx->Pack.SwapBytes);
   }

   if (memCopy) {
      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
      const GLuint bytesPerRow = texImage->Width * bpp;
      GLubyte *dst =
         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
                               texImage->Height, format, type, 0, 0);
      const GLint dstRowStride =
         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
      GLubyte *src;
      GLint srcRowStride;

      /* map src texture buffer */
      ctx->Driver.MapTextureImage(ctx, texImage, 0,
                                  0, 0, texImage->Width, texImage->Height,
                                  GL_MAP_READ_BIT, &src, &srcRowStride);

      if (src) {
         if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
            memcpy(dst, src, bytesPerRow * texImage->Height);
         }
         else {
            GLuint row;
            for (row = 0; row < texImage->Height; row++) {
               memcpy(dst, src, bytesPerRow);
               dst += dstRowStride;
               src += srcRowStride;
            }
         }

         /* unmap src texture buffer */
         ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
      }
      else {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
      }
   }

   return memCopy;
}
Пример #12
0
static bool
do_blit_readpixels(struct gl_context * ctx,
                   GLint x, GLint y, GLsizei width, GLsizei height,
                   GLenum format, GLenum type,
                   const struct gl_pixelstore_attrib *pack, GLvoid * pixels)
{
   struct brw_context *brw = brw_context(ctx);
   struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj);
   GLuint dst_offset;
   drm_intel_bo *dst_buffer;
   GLint dst_x, dst_y;
   GLuint dirty;

   DBG("%s\n", __FUNCTION__);

   assert(_mesa_is_bufferobj(pack->BufferObj));

   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);

   if (ctx->_ImageTransferState ||
       !_mesa_format_matches_format_and_type(irb->mt->format, format, type,
                                             false)) {
      DBG("%s - bad format for blit\n", __FUNCTION__);
      return false;
   }

   if (pack->SwapBytes || pack->LsbFirst) {
      DBG("%s: bad packing params\n", __FUNCTION__);
      return false;
   }

   int dst_stride = _mesa_image_row_stride(pack, width, format, type);
   bool dst_flip = false;
   /* Mesa flips the dst_stride for pack->Invert, but we want our mt to have a
    * normal dst_stride.
    */
   struct gl_pixelstore_attrib uninverted_pack = *pack;
   if (pack->Invert) {
      dst_stride = -dst_stride;
      dst_flip = true;
      uninverted_pack.Invert = false;
   }

   dst_offset = (GLintptr)pixels;
   dst_offset += _mesa_image_offset(2, &uninverted_pack, width, height,
				    format, type, 0, 0, 0);

   if (!_mesa_clip_copytexsubimage(ctx,
				   &dst_x, &dst_y,
				   &x, &y,
				   &width, &height)) {
      return true;
   }

   dirty = brw->front_buffer_dirty;
   intel_prepare_render(brw);
   brw->front_buffer_dirty = dirty;

   dst_buffer = intel_bufferobj_buffer(brw, dst,
				       dst_offset, height * dst_stride);

   struct intel_mipmap_tree *pbo_mt =
      intel_miptree_create_for_bo(brw,
                                  dst_buffer,
                                  irb->mt->format,
                                  dst_offset,
                                  width, height,
                                  dst_stride, I915_TILING_NONE);

   if (!intel_miptree_blit(brw,
                           irb->mt, irb->mt_level, irb->mt_layer,
                           x, y, _mesa_is_winsys_fbo(ctx->ReadBuffer),
                           pbo_mt, 0, 0,
                           0, 0, dst_flip,
                           width, height, GL_COPY)) {
      return false;
   }

   intel_miptree_release(&pbo_mt);

   DBG("%s - DONE\n", __FUNCTION__);

   return true;
}