Exemplo n.º 1
0
static void
copy_miptrees(struct brw_context *brw,
              struct intel_mipmap_tree *src_mt,
              int src_x, int src_y, int src_z, unsigned src_level,
              struct intel_mipmap_tree *dst_mt,
              int dst_x, int dst_y, int dst_z, unsigned dst_level,
              int src_width, int src_height)
{
   unsigned bw, bh;

   if (brw->gen >= 6) {
      brw_blorp_copy_miptrees(brw,
                              src_mt, src_level, src_z,
                              dst_mt, dst_level, dst_z,
                              src_x, src_y, dst_x, dst_y,
                              src_width, src_height);
      return;
   }

   /* We are now going to try and copy the texture using the blitter.  If
    * that fails, we will fall back mapping the texture and using memcpy.
    * In either case, we need to do a full resolve.
    */
   intel_miptree_all_slices_resolve_hiz(brw, src_mt);
   intel_miptree_all_slices_resolve_depth(brw, src_mt);
   intel_miptree_resolve_color(brw, src_mt, 0);

   intel_miptree_all_slices_resolve_hiz(brw, dst_mt);
   intel_miptree_all_slices_resolve_depth(brw, dst_mt);
   intel_miptree_resolve_color(brw, dst_mt, 0);

   _mesa_get_format_block_size(src_mt->format, &bw, &bh);

   /* It's legal to have a WxH that's smaller than a compressed block. This
    * happens for example when you are using a higher level LOD. For this case,
    * we still want to copy the entire block, or else the decompression will be
    * incorrect.
    */
   if (src_width < bw)
      src_width = ALIGN_NPOT(src_width, bw);

   if (src_height < bh)
      src_height = ALIGN_NPOT(src_height, bh);

   if (copy_image_with_blitter(brw, src_mt, src_level,
                               src_x, src_y, src_z,
                               dst_mt, dst_level,
                               dst_x, dst_y, dst_z,
                               src_width, src_height))
      return;

   /* This is a worst-case scenario software fallback that maps the two
    * textures and does a memcpy between them.
    */
   copy_image_with_memcpy(brw, src_mt, src_level,
                          src_x, src_y, src_z,
                          dst_mt, dst_level,
                          dst_x, dst_y, dst_z,
                          src_width, src_height);
}
Exemplo n.º 2
0
/**
 * Interface for getting memory for uploading streamed data to the GPU
 *
 * In most cases, streamed data (for GPU state structures, for example) is
 * uploaded through brw_state_batch(), since that interface allows relocations
 * from the streamed space returned to other BOs.  However, that interface has
 * the restriction that the amount of space allocated has to be "small" (see
 * estimated_max_prim_size in brw_draw.c).
 *
 * This interface, on the other hand, is able to handle arbitrary sized
 * allocation requests, though it will batch small allocations into the same
 * BO for efficiency and reduced memory footprint.
 *
 * \note The returned pointer is valid only until intel_upload_finish(), which
 * will happen at batch flush or the next
 * intel_upload_space()/intel_upload_data().
 *
 * \param out_bo Pointer to a BO, which must point to a valid BO or NULL on
 * entry, and will have a reference to the new BO containing the state on
 * return.
 *
 * \param out_offset Offset within the buffer object that the data will land.
 */
void *
intel_upload_space(struct brw_context *brw,
                   uint32_t size,
                   uint32_t alignment,
                   drm_intel_bo **out_bo,
                   uint32_t *out_offset)
{
   uint32_t offset;

   offset = ALIGN_NPOT(brw->upload.next_offset, alignment);
   if (brw->upload.bo && offset + size > brw->upload.bo->size) {
      intel_upload_finish(brw);
      offset = 0;
   }

   if (!brw->upload.bo) {
      brw->upload.bo = drm_intel_bo_alloc(brw->bufmgr, "streamed data",
                                          MAX2(INTEL_UPLOAD_SIZE, size), 4096);
      if (brw->has_llc)
         drm_intel_bo_map(brw->upload.bo, true);
      else
         drm_intel_gem_bo_map_gtt(brw->upload.bo);
   }

   brw->upload.next_offset = offset + size;

   *out_offset = offset;
   if (*out_bo != brw->upload.bo) {
      drm_intel_bo_unreference(*out_bo);
      *out_bo = brw->upload.bo;
      drm_intel_bo_reference(brw->upload.bo);
   }

   return brw->upload.bo->virtual + offset;
}
Exemplo n.º 3
0
/**
 * Interface for getting memory for uploading streamed data to the GPU
 *
 * In most cases, streamed data (for GPU state structures, for example) is
 * uploaded through brw_state_batch(), since that interface allows relocations
 * from the streamed space returned to other BOs.  However, that interface has
 * the restriction that the amount of space allocated has to be "small" (see
 * estimated_max_prim_size in brw_draw.c).
 *
 * This interface, on the other hand, is able to handle arbitrary sized
 * allocation requests, though it will batch small allocations into the same
 * BO for efficiency and reduced memory footprint.
 *
 * \note The returned pointer is valid only until intel_upload_finish(), which
 * will happen at batch flush or the next
 * intel_upload_space()/intel_upload_data().
 *
 * \param out_bo Pointer to a BO, which must point to a valid BO or NULL on
 * entry, and will have a reference to the new BO containing the state on
 * return.
 *
 * \param out_offset Offset within the buffer object that the data will land.
 */
void *
intel_upload_space(struct brw_context *brw,
                   uint32_t size,
                   uint32_t alignment,
                   struct brw_bo **out_bo,
                   uint32_t *out_offset)
{
   uint32_t offset;

   offset = ALIGN_NPOT(brw->upload.next_offset, alignment);
   if (brw->upload.bo && offset + size > brw->upload.bo->size) {
      intel_upload_finish(brw);
      offset = 0;
   }

   assert((brw->upload.bo == NULL) == (brw->upload.map == NULL));
   if (!brw->upload.bo) {
      brw->upload.bo = brw_bo_alloc(brw->bufmgr, "streamed data",
                                    MAX2(INTEL_UPLOAD_SIZE, size), 4096);
      brw->upload.map = brw_bo_map(brw, brw->upload.bo, MAP_READ | MAP_WRITE);
   }

   brw->upload.next_offset = offset + size;

   *out_offset = offset;
   if (*out_bo != brw->upload.bo) {
      brw_bo_unreference(*out_bo);
      *out_bo = brw->upload.bo;
      brw_bo_reference(brw->upload.bo);
   }

   return brw->upload.map + offset;
}
Exemplo n.º 4
0
unsigned
brw_miptree_get_vertical_slice_pitch(const struct brw_context *brw,
                                     const struct intel_mipmap_tree *mt,
                                     unsigned level)
{
   if (brw->gen >= 9) {
      /* ALL_SLICES_AT_EACH_LOD isn't supported on Gen8+ but this code will
       * effectively end up with a packed qpitch anyway whenever
       * mt->first_level == mt->last_level.
       */
      assert(mt->array_layout != ALL_SLICES_AT_EACH_LOD);

      /* On Gen9 we can pick whatever qpitch we like as long as it's aligned
       * to the vertical alignment so we don't need to add any extra rows.
       */
      unsigned qpitch = mt->total_height;

      /* If the surface might be used as a stencil buffer or HiZ buffer then
       * it needs to be a multiple of 8.
       */
      const GLenum base_format = _mesa_get_format_base_format(mt->format);
      if (_mesa_is_depth_or_stencil_format(base_format))
         qpitch = ALIGN(qpitch, 8);

      /* 3D textures need to be aligned to the tile height. At this point we
       * don't know which tiling will be used so let's just align it to 32
       */
      if (mt->target == GL_TEXTURE_3D)
         qpitch = ALIGN(qpitch, 32);

      return qpitch;

   } else if (mt->target == GL_TEXTURE_3D ||
              (brw->gen == 4 && mt->target == GL_TEXTURE_CUBE_MAP) ||
              mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
      return ALIGN_NPOT(minify(mt->physical_height0, level), mt->align_h);

   } else {
      const unsigned h0 = ALIGN_NPOT(mt->physical_height0, mt->align_h);
      const unsigned h1 = ALIGN_NPOT(minify(mt->physical_height0, 1), mt->align_h);

      return h0 + h1 + (brw->gen >= 7 ? 12 : 11) * mt->align_h;
   }
}
Exemplo n.º 5
0
unsigned
brw_miptree_get_horizontal_slice_pitch(const struct brw_context *brw,
                                       const struct intel_mipmap_tree *mt,
                                       unsigned level)
{
   if ((brw->gen < 9 && mt->target == GL_TEXTURE_3D) ||
       (brw->gen == 4 && mt->target == GL_TEXTURE_CUBE_MAP)) {
      return ALIGN_NPOT(minify(mt->physical_width0, level), mt->align_w);
   } else {
      return 0;
   }
}
Exemplo n.º 6
0
static void
brw_miptree_layout_texture_3d(struct brw_context *brw,
                              struct intel_mipmap_tree *mt)
{
   mt->total_width = 0;
   mt->total_height = 0;

   unsigned ysum = 0;
   unsigned bh, bw;

   _mesa_get_format_block_size(mt->format, &bw, &bh);

   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
      unsigned WL = MAX2(mt->physical_width0 >> level, 1);
      unsigned HL = MAX2(mt->physical_height0 >> level, 1);
      unsigned DL = MAX2(mt->physical_depth0 >> level, 1);
      unsigned wL = ALIGN_NPOT(WL, mt->align_w);
      unsigned hL = ALIGN_NPOT(HL, mt->align_h);

      if (mt->target == GL_TEXTURE_CUBE_MAP)
         DL = 6;

      intel_miptree_set_level_info(mt, level, 0, 0, DL);

      for (unsigned q = 0; q < DL; q++) {
         unsigned x = (q % (1 << level)) * wL;
         unsigned y = ysum + (q >> level) * hL;

         intel_miptree_set_image_offset(mt, level, q, x / bw, y / bh);
         mt->total_width = MAX2(mt->total_width, (x + wL) / bw);
         mt->total_height = MAX2(mt->total_height, (y + hL) / bh);
      }

      ysum += ALIGN(DL, 1 << level) / (1 << level) * hL;
   }

   align_cube(mt);
}
Exemplo n.º 7
0
static void
brw_miptree_layout_texture_array(struct brw_context *brw,
				 struct intel_mipmap_tree *mt)
{
   unsigned height = mt->physical_height0;
   bool layout_1d = gen9_use_linear_1d_layout(brw, mt);
   int physical_qpitch;

   if (layout_1d)
      gen9_miptree_layout_1d(mt);
   else
      brw_miptree_layout_2d(mt);

   if (layout_1d) {
      physical_qpitch = 1;
      /* When using the horizontal layout the qpitch specifies the distance in
       * pixels between array slices. The total_width is forced to be a
       * multiple of the horizontal alignment in brw_miptree_layout_1d (in
       * this case it's always 64). The vertical alignment is ignored.
       */
      mt->qpitch = mt->total_width;
   } else {
      mt->qpitch = brw_miptree_get_vertical_slice_pitch(brw, mt, 0);
      /* Unlike previous generations the qpitch is a multiple of the
       * compressed block size on Gen9 so physical_qpitch matches mt->qpitch.
       */
      physical_qpitch = (mt->compressed && brw->gen < 9 ? mt->qpitch / 4 :
                         mt->qpitch);
   }

   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
      unsigned img_height;
      img_height = ALIGN_NPOT(height, mt->align_h);
      if (mt->compressed)
         img_height /= mt->align_h;

      for (unsigned q = 0; q < mt->level[level].depth; q++) {
         if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
            intel_miptree_set_image_offset(mt, level, q, 0, q * img_height);
         } else {
            intel_miptree_set_image_offset(mt, level, q, 0, q * physical_qpitch);
         }
      }
      height = minify(height, 1);
   }
   if (mt->array_layout == ALL_LOD_IN_EACH_SLICE)
      mt->total_height = physical_qpitch * mt->physical_depth0;

   align_cube(mt);
}
Exemplo n.º 8
0
static void
brw_miptree_layout_2d(struct intel_mipmap_tree *mt)
{
   unsigned x = 0;
   unsigned y = 0;
   unsigned width = mt->physical_width0;
   unsigned height = mt->physical_height0;
   unsigned depth = mt->physical_depth0; /* number of array layers. */
   unsigned int bw, bh;

   _mesa_get_format_block_size(mt->format, &bw, &bh);

   mt->total_width = mt->physical_width0;

   if (mt->compressed)
       mt->total_width = ALIGN_NPOT(mt->total_width, bw);

   /* May need to adjust width to accommodate the placement of
    * the 2nd mipmap.  This occurs when the alignment
    * constraints of mipmap placement push the right edge of the
    * 2nd mipmap out past the width of its parent.
    */
   if (mt->first_level != mt->last_level) {
       unsigned mip1_width;

       if (mt->compressed) {
          mip1_width = ALIGN_NPOT(minify(mt->physical_width0, 1), mt->align_w) +
             ALIGN_NPOT(minify(mt->physical_width0, 2), bw);
       } else {
          mip1_width = ALIGN_NPOT(minify(mt->physical_width0, 1), mt->align_w) +
             minify(mt->physical_width0, 2);
       }

       if (mip1_width > mt->total_width) {
           mt->total_width = mip1_width;
       }
   }

   mt->total_width /= bw;
   mt->total_height = 0;

   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
      unsigned img_height;

      intel_miptree_set_level_info(mt, level, x, y, depth);

      img_height = ALIGN_NPOT(height, mt->align_h);
      if (mt->compressed)
	 img_height /= bh;

      if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
         /* Compact arrays with separated miplevels */
         img_height *= depth;
      }

      /* Because the images are packed better, the final offset
       * might not be the maximal one:
       */
      mt->total_height = MAX2(mt->total_height, y + img_height);

      /* Layout_below: step right after second mipmap.
       */
      if (level == mt->first_level + 1) {
	 x += ALIGN_NPOT(width, mt->align_w) / bw;
      } else {
	 y += img_height;
      }

      width  = minify(width, 1);
      height = minify(height, 1);

      if (mt->target == GL_TEXTURE_3D)
         depth = minify(depth, 1);
   }
}