i965/gen8: Add instruction compaction tables.
[mesa.git] / src / mesa / drivers / dri / i965 / intel_tex_image.c
index 725d3155b291c86cd722c51f139e7e9e7fda2de5..331777919c6e8369dd79b304b63afe6b891c133f 100644 (file)
 #include "main/teximage.h"
 #include "main/texstore.h"
 
+#include "drivers/common/meta.h"
+
 #include "intel_mipmap_tree.h"
 #include "intel_buffer_objects.h"
 #include "intel_batchbuffer.h"
 #include "intel_tex.h"
 #include "intel_blit.h"
 #include "intel_fbo.h"
+#include "intel_image.h"
 
 #include "brw_context.h"
 
@@ -35,7 +38,6 @@ intel_miptree_create_for_teximage(struct brw_context *brw,
                                  struct intel_texture_image *intelImage,
                                  bool expect_accelerated_upload)
 {
-   GLuint firstLevel;
    GLuint lastLevel;
    int width, height, depth;
    GLuint i;
@@ -45,16 +47,8 @@ intel_miptree_create_for_teximage(struct brw_context *brw,
 
    DBG("%s\n", __FUNCTION__);
 
-   /* If this image disrespects BaseLevel, allocate from level zero.
-    * Usually BaseLevel == 0, so it's unlikely to happen.
-    */
-   if (intelImage->base.Base.Level < intelObj->base.BaseLevel)
-      firstLevel = 0;
-   else
-      firstLevel = intelObj->base.BaseLevel;
-
    /* Figure out image dimensions at start level. */
-   for (i = intelImage->base.Base.Level; i > firstLevel; i--) {
+   for (i = intelImage->base.Base.Level; i > 0; i--) {
       width <<= 1;
       if (height != 1)
          height <<= 1;
@@ -69,26 +63,26 @@ intel_miptree_create_for_teximage(struct brw_context *brw,
     */
    if ((intelObj->base.Sampler.MinFilter == GL_NEAREST ||
         intelObj->base.Sampler.MinFilter == GL_LINEAR) &&
-       intelImage->base.Base.Level == firstLevel &&
-       firstLevel == 0) {
-      lastLevel = firstLevel;
+       intelImage->base.Base.Level == 0 &&
+       !intelObj->base.GenerateMipmap) {
+      lastLevel = 0;
    } else {
-      lastLevel = (firstLevel +
-                   _mesa_get_tex_max_num_levels(intelObj->base.Target,
-                                                width, height, depth) - 1);
+      lastLevel = _mesa_get_tex_max_num_levels(intelObj->base.Target,
+                                               width, height, depth) - 1;
    }
 
    return intel_miptree_create(brw,
                               intelObj->base.Target,
                               intelImage->base.Base.TexFormat,
-                              firstLevel,
+                              0,
                               lastLevel,
                               width,
                               height,
                               depth,
                               expect_accelerated_upload,
                                intelImage->base.Base.NumSamples,
-                               INTEL_MIPTREE_TILING_ANY);
+                               INTEL_MIPTREE_TILING_ANY,
+                               false);
 }
 
 /* XXX: Do this for TexSubImage also:
@@ -136,20 +130,21 @@ try_pbo_upload(struct gl_context *ctx,
       return false;
    }
 
-   src_buffer = intel_bufferobj_source(brw, 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);
 
+   /* note: potential 64-bit ptr to 32-bit int cast */
+   src_offset = (GLuint) (unsigned long) pixels;
+   src_buffer = intel_bufferobj_buffer(brw, pbo,
+                                       src_offset, src_stride * image->Height);
+
    struct intel_mipmap_tree *pbo_mt =
       intel_miptree_create_for_bo(brw,
                                   src_buffer,
                                   intelImage->mt->format,
                                   src_offset,
                                   image->Width, image->Height,
-                                  src_stride, I915_TILING_NONE);
+                                  src_stride);
    if (!pbo_mt)
       return false;
 
@@ -179,8 +174,10 @@ intelTexImage(struct gl_context * ctx,
 {
    bool ok;
 
-   DBG("%s target %s level %d %dx%dx%d\n", __FUNCTION__,
+   DBG("%s mesa_format %s target %s format %s type %s level %d %dx%dx%d\n",
+       __FUNCTION__, _mesa_get_format_name(texImage->TexFormat),
        _mesa_lookup_enum_by_nr(texImage->TexObject->Target),
+       _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type),
        texImage->Level, texImage->Width, texImage->Height, texImage->Depth);
 
    ok = intel_texsubimage_tiled_memcpy(ctx, dims, texImage,
@@ -210,22 +207,21 @@ intelTexImage(struct gl_context * ctx,
 
 
 /**
- * Binds a region to a texture image, like it was uploaded by glTexImage2D().
+ * Binds a BO to a texture image, as if it was uploaded by glTexImage2D().
  *
  * Used for GLX_EXT_texture_from_pixmap and EGL image extensions,
  */
 static void
-intel_set_texture_image_region(struct gl_context *ctx,
-                              struct gl_texture_image *image,
-                              struct intel_region *region,
-                              GLenum target,
-                              GLenum internalFormat,
-                              gl_format format,
-                               uint32_t offset,
-                               GLuint width,
-                               GLuint height,
-                               GLuint tile_x,
-                               GLuint tile_y)
+intel_set_texture_image_bo(struct gl_context *ctx,
+                           struct gl_texture_image *image,
+                           drm_intel_bo *bo,
+                           GLenum target,
+                           GLenum internalFormat,
+                           mesa_format format,
+                           uint32_t offset,
+                           GLuint width, GLuint height,
+                           GLuint pitch,
+                           GLuint tile_x, GLuint tile_y)
 {
    struct brw_context *brw = brw_context(ctx);
    struct intel_texture_image *intel_image = intel_texture_image(image);
@@ -239,13 +235,11 @@ intel_set_texture_image_region(struct gl_context *ctx,
 
    ctx->Driver.FreeTextureImageBuffer(ctx, image);
 
-   intel_image->mt = intel_miptree_create_layout(brw, target, image->TexFormat,
-                                                 0, 0,
-                                                 width, height, 1,
-                                                 true, 0 /* num_samples */);
+   intel_image->mt = intel_miptree_create_for_bo(brw, bo, image->TexFormat,
+                                                 0, width, height, pitch);
    if (intel_image->mt == NULL)
        return;
-   intel_region_reference(&intel_image->mt->region, region);
+   intel_image->mt->target = target;
    intel_image->mt->total_width = width;
    intel_image->mt->total_height = height;
    intel_image->mt->level[0].slice[0].x_offset = tile_x;
@@ -267,8 +261,8 @@ intel_set_texture_image_region(struct gl_context *ctx,
    intel_texobj->needs_validate = true;
 
    intel_image->mt->offset = offset;
-   assert(region->pitch % region->cpp == 0);
-   intel_image->base.RowStride = region->pitch / region->cpp;
+   assert(pitch % intel_image->mt->cpp == 0);
+   intel_image->base.RowStride = pitch / intel_image->mt->cpp;
 
    /* Immediately validate the image to the object. */
    intel_miptree_reference(&intel_texobj->mt, intel_image->mt);
@@ -282,17 +276,15 @@ intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
    struct gl_framebuffer *fb = dPriv->driverPrivate;
    struct brw_context *brw = pDRICtx->driverPrivate;
    struct gl_context *ctx = &brw->ctx;
-   struct intel_texture_object *intelObj;
    struct intel_renderbuffer *rb;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    int level = 0, internalFormat = 0;
-   gl_format texFormat = MESA_FORMAT_NONE;
+   mesa_format texFormat = MESA_FORMAT_NONE;
 
    texObj = _mesa_get_current_tex_object(ctx, target);
-   intelObj = intel_texture_object(texObj);
 
-   if (!intelObj)
+   if (!texObj)
       return;
 
    if (dPriv->lastStamp != dPriv->dri2.stamp ||
@@ -300,8 +292,8 @@ intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
       intel_update_renderbuffers(pDRICtx, dPriv);
 
    rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
-   /* If the region isn't set, then intel_update_renderbuffers was unable
-    * to get the buffers for the drawable.
+   /* If the miptree isn't set, then intel_update_renderbuffers was unable
+    * to get the BO for the drawable from the window system.
     */
    if (!rb || !rb->mt)
       return;
@@ -309,28 +301,64 @@ intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
    if (rb->mt->cpp == 4) {
       if (texture_format == __DRI_TEXTURE_FORMAT_RGB) {
          internalFormat = GL_RGB;
-         texFormat = MESA_FORMAT_XRGB8888;
+         texFormat = MESA_FORMAT_B8G8R8X8_UNORM;
       }
       else {
          internalFormat = GL_RGBA;
-         texFormat = MESA_FORMAT_ARGB8888;
+         texFormat = MESA_FORMAT_B8G8R8A8_UNORM;
       }
    } else if (rb->mt->cpp == 2) {
       internalFormat = GL_RGB;
-      texFormat = MESA_FORMAT_RGB565;
+      texFormat = MESA_FORMAT_B5G6R5_UNORM;
    }
 
    _mesa_lock_texture(&brw->ctx, texObj);
    texImage = _mesa_get_tex_image(ctx, texObj, target, level);
    intel_miptree_make_shareable(brw, rb->mt);
-   intel_set_texture_image_region(ctx, texImage, rb->mt->region, target,
-                                  internalFormat, texFormat, 0,
-                                  rb->mt->region->width,
-                                  rb->mt->region->height,
-                                  0, 0);
+   intel_set_texture_image_bo(ctx, texImage, rb->mt->bo, target,
+                              internalFormat, texFormat, 0,
+                              rb->Base.Base.Width,
+                              rb->Base.Base.Height,
+                              rb->mt->pitch,
+                              0, 0);
    _mesa_unlock_texture(&brw->ctx, texObj);
 }
 
+static GLboolean
+intel_bind_renderbuffer_tex_image(struct gl_context *ctx,
+                                  struct gl_renderbuffer *rb,
+                                  struct gl_texture_image *image)
+{
+   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+   struct intel_texture_image *intel_image = intel_texture_image(image);
+   struct gl_texture_object *texobj = image->TexObject;
+   struct intel_texture_object *intel_texobj = intel_texture_object(texobj);
+
+   /* We can only handle RB allocated with AllocRenderbufferStorage, or
+    * window-system renderbuffers.
+    */
+   assert(!rb->TexImage);
+
+   if (!irb->mt)
+      return false;
+
+   _mesa_lock_texture(ctx, texobj);
+   _mesa_init_teximage_fields(ctx, image,
+                             rb->Width, rb->Height, 1,
+                             0, rb->InternalFormat, rb->Format);
+   image->NumSamples = rb->NumSamples;
+
+   intel_miptree_reference(&intel_image->mt, irb->mt);
+
+   /* Immediately validate the image to the object. */
+   intel_miptree_reference(&intel_texobj->mt, intel_image->mt);
+
+   intel_texobj->needs_validate = true;
+   _mesa_unlock_texture(ctx, texobj);
+
+   return true;
+}
+
 void
 intelSetTexBuffer(__DRIcontext *pDRICtx, GLint target, __DRIdrawable *dPriv)
 {
@@ -382,11 +410,119 @@ intel_image_target_texture_2d(struct gl_context *ctx, GLenum target,
       return;
    }
 
-   intel_set_texture_image_region(ctx, texImage, image->region,
-                                 target, image->internal_format,
-                                  image->format, image->offset,
-                                  image->width,  image->height,
-                                  image->tile_x, image->tile_y);
+   intel_set_texture_image_bo(ctx, texImage, image->bo,
+                              target, image->internal_format,
+                              image->format, image->offset,
+                              image->width,  image->height,
+                              image->pitch,
+                              image->tile_x, image->tile_y);
+}
+
+static bool
+blit_texture_to_pbo(struct gl_context *ctx,
+                    GLenum format, GLenum type,
+                    GLvoid * pixels, struct gl_texture_image *texImage)
+{
+   struct intel_texture_image *intelImage = intel_texture_image(texImage);
+   struct brw_context *brw = brw_context(ctx);
+   const struct gl_pixelstore_attrib *pack = &ctx->Pack;
+   struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj);
+   GLuint dst_offset;
+   drm_intel_bo *dst_buffer;
+   GLenum target = texImage->TexObject->Target;
+
+   /* Check if we can use GPU blit 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 (!_mesa_format_matches_format_and_type(intelImage->mt->format, format,
+                                             type, false))
+   {
+      perf_debug("%s: unsupported format, fallback to CPU mapping for PBO\n",
+                 __FUNCTION__);
+
+      return false;
+   }
+
+   if (ctx->_ImageTransferState) {
+      perf_debug("%s: bad transfer state, fallback to CPU mapping for PBO\n",
+                 __FUNCTION__);
+      return false;
+   }
+
+   if (pack->SwapBytes || pack->LsbFirst) {
+      perf_debug("%s: unsupported pack swap params\n",
+                 __FUNCTION__);
+      return false;
+   }
+
+   if (target == GL_TEXTURE_1D_ARRAY ||
+       target == GL_TEXTURE_2D_ARRAY ||
+       target == GL_TEXTURE_CUBE_MAP_ARRAY ||
+       target == GL_TEXTURE_3D) {
+      perf_debug("%s: no support for multiple slices, fallback to CPU mapping "
+                 "for PBO\n", __FUNCTION__);
+      return false;
+   }
+
+   int dst_stride = _mesa_image_row_stride(pack, texImage->Width, format, type);
+   bool dst_flip = false;
+   /* Mesa flips the dst_stride for ctx->Pack.Invert, our mt must have a
+    * normal dst_stride.
+    */
+   struct gl_pixelstore_attrib uninverted_pack = *pack;
+   if (ctx->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, texImage->Width,
+                                    texImage->Height, format, type, 0, 0, 0);
+   dst_buffer = intel_bufferobj_buffer(brw, dst, dst_offset,
+                                       texImage->Height * dst_stride);
+
+   struct intel_mipmap_tree *pbo_mt =
+      intel_miptree_create_for_bo(brw,
+                                  dst_buffer,
+                                  intelImage->mt->format,
+                                  dst_offset,
+                                  texImage->Width, texImage->Height,
+                                  dst_stride);
+
+   if (!pbo_mt)
+      return false;
+
+   if (!intel_miptree_blit(brw,
+                           intelImage->mt, texImage->Level, texImage->Face,
+                           0, 0, false,
+                           pbo_mt, 0, 0,
+                           0, 0, dst_flip,
+                           texImage->Width, texImage->Height, GL_COPY))
+      return false;
+
+   intel_miptree_release(&pbo_mt);
+
+   return true;
+}
+
+static void
+intel_get_tex_image(struct gl_context *ctx,
+                    GLenum format, GLenum type, GLvoid *pixels,
+                    struct gl_texture_image *texImage) {
+   DBG("%s\n", __FUNCTION__);
+
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
+      /* Using PBOs, so try the BLT based path. */
+      if (blit_texture_to_pbo(ctx, format, type, pixels, texImage))
+         return;
+
+   }
+
+   _mesa_meta_GetTexImage(ctx, format, type, pixels, texImage);
+
+   DBG("%s - DONE\n", __FUNCTION__);
 }
 
 void
@@ -394,4 +530,6 @@ intelInitTextureImageFuncs(struct dd_function_table *functions)
 {
    functions->TexImage = intelTexImage;
    functions->EGLImageTargetTexture2D = intel_image_target_texture_2d;
+   functions->BindRenderbufferTexImage = intel_bind_renderbuffer_tex_image;
+   functions->GetTexImage = intel_get_tex_image;
 }