/**
 * Print framebuffer info to stderr, for debugging.
 */
void
_mesa_print_framebuffer(const struct gl_framebuffer *fb)
{
   GLuint i;

   fprintf(stderr, "Mesa Framebuffer %u at %p\n", fb->Name, (void *) fb);
   fprintf(stderr, "  Size: %u x %u  Status: %s\n", fb->Width, fb->Height,
           _mesa_enum_to_string(fb->_Status));
   fprintf(stderr, "  Attachments:\n");

   for (i = 0; i < BUFFER_COUNT; i++) {
      const struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
      if (att->Type == GL_TEXTURE) {
         const struct gl_texture_image *texImage = att->Renderbuffer->TexImage;
         fprintf(stderr,
                 "  %2d: Texture %u, level %u, face %u, slice %u, complete %d\n",
                 i, att->Texture->Name, att->TextureLevel, att->CubeMapFace,
                 att->Zoffset, att->Complete);
         fprintf(stderr, "       Size: %u x %u x %u  Format %s\n",
                 texImage->Width, texImage->Height, texImage->Depth,
                 _mesa_get_format_name(texImage->TexFormat));
      }
      else if (att->Type == GL_RENDERBUFFER) {
         fprintf(stderr, "  %2d: Renderbuffer %u, complete %d\n",
                 i, att->Renderbuffer->Name, att->Complete);
         fprintf(stderr, "       Size: %u x %u  Format %s\n",
                 att->Renderbuffer->Width, att->Renderbuffer->Height,
                 _mesa_get_format_name(att->Renderbuffer->Format));
      }
      else {
         fprintf(stderr, "  %2d: none\n", i);
      }
   }
}
static void
intel_miptree_copy_slice_sw(struct intel_context *intel,
                            struct intel_mipmap_tree *dst_mt,
                            struct intel_mipmap_tree *src_mt,
                            int level,
                            int slice,
                            int width,
                            int height)
{
    void *src, *dst;
    int src_stride, dst_stride;
    int cpp = dst_mt->cpp;

    intel_miptree_map(intel, src_mt,
                      level, slice,
                      0, 0,
                      width, height,
                      GL_MAP_READ_BIT,
                      &src, &src_stride);

    intel_miptree_map(intel, dst_mt,
                      level, slice,
                      0, 0,
                      width, height,
                      GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT,
                      &dst, &dst_stride);

    DBG("sw blit %s mt %p %p/%d -> %s mt %p %p/%d (%dx%d)\n",
        _mesa_get_format_name(src_mt->format),
        src_mt, src, src_stride,
        _mesa_get_format_name(dst_mt->format),
        dst_mt, dst, dst_stride,
        width, height);

    int row_size = cpp * width;
    if (src_stride == row_size &&
            dst_stride == row_size) {
        memcpy(dst, src, row_size * height);
    } else {
        for (int i = 0; i < height; i++) {
            memcpy(dst, src, row_size);
            dst += dst_stride;
            src += src_stride;
        }
    }

    intel_miptree_unmap(intel, dst_mt, level, slice);
    intel_miptree_unmap(intel, src_mt, level, slice);
}
static void
intel_miptree_copy_slice(struct intel_context *intel,
                         struct intel_mipmap_tree *dst_mt,
                         struct intel_mipmap_tree *src_mt,
                         int level,
                         int face,
                         int depth)

{
    mesa_format format = src_mt->format;
    uint32_t width = src_mt->level[level].width;
    uint32_t height = src_mt->level[level].height;
    int slice;

    if (face > 0)
        slice = face;
    else
        slice = depth;

    assert(depth < src_mt->level[level].depth);
    assert(src_mt->format == dst_mt->format);

    if (dst_mt->compressed) {
        height = ALIGN(height, dst_mt->align_h) / dst_mt->align_h;
        width = ALIGN(width, dst_mt->align_w);
    }

    uint32_t dst_x, dst_y, src_x, src_y;
    intel_miptree_get_image_offset(dst_mt, level, slice, &dst_x, &dst_y);
    intel_miptree_get_image_offset(src_mt, level, slice, &src_x, &src_y);

    DBG("validate blit mt %s %p %d,%d/%d -> mt %s %p %d,%d/%d (%dx%d)\n",
        _mesa_get_format_name(src_mt->format),
        src_mt, src_x, src_y, src_mt->region->pitch,
        _mesa_get_format_name(dst_mt->format),
        dst_mt, dst_x, dst_y, dst_mt->region->pitch,
        width, height);

    if (!intel_miptree_blit(intel,
                            src_mt, level, slice, 0, 0, false,
                            dst_mt, level, slice, 0, 0, false,
                            width, height, GL_COPY)) {
        perf_debug("miptree validate blit for %s failed\n",
                   _mesa_get_format_name(format));

        intel_miptree_copy_slice_sw(intel, dst_mt, src_mt, level, slice,
                                    width, height);
    }
}
Пример #4
0
static GLboolean
intel_alloc_private_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
                                         GLenum internalFormat,
                                         GLuint width, GLuint height)
{
   struct intel_context *intel = intel_context(ctx);
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);

   assert(rb->Format != MESA_FORMAT_NONE);

   rb->Width = width;
   rb->Height = height;
   rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);

   intel_miptree_release(&irb->mt);

   DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__,
       _mesa_lookup_enum_by_nr(internalFormat),
       _mesa_get_format_name(rb->Format), width, height);

   if (width == 0 || height == 0)
      return true;

   irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format,
						   width, height);
   if (!irb->mt)
      return false;

   return true;
}
Пример #5
0
/**
 * Called via glRenderbufferStorageEXT() to set the format and allocate
 * storage for a user-created renderbuffer.
 */
GLboolean
intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
                                 GLenum internalFormat,
                                 GLuint width, GLuint height)
{
    struct intel_context *intel = intel_context(ctx);
    struct intel_renderbuffer *irb = intel_renderbuffer(rb);

    ASSERT(rb->Name != 0);

    switch (internalFormat) {
    default:
        /* Use the same format-choice logic as for textures.
         * Renderbuffers aren't any different from textures for us,
         * except they're less useful because you can't texture with
         * them.
         */
        rb->Format = intel->ctx.Driver.ChooseTextureFormat(ctx, internalFormat,
                     GL_NONE, GL_NONE);
        break;
    case GL_STENCIL_INDEX:
    case GL_STENCIL_INDEX1_EXT:
    case GL_STENCIL_INDEX4_EXT:
    case GL_STENCIL_INDEX8_EXT:
    case GL_STENCIL_INDEX16_EXT:
        /* These aren't actual texture formats, so force them here. */
        if (intel->has_separate_stencil) {
            rb->Format = MESA_FORMAT_S8;
        } else {
            assert(!intel->must_use_separate_stencil);
            rb->Format = MESA_FORMAT_S8_Z24;
        }
        break;
    }

    rb->Width = width;
    rb->Height = height;
    rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);

    intel_miptree_release(&irb->mt);

    DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__,
        _mesa_lookup_enum_by_nr(internalFormat),
        _mesa_get_format_name(rb->Format), width, height);

    irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format,
              width, height);
    if (!irb->mt)
        return false;

    if (intel->vtbl.is_hiz_depth_format(intel, rb->Format)) {
        bool ok = intel_miptree_alloc_hiz(intel, irb->mt);
        if (!ok) {
            intel_miptree_release(&irb->mt);
            return false;
        }
    }

    return true;
}
Пример #6
0
/**
 * Apply depth (Z) buffer testing to the span.
 * \return approx number of pixels that passed (only zero is reliable)
 */
GLuint
_swrast_depth_test_span(struct gl_context *ctx, SWspan *span)
{
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
   const GLint bpp = _mesa_get_format_bytes(rb->Format);
   void *zStart;
   const GLuint count = span->end;
   const GLuint *fragZ = span->array->z;
   GLubyte *mask = span->array->mask;
   void *zBufferVals;
   GLuint *zBufferTemp = NULL;
   GLuint passed;
   GLuint zBits = _mesa_get_format_bits(rb->Format, GL_DEPTH_BITS);
   GLboolean ztest16 = GL_FALSE;

   if (span->arrayMask & SPAN_XY)
      zStart = NULL;
   else
      zStart = _swrast_pixel_address(rb, span->x, span->y);

   if (rb->Format == MESA_FORMAT_Z_UNORM16 && !(span->arrayMask & SPAN_XY)) {
      /* directly read/write row of 16-bit Z values */
      zBufferVals = zStart;
      ztest16 = GL_TRUE;
   }
   else if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) {
      /* directly read/write row of 32-bit Z values */
      zBufferVals = zStart;
   }
   else {
      if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) {
         _mesa_problem(ctx, "Incorrectly writing swrast's integer depth "
                       "values to %s depth buffer",
                       _mesa_get_format_name(rb->Format));
      }

      /* copy Z buffer values into temp buffer (32-bit Z values) */
      zBufferTemp = malloc(count * sizeof(GLuint));
      if (!zBufferTemp)
         return 0;

      if (span->arrayMask & SPAN_XY) {
         get_z32_values(ctx, rb, count,
                        span->array->x, span->array->y, zBufferTemp);
      }
      else {
         _mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp);
      }

      if (zBits == 24) {
         GLuint i;
         /* Convert depth buffer values from 32 to 24 bits to match the
          * fragment Z values generated by rasterization.
          */
         for (i = 0; i < count; i++) {
            zBufferTemp[i] >>= 8;
         }
      }
      else if (zBits == 16) {
Пример #7
0
void GLAPIENTRY
_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);

   if (getcompressedteximage_error_check(ctx, target, level, img)) {
      return;
   }

   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
      /* not an error, do nothing */
      return;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);

   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
      _mesa_debug(ctx,
                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
                  texObj->Name,
                  _mesa_get_format_name(texImage->TexFormat),
                  texImage->Width, texImage->Height);
   }

   _mesa_lock_texture(ctx, texObj);
   {
      ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
                                        texObj, texImage);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Пример #8
0
static GLuint
translate_texture_format(gl_format mesa_format, GLenum DepthMode)
{
   switch (mesa_format) {
   case MESA_FORMAT_L8:
      return MAPSURF_8BIT | MT_8BIT_L8;
   case MESA_FORMAT_I8:
      return MAPSURF_8BIT | MT_8BIT_I8;
   case MESA_FORMAT_A8:
      return MAPSURF_8BIT | MT_8BIT_A8;
   case MESA_FORMAT_AL88:
      return MAPSURF_16BIT | MT_16BIT_AY88;
   case MESA_FORMAT_RGB565:
      return MAPSURF_16BIT | MT_16BIT_RGB565;
   case MESA_FORMAT_ARGB1555:
      return MAPSURF_16BIT | MT_16BIT_ARGB1555;
   case MESA_FORMAT_ARGB4444:
      return MAPSURF_16BIT | MT_16BIT_ARGB4444;
   case MESA_FORMAT_ARGB8888:
      return MAPSURF_32BIT | MT_32BIT_ARGB8888;
   case MESA_FORMAT_XRGB8888:
      return MAPSURF_32BIT | MT_32BIT_XRGB8888;
   case MESA_FORMAT_RGBA8888_REV:
      return MAPSURF_32BIT | MT_32BIT_ABGR8888;
   case MESA_FORMAT_YCBCR_REV:
      return (MAPSURF_422 | MT_422_YCRCB_NORMAL);
   case MESA_FORMAT_YCBCR:
      return (MAPSURF_422 | MT_422_YCRCB_SWAPY);
   case MESA_FORMAT_RGB_FXT1:
   case MESA_FORMAT_RGBA_FXT1:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1);
   case MESA_FORMAT_Z16:
      if (DepthMode == GL_ALPHA)
          return (MAPSURF_16BIT | MT_16BIT_A16);
      else if (DepthMode == GL_INTENSITY)
          return (MAPSURF_16BIT | MT_16BIT_I16);
      else
          return (MAPSURF_16BIT | MT_16BIT_L16);
   case MESA_FORMAT_RGBA_DXT1:
   case MESA_FORMAT_RGB_DXT1:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1);
   case MESA_FORMAT_RGBA_DXT3:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3);
   case MESA_FORMAT_RGBA_DXT5:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5);
   case MESA_FORMAT_S8_Z24:
   case MESA_FORMAT_X8_Z24:
      if (DepthMode == GL_ALPHA)
	 return (MAPSURF_32BIT | MT_32BIT_x8A24);
      else if (DepthMode == GL_INTENSITY)
	 return (MAPSURF_32BIT | MT_32BIT_x8I24);
      else
	 return (MAPSURF_32BIT | MT_32BIT_x8L24);
   default:
      fprintf(stderr, "%s: bad image format %s\n", __FUNCTION__,
	      _mesa_get_format_name(mesa_format));
      abort();
      return 0;
   }
}
Пример #9
0
static void
radeon_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
{
	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
	gl_format mesa_format;
	int i;

	for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
		struct gl_renderbuffer_attachment *att;
		if (i == -2) {
			att = &fb->Attachment[BUFFER_DEPTH];
		} else if (i == -1) {
			att = &fb->Attachment[BUFFER_STENCIL];
		} else {
			att = &fb->Attachment[BUFFER_COLOR0 + i];
		}

		if (att->Type == GL_TEXTURE) {
			mesa_format = att->Texture->Image[att->CubeMapFace][att->TextureLevel]->TexFormat;
		} else {
			/* All renderbuffer formats are renderable, but not sampable */
			continue;
		}

		if (!radeon->vtbl.is_format_renderable(mesa_format)){
			fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
			radeon_print(RADEON_TEXTURE, RADEON_TRACE,
						"%s: HW doesn't support format %s as output format of attachment %d\n",
						__FUNCTION__, _mesa_get_format_name(mesa_format), i);
			return;
		}
	}
}
Пример #10
0
/**
 * Determine if fast color clear supports the given clear color.
 *
 * Fast color clear can only clear to color values of 1.0 or 0.0.  At the
 * moment we only support floating point, unorm, and snorm buffers.
 */
static bool
is_color_fast_clear_compatible(struct brw_context *brw,
                               mesa_format format,
                               const union gl_color_union *color)
{
   if (_mesa_is_format_integer_color(format)) {
      if (brw->gen >= 8) {
         perf_debug("Integer fast clear not enabled for (%s)",
                    _mesa_get_format_name(format));
      }
      return false;
   }

   for (int i = 0; i < 4; i++) {
      if (!_mesa_format_has_color_component(format, i)) {
         continue;
      }

      if (brw->gen < 9 &&
          color->f[i] != 0.0f && color->f[i] != 1.0f) {
         return false;
      }
   }
   return true;
}
/**
 * @param for_bo Indicates that the caller is
 *        intel_miptree_create_for_bo(). If true, then do not create
 *        \c stencil_mt.
 */
struct intel_mipmap_tree *
intel_miptree_create_layout(struct intel_context *intel,
                            GLenum target,
                            mesa_format format,
                            GLuint first_level,
                            GLuint last_level,
                            GLuint width0,
                            GLuint height0,
                            GLuint depth0,
                            bool for_bo)
{
    struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);
    if (!mt)
        return NULL;

    DBG("%s target %s format %s level %d..%d <-- %p\n", __func__,
        _mesa_enum_to_string(target),
        _mesa_get_format_name(format),
        first_level, last_level, mt);

    mt->target = target_to_target(target);
    mt->format = format;
    mt->first_level = first_level;
    mt->last_level = last_level;
    mt->logical_width0 = width0;
    mt->logical_height0 = height0;
    mt->logical_depth0 = depth0;

    /* The cpp is bytes per (1, blockheight)-sized block for compressed
     * textures.  This is why you'll see divides by blockheight all over
     */
    unsigned bw, bh;
    _mesa_get_format_block_size(format, &bw, &bh);
    assert(_mesa_get_format_bytes(mt->format) % bw == 0);
    mt->cpp = _mesa_get_format_bytes(mt->format) / bw;

    mt->compressed = _mesa_is_format_compressed(format);
    mt->refcount = 1;

    if (target == GL_TEXTURE_CUBE_MAP) {
        assert(depth0 == 1);
        depth0 = 6;
    }

    mt->physical_width0 = width0;
    mt->physical_height0 = height0;
    mt->physical_depth0 = depth0;

    intel_get_texture_alignment_unit(intel, mt->format,
                                     &mt->align_w, &mt->align_h);

    (void) intel;
    if (intel->is_945)
        i945_miptree_layout(mt);
    else
        i915_miptree_layout(mt);

    return mt;
}
Пример #12
0
/**
 * Called via glRenderbufferStorageEXT() to set the format and allocate
 * storage for a user-created renderbuffer.
 */
static GLboolean
intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
                                 GLenum internalFormat,
                                 GLuint width, GLuint height)
{
   struct brw_context *brw = brw_context(ctx);
   struct intel_screen *screen = brw->intelScreen;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
   rb->NumSamples = intel_quantize_num_samples(screen, rb->NumSamples);

   switch (internalFormat) {
   default:
      /* Use the same format-choice logic as for textures.
       * Renderbuffers aren't any different from textures for us,
       * except they're less useful because you can't texture with
       * them.
       */
      rb->Format = ctx->Driver.ChooseTextureFormat(ctx, GL_TEXTURE_2D,
                                                   internalFormat,
                                                   GL_NONE, GL_NONE);
      break;
   case GL_STENCIL_INDEX:
   case GL_STENCIL_INDEX1_EXT:
   case GL_STENCIL_INDEX4_EXT:
   case GL_STENCIL_INDEX8_EXT:
   case GL_STENCIL_INDEX16_EXT:
      /* These aren't actual texture formats, so force them here. */
      if (brw->has_separate_stencil) {
	 rb->Format = MESA_FORMAT_S8;
      } else {
	 assert(!brw->must_use_separate_stencil);
	 rb->Format = MESA_FORMAT_S8_Z24;
      }
      break;
   }

   rb->Width = width;
   rb->Height = height;
   rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);

   intel_miptree_release(&irb->mt);

   DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__,
       _mesa_lookup_enum_by_nr(internalFormat),
       _mesa_get_format_name(rb->Format), width, height);

   if (width == 0 || height == 0)
      return true;

   irb->mt = intel_miptree_create_for_renderbuffer(brw, rb->Format,
						   width, height,
                                                   rb->NumSamples);
   if (!irb->mt)
      return false;

   return true;
}
Пример #13
0
static void
intelTexImage(struct gl_context * ctx,
              GLuint dims,
              struct gl_texture_image *texImage,
              GLenum format, GLenum type, const void *pixels,
              const struct gl_pixelstore_attrib *unpack)
{
   struct intel_texture_image *intelImage = intel_texture_image(texImage);
   bool ok;

   bool tex_busy = intelImage->mt && drm_intel_bo_busy(intelImage->mt->bo);

   DBG("%s mesa_format %s target %s format %s type %s level %d %dx%dx%d\n",
       __func__, _mesa_get_format_name(texImage->TexFormat),
       _mesa_enum_to_string(texImage->TexObject->Target),
       _mesa_enum_to_string(format), _mesa_enum_to_string(type),
       texImage->Level, texImage->Width, texImage->Height, texImage->Depth);

   /* Allocate storage for texture data. */
   if (!ctx->Driver.AllocTextureImageBuffer(ctx, texImage)) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
      return;
   }

   assert(intelImage->mt);

   if (intelImage->mt->format == MESA_FORMAT_S_UINT8)
      intelImage->mt->r8stencil_needs_update = true;

   ok = _mesa_meta_pbo_TexSubImage(ctx, dims, texImage, 0, 0, 0,
                                   texImage->Width, texImage->Height,
                                   texImage->Depth,
                                   format, type, pixels,
                                   tex_busy, unpack);
   if (ok)
      return;

   ok = intel_texsubimage_tiled_memcpy(ctx, dims, texImage,
                                       0, 0, 0, /*x,y,z offsets*/
                                       texImage->Width,
                                       texImage->Height,
                                       texImage->Depth,
                                       format, type, pixels, unpack,
                                       false /*allocate_storage*/);
   if (ok)
      return;

   DBG("%s: upload image %dx%dx%d pixels %p\n",
       __func__, texImage->Width, texImage->Height, texImage->Depth,
       pixels);

   _mesa_store_teximage(ctx, dims, texImage,
                        format, type, pixels, unpack);
}
/**
 * \see dd_function_table::MapRenderbuffer
 */
static void
intel_map_renderbuffer(struct gl_context *ctx,
		       struct gl_renderbuffer *rb,
		       GLuint x, GLuint y, GLuint w, GLuint h,
		       GLbitfield mode,
		       GLubyte **out_map,
		       GLint *out_stride)
{
   struct intel_context *intel = intel_context(ctx);
   struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
   void *map;
   int stride;

   if (srb->Buffer) {
      /* this is a malloc'd renderbuffer (accum buffer), not an irb */
      GLint bpp = _mesa_get_format_bytes(rb->Format);
      GLint rowStride = srb->RowStride;
      *out_map = (GLubyte *) srb->Buffer + y * rowStride + x * bpp;
      *out_stride = rowStride;
      return;
   }

   /* We sometimes get called with this by our intel_span.c usage. */
   if (!irb->mt) {
      *out_map = NULL;
      *out_stride = 0;
      return;
   }

   /* For a window-system renderbuffer, we need to flip the mapping we receive
    * upside-down.  So we need to ask for a rectangle on flipped vertically, and
    * we then return a pointer to the bottom of it with a negative stride.
    */
   if (rb->Name == 0) {
      y = rb->Height - y - h;
   }

   intel_miptree_map(intel, irb->mt, irb->mt_level, irb->mt_layer,
		     x, y, w, h, mode, &map, &stride);

   if (rb->Name == 0) {
      map += (h - 1) * stride;
      stride = -stride;
   }

   DBG("%s: rb %d (%s) mt mapped: (%d, %d) (%dx%d) -> %p/%d\n",
       __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format),
       x, y, w, h, map, stride);

   *out_map = map;
   *out_stride = stride;
}
uint32_t
brw_depthbuffer_format(struct brw_context *brw)
{
   struct intel_context *intel = &brw->intel;
   struct gl_context *ctx = &intel->ctx;
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_renderbuffer *srb;

   if (!drb &&
       (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) &&
       !srb->mt->stencil_mt &&
       (intel_rb_format(srb) == MESA_FORMAT_S8_Z24 ||
	intel_rb_format(srb) == MESA_FORMAT_Z32_FLOAT_X24S8)) {
      drb = srb;
   }

   if (!drb)
      return BRW_DEPTHFORMAT_D32_FLOAT;

   switch (drb->mt->format) {
   case MESA_FORMAT_Z16:
      return BRW_DEPTHFORMAT_D16_UNORM;
   case MESA_FORMAT_Z32_FLOAT:
      return BRW_DEPTHFORMAT_D32_FLOAT;
   case MESA_FORMAT_X8_Z24:
      if (intel->gen >= 6) {
	 return BRW_DEPTHFORMAT_D24_UNORM_X8_UINT;
      } else {
	 /* Use D24_UNORM_S8, not D24_UNORM_X8.
	  *
	  * D24_UNORM_X8 was not introduced until Gen5. (See the Ironlake PRM,
	  * Volume 2, Part 1, Section 8.4.6 "Depth/Stencil Buffer State", Bits
	  * 3DSTATE_DEPTH_BUFFER.Surface_Format).
	  *
	  * However, on Gen5, D24_UNORM_X8 may be used only if separate
	  * stencil is enabled, and we never enable it. From the Ironlake PRM,
	  * same section as above, Bit 3DSTATE_DEPTH_BUFFER.Separate_Stencil_Buffer_Enable:
	  *     If this field is disabled, the Surface Format of the depth
	  *     buffer cannot be D24_UNORM_X8_UINT.
	  */
	 return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT;
      }
   case MESA_FORMAT_S8_Z24:
      return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT;
   case MESA_FORMAT_Z32_FLOAT_X24S8:
      return BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT;
   default:
      _mesa_problem(ctx, "Unexpected depth format %s\n",
		    _mesa_get_format_name(intel_rb_format(drb)));
      return BRW_DEPTHFORMAT_D16_UNORM;
   }
}
Пример #16
0
/**
 * Called by Mesa when rendering to a texture is done.
 */
static void
intel_finish_render_texture(struct gl_context * ctx, struct gl_renderbuffer *rb)
{
   struct brw_context *brw = brw_context(ctx);

   DBG("Finish render %s texture\n", _mesa_get_format_name(rb->Format));

   /* Since we've (probably) rendered to the texture and will (likely) use
    * it in the texture domain later on in this batchbuffer, flush the
    * batch.  Once again, we wish for a domain tracker in libdrm to cover
    * usage inside of a batchbuffer like GEM does in the kernel.
    */
   intel_batchbuffer_emit_mi_flush(brw);
}
Пример #17
0
/**
 * This is the implementation for glGetnTexImageARB, glGetTextureImage,
 * and glGetTexImage.
 *
 * Requires caller to pass in texImage object because _mesa_GetTextureImage
 * must handle the GL_TEXTURE_CUBE_MAP target.
 *
 * \param target texture target.
 * \param level image level.
 * \param format pixel data format for returned image.
 * \param type pixel data type for returned image.
 * \param bufSize size of the pixels data buffer.
 * \param pixels returned pixel data.
 * \param dsa True when the caller is an ARB_direct_state_access function,
 *            false otherwise
 */
void
_mesa_get_texture_image(struct gl_context *ctx,
                        struct gl_texture_object *texObj,
                        struct gl_texture_image *texImage, GLenum target,
                        GLint level, GLenum format, GLenum type,
                        GLsizei bufSize, GLvoid *pixels, bool dsa)
{
   assert(texObj);
   assert(texImage);

   FLUSH_VERTICES(ctx, 0);

   /*
    * Legal target checking has been moved up to GetnTexImage and
    * GetTextureImage so that it can be caught before receiving a NULL
    * texImage object and exiting.
    */

   if (getteximage_error_check(ctx, texImage, target, level, format,
                               type, bufSize, pixels, dsa)) {
      return;
   }

   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
      /* not an error, do nothing */
      return;
   }

   if (_mesa_is_zero_size_texture(texImage))
      return;

   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
      _mesa_debug(ctx, "glGetTex%sImage(tex %u) format = %s, w=%d, h=%d,"
                  " dstFmt=0x%x, dstType=0x%x\n",
                  dsa ? "ture": "",
                  texObj->Name,
                  _mesa_get_format_name(texImage->TexFormat),
                  texImage->Width, texImage->Height,
                  format, type);
   }

   _mesa_lock_texture(ctx, texObj);
   {
      ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Пример #18
0
static GLboolean
radeon_update_wrapper(struct gl_context *ctx, struct radeon_renderbuffer *rrb, 
		     struct gl_texture_image *texImage)
{
	radeon_print(RADEON_TEXTURE, RADEON_TRACE,
		"%s(%p, rrb %p, texImage %p, texFormat %s) \n",
		__func__, ctx, rrb, texImage, _mesa_get_format_name(texImage->TexFormat));

	switch (texImage->TexFormat) {
		case MESA_FORMAT_RGBA8888:
		case MESA_FORMAT_RGBA8888_REV:
		case MESA_FORMAT_ARGB8888:
		case MESA_FORMAT_ARGB8888_REV:
		case MESA_FORMAT_XRGB8888:
		case MESA_FORMAT_XRGB8888_REV:
		case MESA_FORMAT_RGB565:
		case MESA_FORMAT_RGB565_REV:
		case MESA_FORMAT_RGBA5551:
		case MESA_FORMAT_ARGB1555:
		case MESA_FORMAT_ARGB1555_REV:
		case MESA_FORMAT_ARGB4444:
		case MESA_FORMAT_ARGB4444_REV:
			rrb->base.DataType = GL_UNSIGNED_BYTE;
			break;
		case MESA_FORMAT_Z16:
			rrb->base.DataType = GL_UNSIGNED_SHORT;
			break;
		case MESA_FORMAT_X8_Z24:
			rrb->base.DataType = GL_UNSIGNED_INT;
			break;
		case MESA_FORMAT_S8_Z24:
			rrb->base.DataType = GL_UNSIGNED_INT_24_8_EXT;
			break;
	}
		
	rrb->cpp = _mesa_get_format_bytes(texImage->TexFormat);
	rrb->pitch = texImage->Width * rrb->cpp;
	rrb->base.Format = texImage->TexFormat;
	rrb->base.InternalFormat = texImage->InternalFormat;
	rrb->base._BaseFormat = _mesa_base_fbo_format(ctx, rrb->base.InternalFormat);
	rrb->base.Width = texImage->Width;
	rrb->base.Height = texImage->Height;
	rrb->base.Delete = radeon_delete_renderbuffer;
	rrb->base.AllocStorage = radeon_nop_alloc_storage;

	return GL_TRUE;
}
Пример #19
0
/**
 * Called by glFramebufferTexture[123]DEXT() (and other places) to
 * prepare for rendering into texture memory.  This might be called
 * many times to choose different texture levels, cube faces, etc
 * before intel_finish_render_texture() is ever called.
 */
static void
intel_render_texture(struct gl_context * ctx,
                     struct gl_framebuffer *fb,
                     struct gl_renderbuffer_attachment *att)
{
   struct intel_context *intel = intel_context(ctx);
   struct gl_renderbuffer *rb = att->Renderbuffer;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
   struct gl_texture_image *image = rb->TexImage;
   struct intel_texture_image *intel_image = intel_texture_image(image);
   struct intel_mipmap_tree *mt = intel_image->mt;
   int layer;

   (void) fb;

   if (att->CubeMapFace > 0) {
      assert(att->Zoffset == 0);
      layer = att->CubeMapFace;
   } else {
      layer = att->Zoffset;
   }

   if (!intel_image->mt) {
      /* Fallback on drawing to a texture that doesn't have a miptree
       * (has a border, width/height 0, etc.)
       */
      _swrast_render_texture(ctx, fb, att);
      return;
   }

   intel_miptree_check_level_layer(mt, att->TextureLevel, layer);

   if (!intel_renderbuffer_update_wrapper(intel, irb, image, layer)) {
       _swrast_render_texture(ctx, fb, att);
       return;
   }

   DBG("Begin render %s texture tex=%u w=%d h=%d d=%d refcount=%d\n",
       _mesa_get_format_name(image->TexFormat),
       att->Texture->Name, image->Width, image->Height, image->Depth,
       rb->RefCount);

   /* update drawing region, etc */
   intel_draw_buffer(ctx);
}
/**
 * \see dd_function_table::UnmapRenderbuffer
 */
static void
intel_unmap_renderbuffer(struct gl_context *ctx,
			 struct gl_renderbuffer *rb)
{
   struct intel_context *intel = intel_context(ctx);
   struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);

   DBG("%s: rb %d (%s)\n", __FUNCTION__,
       rb->Name, _mesa_get_format_name(rb->Format));

   if (srb->Buffer) {
      /* this is a malloc'd renderbuffer (accum buffer) */
      /* nothing to do */
      return;
   }

   intel_miptree_unmap(intel, irb->mt, irb->mt_level, irb->mt_layer);
}
Пример #21
0
static GLuint
translate_texture_format(GLuint mesa_format)
{
   switch (mesa_format) {
   case MESA_FORMAT_L8:
      return MAPSURF_8BIT | MT_8BIT_L8;
   case MESA_FORMAT_I8:
      return MAPSURF_8BIT | MT_8BIT_I8;
   case MESA_FORMAT_A8:
      return MAPSURF_8BIT | MT_8BIT_I8; /* Kludge! */
   case MESA_FORMAT_AL88:
      return MAPSURF_16BIT | MT_16BIT_AY88;
   case MESA_FORMAT_RGB565:
      return MAPSURF_16BIT | MT_16BIT_RGB565;
   case MESA_FORMAT_ARGB1555:
      return MAPSURF_16BIT | MT_16BIT_ARGB1555;
   case MESA_FORMAT_ARGB4444:
      return MAPSURF_16BIT | MT_16BIT_ARGB4444;
   case MESA_FORMAT_ARGB8888:
      return MAPSURF_32BIT | MT_32BIT_ARGB8888;
   case MESA_FORMAT_XRGB8888:
      return MAPSURF_32BIT | MT_32BIT_XRGB8888;
   case MESA_FORMAT_YCBCR_REV:
      return (MAPSURF_422 | MT_422_YCRCB_NORMAL);
   case MESA_FORMAT_YCBCR:
      return (MAPSURF_422 | MT_422_YCRCB_SWAPY);
   case MESA_FORMAT_RGB_FXT1:
   case MESA_FORMAT_RGBA_FXT1:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1);
   case MESA_FORMAT_RGBA_DXT1:
   case MESA_FORMAT_RGB_DXT1:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1);
   case MESA_FORMAT_RGBA_DXT3:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3);
   case MESA_FORMAT_RGBA_DXT5:
      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5);
   default:
      fprintf(stderr, "%s: bad image format %s\n", __FUNCTION__,
	      _mesa_get_format_name(mesa_format));
      abort();
      return 0;
   }
}
static void
intel_miptree_map_blit(struct intel_context *intel,
                       struct intel_mipmap_tree *mt,
                       struct intel_miptree_map *map,
                       unsigned int level, unsigned int slice)
{
    map->mt = intel_miptree_create(intel, GL_TEXTURE_2D, mt->format,
                                   0, 0,
                                   map->w, map->h, 1,
                                   false,
                                   INTEL_MIPTREE_TILING_NONE);
    if (!map->mt) {
        fprintf(stderr, "Failed to allocate blit temporary\n");
        goto fail;
    }
    map->stride = map->mt->region->pitch;

    if (!intel_miptree_blit(intel,
                            mt, level, slice,
                            map->x, map->y, false,
                            map->mt, 0, 0,
                            0, 0, false,
                            map->w, map->h, GL_COPY)) {
        fprintf(stderr, "Failed to blit\n");
        goto fail;
    }

    intel_batchbuffer_flush(intel);
    map->ptr = intel_miptree_map_raw(intel, map->mt);

    DBG("%s: %d,%d %dx%d from mt %p (%s) %d,%d = %p/%d\n", __func__,
        map->x, map->y, map->w, map->h,
        mt, _mesa_get_format_name(mt->format),
        level, slice, map->ptr, map->stride);

    return;

fail:
    intel_miptree_release(&map->mt);
    map->ptr = NULL;
    map->stride = 0;
}
/**
 * Determine if fast color clear supports the given clear color.
 *
 * Fast color clear can only clear to color values of 1.0 or 0.0.  At the
 * moment we only support floating point, unorm, and snorm buffers.
 */
bool
brw_is_color_fast_clear_compatible(struct brw_context *brw,
                                   const struct intel_mipmap_tree *mt,
                                   const union gl_color_union *color)
{
   const struct gen_device_info *devinfo = &brw->screen->devinfo;
   const struct gl_context *ctx = &brw->ctx;

   /* If we're mapping the render format to a different format than the
    * format we use for texturing then it is a bit questionable whether it
    * should be possible to use a fast clear. Although we only actually
    * render using a renderable format, without the override workaround it
    * wouldn't be possible to have a non-renderable surface in a fast clear
    * state so the hardware probably legitimately doesn't need to support
    * this case. At least on Gen9 this really does seem to cause problems.
    */
   if (devinfo->gen >= 9 &&
       brw_isl_format_for_mesa_format(mt->format) !=
       brw->mesa_to_isl_render_format[mt->format])
      return false;

   const mesa_format format = _mesa_get_render_format(ctx, mt->format);
   if (_mesa_is_format_integer_color(format)) {
      if (devinfo->gen >= 8) {
         perf_debug("Integer fast clear not enabled for (%s)",
                    _mesa_get_format_name(format));
      }
      return false;
   }

   for (int i = 0; i < 4; i++) {
      if (!_mesa_format_has_color_component(format, i)) {
         continue;
      }

      if (devinfo->gen < 9 &&
          color->f[i] != 0.0f && color->f[i] != 1.0f) {
         return false;
      }
   }
   return true;
}
static void
intel_miptree_map_gtt(struct intel_context *intel,
                      struct intel_mipmap_tree *mt,
                      struct intel_miptree_map *map,
                      unsigned int level, unsigned int slice)
{
    unsigned int bw, bh;
    void *base;
    unsigned int image_x, image_y;
    int x = map->x;
    int y = map->y;

    /* For compressed formats, the stride is the number of bytes per
     * row of blocks.  intel_miptree_get_image_offset() already does
     * the divide.
     */
    _mesa_get_format_block_size(mt->format, &bw, &bh);
    assert(y % bh == 0);
    y /= bh;

    base = intel_miptree_map_raw(intel, mt) + mt->offset;

    if (base == NULL)
        map->ptr = NULL;
    else {
        /* Note that in the case of cube maps, the caller must have passed the
         * slice number referencing the face.
        */
        intel_miptree_get_image_offset(mt, level, slice, &image_x, &image_y);
        x += image_x;
        y += image_y;

        map->stride = mt->region->pitch;
        map->ptr = base + y * map->stride + x * mt->cpp;
    }

    DBG("%s: %d,%d %dx%d from mt %p (%s) %d,%d = %p/%d\n", __func__,
        map->x, map->y, map->w, map->h,
        mt, _mesa_get_format_name(mt->format),
        x, y, map->ptr, map->stride);
}
Пример #25
0
/**
 * Get texture image.  Called by glGetTexImage.
 *
 * \param target texture target.
 * \param level image level.
 * \param format pixel data format for returned image.
 * \param type pixel data type for returned image.
 * \param bufSize size of the pixels data buffer.
 * \param pixels returned pixel data.
 */
void GLAPIENTRY
_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
                       GLenum type, GLsizei bufSize, GLvoid *pixels )
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GET_CURRENT_CONTEXT(ctx);

   FLUSH_VERTICES(ctx, 0);

   if (getteximage_error_check(ctx, target, level, format, type,
                               bufSize, pixels)) {
      return;
   }

   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
      /* not an error, do nothing */
      return;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);

   if (_mesa_is_zero_size_texture(texImage))
      return;

   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
                  " dstFmt=0x%x, dstType=0x%x\n",
                  texObj->Name,
                  _mesa_get_format_name(texImage->TexFormat),
                  texImage->Width, texImage->Height,
                  format, type);
   }

   _mesa_lock_texture(ctx, texObj);
   {
      ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Пример #26
0
/** Implements glGetnCompressedTexImageARB, glGetCompressedTexImage, and
 * glGetCompressedTextureImage.
 *
 * texImage must be passed in because glGetCompressedTexImage must handle the
 * target GL_TEXTURE_CUBE_MAP.
 */
void
_mesa_get_compressed_texture_image(struct gl_context *ctx,
                                   struct gl_texture_object *texObj,
                                   struct gl_texture_image *texImage,
                                   GLenum target, GLint level,
                                   GLsizei bufSize, GLvoid *pixels,
                                   bool dsa)
{
   assert(texObj);
   assert(texImage);

   FLUSH_VERTICES(ctx, 0);

   if (getcompressedteximage_error_check(ctx, texImage, target, level,
                                         bufSize, pixels, dsa)) {
      return;
   }

   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
      /* not an error, do nothing */
      return;
   }

   if (_mesa_is_zero_size_texture(texImage))
      return;

   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
      _mesa_debug(ctx,
                  "glGetCompressedTex%sImage(tex %u) format = %s, w=%d, h=%d\n",
                  dsa ? "ture" : "", texObj->Name,
                  _mesa_get_format_name(texImage->TexFormat),
                  texImage->Width, texImage->Height);
   }

   _mesa_lock_texture(ctx, texObj);
   {
      ctx->Driver.GetCompressedTexImage(ctx, texImage, pixels);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Пример #27
0
uint32_t
brw_depthbuffer_format(struct brw_context *brw)
{
   struct intel_context *intel = &brw->intel;
   struct gl_context *ctx = &intel->ctx;
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
   struct intel_renderbuffer *srb;

   if (!drb &&
       (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) &&
       !srb->mt->stencil_mt &&
       (srb->Base.Format == MESA_FORMAT_S8_Z24 ||
	srb->Base.Format == MESA_FORMAT_Z32_FLOAT_X24S8)) {
      drb = srb;
   }

   if (!drb)
      return BRW_DEPTHFORMAT_D32_FLOAT;

   switch (drb->mt->format) {
   case MESA_FORMAT_Z16:
      return BRW_DEPTHFORMAT_D16_UNORM;
   case MESA_FORMAT_Z32_FLOAT:
      return BRW_DEPTHFORMAT_D32_FLOAT;
   case MESA_FORMAT_X8_Z24:
      if (intel->gen >= 5)
	 return BRW_DEPTHFORMAT_D24_UNORM_X8_UINT;
      else /* Gen4 doesn't support X8; use S8 instead. */
	 return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT;
   case MESA_FORMAT_S8_Z24:
      return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT;
   case MESA_FORMAT_Z32_FLOAT_X24S8:
      return BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT;
   default:
      _mesa_problem(ctx, "Unexpected depth format %s\n",
		    _mesa_get_format_name(drb->Base.Format));
      return BRW_DEPTHFORMAT_D16_UNORM;
   }
}
void
intel_miptree_unmap(struct intel_context *intel,
                    struct intel_mipmap_tree *mt,
                    unsigned int level,
                    unsigned int slice)
{
    struct intel_miptree_map *map = mt->level[level].slice[slice].map;

    if (!map)
        return;

    DBG("%s: mt %p (%s) level %d slice %d\n", __func__,
        mt, _mesa_get_format_name(mt->format), level, slice);

    if (map->mt) {
        intel_miptree_unmap_blit(intel, mt, map, level, slice);
    } else {
        intel_miptree_unmap_gtt(intel, mt, map, level, slice);
    }

    intel_miptree_release_map(mt, level, slice);
}
/**
 * Called by Mesa when rendering to a texture is done.
 */
static void
intel_finish_render_texture(struct gl_context * ctx,
                            struct gl_renderbuffer_attachment *att)
{
   struct intel_context *intel = intel_context(ctx);
   struct gl_texture_object *tex_obj = att->Texture;
   struct gl_texture_image *image =
      tex_obj->Image[att->CubeMapFace][att->TextureLevel];
   struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);

   DBG("Finish render %s texture tex=%u\n",
       _mesa_get_format_name(image->TexFormat), att->Texture->Name);

   if (irb)
      irb->tex_image = NULL;

   /* Since we've (probably) rendered to the texture and will (likely) use
    * it in the texture domain later on in this batchbuffer, flush the
    * batch.  Once again, we wish for a domain tracker in libdrm to cover
    * usage inside of a batchbuffer like GEM does in the kernel.
    */
   intel_batchbuffer_emit_mi_flush(intel);
}
Пример #30
0
/**
 * Implements a rectangular block transfer (blit) of pixels between two
 * miptrees.
 *
 * Our blitter can operate on 1, 2, or 4-byte-per-pixel data, with generous,
 * but limited, pitches and sizes allowed.
 *
 * The src/dst coordinates are relative to the given level/slice of the
 * miptree.
 *
 * If @src_flip or @dst_flip is set, then the rectangle within that miptree
 * will be inverted (including scanline order) when copying.  This is common
 * in GL when copying between window system and user-created
 * renderbuffers/textures.
 */
bool
intel_miptree_blit(struct intel_context *intel,
                   struct intel_mipmap_tree *src_mt,
                   int src_level, int src_slice,
                   uint32_t src_x, uint32_t src_y, bool src_flip,
                   struct intel_mipmap_tree *dst_mt,
                   int dst_level, int dst_slice,
                   uint32_t dst_x, uint32_t dst_y, bool dst_flip,
                   uint32_t width, uint32_t height,
                   GLenum logicop)
{
   /* No sRGB decode or encode is done by the hardware blitter, which is
    * consistent with what we want in the callers (glCopyTexSubImage(),
    * glBlitFramebuffer(), texture validation, etc.).
    */
   gl_format src_format = _mesa_get_srgb_format_linear(src_mt->format);
   gl_format dst_format = _mesa_get_srgb_format_linear(dst_mt->format);

   /* The blitter doesn't support doing any format conversions.  We do also
    * support blitting ARGB8888 to XRGB8888 (trivial, the values dropped into
    * the X channel don't matter), and XRGB8888 to ARGB8888 by setting the A
    * channel to 1.0 at the end.
    */
   if (src_format != dst_format &&
      ((src_format != MESA_FORMAT_ARGB8888 &&
        src_format != MESA_FORMAT_XRGB8888) ||
       (dst_format != MESA_FORMAT_ARGB8888 &&
        dst_format != MESA_FORMAT_XRGB8888))) {
      perf_debug("%s: Can't use hardware blitter from %s to %s, "
                 "falling back.\n", __FUNCTION__,
                 _mesa_get_format_name(src_format),
                 _mesa_get_format_name(dst_format));
      return false;
   }

   /* According to the Ivy Bridge PRM, Vol1 Part4, section 1.2.1.2 (Graphics
    * Data Size Limitations):
    *
    *    The BLT engine is capable of transferring very large quantities of
    *    graphics data. Any graphics data read from and written to the
    *    destination is permitted to represent a number of pixels that
    *    occupies up to 65,536 scan lines and up to 32,768 bytes per scan line
    *    at the destination. The maximum number of pixels that may be
    *    represented per scan line’s worth of graphics data depends on the
    *    color depth.
    *
    * Furthermore, intelEmitCopyBlit (which is called below) uses a signed
    * 16-bit integer to represent buffer pitch, so it can only handle buffer
    * pitches < 32k.
    *
    * As a result of these two limitations, we can only use the blitter to do
    * this copy when the region's pitch is less than 32k.
    */
   if (src_mt->region->pitch > 32768 ||
       dst_mt->region->pitch > 32768) {
      perf_debug("Falling back due to >32k pitch\n");
      return false;
   }

   if (src_flip)
      src_y = src_mt->level[src_level].height - src_y - height;

   if (dst_flip)
      dst_y = dst_mt->level[dst_level].height - dst_y - height;

   int src_pitch = src_mt->region->pitch;
   if (src_flip != dst_flip)
      src_pitch = -src_pitch;

   uint32_t src_image_x, src_image_y;
   intel_miptree_get_image_offset(src_mt, src_level, src_slice,
                                  &src_image_x, &src_image_y);
   src_x += src_image_x;
   src_y += src_image_y;

   uint32_t dst_image_x, dst_image_y;
   intel_miptree_get_image_offset(dst_mt, dst_level, dst_slice,
                                  &dst_image_x, &dst_image_y);
   dst_x += dst_image_x;
   dst_y += dst_image_y;

   if (!intelEmitCopyBlit(intel,
                          src_mt->cpp,
                          src_pitch,
                          src_mt->region->bo, src_mt->offset,
                          src_mt->region->tiling,
                          dst_mt->region->pitch,
                          dst_mt->region->bo, dst_mt->offset,
                          dst_mt->region->tiling,
                          src_x, src_y,
                          dst_x, dst_y,
                          width, height,
                          logicop)) {
      return false;
   }

   if (src_mt->format == MESA_FORMAT_XRGB8888 &&
       dst_mt->format == MESA_FORMAT_ARGB8888) {
      intel_miptree_set_alpha_to_one(intel, dst_mt,
                                     dst_x, dst_y,
                                     width, height);
   }

   return true;
}