isl.c revision 9f464c52
101e04c3fSmrg/*
201e04c3fSmrg * Copyright 2015 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg *  Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg *  copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg *  to deal in the Software without restriction, including without limitation
701e04c3fSmrg *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg *  and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg *  Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg *  The above copyright notice and this permission notice (including the next
1201e04c3fSmrg *  paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg *  Software.
1401e04c3fSmrg *
1501e04c3fSmrg *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg *  IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#include <assert.h>
2501e04c3fSmrg#include <stdarg.h>
2601e04c3fSmrg#include <stdio.h>
2701e04c3fSmrg
2801e04c3fSmrg#include "genxml/genX_bits.h"
2901e04c3fSmrg
3001e04c3fSmrg#include "isl.h"
3101e04c3fSmrg#include "isl_gen4.h"
3201e04c3fSmrg#include "isl_gen6.h"
3301e04c3fSmrg#include "isl_gen7.h"
3401e04c3fSmrg#include "isl_gen8.h"
3501e04c3fSmrg#include "isl_gen9.h"
3601e04c3fSmrg#include "isl_priv.h"
3701e04c3fSmrg
389f464c52Smayavoid
399f464c52Smayaisl_memcpy_linear_to_tiled(uint32_t xt1, uint32_t xt2,
409f464c52Smaya                           uint32_t yt1, uint32_t yt2,
419f464c52Smaya                           char *dst, const char *src,
429f464c52Smaya                           uint32_t dst_pitch, int32_t src_pitch,
439f464c52Smaya                           bool has_swizzling,
449f464c52Smaya                           enum isl_tiling tiling,
459f464c52Smaya                           isl_memcpy_type copy_type)
469f464c52Smaya{
479f464c52Smaya#ifdef USE_SSE41
489f464c52Smaya   if (copy_type == ISL_MEMCPY_STREAMING_LOAD) {
499f464c52Smaya      _isl_memcpy_linear_to_tiled_sse41(
509f464c52Smaya         xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
519f464c52Smaya         tiling, copy_type);
529f464c52Smaya      return;
539f464c52Smaya   }
549f464c52Smaya#endif
559f464c52Smaya
569f464c52Smaya   _isl_memcpy_linear_to_tiled(
579f464c52Smaya      xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
589f464c52Smaya      tiling, copy_type);
599f464c52Smaya}
609f464c52Smaya
619f464c52Smayavoid
629f464c52Smayaisl_memcpy_tiled_to_linear(uint32_t xt1, uint32_t xt2,
639f464c52Smaya                           uint32_t yt1, uint32_t yt2,
649f464c52Smaya                           char *dst, const char *src,
659f464c52Smaya                           int32_t dst_pitch, uint32_t src_pitch,
669f464c52Smaya                           bool has_swizzling,
679f464c52Smaya                           enum isl_tiling tiling,
689f464c52Smaya                           isl_memcpy_type copy_type)
699f464c52Smaya{
709f464c52Smaya#ifdef USE_SSE41
719f464c52Smaya   if (copy_type == ISL_MEMCPY_STREAMING_LOAD) {
729f464c52Smaya      _isl_memcpy_tiled_to_linear_sse41(
739f464c52Smaya         xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
749f464c52Smaya         tiling, copy_type);
759f464c52Smaya      return;
769f464c52Smaya   }
779f464c52Smaya#endif
789f464c52Smaya
799f464c52Smaya   _isl_memcpy_tiled_to_linear(
809f464c52Smaya      xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
819f464c52Smaya      tiling, copy_type);
829f464c52Smaya}
839f464c52Smaya
8401e04c3fSmrgvoid PRINTFLIKE(3, 4) UNUSED
8501e04c3fSmrg__isl_finishme(const char *file, int line, const char *fmt, ...)
8601e04c3fSmrg{
8701e04c3fSmrg   va_list ap;
8801e04c3fSmrg   char buf[512];
8901e04c3fSmrg
9001e04c3fSmrg   va_start(ap, fmt);
9101e04c3fSmrg   vsnprintf(buf, sizeof(buf), fmt, ap);
9201e04c3fSmrg   va_end(ap);
9301e04c3fSmrg
9401e04c3fSmrg   fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buf);
9501e04c3fSmrg}
9601e04c3fSmrg
9701e04c3fSmrgvoid
9801e04c3fSmrgisl_device_init(struct isl_device *dev,
9901e04c3fSmrg                const struct gen_device_info *info,
10001e04c3fSmrg                bool has_bit6_swizzling)
10101e04c3fSmrg{
1029f464c52Smaya   /* Gen8+ don't have bit6 swizzling, ensure callsite is not confused. */
1039f464c52Smaya   assert(!(has_bit6_swizzling && info->gen >= 8));
1049f464c52Smaya
10501e04c3fSmrg   dev->info = info;
10601e04c3fSmrg   dev->use_separate_stencil = ISL_DEV_GEN(dev) >= 6;
10701e04c3fSmrg   dev->has_bit6_swizzling = has_bit6_swizzling;
10801e04c3fSmrg
10901e04c3fSmrg   /* The ISL_DEV macros may be defined in the CFLAGS, thus hardcoding some
11001e04c3fSmrg    * device properties at buildtime. Verify that the macros with the device
11101e04c3fSmrg    * properties chosen during runtime.
11201e04c3fSmrg    */
11301e04c3fSmrg   ISL_DEV_GEN_SANITIZE(dev);
11401e04c3fSmrg   ISL_DEV_USE_SEPARATE_STENCIL_SANITIZE(dev);
11501e04c3fSmrg
11601e04c3fSmrg   /* Did we break hiz or stencil? */
11701e04c3fSmrg   if (ISL_DEV_USE_SEPARATE_STENCIL(dev))
11801e04c3fSmrg      assert(info->has_hiz_and_separate_stencil);
11901e04c3fSmrg   if (info->must_use_separate_stencil)
12001e04c3fSmrg      assert(ISL_DEV_USE_SEPARATE_STENCIL(dev));
12101e04c3fSmrg
12201e04c3fSmrg   dev->ss.size = RENDER_SURFACE_STATE_length(info) * 4;
12301e04c3fSmrg   dev->ss.align = isl_align(dev->ss.size, 32);
12401e04c3fSmrg
1259f464c52Smaya   dev->ss.clear_color_state_size =
1269f464c52Smaya      isl_align(CLEAR_COLOR_length(info) * 4, 64);
12701e04c3fSmrg   dev->ss.clear_color_state_offset =
12801e04c3fSmrg      RENDER_SURFACE_STATE_ClearValueAddress_start(info) / 32 * 4;
12901e04c3fSmrg
13001e04c3fSmrg   dev->ss.clear_value_size =
13101e04c3fSmrg      isl_align(RENDER_SURFACE_STATE_RedClearColor_bits(info) +
13201e04c3fSmrg                RENDER_SURFACE_STATE_GreenClearColor_bits(info) +
13301e04c3fSmrg                RENDER_SURFACE_STATE_BlueClearColor_bits(info) +
13401e04c3fSmrg                RENDER_SURFACE_STATE_AlphaClearColor_bits(info), 32) / 8;
13501e04c3fSmrg
13601e04c3fSmrg   dev->ss.clear_value_offset =
13701e04c3fSmrg      RENDER_SURFACE_STATE_RedClearColor_start(info) / 32 * 4;
13801e04c3fSmrg
13901e04c3fSmrg   assert(RENDER_SURFACE_STATE_SurfaceBaseAddress_start(info) % 8 == 0);
14001e04c3fSmrg   dev->ss.addr_offset =
14101e04c3fSmrg      RENDER_SURFACE_STATE_SurfaceBaseAddress_start(info) / 8;
14201e04c3fSmrg
14301e04c3fSmrg   /* The "Auxiliary Surface Base Address" field starts a bit higher up
14401e04c3fSmrg    * because the bottom 12 bits are used for other things.  Round down to
14501e04c3fSmrg    * the nearest dword before.
14601e04c3fSmrg    */
14701e04c3fSmrg   dev->ss.aux_addr_offset =
14801e04c3fSmrg      (RENDER_SURFACE_STATE_AuxiliarySurfaceBaseAddress_start(info) & ~31) / 8;
14901e04c3fSmrg
15001e04c3fSmrg   dev->ds.size = _3DSTATE_DEPTH_BUFFER_length(info) * 4;
15101e04c3fSmrg   assert(_3DSTATE_DEPTH_BUFFER_SurfaceBaseAddress_start(info) % 8 == 0);
15201e04c3fSmrg   dev->ds.depth_offset =
15301e04c3fSmrg      _3DSTATE_DEPTH_BUFFER_SurfaceBaseAddress_start(info) / 8;
15401e04c3fSmrg
15501e04c3fSmrg   if (dev->use_separate_stencil) {
15601e04c3fSmrg      dev->ds.size += _3DSTATE_STENCIL_BUFFER_length(info) * 4 +
15701e04c3fSmrg                      _3DSTATE_HIER_DEPTH_BUFFER_length(info) * 4 +
15801e04c3fSmrg                      _3DSTATE_CLEAR_PARAMS_length(info) * 4;
15901e04c3fSmrg
16001e04c3fSmrg      assert(_3DSTATE_STENCIL_BUFFER_SurfaceBaseAddress_start(info) % 8 == 0);
16101e04c3fSmrg      dev->ds.stencil_offset =
16201e04c3fSmrg         _3DSTATE_DEPTH_BUFFER_length(info) * 4 +
16301e04c3fSmrg         _3DSTATE_STENCIL_BUFFER_SurfaceBaseAddress_start(info) / 8;
16401e04c3fSmrg
16501e04c3fSmrg      assert(_3DSTATE_HIER_DEPTH_BUFFER_SurfaceBaseAddress_start(info) % 8 == 0);
16601e04c3fSmrg      dev->ds.hiz_offset =
16701e04c3fSmrg         _3DSTATE_DEPTH_BUFFER_length(info) * 4 +
16801e04c3fSmrg         _3DSTATE_STENCIL_BUFFER_length(info) * 4 +
16901e04c3fSmrg         _3DSTATE_HIER_DEPTH_BUFFER_SurfaceBaseAddress_start(info) / 8;
17001e04c3fSmrg   } else {
17101e04c3fSmrg      dev->ds.stencil_offset = 0;
17201e04c3fSmrg      dev->ds.hiz_offset = 0;
17301e04c3fSmrg   }
17401e04c3fSmrg}
17501e04c3fSmrg
17601e04c3fSmrg/**
17701e04c3fSmrg * @brief Query the set of multisamples supported by the device.
17801e04c3fSmrg *
17901e04c3fSmrg * This function always returns non-zero, as ISL_SAMPLE_COUNT_1_BIT is always
18001e04c3fSmrg * supported.
18101e04c3fSmrg */
18201e04c3fSmrgisl_sample_count_mask_t ATTRIBUTE_CONST
18301e04c3fSmrgisl_device_get_sample_counts(struct isl_device *dev)
18401e04c3fSmrg{
18501e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 9) {
18601e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
18701e04c3fSmrg             ISL_SAMPLE_COUNT_2_BIT |
18801e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT |
18901e04c3fSmrg             ISL_SAMPLE_COUNT_8_BIT |
19001e04c3fSmrg             ISL_SAMPLE_COUNT_16_BIT;
19101e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 8) {
19201e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
19301e04c3fSmrg             ISL_SAMPLE_COUNT_2_BIT |
19401e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT |
19501e04c3fSmrg             ISL_SAMPLE_COUNT_8_BIT;
19601e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 7) {
19701e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
19801e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT |
19901e04c3fSmrg             ISL_SAMPLE_COUNT_8_BIT;
20001e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 6) {
20101e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
20201e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT;
20301e04c3fSmrg   } else {
20401e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT;
20501e04c3fSmrg   }
20601e04c3fSmrg}
20701e04c3fSmrg
20801e04c3fSmrg/**
20901e04c3fSmrg * @param[out] info is written only on success
21001e04c3fSmrg */
21101e04c3fSmrgstatic void
21201e04c3fSmrgisl_tiling_get_info(enum isl_tiling tiling,
21301e04c3fSmrg                    uint32_t format_bpb,
21401e04c3fSmrg                    struct isl_tile_info *tile_info)
21501e04c3fSmrg{
21601e04c3fSmrg   const uint32_t bs = format_bpb / 8;
21701e04c3fSmrg   struct isl_extent2d logical_el, phys_B;
21801e04c3fSmrg
21901e04c3fSmrg   if (tiling != ISL_TILING_LINEAR && !isl_is_pow2(format_bpb)) {
22001e04c3fSmrg      /* It is possible to have non-power-of-two formats in a tiled buffer.
22101e04c3fSmrg       * The easiest way to handle this is to treat the tile as if it is three
22201e04c3fSmrg       * times as wide.  This way no pixel will ever cross a tile boundary.
22301e04c3fSmrg       * This really only works on legacy X and Y tiling formats.
22401e04c3fSmrg       */
22501e04c3fSmrg      assert(tiling == ISL_TILING_X || tiling == ISL_TILING_Y0);
22601e04c3fSmrg      assert(bs % 3 == 0 && isl_is_pow2(format_bpb / 3));
22701e04c3fSmrg      isl_tiling_get_info(tiling, format_bpb / 3, tile_info);
22801e04c3fSmrg      return;
22901e04c3fSmrg   }
23001e04c3fSmrg
23101e04c3fSmrg   switch (tiling) {
23201e04c3fSmrg   case ISL_TILING_LINEAR:
23301e04c3fSmrg      assert(bs > 0);
23401e04c3fSmrg      logical_el = isl_extent2d(1, 1);
23501e04c3fSmrg      phys_B = isl_extent2d(bs, 1);
23601e04c3fSmrg      break;
23701e04c3fSmrg
23801e04c3fSmrg   case ISL_TILING_X:
23901e04c3fSmrg      assert(bs > 0);
24001e04c3fSmrg      logical_el = isl_extent2d(512 / bs, 8);
24101e04c3fSmrg      phys_B = isl_extent2d(512, 8);
24201e04c3fSmrg      break;
24301e04c3fSmrg
24401e04c3fSmrg   case ISL_TILING_Y0:
24501e04c3fSmrg      assert(bs > 0);
24601e04c3fSmrg      logical_el = isl_extent2d(128 / bs, 32);
24701e04c3fSmrg      phys_B = isl_extent2d(128, 32);
24801e04c3fSmrg      break;
24901e04c3fSmrg
25001e04c3fSmrg   case ISL_TILING_W:
25101e04c3fSmrg      assert(bs == 1);
25201e04c3fSmrg      logical_el = isl_extent2d(64, 64);
25301e04c3fSmrg      /* From the Broadwell PRM Vol 2d, RENDER_SURFACE_STATE::SurfacePitch:
25401e04c3fSmrg       *
25501e04c3fSmrg       *    "If the surface is a stencil buffer (and thus has Tile Mode set
25601e04c3fSmrg       *    to TILEMODE_WMAJOR), the pitch must be set to 2x the value
25701e04c3fSmrg       *    computed based on width, as the stencil buffer is stored with two
25801e04c3fSmrg       *    rows interleaved."
25901e04c3fSmrg       *
26001e04c3fSmrg       * This, together with the fact that stencil buffers are referred to as
26101e04c3fSmrg       * being Y-tiled in the PRMs for older hardware implies that the
26201e04c3fSmrg       * physical size of a W-tile is actually the same as for a Y-tile.
26301e04c3fSmrg       */
26401e04c3fSmrg      phys_B = isl_extent2d(128, 32);
26501e04c3fSmrg      break;
26601e04c3fSmrg
26701e04c3fSmrg   case ISL_TILING_Yf:
26801e04c3fSmrg   case ISL_TILING_Ys: {
26901e04c3fSmrg      bool is_Ys = tiling == ISL_TILING_Ys;
27001e04c3fSmrg
27101e04c3fSmrg      assert(bs > 0);
27201e04c3fSmrg      unsigned width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys));
27301e04c3fSmrg      unsigned height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys));
27401e04c3fSmrg
27501e04c3fSmrg      logical_el = isl_extent2d(width / bs, height);
27601e04c3fSmrg      phys_B = isl_extent2d(width, height);
27701e04c3fSmrg      break;
27801e04c3fSmrg   }
27901e04c3fSmrg
28001e04c3fSmrg   case ISL_TILING_HIZ:
28101e04c3fSmrg      /* HiZ buffers are required to have ISL_FORMAT_HIZ which is an 8x4
28201e04c3fSmrg       * 128bpb format.  The tiling has the same physical dimensions as
28301e04c3fSmrg       * Y-tiling but actually has two HiZ columns per Y-tiled column.
28401e04c3fSmrg       */
28501e04c3fSmrg      assert(bs == 16);
28601e04c3fSmrg      logical_el = isl_extent2d(16, 16);
28701e04c3fSmrg      phys_B = isl_extent2d(128, 32);
28801e04c3fSmrg      break;
28901e04c3fSmrg
29001e04c3fSmrg   case ISL_TILING_CCS:
29101e04c3fSmrg      /* CCS surfaces are required to have one of the GENX_CCS_* formats which
29201e04c3fSmrg       * have a block size of 1 or 2 bits per block and each CCS element
29301e04c3fSmrg       * corresponds to one cache-line pair in the main surface.  From the Sky
29401e04c3fSmrg       * Lake PRM Vol. 12 in the section on planes:
29501e04c3fSmrg       *
29601e04c3fSmrg       *    "The Color Control Surface (CCS) contains the compression status
29701e04c3fSmrg       *    of the cache-line pairs. The compression state of the cache-line
29801e04c3fSmrg       *    pair is specified by 2 bits in the CCS.  Each CCS cache-line
29901e04c3fSmrg       *    represents an area on the main surface of 16x16 sets of 128 byte
30001e04c3fSmrg       *    Y-tiled cache-line-pairs. CCS is always Y tiled."
30101e04c3fSmrg       *
30201e04c3fSmrg       * The CCS being Y-tiled implies that it's an 8x8 grid of cache-lines.
30301e04c3fSmrg       * Since each cache line corresponds to a 16x16 set of cache-line pairs,
30401e04c3fSmrg       * that yields total tile area of 128x128 cache-line pairs or CCS
30501e04c3fSmrg       * elements.  On older hardware, each CCS element is 1 bit and the tile
30601e04c3fSmrg       * is 128x256 elements.
30701e04c3fSmrg       */
30801e04c3fSmrg      assert(format_bpb == 1 || format_bpb == 2);
30901e04c3fSmrg      logical_el = isl_extent2d(128, 256 / format_bpb);
31001e04c3fSmrg      phys_B = isl_extent2d(128, 32);
31101e04c3fSmrg      break;
31201e04c3fSmrg
31301e04c3fSmrg   default:
31401e04c3fSmrg      unreachable("not reached");
31501e04c3fSmrg   } /* end switch */
31601e04c3fSmrg
31701e04c3fSmrg   *tile_info = (struct isl_tile_info) {
31801e04c3fSmrg      .tiling = tiling,
31901e04c3fSmrg      .format_bpb = format_bpb,
32001e04c3fSmrg      .logical_extent_el = logical_el,
32101e04c3fSmrg      .phys_extent_B = phys_B,
32201e04c3fSmrg   };
32301e04c3fSmrg}
32401e04c3fSmrg
32501e04c3fSmrgbool
32601e04c3fSmrgisl_color_value_is_zero(union isl_color_value value,
32701e04c3fSmrg                        enum isl_format format)
32801e04c3fSmrg{
32901e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(format);
33001e04c3fSmrg
33101e04c3fSmrg#define RETURN_FALSE_IF_NOT_0(c, i) \
33201e04c3fSmrg   if (fmtl->channels.c.bits && value.u32[i] != 0) \
33301e04c3fSmrg      return false
33401e04c3fSmrg
33501e04c3fSmrg   RETURN_FALSE_IF_NOT_0(r, 0);
33601e04c3fSmrg   RETURN_FALSE_IF_NOT_0(g, 1);
33701e04c3fSmrg   RETURN_FALSE_IF_NOT_0(b, 2);
33801e04c3fSmrg   RETURN_FALSE_IF_NOT_0(a, 3);
33901e04c3fSmrg
34001e04c3fSmrg#undef RETURN_FALSE_IF_NOT_0
34101e04c3fSmrg
34201e04c3fSmrg   return true;
34301e04c3fSmrg}
34401e04c3fSmrg
34501e04c3fSmrgbool
34601e04c3fSmrgisl_color_value_is_zero_one(union isl_color_value value,
34701e04c3fSmrg                            enum isl_format format)
34801e04c3fSmrg{
34901e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(format);
35001e04c3fSmrg
35101e04c3fSmrg#define RETURN_FALSE_IF_NOT_0_1(c, i, field) \
35201e04c3fSmrg   if (fmtl->channels.c.bits && value.field[i] != 0 && value.field[i] != 1) \
35301e04c3fSmrg      return false
35401e04c3fSmrg
35501e04c3fSmrg   if (isl_format_has_int_channel(format)) {
35601e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(r, 0, u32);
35701e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(g, 1, u32);
35801e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(b, 2, u32);
35901e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(a, 3, u32);
36001e04c3fSmrg   } else {
36101e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(r, 0, f32);
36201e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(g, 1, f32);
36301e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(b, 2, f32);
36401e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(a, 3, f32);
36501e04c3fSmrg   }
36601e04c3fSmrg
36701e04c3fSmrg#undef RETURN_FALSE_IF_NOT_0_1
36801e04c3fSmrg
36901e04c3fSmrg   return true;
37001e04c3fSmrg}
37101e04c3fSmrg
37201e04c3fSmrg/**
37301e04c3fSmrg * @param[out] tiling is set only on success
37401e04c3fSmrg */
37501e04c3fSmrgstatic bool
37601e04c3fSmrgisl_surf_choose_tiling(const struct isl_device *dev,
37701e04c3fSmrg                       const struct isl_surf_init_info *restrict info,
37801e04c3fSmrg                       enum isl_tiling *tiling)
37901e04c3fSmrg{
38001e04c3fSmrg   isl_tiling_flags_t tiling_flags = info->tiling_flags;
38101e04c3fSmrg
38201e04c3fSmrg   /* HiZ surfaces always use the HiZ tiling */
38301e04c3fSmrg   if (info->usage & ISL_SURF_USAGE_HIZ_BIT) {
38401e04c3fSmrg      assert(info->format == ISL_FORMAT_HIZ);
38501e04c3fSmrg      assert(tiling_flags == ISL_TILING_HIZ_BIT);
38601e04c3fSmrg      *tiling = ISL_TILING_HIZ;
38701e04c3fSmrg      return true;
38801e04c3fSmrg   }
38901e04c3fSmrg
39001e04c3fSmrg   /* CCS surfaces always use the CCS tiling */
39101e04c3fSmrg   if (info->usage & ISL_SURF_USAGE_CCS_BIT) {
39201e04c3fSmrg      assert(isl_format_get_layout(info->format)->txc == ISL_TXC_CCS);
39301e04c3fSmrg      assert(tiling_flags == ISL_TILING_CCS_BIT);
39401e04c3fSmrg      *tiling = ISL_TILING_CCS;
39501e04c3fSmrg      return true;
39601e04c3fSmrg   }
39701e04c3fSmrg
39801e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 6) {
39901e04c3fSmrg      isl_gen6_filter_tiling(dev, info, &tiling_flags);
40001e04c3fSmrg   } else {
40101e04c3fSmrg      isl_gen4_filter_tiling(dev, info, &tiling_flags);
40201e04c3fSmrg   }
40301e04c3fSmrg
40401e04c3fSmrg   #define CHOOSE(__tiling) \
40501e04c3fSmrg      do { \
40601e04c3fSmrg         if (tiling_flags & (1u << (__tiling))) { \
40701e04c3fSmrg            *tiling = (__tiling); \
40801e04c3fSmrg            return true; \
40901e04c3fSmrg          } \
41001e04c3fSmrg      } while (0)
41101e04c3fSmrg
41201e04c3fSmrg   /* Of the tiling modes remaining, choose the one that offers the best
41301e04c3fSmrg    * performance.
41401e04c3fSmrg    */
41501e04c3fSmrg
41601e04c3fSmrg   if (info->dim == ISL_SURF_DIM_1D) {
41701e04c3fSmrg      /* Prefer linear for 1D surfaces because they do not benefit from
41801e04c3fSmrg       * tiling. To the contrary, tiling leads to wasted memory and poor
41901e04c3fSmrg       * memory locality due to the swizzling and alignment restrictions
42001e04c3fSmrg       * required in tiled surfaces.
42101e04c3fSmrg       */
42201e04c3fSmrg      CHOOSE(ISL_TILING_LINEAR);
42301e04c3fSmrg   }
42401e04c3fSmrg
42501e04c3fSmrg   CHOOSE(ISL_TILING_Ys);
42601e04c3fSmrg   CHOOSE(ISL_TILING_Yf);
42701e04c3fSmrg   CHOOSE(ISL_TILING_Y0);
42801e04c3fSmrg   CHOOSE(ISL_TILING_X);
42901e04c3fSmrg   CHOOSE(ISL_TILING_W);
43001e04c3fSmrg   CHOOSE(ISL_TILING_LINEAR);
43101e04c3fSmrg
43201e04c3fSmrg   #undef CHOOSE
43301e04c3fSmrg
43401e04c3fSmrg   /* No tiling mode accomodates the inputs. */
43501e04c3fSmrg   return false;
43601e04c3fSmrg}
43701e04c3fSmrg
43801e04c3fSmrgstatic bool
43901e04c3fSmrgisl_choose_msaa_layout(const struct isl_device *dev,
44001e04c3fSmrg                 const struct isl_surf_init_info *info,
44101e04c3fSmrg                 enum isl_tiling tiling,
44201e04c3fSmrg                 enum isl_msaa_layout *msaa_layout)
44301e04c3fSmrg{
44401e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 8) {
44501e04c3fSmrg      return isl_gen8_choose_msaa_layout(dev, info, tiling, msaa_layout);
44601e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 7) {
44701e04c3fSmrg      return isl_gen7_choose_msaa_layout(dev, info, tiling, msaa_layout);
44801e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 6) {
44901e04c3fSmrg      return isl_gen6_choose_msaa_layout(dev, info, tiling, msaa_layout);
45001e04c3fSmrg   } else {
45101e04c3fSmrg      return isl_gen4_choose_msaa_layout(dev, info, tiling, msaa_layout);
45201e04c3fSmrg   }
45301e04c3fSmrg}
45401e04c3fSmrg
45501e04c3fSmrgstruct isl_extent2d
45601e04c3fSmrgisl_get_interleaved_msaa_px_size_sa(uint32_t samples)
45701e04c3fSmrg{
45801e04c3fSmrg   assert(isl_is_pow2(samples));
45901e04c3fSmrg
46001e04c3fSmrg   /* From the Broadwell PRM >> Volume 5: Memory Views >> Computing Mip Level
46101e04c3fSmrg    * Sizes (p133):
46201e04c3fSmrg    *
46301e04c3fSmrg    *    If the surface is multisampled and it is a depth or stencil surface
46401e04c3fSmrg    *    or Multisampled Surface StorageFormat in SURFACE_STATE is
46501e04c3fSmrg    *    MSFMT_DEPTH_STENCIL, W_L and H_L must be adjusted as follows before
46601e04c3fSmrg    *    proceeding: [...]
46701e04c3fSmrg    */
46801e04c3fSmrg   return (struct isl_extent2d) {
46901e04c3fSmrg      .width = 1 << ((ffs(samples) - 0) / 2),
47001e04c3fSmrg      .height = 1 << ((ffs(samples) - 1) / 2),
47101e04c3fSmrg   };
47201e04c3fSmrg}
47301e04c3fSmrg
47401e04c3fSmrgstatic void
47501e04c3fSmrgisl_msaa_interleaved_scale_px_to_sa(uint32_t samples,
47601e04c3fSmrg                                    uint32_t *width, uint32_t *height)
47701e04c3fSmrg{
47801e04c3fSmrg   const struct isl_extent2d px_size_sa =
47901e04c3fSmrg      isl_get_interleaved_msaa_px_size_sa(samples);
48001e04c3fSmrg
48101e04c3fSmrg   if (width)
48201e04c3fSmrg      *width = isl_align(*width, 2) * px_size_sa.width;
48301e04c3fSmrg   if (height)
48401e04c3fSmrg      *height = isl_align(*height, 2) * px_size_sa.height;
48501e04c3fSmrg}
48601e04c3fSmrg
48701e04c3fSmrgstatic enum isl_array_pitch_span
48801e04c3fSmrgisl_choose_array_pitch_span(const struct isl_device *dev,
48901e04c3fSmrg                            const struct isl_surf_init_info *restrict info,
49001e04c3fSmrg                            enum isl_dim_layout dim_layout,
49101e04c3fSmrg                            const struct isl_extent4d *phys_level0_sa)
49201e04c3fSmrg{
49301e04c3fSmrg   switch (dim_layout) {
49401e04c3fSmrg   case ISL_DIM_LAYOUT_GEN9_1D:
49501e04c3fSmrg   case ISL_DIM_LAYOUT_GEN4_2D:
49601e04c3fSmrg      if (ISL_DEV_GEN(dev) >= 8) {
49701e04c3fSmrg         /* QPitch becomes programmable in Broadwell. So choose the
49801e04c3fSmrg          * most compact QPitch possible in order to conserve memory.
49901e04c3fSmrg          *
50001e04c3fSmrg          * From the Broadwell PRM >> Volume 2d: Command Reference: Structures
50101e04c3fSmrg          * >> RENDER_SURFACE_STATE Surface QPitch (p325):
50201e04c3fSmrg          *
50301e04c3fSmrg          *    - Software must ensure that this field is set to a value
50401e04c3fSmrg          *      sufficiently large such that the array slices in the surface
50501e04c3fSmrg          *      do not overlap. Refer to the Memory Data Formats section for
50601e04c3fSmrg          *      information on how surfaces are stored in memory.
50701e04c3fSmrg          *
50801e04c3fSmrg          *    - This field specifies the distance in rows between array
50901e04c3fSmrg          *      slices.  It is used only in the following cases:
51001e04c3fSmrg          *
51101e04c3fSmrg          *          - Surface Array is enabled OR
51201e04c3fSmrg          *          - Number of Mulitsamples is not NUMSAMPLES_1 and
51301e04c3fSmrg          *            Multisampled Surface Storage Format set to MSFMT_MSS OR
51401e04c3fSmrg          *          - Surface Type is SURFTYPE_CUBE
51501e04c3fSmrg          */
51601e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_COMPACT;
51701e04c3fSmrg      } else if (ISL_DEV_GEN(dev) >= 7) {
51801e04c3fSmrg         /* Note that Ivybridge introduces
51901e04c3fSmrg          * RENDER_SURFACE_STATE.SurfaceArraySpacing, which provides the
52001e04c3fSmrg          * driver more control over the QPitch.
52101e04c3fSmrg          */
52201e04c3fSmrg
52301e04c3fSmrg         if (phys_level0_sa->array_len == 1) {
52401e04c3fSmrg            /* The hardware will never use the QPitch. So choose the most
52501e04c3fSmrg             * compact QPitch possible in order to conserve memory.
52601e04c3fSmrg             */
52701e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
52801e04c3fSmrg         }
52901e04c3fSmrg
53001e04c3fSmrg         if (isl_surf_usage_is_depth_or_stencil(info->usage) ||
53101e04c3fSmrg             (info->usage & ISL_SURF_USAGE_HIZ_BIT)) {
53201e04c3fSmrg            /* From the Ivybridge PRM >> Volume 1 Part 1: Graphics Core >>
53301e04c3fSmrg             * Section 6.18.4.7: Surface Arrays (p112):
53401e04c3fSmrg             *
53501e04c3fSmrg             *    If Surface Array Spacing is set to ARYSPC_FULL (note that
53601e04c3fSmrg             *    the depth buffer and stencil buffer have an implied value of
53701e04c3fSmrg             *    ARYSPC_FULL):
53801e04c3fSmrg             */
53901e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_FULL;
54001e04c3fSmrg         }
54101e04c3fSmrg
54201e04c3fSmrg         if (info->levels == 1) {
54301e04c3fSmrg            /* We are able to set RENDER_SURFACE_STATE.SurfaceArraySpacing
54401e04c3fSmrg             * to ARYSPC_LOD0.
54501e04c3fSmrg             */
54601e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
54701e04c3fSmrg         }
54801e04c3fSmrg
54901e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_FULL;
55001e04c3fSmrg      } else if ((ISL_DEV_GEN(dev) == 5 || ISL_DEV_GEN(dev) == 6) &&
55101e04c3fSmrg                 ISL_DEV_USE_SEPARATE_STENCIL(dev) &&
55201e04c3fSmrg                 isl_surf_usage_is_stencil(info->usage)) {
55301e04c3fSmrg         /* [ILK-SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
55401e04c3fSmrg          * Graphics Core >> Section 7.18.3.7: Surface Arrays:
55501e04c3fSmrg          *
55601e04c3fSmrg          *    The separate stencil buffer does not support mip mapping, thus
55701e04c3fSmrg          *    the storage for LODs other than LOD 0 is not needed.
55801e04c3fSmrg          */
55901e04c3fSmrg         assert(info->levels == 1);
56001e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_COMPACT;
56101e04c3fSmrg      } else {
56201e04c3fSmrg         if ((ISL_DEV_GEN(dev) == 5 || ISL_DEV_GEN(dev) == 6) &&
56301e04c3fSmrg             ISL_DEV_USE_SEPARATE_STENCIL(dev) &&
56401e04c3fSmrg             isl_surf_usage_is_stencil(info->usage)) {
56501e04c3fSmrg            /* [ILK-SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
56601e04c3fSmrg             * Graphics Core >> Section 7.18.3.7: Surface Arrays:
56701e04c3fSmrg             *
56801e04c3fSmrg             *    The separate stencil buffer does not support mip mapping,
56901e04c3fSmrg             *    thus the storage for LODs other than LOD 0 is not needed.
57001e04c3fSmrg             */
57101e04c3fSmrg            assert(info->levels == 1);
57201e04c3fSmrg            assert(phys_level0_sa->array_len == 1);
57301e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
57401e04c3fSmrg         }
57501e04c3fSmrg
57601e04c3fSmrg         if (phys_level0_sa->array_len == 1) {
57701e04c3fSmrg            /* The hardware will never use the QPitch. So choose the most
57801e04c3fSmrg             * compact QPitch possible in order to conserve memory.
57901e04c3fSmrg             */
58001e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
58101e04c3fSmrg         }
58201e04c3fSmrg
58301e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_FULL;
58401e04c3fSmrg      }
58501e04c3fSmrg
58601e04c3fSmrg   case ISL_DIM_LAYOUT_GEN4_3D:
58701e04c3fSmrg      /* The hardware will never use the QPitch. So choose the most
58801e04c3fSmrg       * compact QPitch possible in order to conserve memory.
58901e04c3fSmrg       */
59001e04c3fSmrg      return ISL_ARRAY_PITCH_SPAN_COMPACT;
59101e04c3fSmrg
59201e04c3fSmrg   case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
59301e04c3fSmrg      /* Each array image in the gen6 stencil of HiZ surface is compact in the
59401e04c3fSmrg       * sense that every LOD is a compact array of the same size as LOD0.
59501e04c3fSmrg       */
59601e04c3fSmrg      return ISL_ARRAY_PITCH_SPAN_COMPACT;
59701e04c3fSmrg   }
59801e04c3fSmrg
59901e04c3fSmrg   unreachable("bad isl_dim_layout");
60001e04c3fSmrg   return ISL_ARRAY_PITCH_SPAN_FULL;
60101e04c3fSmrg}
60201e04c3fSmrg
60301e04c3fSmrgstatic void
60401e04c3fSmrgisl_choose_image_alignment_el(const struct isl_device *dev,
60501e04c3fSmrg                              const struct isl_surf_init_info *restrict info,
60601e04c3fSmrg                              enum isl_tiling tiling,
60701e04c3fSmrg                              enum isl_dim_layout dim_layout,
60801e04c3fSmrg                              enum isl_msaa_layout msaa_layout,
60901e04c3fSmrg                              struct isl_extent3d *image_align_el)
61001e04c3fSmrg{
61101e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
61201e04c3fSmrg   if (fmtl->txc == ISL_TXC_MCS) {
61301e04c3fSmrg      assert(tiling == ISL_TILING_Y0);
61401e04c3fSmrg
61501e04c3fSmrg      /*
61601e04c3fSmrg       * IvyBrigde PRM Vol 2, Part 1, "11.7 MCS Buffer for Render Target(s)":
61701e04c3fSmrg       *
61801e04c3fSmrg       * Height, width, and layout of MCS buffer in this case must match with
61901e04c3fSmrg       * Render Target height, width, and layout. MCS buffer is tiledY.
62001e04c3fSmrg       *
62101e04c3fSmrg       * To avoid wasting memory, choose the smallest alignment possible:
62201e04c3fSmrg       * HALIGN_4 and VALIGN_4.
62301e04c3fSmrg       */
62401e04c3fSmrg      *image_align_el = isl_extent3d(4, 4, 1);
62501e04c3fSmrg      return;
62601e04c3fSmrg   } else if (info->format == ISL_FORMAT_HIZ) {
62701e04c3fSmrg      assert(ISL_DEV_GEN(dev) >= 6);
62801e04c3fSmrg      if (ISL_DEV_GEN(dev) == 6) {
62901e04c3fSmrg         /* HiZ surfaces on Sandy Bridge are packed tightly. */
63001e04c3fSmrg         *image_align_el = isl_extent3d(1, 1, 1);
63101e04c3fSmrg      } else {
63201e04c3fSmrg         /* On gen7+, HiZ surfaces are always aligned to 16x8 pixels in the
63301e04c3fSmrg          * primary surface which works out to 2x2 HiZ elments.
63401e04c3fSmrg          */
63501e04c3fSmrg         *image_align_el = isl_extent3d(2, 2, 1);
63601e04c3fSmrg      }
63701e04c3fSmrg      return;
63801e04c3fSmrg   }
63901e04c3fSmrg
64001e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 9) {
64101e04c3fSmrg      isl_gen9_choose_image_alignment_el(dev, info, tiling, dim_layout,
64201e04c3fSmrg                                         msaa_layout, image_align_el);
64301e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 8) {
64401e04c3fSmrg      isl_gen8_choose_image_alignment_el(dev, info, tiling, dim_layout,
64501e04c3fSmrg                                         msaa_layout, image_align_el);
64601e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 7) {
64701e04c3fSmrg      isl_gen7_choose_image_alignment_el(dev, info, tiling, dim_layout,
64801e04c3fSmrg                                          msaa_layout, image_align_el);
64901e04c3fSmrg   } else if (ISL_DEV_GEN(dev) >= 6) {
65001e04c3fSmrg      isl_gen6_choose_image_alignment_el(dev, info, tiling, dim_layout,
65101e04c3fSmrg                                         msaa_layout, image_align_el);
65201e04c3fSmrg   } else {
65301e04c3fSmrg      isl_gen4_choose_image_alignment_el(dev, info, tiling, dim_layout,
65401e04c3fSmrg                                         msaa_layout, image_align_el);
65501e04c3fSmrg   }
65601e04c3fSmrg}
65701e04c3fSmrg
65801e04c3fSmrgstatic enum isl_dim_layout
65901e04c3fSmrgisl_surf_choose_dim_layout(const struct isl_device *dev,
66001e04c3fSmrg                           enum isl_surf_dim logical_dim,
66101e04c3fSmrg                           enum isl_tiling tiling,
66201e04c3fSmrg                           isl_surf_usage_flags_t usage)
66301e04c3fSmrg{
66401e04c3fSmrg   /* Sandy bridge needs a special layout for HiZ and stencil. */
66501e04c3fSmrg   if (ISL_DEV_GEN(dev) == 6 &&
66601e04c3fSmrg       (tiling == ISL_TILING_W || tiling == ISL_TILING_HIZ))
66701e04c3fSmrg      return ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ;
66801e04c3fSmrg
66901e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 9) {
67001e04c3fSmrg      switch (logical_dim) {
67101e04c3fSmrg      case ISL_SURF_DIM_1D:
67201e04c3fSmrg         /* From the Sky Lake PRM Vol. 5, "1D Surfaces":
67301e04c3fSmrg          *
67401e04c3fSmrg          *    One-dimensional surfaces use a tiling mode of linear.
67501e04c3fSmrg          *    Technically, they are not tiled resources, but the Tiled
67601e04c3fSmrg          *    Resource Mode field in RENDER_SURFACE_STATE is still used to
67701e04c3fSmrg          *    indicate the alignment requirements for this linear surface
67801e04c3fSmrg          *    (See 1D Alignment requirements for how 4K and 64KB Tiled
67901e04c3fSmrg          *    Resource Modes impact alignment). Alternatively, a 1D surface
68001e04c3fSmrg          *    can be defined as a 2D tiled surface (e.g. TileY or TileX) with
68101e04c3fSmrg          *    a height of 0.
68201e04c3fSmrg          *
68301e04c3fSmrg          * In other words, ISL_DIM_LAYOUT_GEN9_1D is only used for linear
68401e04c3fSmrg          * surfaces and, for tiled surfaces, ISL_DIM_LAYOUT_GEN4_2D is used.
68501e04c3fSmrg          */
68601e04c3fSmrg         if (tiling == ISL_TILING_LINEAR)
68701e04c3fSmrg            return ISL_DIM_LAYOUT_GEN9_1D;
68801e04c3fSmrg         else
68901e04c3fSmrg            return ISL_DIM_LAYOUT_GEN4_2D;
69001e04c3fSmrg      case ISL_SURF_DIM_2D:
69101e04c3fSmrg      case ISL_SURF_DIM_3D:
69201e04c3fSmrg         return ISL_DIM_LAYOUT_GEN4_2D;
69301e04c3fSmrg      }
69401e04c3fSmrg   } else {
69501e04c3fSmrg      switch (logical_dim) {
69601e04c3fSmrg      case ISL_SURF_DIM_1D:
69701e04c3fSmrg      case ISL_SURF_DIM_2D:
69801e04c3fSmrg         /* From the G45 PRM Vol. 1a, "6.17.4.1 Hardware Cube Map Layout":
69901e04c3fSmrg          *
70001e04c3fSmrg          * The cube face textures are stored in the same way as 3D surfaces
70101e04c3fSmrg          * are stored (see section 6.17.5 for details).  For cube surfaces,
70201e04c3fSmrg          * however, the depth is equal to the number of faces (always 6) and
70301e04c3fSmrg          * is not reduced for each MIP.
70401e04c3fSmrg          */
70501e04c3fSmrg         if (ISL_DEV_GEN(dev) == 4 && (usage & ISL_SURF_USAGE_CUBE_BIT))
70601e04c3fSmrg            return ISL_DIM_LAYOUT_GEN4_3D;
70701e04c3fSmrg
70801e04c3fSmrg         return ISL_DIM_LAYOUT_GEN4_2D;
70901e04c3fSmrg      case ISL_SURF_DIM_3D:
71001e04c3fSmrg         return ISL_DIM_LAYOUT_GEN4_3D;
71101e04c3fSmrg      }
71201e04c3fSmrg   }
71301e04c3fSmrg
71401e04c3fSmrg   unreachable("bad isl_surf_dim");
71501e04c3fSmrg   return ISL_DIM_LAYOUT_GEN4_2D;
71601e04c3fSmrg}
71701e04c3fSmrg
71801e04c3fSmrg/**
71901e04c3fSmrg * Calculate the physical extent of the surface's first level, in units of
7209f464c52Smaya * surface samples.
72101e04c3fSmrg */
72201e04c3fSmrgstatic void
72301e04c3fSmrgisl_calc_phys_level0_extent_sa(const struct isl_device *dev,
72401e04c3fSmrg                               const struct isl_surf_init_info *restrict info,
72501e04c3fSmrg                               enum isl_dim_layout dim_layout,
72601e04c3fSmrg                               enum isl_tiling tiling,
72701e04c3fSmrg                               enum isl_msaa_layout msaa_layout,
72801e04c3fSmrg                               struct isl_extent4d *phys_level0_sa)
72901e04c3fSmrg{
73001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
73101e04c3fSmrg
73201e04c3fSmrg   if (isl_format_is_yuv(info->format))
73301e04c3fSmrg      isl_finishme("%s:%s: YUV format", __FILE__, __func__);
73401e04c3fSmrg
73501e04c3fSmrg   switch (info->dim) {
73601e04c3fSmrg   case ISL_SURF_DIM_1D:
73701e04c3fSmrg      assert(info->height == 1);
73801e04c3fSmrg      assert(info->depth == 1);
73901e04c3fSmrg      assert(info->samples == 1);
74001e04c3fSmrg
74101e04c3fSmrg      switch (dim_layout) {
74201e04c3fSmrg      case ISL_DIM_LAYOUT_GEN4_3D:
74301e04c3fSmrg         unreachable("bad isl_dim_layout");
74401e04c3fSmrg
74501e04c3fSmrg      case ISL_DIM_LAYOUT_GEN9_1D:
74601e04c3fSmrg      case ISL_DIM_LAYOUT_GEN4_2D:
74701e04c3fSmrg      case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
74801e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
7499f464c52Smaya            .w = info->width,
7509f464c52Smaya            .h = 1,
75101e04c3fSmrg            .d = 1,
75201e04c3fSmrg            .a = info->array_len,
75301e04c3fSmrg         };
75401e04c3fSmrg         break;
75501e04c3fSmrg      }
75601e04c3fSmrg      break;
75701e04c3fSmrg
75801e04c3fSmrg   case ISL_SURF_DIM_2D:
75901e04c3fSmrg      if (ISL_DEV_GEN(dev) == 4 && (info->usage & ISL_SURF_USAGE_CUBE_BIT))
76001e04c3fSmrg         assert(dim_layout == ISL_DIM_LAYOUT_GEN4_3D);
76101e04c3fSmrg      else
76201e04c3fSmrg         assert(dim_layout == ISL_DIM_LAYOUT_GEN4_2D ||
76301e04c3fSmrg                dim_layout == ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ);
76401e04c3fSmrg
76501e04c3fSmrg      if (tiling == ISL_TILING_Ys && info->samples > 1)
76601e04c3fSmrg         isl_finishme("%s:%s: multisample TileYs layout", __FILE__, __func__);
76701e04c3fSmrg
76801e04c3fSmrg      switch (msaa_layout) {
76901e04c3fSmrg      case ISL_MSAA_LAYOUT_NONE:
77001e04c3fSmrg         assert(info->depth == 1);
77101e04c3fSmrg         assert(info->samples == 1);
77201e04c3fSmrg
77301e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
7749f464c52Smaya            .w = info->width,
7759f464c52Smaya            .h = info->height,
77601e04c3fSmrg            .d = 1,
77701e04c3fSmrg            .a = info->array_len,
77801e04c3fSmrg         };
77901e04c3fSmrg         break;
78001e04c3fSmrg
78101e04c3fSmrg      case ISL_MSAA_LAYOUT_ARRAY:
78201e04c3fSmrg         assert(info->depth == 1);
78301e04c3fSmrg         assert(info->levels == 1);
78401e04c3fSmrg         assert(isl_format_supports_multisampling(dev->info, info->format));
78501e04c3fSmrg         assert(fmtl->bw == 1 && fmtl->bh == 1);
78601e04c3fSmrg
78701e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
78801e04c3fSmrg            .w = info->width,
78901e04c3fSmrg            .h = info->height,
79001e04c3fSmrg            .d = 1,
79101e04c3fSmrg            .a = info->array_len * info->samples,
79201e04c3fSmrg         };
79301e04c3fSmrg         break;
79401e04c3fSmrg
79501e04c3fSmrg      case ISL_MSAA_LAYOUT_INTERLEAVED:
79601e04c3fSmrg         assert(info->depth == 1);
79701e04c3fSmrg         assert(info->levels == 1);
79801e04c3fSmrg         assert(isl_format_supports_multisampling(dev->info, info->format));
79901e04c3fSmrg
80001e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
80101e04c3fSmrg            .w = info->width,
80201e04c3fSmrg            .h = info->height,
80301e04c3fSmrg            .d = 1,
80401e04c3fSmrg            .a = info->array_len,
80501e04c3fSmrg         };
80601e04c3fSmrg
80701e04c3fSmrg         isl_msaa_interleaved_scale_px_to_sa(info->samples,
80801e04c3fSmrg                                             &phys_level0_sa->w,
80901e04c3fSmrg                                             &phys_level0_sa->h);
81001e04c3fSmrg         break;
81101e04c3fSmrg      }
81201e04c3fSmrg      break;
81301e04c3fSmrg
81401e04c3fSmrg   case ISL_SURF_DIM_3D:
81501e04c3fSmrg      assert(info->array_len == 1);
81601e04c3fSmrg      assert(info->samples == 1);
81701e04c3fSmrg
81801e04c3fSmrg      if (fmtl->bd > 1) {
81901e04c3fSmrg         isl_finishme("%s:%s: compression block with depth > 1",
82001e04c3fSmrg                      __FILE__, __func__);
82101e04c3fSmrg      }
82201e04c3fSmrg
82301e04c3fSmrg      switch (dim_layout) {
82401e04c3fSmrg      case ISL_DIM_LAYOUT_GEN9_1D:
82501e04c3fSmrg      case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
82601e04c3fSmrg         unreachable("bad isl_dim_layout");
82701e04c3fSmrg
82801e04c3fSmrg      case ISL_DIM_LAYOUT_GEN4_2D:
82901e04c3fSmrg         assert(ISL_DEV_GEN(dev) >= 9);
83001e04c3fSmrg
83101e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
8329f464c52Smaya            .w = info->width,
8339f464c52Smaya            .h = info->height,
83401e04c3fSmrg            .d = 1,
83501e04c3fSmrg            .a = info->depth,
83601e04c3fSmrg         };
83701e04c3fSmrg         break;
83801e04c3fSmrg
83901e04c3fSmrg      case ISL_DIM_LAYOUT_GEN4_3D:
84001e04c3fSmrg         assert(ISL_DEV_GEN(dev) < 9);
84101e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
8429f464c52Smaya            .w = info->width,
8439f464c52Smaya            .h = info->height,
84401e04c3fSmrg            .d = info->depth,
84501e04c3fSmrg            .a = 1,
84601e04c3fSmrg         };
84701e04c3fSmrg         break;
84801e04c3fSmrg      }
84901e04c3fSmrg      break;
85001e04c3fSmrg   }
85101e04c3fSmrg}
85201e04c3fSmrg
85301e04c3fSmrg/**
85401e04c3fSmrg * Calculate the pitch between physical array slices, in units of rows of
85501e04c3fSmrg * surface elements.
85601e04c3fSmrg */
85701e04c3fSmrgstatic uint32_t
85801e04c3fSmrgisl_calc_array_pitch_el_rows_gen4_2d(
85901e04c3fSmrg      const struct isl_device *dev,
86001e04c3fSmrg      const struct isl_surf_init_info *restrict info,
86101e04c3fSmrg      const struct isl_tile_info *tile_info,
86201e04c3fSmrg      const struct isl_extent3d *image_align_sa,
86301e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
86401e04c3fSmrg      enum isl_array_pitch_span array_pitch_span,
86501e04c3fSmrg      const struct isl_extent2d *phys_slice0_sa)
86601e04c3fSmrg{
86701e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
86801e04c3fSmrg   uint32_t pitch_sa_rows = 0;
86901e04c3fSmrg
87001e04c3fSmrg   switch (array_pitch_span) {
87101e04c3fSmrg   case ISL_ARRAY_PITCH_SPAN_COMPACT:
87201e04c3fSmrg      pitch_sa_rows = isl_align_npot(phys_slice0_sa->h, image_align_sa->h);
87301e04c3fSmrg      break;
87401e04c3fSmrg   case ISL_ARRAY_PITCH_SPAN_FULL: {
87501e04c3fSmrg      /* The QPitch equation is found in the Broadwell PRM >> Volume 5:
87601e04c3fSmrg       * Memory Views >> Common Surface Formats >> Surface Layout >> 2D
87701e04c3fSmrg       * Surfaces >> Surface Arrays.
87801e04c3fSmrg       */
87901e04c3fSmrg      uint32_t H0_sa = phys_level0_sa->h;
88001e04c3fSmrg      uint32_t H1_sa = isl_minify(H0_sa, 1);
88101e04c3fSmrg
88201e04c3fSmrg      uint32_t h0_sa = isl_align_npot(H0_sa, image_align_sa->h);
88301e04c3fSmrg      uint32_t h1_sa = isl_align_npot(H1_sa, image_align_sa->h);
88401e04c3fSmrg
88501e04c3fSmrg      uint32_t m;
88601e04c3fSmrg      if (ISL_DEV_GEN(dev) >= 7) {
88701e04c3fSmrg         /* The QPitch equation changed slightly in Ivybridge. */
88801e04c3fSmrg         m = 12;
88901e04c3fSmrg      } else {
89001e04c3fSmrg         m = 11;
89101e04c3fSmrg      }
89201e04c3fSmrg
89301e04c3fSmrg      pitch_sa_rows = h0_sa + h1_sa + (m * image_align_sa->h);
89401e04c3fSmrg
89501e04c3fSmrg      if (ISL_DEV_GEN(dev) == 6 && info->samples > 1 &&
89601e04c3fSmrg          (info->height % 4 == 1)) {
89701e04c3fSmrg         /* [SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
89801e04c3fSmrg          * Graphics Core >> Section 7.18.3.7: Surface Arrays:
89901e04c3fSmrg          *
90001e04c3fSmrg          *    [SNB] Errata: Sampler MSAA Qpitch will be 4 greater than
90101e04c3fSmrg          *    the value calculated in the equation above , for every
90201e04c3fSmrg          *    other odd Surface Height starting from 1 i.e. 1,5,9,13.
90301e04c3fSmrg          *
90401e04c3fSmrg          * XXX(chadv): Is the errata natural corollary of the physical
90501e04c3fSmrg          * layout of interleaved samples?
90601e04c3fSmrg          */
90701e04c3fSmrg         pitch_sa_rows += 4;
90801e04c3fSmrg      }
90901e04c3fSmrg
91001e04c3fSmrg      pitch_sa_rows = isl_align_npot(pitch_sa_rows, fmtl->bh);
91101e04c3fSmrg      } /* end case */
91201e04c3fSmrg      break;
91301e04c3fSmrg   }
91401e04c3fSmrg
91501e04c3fSmrg   assert(pitch_sa_rows % fmtl->bh == 0);
91601e04c3fSmrg   uint32_t pitch_el_rows = pitch_sa_rows / fmtl->bh;
91701e04c3fSmrg
91801e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 9 && fmtl->txc == ISL_TXC_CCS) {
91901e04c3fSmrg      /*
92001e04c3fSmrg       * From the Sky Lake PRM Vol 7, "MCS Buffer for Render Target(s)" (p. 632):
92101e04c3fSmrg       *
92201e04c3fSmrg       *    "Mip-mapped and arrayed surfaces are supported with MCS buffer
92301e04c3fSmrg       *    layout with these alignments in the RT space: Horizontal
92401e04c3fSmrg       *    Alignment = 128 and Vertical Alignment = 64."
92501e04c3fSmrg       *
92601e04c3fSmrg       * From the Sky Lake PRM Vol. 2d, "RENDER_SURFACE_STATE" (p. 435):
92701e04c3fSmrg       *
92801e04c3fSmrg       *    "For non-multisampled render target's CCS auxiliary surface,
92901e04c3fSmrg       *    QPitch must be computed with Horizontal Alignment = 128 and
93001e04c3fSmrg       *    Surface Vertical Alignment = 256. These alignments are only for
93101e04c3fSmrg       *    CCS buffer and not for associated render target."
93201e04c3fSmrg       *
93301e04c3fSmrg       * The first restriction is already handled by isl_choose_image_alignment_el
93401e04c3fSmrg       * but the second restriction, which is an extension of the first, only
93501e04c3fSmrg       * applies to qpitch and must be applied here.
93601e04c3fSmrg       */
93701e04c3fSmrg      assert(fmtl->bh == 4);
93801e04c3fSmrg      pitch_el_rows = isl_align(pitch_el_rows, 256 / 4);
93901e04c3fSmrg   }
94001e04c3fSmrg
94101e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 9 &&
94201e04c3fSmrg       info->dim == ISL_SURF_DIM_3D &&
94301e04c3fSmrg       tile_info->tiling != ISL_TILING_LINEAR) {
94401e04c3fSmrg      /* From the Skylake BSpec >> RENDER_SURFACE_STATE >> Surface QPitch:
94501e04c3fSmrg       *
94601e04c3fSmrg       *    Tile Mode != Linear: This field must be set to an integer multiple
94701e04c3fSmrg       *    of the tile height
94801e04c3fSmrg       */
94901e04c3fSmrg      pitch_el_rows = isl_align(pitch_el_rows, tile_info->logical_extent_el.height);
95001e04c3fSmrg   }
95101e04c3fSmrg
95201e04c3fSmrg   return pitch_el_rows;
95301e04c3fSmrg}
95401e04c3fSmrg
95501e04c3fSmrg/**
95601e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
95701e04c3fSmrg * ISL_DIM_LAYOUT_GEN4_2D.
95801e04c3fSmrg */
95901e04c3fSmrgstatic void
96001e04c3fSmrgisl_calc_phys_slice0_extent_sa_gen4_2d(
96101e04c3fSmrg      const struct isl_device *dev,
96201e04c3fSmrg      const struct isl_surf_init_info *restrict info,
96301e04c3fSmrg      enum isl_msaa_layout msaa_layout,
96401e04c3fSmrg      const struct isl_extent3d *image_align_sa,
96501e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
96601e04c3fSmrg      struct isl_extent2d *phys_slice0_sa)
96701e04c3fSmrg{
96801e04c3fSmrg   assert(phys_level0_sa->depth == 1);
96901e04c3fSmrg
97001e04c3fSmrg   if (info->levels == 1) {
9719f464c52Smaya      /* Do not pad the surface to the image alignment.
97201e04c3fSmrg       *
97301e04c3fSmrg       * For tiled surfaces, using a reduced alignment here avoids wasting CPU
97401e04c3fSmrg       * cycles on the below mipmap layout caluclations. Reducing the
97501e04c3fSmrg       * alignment here is safe because we later align the row pitch and array
97601e04c3fSmrg       * pitch to the tile boundary. It is safe even for
97701e04c3fSmrg       * ISL_MSAA_LAYOUT_INTERLEAVED, because phys_level0_sa is already scaled
97801e04c3fSmrg       * to accomodate the interleaved samples.
97901e04c3fSmrg       *
98001e04c3fSmrg       * For linear surfaces, reducing the alignment here permits us to later
98101e04c3fSmrg       * choose an arbitrary, non-aligned row pitch. If the surface backs
98201e04c3fSmrg       * a VkBuffer, then an arbitrary pitch may be needed to accomodate
98301e04c3fSmrg       * VkBufferImageCopy::bufferRowLength.
98401e04c3fSmrg       */
98501e04c3fSmrg      *phys_slice0_sa = (struct isl_extent2d) {
9869f464c52Smaya         .w = phys_level0_sa->w,
9879f464c52Smaya         .h = phys_level0_sa->h,
98801e04c3fSmrg      };
98901e04c3fSmrg      return;
99001e04c3fSmrg   }
99101e04c3fSmrg
99201e04c3fSmrg   uint32_t slice_top_w = 0;
99301e04c3fSmrg   uint32_t slice_bottom_w = 0;
99401e04c3fSmrg   uint32_t slice_left_h = 0;
99501e04c3fSmrg   uint32_t slice_right_h = 0;
99601e04c3fSmrg
99701e04c3fSmrg   uint32_t W0 = phys_level0_sa->w;
99801e04c3fSmrg   uint32_t H0 = phys_level0_sa->h;
99901e04c3fSmrg
100001e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
100101e04c3fSmrg      uint32_t W = isl_minify(W0, l);
100201e04c3fSmrg      uint32_t H = isl_minify(H0, l);
100301e04c3fSmrg
100401e04c3fSmrg      uint32_t w = isl_align_npot(W, image_align_sa->w);
100501e04c3fSmrg      uint32_t h = isl_align_npot(H, image_align_sa->h);
100601e04c3fSmrg
100701e04c3fSmrg      if (l == 0) {
100801e04c3fSmrg         slice_top_w = w;
100901e04c3fSmrg         slice_left_h = h;
101001e04c3fSmrg         slice_right_h = h;
101101e04c3fSmrg      } else if (l == 1) {
101201e04c3fSmrg         slice_bottom_w = w;
101301e04c3fSmrg         slice_left_h += h;
101401e04c3fSmrg      } else if (l == 2) {
101501e04c3fSmrg         slice_bottom_w += w;
101601e04c3fSmrg         slice_right_h += h;
101701e04c3fSmrg      } else {
101801e04c3fSmrg         slice_right_h += h;
101901e04c3fSmrg      }
102001e04c3fSmrg   }
102101e04c3fSmrg
102201e04c3fSmrg   *phys_slice0_sa = (struct isl_extent2d) {
102301e04c3fSmrg      .w = MAX(slice_top_w, slice_bottom_w),
102401e04c3fSmrg      .h = MAX(slice_left_h, slice_right_h),
102501e04c3fSmrg   };
102601e04c3fSmrg}
102701e04c3fSmrg
102801e04c3fSmrgstatic void
102901e04c3fSmrgisl_calc_phys_total_extent_el_gen4_2d(
103001e04c3fSmrg      const struct isl_device *dev,
103101e04c3fSmrg      const struct isl_surf_init_info *restrict info,
103201e04c3fSmrg      const struct isl_tile_info *tile_info,
103301e04c3fSmrg      enum isl_msaa_layout msaa_layout,
103401e04c3fSmrg      const struct isl_extent3d *image_align_sa,
103501e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
103601e04c3fSmrg      enum isl_array_pitch_span array_pitch_span,
103701e04c3fSmrg      uint32_t *array_pitch_el_rows,
103801e04c3fSmrg      struct isl_extent2d *total_extent_el)
103901e04c3fSmrg{
104001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
104101e04c3fSmrg
104201e04c3fSmrg   struct isl_extent2d phys_slice0_sa;
104301e04c3fSmrg   isl_calc_phys_slice0_extent_sa_gen4_2d(dev, info, msaa_layout,
104401e04c3fSmrg                                          image_align_sa, phys_level0_sa,
104501e04c3fSmrg                                          &phys_slice0_sa);
104601e04c3fSmrg   *array_pitch_el_rows =
104701e04c3fSmrg      isl_calc_array_pitch_el_rows_gen4_2d(dev, info, tile_info,
104801e04c3fSmrg                                           image_align_sa, phys_level0_sa,
104901e04c3fSmrg                                           array_pitch_span,
105001e04c3fSmrg                                           &phys_slice0_sa);
105101e04c3fSmrg   *total_extent_el = (struct isl_extent2d) {
10529f464c52Smaya      .w = isl_align_div_npot(phys_slice0_sa.w, fmtl->bw),
105301e04c3fSmrg      .h = *array_pitch_el_rows * (phys_level0_sa->array_len - 1) +
10549f464c52Smaya           isl_align_div_npot(phys_slice0_sa.h, fmtl->bh),
105501e04c3fSmrg   };
105601e04c3fSmrg}
105701e04c3fSmrg
105801e04c3fSmrg/**
105901e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
106001e04c3fSmrg * ISL_DIM_LAYOUT_GEN4_3D.
106101e04c3fSmrg */
106201e04c3fSmrgstatic void
106301e04c3fSmrgisl_calc_phys_total_extent_el_gen4_3d(
106401e04c3fSmrg      const struct isl_device *dev,
106501e04c3fSmrg      const struct isl_surf_init_info *restrict info,
106601e04c3fSmrg      const struct isl_extent3d *image_align_sa,
106701e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
106801e04c3fSmrg      uint32_t *array_pitch_el_rows,
106901e04c3fSmrg      struct isl_extent2d *phys_total_el)
107001e04c3fSmrg{
107101e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
107201e04c3fSmrg
107301e04c3fSmrg   assert(info->samples == 1);
107401e04c3fSmrg
107501e04c3fSmrg   if (info->dim != ISL_SURF_DIM_3D) {
107601e04c3fSmrg      /* From the G45 PRM Vol. 1a, "6.17.4.1 Hardware Cube Map Layout":
107701e04c3fSmrg       *
107801e04c3fSmrg       * The cube face textures are stored in the same way as 3D surfaces
107901e04c3fSmrg       * are stored (see section 6.17.5 for details).  For cube surfaces,
108001e04c3fSmrg       * however, the depth is equal to the number of faces (always 6) and
108101e04c3fSmrg       * is not reduced for each MIP.
108201e04c3fSmrg       */
108301e04c3fSmrg      assert(ISL_DEV_GEN(dev) == 4);
108401e04c3fSmrg      assert(info->usage & ISL_SURF_USAGE_CUBE_BIT);
108501e04c3fSmrg      assert(phys_level0_sa->array_len == 6);
108601e04c3fSmrg   } else {
108701e04c3fSmrg      assert(phys_level0_sa->array_len == 1);
108801e04c3fSmrg   }
108901e04c3fSmrg
109001e04c3fSmrg   uint32_t total_w = 0;
109101e04c3fSmrg   uint32_t total_h = 0;
109201e04c3fSmrg
109301e04c3fSmrg   uint32_t W0 = phys_level0_sa->w;
109401e04c3fSmrg   uint32_t H0 = phys_level0_sa->h;
109501e04c3fSmrg   uint32_t D0 = phys_level0_sa->d;
109601e04c3fSmrg   uint32_t A0 = phys_level0_sa->a;
109701e04c3fSmrg
109801e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
109901e04c3fSmrg      uint32_t level_w = isl_align_npot(isl_minify(W0, l), image_align_sa->w);
110001e04c3fSmrg      uint32_t level_h = isl_align_npot(isl_minify(H0, l), image_align_sa->h);
110101e04c3fSmrg      uint32_t level_d = info->dim == ISL_SURF_DIM_3D ? isl_minify(D0, l) : A0;
110201e04c3fSmrg
110301e04c3fSmrg      uint32_t max_layers_horiz = MIN(level_d, 1u << l);
110401e04c3fSmrg      uint32_t max_layers_vert = isl_align(level_d, 1u << l) / (1u << l);
110501e04c3fSmrg
110601e04c3fSmrg      total_w = MAX(total_w, level_w * max_layers_horiz);
110701e04c3fSmrg      total_h += level_h * max_layers_vert;
110801e04c3fSmrg   }
110901e04c3fSmrg
111001e04c3fSmrg   /* GEN4_3D layouts don't really have an array pitch since each LOD has a
111101e04c3fSmrg    * different number of horizontal and vertical layers.  We have to set it
111201e04c3fSmrg    * to something, so at least make it true for LOD0.
111301e04c3fSmrg    */
111401e04c3fSmrg   *array_pitch_el_rows =
111501e04c3fSmrg      isl_align_npot(phys_level0_sa->h, image_align_sa->h) / fmtl->bw;
111601e04c3fSmrg   *phys_total_el = (struct isl_extent2d) {
111701e04c3fSmrg      .w = isl_assert_div(total_w, fmtl->bw),
111801e04c3fSmrg      .h = isl_assert_div(total_h, fmtl->bh),
111901e04c3fSmrg   };
112001e04c3fSmrg}
112101e04c3fSmrg
112201e04c3fSmrg/**
112301e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
112401e04c3fSmrg * ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ.
112501e04c3fSmrg */
112601e04c3fSmrgstatic void
112701e04c3fSmrgisl_calc_phys_total_extent_el_gen6_stencil_hiz(
112801e04c3fSmrg      const struct isl_device *dev,
112901e04c3fSmrg      const struct isl_surf_init_info *restrict info,
113001e04c3fSmrg      const struct isl_tile_info *tile_info,
113101e04c3fSmrg      const struct isl_extent3d *image_align_sa,
113201e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
113301e04c3fSmrg      uint32_t *array_pitch_el_rows,
113401e04c3fSmrg      struct isl_extent2d *phys_total_el)
113501e04c3fSmrg{
113601e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
113701e04c3fSmrg
113801e04c3fSmrg   const struct isl_extent2d tile_extent_sa = {
113901e04c3fSmrg      .w = tile_info->logical_extent_el.w * fmtl->bw,
114001e04c3fSmrg      .h = tile_info->logical_extent_el.h * fmtl->bh,
114101e04c3fSmrg   };
114201e04c3fSmrg   /* Tile size is a multiple of image alignment */
114301e04c3fSmrg   assert(tile_extent_sa.w % image_align_sa->w == 0);
114401e04c3fSmrg   assert(tile_extent_sa.h % image_align_sa->h == 0);
114501e04c3fSmrg
114601e04c3fSmrg   const uint32_t W0 = phys_level0_sa->w;
114701e04c3fSmrg   const uint32_t H0 = phys_level0_sa->h;
114801e04c3fSmrg
114901e04c3fSmrg   /* Each image has the same height as LOD0 because the hardware thinks
115001e04c3fSmrg    * everything is LOD0
115101e04c3fSmrg    */
115201e04c3fSmrg   const uint32_t H = isl_align(H0, image_align_sa->h) * phys_level0_sa->a;
115301e04c3fSmrg
115401e04c3fSmrg   uint32_t total_top_w = 0;
115501e04c3fSmrg   uint32_t total_bottom_w = 0;
115601e04c3fSmrg   uint32_t total_h = 0;
115701e04c3fSmrg
115801e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
115901e04c3fSmrg      const uint32_t W = isl_minify(W0, l);
116001e04c3fSmrg
116101e04c3fSmrg      const uint32_t w = isl_align(W, tile_extent_sa.w);
116201e04c3fSmrg      const uint32_t h = isl_align(H, tile_extent_sa.h);
116301e04c3fSmrg
116401e04c3fSmrg      if (l == 0) {
116501e04c3fSmrg         total_top_w = w;
116601e04c3fSmrg         total_h = h;
116701e04c3fSmrg      } else if (l == 1) {
116801e04c3fSmrg         total_bottom_w = w;
116901e04c3fSmrg         total_h += h;
117001e04c3fSmrg      } else {
117101e04c3fSmrg         total_bottom_w += w;
117201e04c3fSmrg      }
117301e04c3fSmrg   }
117401e04c3fSmrg
117501e04c3fSmrg   *array_pitch_el_rows =
117601e04c3fSmrg      isl_assert_div(isl_align(H0, image_align_sa->h), fmtl->bh);
117701e04c3fSmrg   *phys_total_el = (struct isl_extent2d) {
117801e04c3fSmrg      .w = isl_assert_div(MAX(total_top_w, total_bottom_w), fmtl->bw),
117901e04c3fSmrg      .h = isl_assert_div(total_h, fmtl->bh),
118001e04c3fSmrg   };
118101e04c3fSmrg}
118201e04c3fSmrg
118301e04c3fSmrg/**
118401e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
118501e04c3fSmrg * ISL_DIM_LAYOUT_GEN9_1D.
118601e04c3fSmrg */
118701e04c3fSmrgstatic void
118801e04c3fSmrgisl_calc_phys_total_extent_el_gen9_1d(
118901e04c3fSmrg      const struct isl_device *dev,
119001e04c3fSmrg      const struct isl_surf_init_info *restrict info,
119101e04c3fSmrg      const struct isl_extent3d *image_align_sa,
119201e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
119301e04c3fSmrg      uint32_t *array_pitch_el_rows,
119401e04c3fSmrg      struct isl_extent2d *phys_total_el)
119501e04c3fSmrg{
119601e04c3fSmrg   MAYBE_UNUSED const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
119701e04c3fSmrg
11989f464c52Smaya   assert(phys_level0_sa->height == 1);
119901e04c3fSmrg   assert(phys_level0_sa->depth == 1);
120001e04c3fSmrg   assert(info->samples == 1);
120101e04c3fSmrg   assert(image_align_sa->w >= fmtl->bw);
120201e04c3fSmrg
120301e04c3fSmrg   uint32_t slice_w = 0;
120401e04c3fSmrg   const uint32_t W0 = phys_level0_sa->w;
120501e04c3fSmrg
120601e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
120701e04c3fSmrg      uint32_t W = isl_minify(W0, l);
120801e04c3fSmrg      uint32_t w = isl_align_npot(W, image_align_sa->w);
120901e04c3fSmrg
121001e04c3fSmrg      slice_w += w;
121101e04c3fSmrg   }
121201e04c3fSmrg
121301e04c3fSmrg   *array_pitch_el_rows = 1;
121401e04c3fSmrg   *phys_total_el = (struct isl_extent2d) {
121501e04c3fSmrg      .w = isl_assert_div(slice_w, fmtl->bw),
121601e04c3fSmrg      .h = phys_level0_sa->array_len,
121701e04c3fSmrg   };
121801e04c3fSmrg}
121901e04c3fSmrg
122001e04c3fSmrg/**
122101e04c3fSmrg * Calculate the two-dimensional total physical extent of the surface, in
122201e04c3fSmrg * units of surface elements.
122301e04c3fSmrg */
122401e04c3fSmrgstatic void
122501e04c3fSmrgisl_calc_phys_total_extent_el(const struct isl_device *dev,
122601e04c3fSmrg                              const struct isl_surf_init_info *restrict info,
122701e04c3fSmrg                              const struct isl_tile_info *tile_info,
122801e04c3fSmrg                              enum isl_dim_layout dim_layout,
122901e04c3fSmrg                              enum isl_msaa_layout msaa_layout,
123001e04c3fSmrg                              const struct isl_extent3d *image_align_sa,
123101e04c3fSmrg                              const struct isl_extent4d *phys_level0_sa,
123201e04c3fSmrg                              enum isl_array_pitch_span array_pitch_span,
123301e04c3fSmrg                              uint32_t *array_pitch_el_rows,
123401e04c3fSmrg                              struct isl_extent2d *total_extent_el)
123501e04c3fSmrg{
123601e04c3fSmrg   switch (dim_layout) {
123701e04c3fSmrg   case ISL_DIM_LAYOUT_GEN9_1D:
123801e04c3fSmrg      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
123901e04c3fSmrg      isl_calc_phys_total_extent_el_gen9_1d(dev, info,
124001e04c3fSmrg                                            image_align_sa, phys_level0_sa,
124101e04c3fSmrg                                            array_pitch_el_rows,
124201e04c3fSmrg                                            total_extent_el);
124301e04c3fSmrg      return;
124401e04c3fSmrg   case ISL_DIM_LAYOUT_GEN4_2D:
124501e04c3fSmrg      isl_calc_phys_total_extent_el_gen4_2d(dev, info, tile_info, msaa_layout,
124601e04c3fSmrg                                            image_align_sa, phys_level0_sa,
124701e04c3fSmrg                                            array_pitch_span,
124801e04c3fSmrg                                            array_pitch_el_rows,
124901e04c3fSmrg                                            total_extent_el);
125001e04c3fSmrg      return;
125101e04c3fSmrg   case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
125201e04c3fSmrg      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
125301e04c3fSmrg      isl_calc_phys_total_extent_el_gen6_stencil_hiz(dev, info, tile_info,
125401e04c3fSmrg                                                     image_align_sa,
125501e04c3fSmrg                                                     phys_level0_sa,
125601e04c3fSmrg                                                     array_pitch_el_rows,
125701e04c3fSmrg                                                     total_extent_el);
125801e04c3fSmrg      return;
125901e04c3fSmrg   case ISL_DIM_LAYOUT_GEN4_3D:
126001e04c3fSmrg      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
126101e04c3fSmrg      isl_calc_phys_total_extent_el_gen4_3d(dev, info,
126201e04c3fSmrg                                            image_align_sa, phys_level0_sa,
126301e04c3fSmrg                                            array_pitch_el_rows,
126401e04c3fSmrg                                            total_extent_el);
126501e04c3fSmrg      return;
126601e04c3fSmrg   }
126701e04c3fSmrg}
126801e04c3fSmrg
126901e04c3fSmrgstatic uint32_t
127001e04c3fSmrgisl_calc_row_pitch_alignment(const struct isl_surf_init_info *surf_info,
127101e04c3fSmrg                             const struct isl_tile_info *tile_info)
127201e04c3fSmrg{
127301e04c3fSmrg   if (tile_info->tiling != ISL_TILING_LINEAR)
127401e04c3fSmrg      return tile_info->phys_extent_B.width;
127501e04c3fSmrg
127601e04c3fSmrg   /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
127701e04c3fSmrg    * RENDER_SURFACE_STATE Surface Pitch (p349):
127801e04c3fSmrg    *
127901e04c3fSmrg    *    - For linear render target surfaces and surfaces accessed with the
128001e04c3fSmrg    *      typed data port messages, the pitch must be a multiple of the
128101e04c3fSmrg    *      element size for non-YUV surface formats.  Pitch must be
128201e04c3fSmrg    *      a multiple of 2 * element size for YUV surface formats.
128301e04c3fSmrg    *
128401e04c3fSmrg    *    - [Requirements for SURFTYPE_BUFFER and SURFTYPE_STRBUF, which we
128501e04c3fSmrg    *      ignore because isl doesn't do buffers.]
128601e04c3fSmrg    *
128701e04c3fSmrg    *    - For other linear surfaces, the pitch can be any multiple of
128801e04c3fSmrg    *      bytes.
128901e04c3fSmrg    */
129001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf_info->format);
129101e04c3fSmrg   const uint32_t bs = fmtl->bpb / 8;
129201e04c3fSmrg
129301e04c3fSmrg   if (surf_info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
129401e04c3fSmrg      if (isl_format_is_yuv(surf_info->format)) {
129501e04c3fSmrg         return 2 * bs;
129601e04c3fSmrg      } else  {
129701e04c3fSmrg         return bs;
129801e04c3fSmrg      }
129901e04c3fSmrg   }
130001e04c3fSmrg
130101e04c3fSmrg   return 1;
130201e04c3fSmrg}
130301e04c3fSmrg
130401e04c3fSmrgstatic uint32_t
130501e04c3fSmrgisl_calc_linear_min_row_pitch(const struct isl_device *dev,
130601e04c3fSmrg                              const struct isl_surf_init_info *info,
130701e04c3fSmrg                              const struct isl_extent2d *phys_total_el,
130801e04c3fSmrg                              uint32_t alignment_B)
130901e04c3fSmrg{
131001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
131101e04c3fSmrg   const uint32_t bs = fmtl->bpb / 8;
131201e04c3fSmrg
131301e04c3fSmrg   return isl_align_npot(bs * phys_total_el->w, alignment_B);
131401e04c3fSmrg}
131501e04c3fSmrg
131601e04c3fSmrgstatic uint32_t
131701e04c3fSmrgisl_calc_tiled_min_row_pitch(const struct isl_device *dev,
131801e04c3fSmrg                             const struct isl_surf_init_info *surf_info,
131901e04c3fSmrg                             const struct isl_tile_info *tile_info,
132001e04c3fSmrg                             const struct isl_extent2d *phys_total_el,
132101e04c3fSmrg                             uint32_t alignment_B)
132201e04c3fSmrg{
132301e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf_info->format);
132401e04c3fSmrg
132501e04c3fSmrg   assert(fmtl->bpb % tile_info->format_bpb == 0);
132601e04c3fSmrg
132701e04c3fSmrg   const uint32_t tile_el_scale = fmtl->bpb / tile_info->format_bpb;
132801e04c3fSmrg   const uint32_t total_w_tl =
132901e04c3fSmrg      isl_align_div(phys_total_el->w * tile_el_scale,
133001e04c3fSmrg                    tile_info->logical_extent_el.width);
133101e04c3fSmrg
133201e04c3fSmrg   assert(alignment_B == tile_info->phys_extent_B.width);
133301e04c3fSmrg   return total_w_tl * tile_info->phys_extent_B.width;
133401e04c3fSmrg}
133501e04c3fSmrg
133601e04c3fSmrgstatic uint32_t
133701e04c3fSmrgisl_calc_min_row_pitch(const struct isl_device *dev,
133801e04c3fSmrg                       const struct isl_surf_init_info *surf_info,
133901e04c3fSmrg                       const struct isl_tile_info *tile_info,
134001e04c3fSmrg                       const struct isl_extent2d *phys_total_el,
134101e04c3fSmrg                       uint32_t alignment_B)
134201e04c3fSmrg{
134301e04c3fSmrg   if (tile_info->tiling == ISL_TILING_LINEAR) {
134401e04c3fSmrg      return isl_calc_linear_min_row_pitch(dev, surf_info, phys_total_el,
134501e04c3fSmrg                                           alignment_B);
134601e04c3fSmrg   } else {
134701e04c3fSmrg      return isl_calc_tiled_min_row_pitch(dev, surf_info, tile_info,
134801e04c3fSmrg                                          phys_total_el, alignment_B);
134901e04c3fSmrg   }
135001e04c3fSmrg}
135101e04c3fSmrg
135201e04c3fSmrg/**
135301e04c3fSmrg * Is `pitch` in the valid range for a hardware bitfield, if the bitfield's
135401e04c3fSmrg * size is `bits` bits?
135501e04c3fSmrg *
135601e04c3fSmrg * Hardware pitch fields are offset by 1. For example, if the size of
135701e04c3fSmrg * RENDER_SURFACE_STATE::SurfacePitch is B bits, then the range of valid
135801e04c3fSmrg * pitches is [1, 2^b] inclusive.  If the surface pitch is N, then
135901e04c3fSmrg * RENDER_SURFACE_STATE::SurfacePitch must be set to N-1.
136001e04c3fSmrg */
136101e04c3fSmrgstatic bool
136201e04c3fSmrgpitch_in_range(uint32_t n, uint32_t bits)
136301e04c3fSmrg{
136401e04c3fSmrg   assert(n != 0);
136501e04c3fSmrg   return likely(bits != 0 && 1 <= n && n <= (1 << bits));
136601e04c3fSmrg}
136701e04c3fSmrg
136801e04c3fSmrgstatic bool
136901e04c3fSmrgisl_calc_row_pitch(const struct isl_device *dev,
137001e04c3fSmrg                   const struct isl_surf_init_info *surf_info,
137101e04c3fSmrg                   const struct isl_tile_info *tile_info,
137201e04c3fSmrg                   enum isl_dim_layout dim_layout,
137301e04c3fSmrg                   const struct isl_extent2d *phys_total_el,
137401e04c3fSmrg                   uint32_t *out_row_pitch_B)
137501e04c3fSmrg{
137601e04c3fSmrg   uint32_t alignment_B =
137701e04c3fSmrg      isl_calc_row_pitch_alignment(surf_info, tile_info);
137801e04c3fSmrg
137901e04c3fSmrg   const uint32_t min_row_pitch_B =
138001e04c3fSmrg      isl_calc_min_row_pitch(dev, surf_info, tile_info, phys_total_el,
138101e04c3fSmrg                             alignment_B);
138201e04c3fSmrg
138301e04c3fSmrg   uint32_t row_pitch_B = min_row_pitch_B;
138401e04c3fSmrg
138501e04c3fSmrg   if (surf_info->row_pitch_B != 0) {
138601e04c3fSmrg      row_pitch_B = surf_info->row_pitch_B;
138701e04c3fSmrg
138801e04c3fSmrg      if (row_pitch_B < min_row_pitch_B)
138901e04c3fSmrg         return false;
139001e04c3fSmrg
139101e04c3fSmrg      if (row_pitch_B % alignment_B != 0)
139201e04c3fSmrg         return false;
139301e04c3fSmrg   }
139401e04c3fSmrg
139501e04c3fSmrg   const uint32_t row_pitch_tl = row_pitch_B / tile_info->phys_extent_B.width;
139601e04c3fSmrg
139701e04c3fSmrg   if (row_pitch_B == 0)
139801e04c3fSmrg      return false;
139901e04c3fSmrg
140001e04c3fSmrg   if (dim_layout == ISL_DIM_LAYOUT_GEN9_1D) {
140101e04c3fSmrg      /* SurfacePitch is ignored for this layout. */
140201e04c3fSmrg      goto done;
140301e04c3fSmrg   }
140401e04c3fSmrg
140501e04c3fSmrg   if ((surf_info->usage & (ISL_SURF_USAGE_RENDER_TARGET_BIT |
140601e04c3fSmrg                            ISL_SURF_USAGE_TEXTURE_BIT |
140701e04c3fSmrg                            ISL_SURF_USAGE_STORAGE_BIT)) &&
140801e04c3fSmrg       !pitch_in_range(row_pitch_B, RENDER_SURFACE_STATE_SurfacePitch_bits(dev->info)))
140901e04c3fSmrg      return false;
141001e04c3fSmrg
141101e04c3fSmrg   if ((surf_info->usage & (ISL_SURF_USAGE_CCS_BIT |
141201e04c3fSmrg                            ISL_SURF_USAGE_MCS_BIT)) &&
141301e04c3fSmrg       !pitch_in_range(row_pitch_tl, RENDER_SURFACE_STATE_AuxiliarySurfacePitch_bits(dev->info)))
141401e04c3fSmrg      return false;
141501e04c3fSmrg
141601e04c3fSmrg   if ((surf_info->usage & ISL_SURF_USAGE_DEPTH_BIT) &&
141701e04c3fSmrg       !pitch_in_range(row_pitch_B, _3DSTATE_DEPTH_BUFFER_SurfacePitch_bits(dev->info)))
141801e04c3fSmrg      return false;
141901e04c3fSmrg
142001e04c3fSmrg   if ((surf_info->usage & ISL_SURF_USAGE_HIZ_BIT) &&
142101e04c3fSmrg       !pitch_in_range(row_pitch_B, _3DSTATE_HIER_DEPTH_BUFFER_SurfacePitch_bits(dev->info)))
142201e04c3fSmrg      return false;
142301e04c3fSmrg
142401e04c3fSmrg   const uint32_t stencil_pitch_bits = dev->use_separate_stencil ?
142501e04c3fSmrg      _3DSTATE_STENCIL_BUFFER_SurfacePitch_bits(dev->info) :
142601e04c3fSmrg      _3DSTATE_DEPTH_BUFFER_SurfacePitch_bits(dev->info);
142701e04c3fSmrg
142801e04c3fSmrg   if ((surf_info->usage & ISL_SURF_USAGE_STENCIL_BIT) &&
142901e04c3fSmrg       !pitch_in_range(row_pitch_B, stencil_pitch_bits))
143001e04c3fSmrg      return false;
143101e04c3fSmrg
143201e04c3fSmrg done:
143301e04c3fSmrg   *out_row_pitch_B = row_pitch_B;
143401e04c3fSmrg   return true;
143501e04c3fSmrg}
143601e04c3fSmrg
143701e04c3fSmrgbool
143801e04c3fSmrgisl_surf_init_s(const struct isl_device *dev,
143901e04c3fSmrg                struct isl_surf *surf,
144001e04c3fSmrg                const struct isl_surf_init_info *restrict info)
144101e04c3fSmrg{
144201e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
144301e04c3fSmrg
144401e04c3fSmrg   const struct isl_extent4d logical_level0_px = {
144501e04c3fSmrg      .w = info->width,
144601e04c3fSmrg      .h = info->height,
144701e04c3fSmrg      .d = info->depth,
144801e04c3fSmrg      .a = info->array_len,
144901e04c3fSmrg   };
145001e04c3fSmrg
145101e04c3fSmrg   enum isl_tiling tiling;
145201e04c3fSmrg   if (!isl_surf_choose_tiling(dev, info, &tiling))
145301e04c3fSmrg      return false;
145401e04c3fSmrg
145501e04c3fSmrg   struct isl_tile_info tile_info;
145601e04c3fSmrg   isl_tiling_get_info(tiling, fmtl->bpb, &tile_info);
145701e04c3fSmrg
145801e04c3fSmrg   const enum isl_dim_layout dim_layout =
145901e04c3fSmrg      isl_surf_choose_dim_layout(dev, info->dim, tiling, info->usage);
146001e04c3fSmrg
146101e04c3fSmrg   enum isl_msaa_layout msaa_layout;
146201e04c3fSmrg   if (!isl_choose_msaa_layout(dev, info, tiling, &msaa_layout))
146301e04c3fSmrg       return false;
146401e04c3fSmrg
146501e04c3fSmrg   struct isl_extent3d image_align_el;
146601e04c3fSmrg   isl_choose_image_alignment_el(dev, info, tiling, dim_layout, msaa_layout,
146701e04c3fSmrg                                 &image_align_el);
146801e04c3fSmrg
146901e04c3fSmrg   struct isl_extent3d image_align_sa =
147001e04c3fSmrg      isl_extent3d_el_to_sa(info->format, image_align_el);
147101e04c3fSmrg
147201e04c3fSmrg   struct isl_extent4d phys_level0_sa;
147301e04c3fSmrg   isl_calc_phys_level0_extent_sa(dev, info, dim_layout, tiling, msaa_layout,
147401e04c3fSmrg                                  &phys_level0_sa);
147501e04c3fSmrg
147601e04c3fSmrg   enum isl_array_pitch_span array_pitch_span =
147701e04c3fSmrg      isl_choose_array_pitch_span(dev, info, dim_layout, &phys_level0_sa);
147801e04c3fSmrg
147901e04c3fSmrg   uint32_t array_pitch_el_rows;
148001e04c3fSmrg   struct isl_extent2d phys_total_el;
148101e04c3fSmrg   isl_calc_phys_total_extent_el(dev, info, &tile_info,
148201e04c3fSmrg                                 dim_layout, msaa_layout,
148301e04c3fSmrg                                 &image_align_sa, &phys_level0_sa,
148401e04c3fSmrg                                 array_pitch_span, &array_pitch_el_rows,
148501e04c3fSmrg                                 &phys_total_el);
148601e04c3fSmrg
148701e04c3fSmrg   uint32_t row_pitch_B;
148801e04c3fSmrg   if (!isl_calc_row_pitch(dev, info, &tile_info, dim_layout,
148901e04c3fSmrg                           &phys_total_el, &row_pitch_B))
149001e04c3fSmrg      return false;
149101e04c3fSmrg
149201e04c3fSmrg   uint32_t base_alignment_B;
149301e04c3fSmrg   uint64_t size_B;
149401e04c3fSmrg   if (tiling == ISL_TILING_LINEAR) {
149501e04c3fSmrg      size_B = (uint64_t) row_pitch_B * phys_total_el.h;
149601e04c3fSmrg
149701e04c3fSmrg      /* From the Broadwell PRM Vol 2d, RENDER_SURFACE_STATE::SurfaceBaseAddress:
149801e04c3fSmrg       *
149901e04c3fSmrg       *    "The Base Address for linear render target surfaces and surfaces
150001e04c3fSmrg       *    accessed with the typed surface read/write data port messages must
150101e04c3fSmrg       *    be element-size aligned, for non-YUV surface formats, or a
150201e04c3fSmrg       *    multiple of 2 element-sizes for YUV surface formats. Other linear
150301e04c3fSmrg       *    surfaces have no alignment requirements (byte alignment is
150401e04c3fSmrg       *    sufficient.)"
150501e04c3fSmrg       */
150601e04c3fSmrg      base_alignment_B = MAX(1, info->min_alignment_B);
150701e04c3fSmrg      if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
150801e04c3fSmrg         if (isl_format_is_yuv(info->format)) {
150901e04c3fSmrg            base_alignment_B = MAX(base_alignment_B, fmtl->bpb / 4);
151001e04c3fSmrg         } else {
151101e04c3fSmrg            base_alignment_B = MAX(base_alignment_B, fmtl->bpb / 8);
151201e04c3fSmrg         }
151301e04c3fSmrg      }
151401e04c3fSmrg      base_alignment_B = isl_round_up_to_power_of_two(base_alignment_B);
15159f464c52Smaya
15169f464c52Smaya      /* From the Skylake PRM Vol 2c, PLANE_STRIDE::Stride:
15179f464c52Smaya       *
15189f464c52Smaya       *     "For Linear memory, this field specifies the stride in chunks of
15199f464c52Smaya       *     64 bytes (1 cache line)."
15209f464c52Smaya       */
15219f464c52Smaya      if (isl_surf_usage_is_display(info->usage))
15229f464c52Smaya         base_alignment_B = MAX(base_alignment_B, 64);
152301e04c3fSmrg   } else {
152401e04c3fSmrg      const uint32_t total_h_tl =
152501e04c3fSmrg         isl_align_div(phys_total_el.h, tile_info.logical_extent_el.height);
152601e04c3fSmrg
152701e04c3fSmrg      size_B = (uint64_t) total_h_tl * tile_info.phys_extent_B.height * row_pitch_B;
152801e04c3fSmrg
152901e04c3fSmrg      const uint32_t tile_size_B = tile_info.phys_extent_B.width *
153001e04c3fSmrg                                   tile_info.phys_extent_B.height;
153101e04c3fSmrg      assert(isl_is_pow2(info->min_alignment_B) && isl_is_pow2(tile_size_B));
153201e04c3fSmrg      base_alignment_B = MAX(info->min_alignment_B, tile_size_B);
153301e04c3fSmrg   }
153401e04c3fSmrg
153501e04c3fSmrg   if (ISL_DEV_GEN(dev) < 9) {
153601e04c3fSmrg      /* From the Broadwell PRM Vol 5, Surface Layout:
153701e04c3fSmrg       *
153801e04c3fSmrg       *    "In addition to restrictions on maximum height, width, and depth,
153901e04c3fSmrg       *     surfaces are also restricted to a maximum size in bytes. This
154001e04c3fSmrg       *     maximum is 2 GB for all products and all surface types."
154101e04c3fSmrg       *
154201e04c3fSmrg       * This comment is applicable to all Pre-gen9 platforms.
154301e04c3fSmrg       */
154401e04c3fSmrg      if (size_B > (uint64_t) 1 << 31)
154501e04c3fSmrg         return false;
154601e04c3fSmrg   } else if (ISL_DEV_GEN(dev) < 11) {
154701e04c3fSmrg      /* From the Skylake PRM Vol 5, Maximum Surface Size in Bytes:
154801e04c3fSmrg       *    "In addition to restrictions on maximum height, width, and depth,
154901e04c3fSmrg       *     surfaces are also restricted to a maximum size of 2^38 bytes.
155001e04c3fSmrg       *     All pixels within the surface must be contained within 2^38 bytes
155101e04c3fSmrg       *     of the base address."
155201e04c3fSmrg       */
155301e04c3fSmrg      if (size_B > (uint64_t) 1 << 38)
155401e04c3fSmrg         return false;
155501e04c3fSmrg   } else {
155601e04c3fSmrg      /* gen11+ platforms raised this limit to 2^44 bytes. */
155701e04c3fSmrg      if (size_B > (uint64_t) 1 << 44)
155801e04c3fSmrg         return false;
155901e04c3fSmrg   }
156001e04c3fSmrg
156101e04c3fSmrg   *surf = (struct isl_surf) {
156201e04c3fSmrg      .dim = info->dim,
156301e04c3fSmrg      .dim_layout = dim_layout,
156401e04c3fSmrg      .msaa_layout = msaa_layout,
156501e04c3fSmrg      .tiling = tiling,
156601e04c3fSmrg      .format = info->format,
156701e04c3fSmrg
156801e04c3fSmrg      .levels = info->levels,
156901e04c3fSmrg      .samples = info->samples,
157001e04c3fSmrg
157101e04c3fSmrg      .image_alignment_el = image_align_el,
157201e04c3fSmrg      .logical_level0_px = logical_level0_px,
157301e04c3fSmrg      .phys_level0_sa = phys_level0_sa,
157401e04c3fSmrg
157501e04c3fSmrg      .size_B = size_B,
157601e04c3fSmrg      .alignment_B = base_alignment_B,
157701e04c3fSmrg      .row_pitch_B = row_pitch_B,
157801e04c3fSmrg      .array_pitch_el_rows = array_pitch_el_rows,
157901e04c3fSmrg      .array_pitch_span = array_pitch_span,
158001e04c3fSmrg
158101e04c3fSmrg      .usage = info->usage,
158201e04c3fSmrg   };
158301e04c3fSmrg
158401e04c3fSmrg   return true;
158501e04c3fSmrg}
158601e04c3fSmrg
158701e04c3fSmrgvoid
158801e04c3fSmrgisl_surf_get_tile_info(const struct isl_surf *surf,
158901e04c3fSmrg                       struct isl_tile_info *tile_info)
159001e04c3fSmrg{
159101e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
159201e04c3fSmrg   isl_tiling_get_info(surf->tiling, fmtl->bpb, tile_info);
159301e04c3fSmrg}
159401e04c3fSmrg
159501e04c3fSmrgbool
159601e04c3fSmrgisl_surf_get_hiz_surf(const struct isl_device *dev,
159701e04c3fSmrg                      const struct isl_surf *surf,
159801e04c3fSmrg                      struct isl_surf *hiz_surf)
159901e04c3fSmrg{
160001e04c3fSmrg   assert(ISL_DEV_GEN(dev) >= 5 && ISL_DEV_USE_SEPARATE_STENCIL(dev));
160101e04c3fSmrg
160201e04c3fSmrg   /* Multisampled depth is always interleaved */
160301e04c3fSmrg   assert(surf->msaa_layout == ISL_MSAA_LAYOUT_NONE ||
160401e04c3fSmrg          surf->msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED);
160501e04c3fSmrg
160601e04c3fSmrg   /* From the Broadwell PRM Vol. 7, "Hierarchical Depth Buffer":
160701e04c3fSmrg    *
160801e04c3fSmrg    *    "The Surface Type, Height, Width, Depth, Minimum Array Element, Render
160901e04c3fSmrg    *    Target View Extent, and Depth Coordinate Offset X/Y of the
161001e04c3fSmrg    *    hierarchical depth buffer are inherited from the depth buffer. The
161101e04c3fSmrg    *    height and width of the hierarchical depth buffer that must be
161201e04c3fSmrg    *    allocated are computed by the following formulas, where HZ is the
161301e04c3fSmrg    *    hierarchical depth buffer and Z is the depth buffer. The Z_Height,
161401e04c3fSmrg    *    Z_Width, and Z_Depth values given in these formulas are those present
161501e04c3fSmrg    *    in 3DSTATE_DEPTH_BUFFER incremented by one.
161601e04c3fSmrg    *
161701e04c3fSmrg    *    "The value of Z_Height and Z_Width must each be multiplied by 2 before
161801e04c3fSmrg    *    being applied to the table below if Number of Multisamples is set to
161901e04c3fSmrg    *    NUMSAMPLES_4. The value of Z_Height must be multiplied by 2 and
162001e04c3fSmrg    *    Z_Width must be multiplied by 4 before being applied to the table
162101e04c3fSmrg    *    below if Number of Multisamples is set to NUMSAMPLES_8."
162201e04c3fSmrg    *
162301e04c3fSmrg    * In the Sky Lake PRM, the second paragraph is replaced with this:
162401e04c3fSmrg    *
162501e04c3fSmrg    *    "The Z_Height and Z_Width values must equal those present in
162601e04c3fSmrg    *    3DSTATE_DEPTH_BUFFER incremented by one."
162701e04c3fSmrg    *
162801e04c3fSmrg    * In other words, on Sandy Bridge through Broadwell, each 128-bit HiZ
162901e04c3fSmrg    * block corresponds to a region of 8x4 samples in the primary depth
163001e04c3fSmrg    * surface.  On Sky Lake, on the other hand, each HiZ block corresponds to
163101e04c3fSmrg    * a region of 8x4 pixels in the primary depth surface regardless of the
163201e04c3fSmrg    * number of samples.  The dimensions of a HiZ block in both pixels and
163301e04c3fSmrg    * samples are given in the table below:
163401e04c3fSmrg    *
163501e04c3fSmrg    *                    | SNB - BDW |     SKL+
163601e04c3fSmrg    *              ------+-----------+-------------
163701e04c3fSmrg    *                1x  |  8 x 4 sa |   8 x 4 sa
163801e04c3fSmrg    *               MSAA |  8 x 4 px |   8 x 4 px
163901e04c3fSmrg    *              ------+-----------+-------------
164001e04c3fSmrg    *                2x  |  8 x 4 sa |  16 x 4 sa
164101e04c3fSmrg    *               MSAA |  4 x 4 px |   8 x 4 px
164201e04c3fSmrg    *              ------+-----------+-------------
164301e04c3fSmrg    *                4x  |  8 x 4 sa |  16 x 8 sa
164401e04c3fSmrg    *               MSAA |  4 x 2 px |   8 x 4 px
164501e04c3fSmrg    *              ------+-----------+-------------
164601e04c3fSmrg    *                8x  |  8 x 4 sa |  32 x 8 sa
164701e04c3fSmrg    *               MSAA |  2 x 2 px |   8 x 4 px
164801e04c3fSmrg    *              ------+-----------+-------------
164901e04c3fSmrg    *               16x  |    N/A    | 32 x 16 sa
165001e04c3fSmrg    *               MSAA |    N/A    |  8 x  4 px
165101e04c3fSmrg    *              ------+-----------+-------------
165201e04c3fSmrg    *
165301e04c3fSmrg    * There are a number of different ways that this discrepency could be
165401e04c3fSmrg    * handled.  The way we have chosen is to simply make MSAA HiZ have the
165501e04c3fSmrg    * same number of samples as the parent surface pre-Sky Lake and always be
165601e04c3fSmrg    * single-sampled on Sky Lake and above.  Since the block sizes of
165701e04c3fSmrg    * compressed formats are given in samples, this neatly handles everything
165801e04c3fSmrg    * without the need for additional HiZ formats with different block sizes
165901e04c3fSmrg    * on SKL+.
166001e04c3fSmrg    */
166101e04c3fSmrg   const unsigned samples = ISL_DEV_GEN(dev) >= 9 ? 1 : surf->samples;
166201e04c3fSmrg
166301e04c3fSmrg   return isl_surf_init(dev, hiz_surf,
166401e04c3fSmrg                        .dim = surf->dim,
166501e04c3fSmrg                        .format = ISL_FORMAT_HIZ,
166601e04c3fSmrg                        .width = surf->logical_level0_px.width,
166701e04c3fSmrg                        .height = surf->logical_level0_px.height,
166801e04c3fSmrg                        .depth = surf->logical_level0_px.depth,
166901e04c3fSmrg                        .levels = surf->levels,
167001e04c3fSmrg                        .array_len = surf->logical_level0_px.array_len,
167101e04c3fSmrg                        .samples = samples,
167201e04c3fSmrg                        .usage = ISL_SURF_USAGE_HIZ_BIT,
167301e04c3fSmrg                        .tiling_flags = ISL_TILING_HIZ_BIT);
167401e04c3fSmrg}
167501e04c3fSmrg
167601e04c3fSmrgbool
167701e04c3fSmrgisl_surf_get_mcs_surf(const struct isl_device *dev,
167801e04c3fSmrg                      const struct isl_surf *surf,
167901e04c3fSmrg                      struct isl_surf *mcs_surf)
168001e04c3fSmrg{
168101e04c3fSmrg   assert(ISL_DEV_GEN(dev) >= 7);
168201e04c3fSmrg
168301e04c3fSmrg   /* It must be multisampled with an array layout */
168401e04c3fSmrg   assert(surf->samples > 1 && surf->msaa_layout == ISL_MSAA_LAYOUT_ARRAY);
168501e04c3fSmrg
168601e04c3fSmrg   /* The following are true of all multisampled surfaces */
168701e04c3fSmrg   assert(surf->dim == ISL_SURF_DIM_2D);
168801e04c3fSmrg   assert(surf->levels == 1);
168901e04c3fSmrg   assert(surf->logical_level0_px.depth == 1);
169001e04c3fSmrg
169101e04c3fSmrg   /* The "Auxiliary Surface Pitch" field in RENDER_SURFACE_STATE is only 9
169201e04c3fSmrg    * bits which means the maximum pitch of a compression surface is 512
169301e04c3fSmrg    * tiles or 64KB (since MCS is always Y-tiled).  Since a 16x MCS buffer is
169401e04c3fSmrg    * 64bpp, this gives us a maximum width of 8192 pixels.  We can create
169501e04c3fSmrg    * larger multisampled surfaces, we just can't compress them.   For 2x, 4x,
169601e04c3fSmrg    * and 8x, we have enough room for the full 16k supported by the hardware.
169701e04c3fSmrg    */
169801e04c3fSmrg   if (surf->samples == 16 && surf->logical_level0_px.width > 8192)
169901e04c3fSmrg      return false;
170001e04c3fSmrg
170101e04c3fSmrg   enum isl_format mcs_format;
170201e04c3fSmrg   switch (surf->samples) {
170301e04c3fSmrg   case 2:  mcs_format = ISL_FORMAT_MCS_2X;  break;
170401e04c3fSmrg   case 4:  mcs_format = ISL_FORMAT_MCS_4X;  break;
170501e04c3fSmrg   case 8:  mcs_format = ISL_FORMAT_MCS_8X;  break;
170601e04c3fSmrg   case 16: mcs_format = ISL_FORMAT_MCS_16X; break;
170701e04c3fSmrg   default:
170801e04c3fSmrg      unreachable("Invalid sample count");
170901e04c3fSmrg   }
171001e04c3fSmrg
171101e04c3fSmrg   return isl_surf_init(dev, mcs_surf,
171201e04c3fSmrg                        .dim = ISL_SURF_DIM_2D,
171301e04c3fSmrg                        .format = mcs_format,
171401e04c3fSmrg                        .width = surf->logical_level0_px.width,
171501e04c3fSmrg                        .height = surf->logical_level0_px.height,
171601e04c3fSmrg                        .depth = 1,
171701e04c3fSmrg                        .levels = 1,
171801e04c3fSmrg                        .array_len = surf->logical_level0_px.array_len,
171901e04c3fSmrg                        .samples = 1, /* MCS surfaces are really single-sampled */
172001e04c3fSmrg                        .usage = ISL_SURF_USAGE_MCS_BIT,
172101e04c3fSmrg                        .tiling_flags = ISL_TILING_Y0_BIT);
172201e04c3fSmrg}
172301e04c3fSmrg
172401e04c3fSmrgbool
172501e04c3fSmrgisl_surf_get_ccs_surf(const struct isl_device *dev,
172601e04c3fSmrg                      const struct isl_surf *surf,
172701e04c3fSmrg                      struct isl_surf *ccs_surf,
172801e04c3fSmrg                      uint32_t row_pitch_B)
172901e04c3fSmrg{
173001e04c3fSmrg   assert(surf->samples == 1 && surf->msaa_layout == ISL_MSAA_LAYOUT_NONE);
173101e04c3fSmrg   assert(ISL_DEV_GEN(dev) >= 7);
173201e04c3fSmrg
173301e04c3fSmrg   if (surf->usage & ISL_SURF_USAGE_DISABLE_AUX_BIT)
173401e04c3fSmrg      return false;
173501e04c3fSmrg
173601e04c3fSmrg   /* The PRM doesn't say this explicitly, but fast-clears don't appear to
173701e04c3fSmrg    * work for 3D textures until gen9 where the layout of 3D textures changes
173801e04c3fSmrg    * to match 2D array textures.
173901e04c3fSmrg    */
174001e04c3fSmrg   if (ISL_DEV_GEN(dev) <= 8 && surf->dim != ISL_SURF_DIM_2D)
174101e04c3fSmrg      return false;
174201e04c3fSmrg
174301e04c3fSmrg   /* From the HSW PRM Volume 7: 3D-Media-GPGPU, page 652 (Color Clear of
174401e04c3fSmrg    * Non-MultiSampler Render Target Restrictions):
174501e04c3fSmrg    *
174601e04c3fSmrg    *    "Support is for non-mip-mapped and non-array surface types only."
174701e04c3fSmrg    *
174801e04c3fSmrg    * This restriction is lifted on gen8+.  Technically, it may be possible to
174901e04c3fSmrg    * create a CCS for an arrayed or mipmapped image and only enable CCS_D
175001e04c3fSmrg    * when rendering to the base slice.  However, there is no documentation
175101e04c3fSmrg    * tell us what the hardware would do in that case or what it does if you
175201e04c3fSmrg    * walk off the bases slice.  (Does it ignore CCS or does it start
175301e04c3fSmrg    * scribbling over random memory?)  We play it safe and just follow the
175401e04c3fSmrg    * docs and don't allow CCS_D for arrayed or mip-mapped surfaces.
175501e04c3fSmrg    */
175601e04c3fSmrg   if (ISL_DEV_GEN(dev) <= 7 &&
175701e04c3fSmrg       (surf->levels > 1 || surf->logical_level0_px.array_len > 1))
175801e04c3fSmrg      return false;
175901e04c3fSmrg
176001e04c3fSmrg   if (isl_format_is_compressed(surf->format))
176101e04c3fSmrg      return false;
176201e04c3fSmrg
176301e04c3fSmrg   /* TODO: More conditions where it can fail. */
176401e04c3fSmrg
176501e04c3fSmrg   enum isl_format ccs_format;
176601e04c3fSmrg   if (ISL_DEV_GEN(dev) >= 9) {
176701e04c3fSmrg      if (!isl_tiling_is_any_y(surf->tiling))
176801e04c3fSmrg         return false;
176901e04c3fSmrg
177001e04c3fSmrg      switch (isl_format_get_layout(surf->format)->bpb) {
177101e04c3fSmrg      case 32:    ccs_format = ISL_FORMAT_GEN9_CCS_32BPP;   break;
177201e04c3fSmrg      case 64:    ccs_format = ISL_FORMAT_GEN9_CCS_64BPP;   break;
177301e04c3fSmrg      case 128:   ccs_format = ISL_FORMAT_GEN9_CCS_128BPP;  break;
177401e04c3fSmrg      default:
177501e04c3fSmrg         return false;
177601e04c3fSmrg      }
177701e04c3fSmrg   } else if (surf->tiling == ISL_TILING_Y0) {
177801e04c3fSmrg      switch (isl_format_get_layout(surf->format)->bpb) {
177901e04c3fSmrg      case 32:    ccs_format = ISL_FORMAT_GEN7_CCS_32BPP_Y;    break;
178001e04c3fSmrg      case 64:    ccs_format = ISL_FORMAT_GEN7_CCS_64BPP_Y;    break;
178101e04c3fSmrg      case 128:   ccs_format = ISL_FORMAT_GEN7_CCS_128BPP_Y;   break;
178201e04c3fSmrg      default:
178301e04c3fSmrg         return false;
178401e04c3fSmrg      }
178501e04c3fSmrg   } else if (surf->tiling == ISL_TILING_X) {
178601e04c3fSmrg      switch (isl_format_get_layout(surf->format)->bpb) {
178701e04c3fSmrg      case 32:    ccs_format = ISL_FORMAT_GEN7_CCS_32BPP_X;    break;
178801e04c3fSmrg      case 64:    ccs_format = ISL_FORMAT_GEN7_CCS_64BPP_X;    break;
178901e04c3fSmrg      case 128:   ccs_format = ISL_FORMAT_GEN7_CCS_128BPP_X;   break;
179001e04c3fSmrg      default:
179101e04c3fSmrg         return false;
179201e04c3fSmrg      }
179301e04c3fSmrg   } else {
179401e04c3fSmrg      return false;
179501e04c3fSmrg   }
179601e04c3fSmrg
179701e04c3fSmrg   return isl_surf_init(dev, ccs_surf,
179801e04c3fSmrg                        .dim = surf->dim,
179901e04c3fSmrg                        .format = ccs_format,
180001e04c3fSmrg                        .width = surf->logical_level0_px.width,
180101e04c3fSmrg                        .height = surf->logical_level0_px.height,
180201e04c3fSmrg                        .depth = surf->logical_level0_px.depth,
180301e04c3fSmrg                        .levels = surf->levels,
180401e04c3fSmrg                        .array_len = surf->logical_level0_px.array_len,
180501e04c3fSmrg                        .samples = 1,
180601e04c3fSmrg                        .row_pitch_B = row_pitch_B,
180701e04c3fSmrg                        .usage = ISL_SURF_USAGE_CCS_BIT,
180801e04c3fSmrg                        .tiling_flags = ISL_TILING_CCS_BIT);
180901e04c3fSmrg}
181001e04c3fSmrg
181101e04c3fSmrg#define isl_genX_call(dev, func, ...)              \
181201e04c3fSmrg   switch (ISL_DEV_GEN(dev)) {                     \
181301e04c3fSmrg   case 4:                                         \
181401e04c3fSmrg      /* G45 surface state is the same as gen5 */  \
181501e04c3fSmrg      if (ISL_DEV_IS_G4X(dev)) {                   \
181601e04c3fSmrg         isl_gen5_##func(__VA_ARGS__);             \
181701e04c3fSmrg      } else {                                     \
181801e04c3fSmrg         isl_gen4_##func(__VA_ARGS__);             \
181901e04c3fSmrg      }                                            \
182001e04c3fSmrg      break;                                       \
182101e04c3fSmrg   case 5:                                         \
182201e04c3fSmrg      isl_gen5_##func(__VA_ARGS__);                \
182301e04c3fSmrg      break;                                       \
182401e04c3fSmrg   case 6:                                         \
182501e04c3fSmrg      isl_gen6_##func(__VA_ARGS__);                \
182601e04c3fSmrg      break;                                       \
182701e04c3fSmrg   case 7:                                         \
182801e04c3fSmrg      if (ISL_DEV_IS_HASWELL(dev)) {               \
182901e04c3fSmrg         isl_gen75_##func(__VA_ARGS__);            \
183001e04c3fSmrg      } else {                                     \
183101e04c3fSmrg         isl_gen7_##func(__VA_ARGS__);             \
183201e04c3fSmrg      }                                            \
183301e04c3fSmrg      break;                                       \
183401e04c3fSmrg   case 8:                                         \
183501e04c3fSmrg      isl_gen8_##func(__VA_ARGS__);                \
183601e04c3fSmrg      break;                                       \
183701e04c3fSmrg   case 9:                                         \
183801e04c3fSmrg      isl_gen9_##func(__VA_ARGS__);                \
183901e04c3fSmrg      break;                                       \
184001e04c3fSmrg   case 10:                                        \
184101e04c3fSmrg      isl_gen10_##func(__VA_ARGS__);               \
184201e04c3fSmrg      break;                                       \
184301e04c3fSmrg   case 11:                                        \
184401e04c3fSmrg      isl_gen11_##func(__VA_ARGS__);               \
184501e04c3fSmrg      break;                                       \
184601e04c3fSmrg   default:                                        \
184701e04c3fSmrg      assert(!"Unknown hardware generation");      \
184801e04c3fSmrg   }
184901e04c3fSmrg
185001e04c3fSmrgvoid
185101e04c3fSmrgisl_surf_fill_state_s(const struct isl_device *dev, void *state,
185201e04c3fSmrg                      const struct isl_surf_fill_state_info *restrict info)
185301e04c3fSmrg{
185401e04c3fSmrg#ifndef NDEBUG
185501e04c3fSmrg   isl_surf_usage_flags_t _base_usage =
185601e04c3fSmrg      info->view->usage & (ISL_SURF_USAGE_RENDER_TARGET_BIT |
185701e04c3fSmrg                           ISL_SURF_USAGE_TEXTURE_BIT |
185801e04c3fSmrg                           ISL_SURF_USAGE_STORAGE_BIT);
185901e04c3fSmrg   /* They may only specify one of the above bits at a time */
186001e04c3fSmrg   assert(__builtin_popcount(_base_usage) == 1);
186101e04c3fSmrg   /* The only other allowed bit is ISL_SURF_USAGE_CUBE_BIT */
186201e04c3fSmrg   assert((info->view->usage & ~ISL_SURF_USAGE_CUBE_BIT) == _base_usage);
186301e04c3fSmrg#endif
186401e04c3fSmrg
186501e04c3fSmrg   if (info->surf->dim == ISL_SURF_DIM_3D) {
186601e04c3fSmrg      assert(info->view->base_array_layer + info->view->array_len <=
186701e04c3fSmrg             info->surf->logical_level0_px.depth);
186801e04c3fSmrg   } else {
186901e04c3fSmrg      assert(info->view->base_array_layer + info->view->array_len <=
187001e04c3fSmrg             info->surf->logical_level0_px.array_len);
187101e04c3fSmrg   }
187201e04c3fSmrg
187301e04c3fSmrg   isl_genX_call(dev, surf_fill_state_s, dev, state, info);
187401e04c3fSmrg}
187501e04c3fSmrg
187601e04c3fSmrgvoid
187701e04c3fSmrgisl_buffer_fill_state_s(const struct isl_device *dev, void *state,
187801e04c3fSmrg                        const struct isl_buffer_fill_state_info *restrict info)
187901e04c3fSmrg{
188001e04c3fSmrg   isl_genX_call(dev, buffer_fill_state_s, state, info);
188101e04c3fSmrg}
188201e04c3fSmrg
188301e04c3fSmrgvoid
188401e04c3fSmrgisl_null_fill_state(const struct isl_device *dev, void *state,
188501e04c3fSmrg                    struct isl_extent3d size)
188601e04c3fSmrg{
188701e04c3fSmrg   isl_genX_call(dev, null_fill_state, state, size);
188801e04c3fSmrg}
188901e04c3fSmrg
189001e04c3fSmrgvoid
189101e04c3fSmrgisl_emit_depth_stencil_hiz_s(const struct isl_device *dev, void *batch,
189201e04c3fSmrg                             const struct isl_depth_stencil_hiz_emit_info *restrict info)
189301e04c3fSmrg{
189401e04c3fSmrg   if (info->depth_surf && info->stencil_surf) {
189501e04c3fSmrg      if (!dev->info->has_hiz_and_separate_stencil) {
189601e04c3fSmrg         assert(info->depth_surf == info->stencil_surf);
189701e04c3fSmrg         assert(info->depth_address == info->stencil_address);
189801e04c3fSmrg      }
189901e04c3fSmrg      assert(info->depth_surf->dim == info->stencil_surf->dim);
190001e04c3fSmrg   }
190101e04c3fSmrg
190201e04c3fSmrg   if (info->depth_surf) {
190301e04c3fSmrg      assert((info->depth_surf->usage & ISL_SURF_USAGE_DEPTH_BIT));
190401e04c3fSmrg      if (info->depth_surf->dim == ISL_SURF_DIM_3D) {
190501e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
190601e04c3fSmrg                info->depth_surf->logical_level0_px.depth);
190701e04c3fSmrg      } else {
190801e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
190901e04c3fSmrg                info->depth_surf->logical_level0_px.array_len);
191001e04c3fSmrg      }
191101e04c3fSmrg   }
191201e04c3fSmrg
191301e04c3fSmrg   if (info->stencil_surf) {
191401e04c3fSmrg      assert((info->stencil_surf->usage & ISL_SURF_USAGE_STENCIL_BIT));
191501e04c3fSmrg      if (info->stencil_surf->dim == ISL_SURF_DIM_3D) {
191601e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
191701e04c3fSmrg                info->stencil_surf->logical_level0_px.depth);
191801e04c3fSmrg      } else {
191901e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
192001e04c3fSmrg                info->stencil_surf->logical_level0_px.array_len);
192101e04c3fSmrg      }
192201e04c3fSmrg   }
192301e04c3fSmrg
192401e04c3fSmrg   isl_genX_call(dev, emit_depth_stencil_hiz_s, dev, batch, info);
192501e04c3fSmrg}
192601e04c3fSmrg
192701e04c3fSmrg/**
192801e04c3fSmrg * A variant of isl_surf_get_image_offset_sa() specific to
192901e04c3fSmrg * ISL_DIM_LAYOUT_GEN4_2D.
193001e04c3fSmrg */
193101e04c3fSmrgstatic void
193201e04c3fSmrgget_image_offset_sa_gen4_2d(const struct isl_surf *surf,
193301e04c3fSmrg                            uint32_t level, uint32_t logical_array_layer,
193401e04c3fSmrg                            uint32_t *x_offset_sa,
193501e04c3fSmrg                            uint32_t *y_offset_sa)
193601e04c3fSmrg{
193701e04c3fSmrg   assert(level < surf->levels);
193801e04c3fSmrg   if (surf->dim == ISL_SURF_DIM_3D)
193901e04c3fSmrg      assert(logical_array_layer < surf->logical_level0_px.depth);
194001e04c3fSmrg   else
194101e04c3fSmrg      assert(logical_array_layer < surf->logical_level0_px.array_len);
194201e04c3fSmrg
194301e04c3fSmrg   const struct isl_extent3d image_align_sa =
194401e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
194501e04c3fSmrg
194601e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.width;
194701e04c3fSmrg   const uint32_t H0 = surf->phys_level0_sa.height;
194801e04c3fSmrg
194901e04c3fSmrg   const uint32_t phys_layer = logical_array_layer *
195001e04c3fSmrg      (surf->msaa_layout == ISL_MSAA_LAYOUT_ARRAY ? surf->samples : 1);
195101e04c3fSmrg
195201e04c3fSmrg   uint32_t x = 0;
195301e04c3fSmrg   uint32_t y = phys_layer * isl_surf_get_array_pitch_sa_rows(surf);
195401e04c3fSmrg
195501e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
195601e04c3fSmrg      if (l == 1) {
195701e04c3fSmrg         uint32_t W = isl_minify(W0, l);
195801e04c3fSmrg         x += isl_align_npot(W, image_align_sa.w);
195901e04c3fSmrg      } else {
196001e04c3fSmrg         uint32_t H = isl_minify(H0, l);
196101e04c3fSmrg         y += isl_align_npot(H, image_align_sa.h);
196201e04c3fSmrg      }
196301e04c3fSmrg   }
196401e04c3fSmrg
196501e04c3fSmrg   *x_offset_sa = x;
196601e04c3fSmrg   *y_offset_sa = y;
196701e04c3fSmrg}
196801e04c3fSmrg
196901e04c3fSmrg/**
197001e04c3fSmrg * A variant of isl_surf_get_image_offset_sa() specific to
197101e04c3fSmrg * ISL_DIM_LAYOUT_GEN4_3D.
197201e04c3fSmrg */
197301e04c3fSmrgstatic void
197401e04c3fSmrgget_image_offset_sa_gen4_3d(const struct isl_surf *surf,
197501e04c3fSmrg                            uint32_t level, uint32_t logical_z_offset_px,
197601e04c3fSmrg                            uint32_t *x_offset_sa,
197701e04c3fSmrg                            uint32_t *y_offset_sa)
197801e04c3fSmrg{
197901e04c3fSmrg   assert(level < surf->levels);
198001e04c3fSmrg   if (surf->dim == ISL_SURF_DIM_3D) {
198101e04c3fSmrg      assert(surf->phys_level0_sa.array_len == 1);
198201e04c3fSmrg      assert(logical_z_offset_px < isl_minify(surf->phys_level0_sa.depth, level));
198301e04c3fSmrg   } else {
198401e04c3fSmrg      assert(surf->dim == ISL_SURF_DIM_2D);
198501e04c3fSmrg      assert(surf->usage & ISL_SURF_USAGE_CUBE_BIT);
198601e04c3fSmrg      assert(surf->phys_level0_sa.array_len == 6);
198701e04c3fSmrg      assert(logical_z_offset_px < surf->phys_level0_sa.array_len);
198801e04c3fSmrg   }
198901e04c3fSmrg
199001e04c3fSmrg   const struct isl_extent3d image_align_sa =
199101e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
199201e04c3fSmrg
199301e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.width;
199401e04c3fSmrg   const uint32_t H0 = surf->phys_level0_sa.height;
199501e04c3fSmrg   const uint32_t D0 = surf->phys_level0_sa.depth;
199601e04c3fSmrg   const uint32_t AL = surf->phys_level0_sa.array_len;
199701e04c3fSmrg
199801e04c3fSmrg   uint32_t x = 0;
199901e04c3fSmrg   uint32_t y = 0;
200001e04c3fSmrg
200101e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
200201e04c3fSmrg      const uint32_t level_h = isl_align_npot(isl_minify(H0, l), image_align_sa.h);
200301e04c3fSmrg      const uint32_t level_d =
200401e04c3fSmrg         isl_align_npot(surf->dim == ISL_SURF_DIM_3D ? isl_minify(D0, l) : AL,
200501e04c3fSmrg                        image_align_sa.d);
200601e04c3fSmrg      const uint32_t max_layers_vert = isl_align(level_d, 1u << l) / (1u << l);
200701e04c3fSmrg
200801e04c3fSmrg      y += level_h * max_layers_vert;
200901e04c3fSmrg   }
201001e04c3fSmrg
201101e04c3fSmrg   const uint32_t level_w = isl_align_npot(isl_minify(W0, level), image_align_sa.w);
201201e04c3fSmrg   const uint32_t level_h = isl_align_npot(isl_minify(H0, level), image_align_sa.h);
201301e04c3fSmrg   const uint32_t level_d =
201401e04c3fSmrg      isl_align_npot(surf->dim == ISL_SURF_DIM_3D ? isl_minify(D0, level) : AL,
201501e04c3fSmrg                     image_align_sa.d);
201601e04c3fSmrg
201701e04c3fSmrg   const uint32_t max_layers_horiz = MIN(level_d, 1u << level);
201801e04c3fSmrg
201901e04c3fSmrg   x += level_w * (logical_z_offset_px % max_layers_horiz);
202001e04c3fSmrg   y += level_h * (logical_z_offset_px / max_layers_horiz);
202101e04c3fSmrg
202201e04c3fSmrg   *x_offset_sa = x;
202301e04c3fSmrg   *y_offset_sa = y;
202401e04c3fSmrg}
202501e04c3fSmrg
202601e04c3fSmrgstatic void
202701e04c3fSmrgget_image_offset_sa_gen6_stencil_hiz(const struct isl_surf *surf,
202801e04c3fSmrg                                     uint32_t level,
202901e04c3fSmrg                                     uint32_t logical_array_layer,
203001e04c3fSmrg                                     uint32_t *x_offset_sa,
203101e04c3fSmrg                                     uint32_t *y_offset_sa)
203201e04c3fSmrg{
203301e04c3fSmrg   assert(level < surf->levels);
203401e04c3fSmrg   assert(surf->logical_level0_px.depth == 1);
203501e04c3fSmrg   assert(logical_array_layer < surf->logical_level0_px.array_len);
203601e04c3fSmrg
203701e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
203801e04c3fSmrg
203901e04c3fSmrg   const struct isl_extent3d image_align_sa =
204001e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
204101e04c3fSmrg
204201e04c3fSmrg   struct isl_tile_info tile_info;
204301e04c3fSmrg   isl_tiling_get_info(surf->tiling, fmtl->bpb, &tile_info);
204401e04c3fSmrg   const struct isl_extent2d tile_extent_sa = {
204501e04c3fSmrg      .w = tile_info.logical_extent_el.w * fmtl->bw,
204601e04c3fSmrg      .h = tile_info.logical_extent_el.h * fmtl->bh,
204701e04c3fSmrg   };
204801e04c3fSmrg   /* Tile size is a multiple of image alignment */
204901e04c3fSmrg   assert(tile_extent_sa.w % image_align_sa.w == 0);
205001e04c3fSmrg   assert(tile_extent_sa.h % image_align_sa.h == 0);
205101e04c3fSmrg
205201e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.w;
205301e04c3fSmrg   const uint32_t H0 = surf->phys_level0_sa.h;
205401e04c3fSmrg
205501e04c3fSmrg   /* Each image has the same height as LOD0 because the hardware thinks
205601e04c3fSmrg    * everything is LOD0
205701e04c3fSmrg    */
205801e04c3fSmrg   const uint32_t H = isl_align(H0, image_align_sa.h);
205901e04c3fSmrg
206001e04c3fSmrg   /* Quick sanity check for consistency */
206101e04c3fSmrg   if (surf->phys_level0_sa.array_len > 1)
206201e04c3fSmrg      assert(surf->array_pitch_el_rows == isl_assert_div(H, fmtl->bh));
206301e04c3fSmrg
206401e04c3fSmrg   uint32_t x = 0, y = 0;
206501e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
206601e04c3fSmrg      const uint32_t W = isl_minify(W0, l);
206701e04c3fSmrg
206801e04c3fSmrg      const uint32_t w = isl_align(W, tile_extent_sa.w);
206901e04c3fSmrg      const uint32_t h = isl_align(H * surf->phys_level0_sa.a,
207001e04c3fSmrg                                   tile_extent_sa.h);
207101e04c3fSmrg
207201e04c3fSmrg      if (l == 0) {
207301e04c3fSmrg         y += h;
207401e04c3fSmrg      } else {
207501e04c3fSmrg         x += w;
207601e04c3fSmrg      }
207701e04c3fSmrg   }
207801e04c3fSmrg
207901e04c3fSmrg   y += H * logical_array_layer;
208001e04c3fSmrg
208101e04c3fSmrg   *x_offset_sa = x;
208201e04c3fSmrg   *y_offset_sa = y;
208301e04c3fSmrg}
208401e04c3fSmrg
208501e04c3fSmrg/**
208601e04c3fSmrg * A variant of isl_surf_get_image_offset_sa() specific to
208701e04c3fSmrg * ISL_DIM_LAYOUT_GEN9_1D.
208801e04c3fSmrg */
208901e04c3fSmrgstatic void
209001e04c3fSmrgget_image_offset_sa_gen9_1d(const struct isl_surf *surf,
209101e04c3fSmrg                            uint32_t level, uint32_t layer,
209201e04c3fSmrg                            uint32_t *x_offset_sa,
209301e04c3fSmrg                            uint32_t *y_offset_sa)
209401e04c3fSmrg{
209501e04c3fSmrg   assert(level < surf->levels);
209601e04c3fSmrg   assert(layer < surf->phys_level0_sa.array_len);
209701e04c3fSmrg   assert(surf->phys_level0_sa.height == 1);
209801e04c3fSmrg   assert(surf->phys_level0_sa.depth == 1);
209901e04c3fSmrg   assert(surf->samples == 1);
210001e04c3fSmrg
210101e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.width;
210201e04c3fSmrg   const struct isl_extent3d image_align_sa =
210301e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
210401e04c3fSmrg
210501e04c3fSmrg   uint32_t x = 0;
210601e04c3fSmrg
210701e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
210801e04c3fSmrg      uint32_t W = isl_minify(W0, l);
210901e04c3fSmrg      uint32_t w = isl_align_npot(W, image_align_sa.w);
211001e04c3fSmrg
211101e04c3fSmrg      x += w;
211201e04c3fSmrg   }
211301e04c3fSmrg
211401e04c3fSmrg   *x_offset_sa = x;
211501e04c3fSmrg   *y_offset_sa = layer * isl_surf_get_array_pitch_sa_rows(surf);
211601e04c3fSmrg}
211701e04c3fSmrg
211801e04c3fSmrg/**
211901e04c3fSmrg * Calculate the offset, in units of surface samples, to a subimage in the
212001e04c3fSmrg * surface.
212101e04c3fSmrg *
212201e04c3fSmrg * @invariant level < surface levels
212301e04c3fSmrg * @invariant logical_array_layer < logical array length of surface
212401e04c3fSmrg * @invariant logical_z_offset_px < logical depth of surface at level
212501e04c3fSmrg */
212601e04c3fSmrgvoid
212701e04c3fSmrgisl_surf_get_image_offset_sa(const struct isl_surf *surf,
212801e04c3fSmrg                             uint32_t level,
212901e04c3fSmrg                             uint32_t logical_array_layer,
213001e04c3fSmrg                             uint32_t logical_z_offset_px,
213101e04c3fSmrg                             uint32_t *x_offset_sa,
213201e04c3fSmrg                             uint32_t *y_offset_sa)
213301e04c3fSmrg{
213401e04c3fSmrg   assert(level < surf->levels);
213501e04c3fSmrg   assert(logical_array_layer < surf->logical_level0_px.array_len);
213601e04c3fSmrg   assert(logical_z_offset_px
213701e04c3fSmrg          < isl_minify(surf->logical_level0_px.depth, level));
213801e04c3fSmrg
213901e04c3fSmrg   switch (surf->dim_layout) {
214001e04c3fSmrg   case ISL_DIM_LAYOUT_GEN9_1D:
214101e04c3fSmrg      get_image_offset_sa_gen9_1d(surf, level, logical_array_layer,
214201e04c3fSmrg                                  x_offset_sa, y_offset_sa);
214301e04c3fSmrg      break;
214401e04c3fSmrg   case ISL_DIM_LAYOUT_GEN4_2D:
214501e04c3fSmrg      get_image_offset_sa_gen4_2d(surf, level, logical_array_layer
214601e04c3fSmrg                                  + logical_z_offset_px,
214701e04c3fSmrg                                  x_offset_sa, y_offset_sa);
214801e04c3fSmrg      break;
214901e04c3fSmrg   case ISL_DIM_LAYOUT_GEN4_3D:
215001e04c3fSmrg      get_image_offset_sa_gen4_3d(surf, level, logical_array_layer +
215101e04c3fSmrg                                  logical_z_offset_px,
215201e04c3fSmrg                                  x_offset_sa, y_offset_sa);
215301e04c3fSmrg      break;
215401e04c3fSmrg   case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
215501e04c3fSmrg      get_image_offset_sa_gen6_stencil_hiz(surf, level, logical_array_layer +
215601e04c3fSmrg                                           logical_z_offset_px,
215701e04c3fSmrg                                           x_offset_sa, y_offset_sa);
215801e04c3fSmrg      break;
215901e04c3fSmrg
216001e04c3fSmrg   default:
216101e04c3fSmrg      unreachable("not reached");
216201e04c3fSmrg   }
216301e04c3fSmrg}
216401e04c3fSmrg
216501e04c3fSmrgvoid
216601e04c3fSmrgisl_surf_get_image_offset_el(const struct isl_surf *surf,
216701e04c3fSmrg                             uint32_t level,
216801e04c3fSmrg                             uint32_t logical_array_layer,
216901e04c3fSmrg                             uint32_t logical_z_offset_px,
217001e04c3fSmrg                             uint32_t *x_offset_el,
217101e04c3fSmrg                             uint32_t *y_offset_el)
217201e04c3fSmrg{
217301e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
217401e04c3fSmrg
217501e04c3fSmrg   assert(level < surf->levels);
217601e04c3fSmrg   assert(logical_array_layer < surf->logical_level0_px.array_len);
217701e04c3fSmrg   assert(logical_z_offset_px
217801e04c3fSmrg          < isl_minify(surf->logical_level0_px.depth, level));
217901e04c3fSmrg
218001e04c3fSmrg   uint32_t x_offset_sa, y_offset_sa;
218101e04c3fSmrg   isl_surf_get_image_offset_sa(surf, level,
218201e04c3fSmrg                                logical_array_layer,
218301e04c3fSmrg                                logical_z_offset_px,
218401e04c3fSmrg                                &x_offset_sa,
218501e04c3fSmrg                                &y_offset_sa);
218601e04c3fSmrg
218701e04c3fSmrg   *x_offset_el = x_offset_sa / fmtl->bw;
218801e04c3fSmrg   *y_offset_el = y_offset_sa / fmtl->bh;
218901e04c3fSmrg}
219001e04c3fSmrg
219101e04c3fSmrgvoid
219201e04c3fSmrgisl_surf_get_image_offset_B_tile_sa(const struct isl_surf *surf,
219301e04c3fSmrg                                    uint32_t level,
219401e04c3fSmrg                                    uint32_t logical_array_layer,
219501e04c3fSmrg                                    uint32_t logical_z_offset_px,
219601e04c3fSmrg                                    uint32_t *offset_B,
219701e04c3fSmrg                                    uint32_t *x_offset_sa,
219801e04c3fSmrg                                    uint32_t *y_offset_sa)
219901e04c3fSmrg{
220001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
220101e04c3fSmrg
220201e04c3fSmrg   uint32_t total_x_offset_el, total_y_offset_el;
220301e04c3fSmrg   isl_surf_get_image_offset_el(surf, level, logical_array_layer,
220401e04c3fSmrg                                logical_z_offset_px,
220501e04c3fSmrg                                &total_x_offset_el,
220601e04c3fSmrg                                &total_y_offset_el);
220701e04c3fSmrg
220801e04c3fSmrg   uint32_t x_offset_el, y_offset_el;
220901e04c3fSmrg   isl_tiling_get_intratile_offset_el(surf->tiling, fmtl->bpb,
221001e04c3fSmrg                                      surf->row_pitch_B,
221101e04c3fSmrg                                      total_x_offset_el,
221201e04c3fSmrg                                      total_y_offset_el,
221301e04c3fSmrg                                      offset_B,
221401e04c3fSmrg                                      &x_offset_el,
221501e04c3fSmrg                                      &y_offset_el);
221601e04c3fSmrg
221701e04c3fSmrg   if (x_offset_sa) {
221801e04c3fSmrg      *x_offset_sa = x_offset_el * fmtl->bw;
221901e04c3fSmrg   } else {
222001e04c3fSmrg      assert(x_offset_el == 0);
222101e04c3fSmrg   }
222201e04c3fSmrg
222301e04c3fSmrg   if (y_offset_sa) {
222401e04c3fSmrg      *y_offset_sa = y_offset_el * fmtl->bh;
222501e04c3fSmrg   } else {
222601e04c3fSmrg      assert(y_offset_el == 0);
222701e04c3fSmrg   }
222801e04c3fSmrg}
222901e04c3fSmrg
223001e04c3fSmrgvoid
223101e04c3fSmrgisl_surf_get_image_surf(const struct isl_device *dev,
223201e04c3fSmrg                        const struct isl_surf *surf,
223301e04c3fSmrg                        uint32_t level,
223401e04c3fSmrg                        uint32_t logical_array_layer,
223501e04c3fSmrg                        uint32_t logical_z_offset_px,
223601e04c3fSmrg                        struct isl_surf *image_surf,
223701e04c3fSmrg                        uint32_t *offset_B,
223801e04c3fSmrg                        uint32_t *x_offset_sa,
223901e04c3fSmrg                        uint32_t *y_offset_sa)
224001e04c3fSmrg{
224101e04c3fSmrg   isl_surf_get_image_offset_B_tile_sa(surf,
224201e04c3fSmrg                                       level,
224301e04c3fSmrg                                       logical_array_layer,
224401e04c3fSmrg                                       logical_z_offset_px,
224501e04c3fSmrg                                       offset_B,
224601e04c3fSmrg                                       x_offset_sa,
224701e04c3fSmrg                                       y_offset_sa);
224801e04c3fSmrg
224901e04c3fSmrg   /* Even for cube maps there will be only single face, therefore drop the
225001e04c3fSmrg    * corresponding flag if present.
225101e04c3fSmrg    */
225201e04c3fSmrg   const isl_surf_usage_flags_t usage =
225301e04c3fSmrg      surf->usage & (~ISL_SURF_USAGE_CUBE_BIT);
225401e04c3fSmrg
225501e04c3fSmrg   bool ok UNUSED;
225601e04c3fSmrg   ok = isl_surf_init(dev, image_surf,
225701e04c3fSmrg                      .dim = ISL_SURF_DIM_2D,
225801e04c3fSmrg                      .format = surf->format,
225901e04c3fSmrg                      .width = isl_minify(surf->logical_level0_px.w, level),
226001e04c3fSmrg                      .height = isl_minify(surf->logical_level0_px.h, level),
226101e04c3fSmrg                      .depth = 1,
226201e04c3fSmrg                      .levels = 1,
226301e04c3fSmrg                      .array_len = 1,
226401e04c3fSmrg                      .samples = surf->samples,
226501e04c3fSmrg                      .row_pitch_B = surf->row_pitch_B,
226601e04c3fSmrg                      .usage = usage,
226701e04c3fSmrg                      .tiling_flags = (1 << surf->tiling));
226801e04c3fSmrg   assert(ok);
226901e04c3fSmrg}
227001e04c3fSmrg
227101e04c3fSmrgvoid
227201e04c3fSmrgisl_tiling_get_intratile_offset_el(enum isl_tiling tiling,
227301e04c3fSmrg                                   uint32_t bpb,
227401e04c3fSmrg                                   uint32_t row_pitch_B,
227501e04c3fSmrg                                   uint32_t total_x_offset_el,
227601e04c3fSmrg                                   uint32_t total_y_offset_el,
227701e04c3fSmrg                                   uint32_t *base_address_offset,
227801e04c3fSmrg                                   uint32_t *x_offset_el,
227901e04c3fSmrg                                   uint32_t *y_offset_el)
228001e04c3fSmrg{
228101e04c3fSmrg   if (tiling == ISL_TILING_LINEAR) {
228201e04c3fSmrg      assert(bpb % 8 == 0);
228301e04c3fSmrg      *base_address_offset = total_y_offset_el * row_pitch_B +
228401e04c3fSmrg                             total_x_offset_el * (bpb / 8);
228501e04c3fSmrg      *x_offset_el = 0;
228601e04c3fSmrg      *y_offset_el = 0;
228701e04c3fSmrg      return;
228801e04c3fSmrg   }
228901e04c3fSmrg
229001e04c3fSmrg   struct isl_tile_info tile_info;
229101e04c3fSmrg   isl_tiling_get_info(tiling, bpb, &tile_info);
229201e04c3fSmrg
229301e04c3fSmrg   assert(row_pitch_B % tile_info.phys_extent_B.width == 0);
229401e04c3fSmrg
229501e04c3fSmrg   /* For non-power-of-two formats, we need the address to be both tile and
229601e04c3fSmrg    * element-aligned.  The easiest way to achieve this is to work with a tile
229701e04c3fSmrg    * that is three times as wide as the regular tile.
229801e04c3fSmrg    *
229901e04c3fSmrg    * The tile info returned by get_tile_info has a logical size that is an
230001e04c3fSmrg    * integer number of tile_info.format_bpb size elements.  To scale the
230101e04c3fSmrg    * tile, we scale up the physical width and then treat the logical tile
230201e04c3fSmrg    * size as if it has bpb size elements.
230301e04c3fSmrg    */
230401e04c3fSmrg   const uint32_t tile_el_scale = bpb / tile_info.format_bpb;
230501e04c3fSmrg   tile_info.phys_extent_B.width *= tile_el_scale;
230601e04c3fSmrg
230701e04c3fSmrg   /* Compute the offset into the tile */
230801e04c3fSmrg   *x_offset_el = total_x_offset_el % tile_info.logical_extent_el.w;
230901e04c3fSmrg   *y_offset_el = total_y_offset_el % tile_info.logical_extent_el.h;
231001e04c3fSmrg
231101e04c3fSmrg   /* Compute the offset of the tile in units of whole tiles */
231201e04c3fSmrg   uint32_t x_offset_tl = total_x_offset_el / tile_info.logical_extent_el.w;
231301e04c3fSmrg   uint32_t y_offset_tl = total_y_offset_el / tile_info.logical_extent_el.h;
231401e04c3fSmrg
231501e04c3fSmrg   *base_address_offset =
231601e04c3fSmrg      y_offset_tl * tile_info.phys_extent_B.h * row_pitch_B +
231701e04c3fSmrg      x_offset_tl * tile_info.phys_extent_B.h * tile_info.phys_extent_B.w;
231801e04c3fSmrg}
231901e04c3fSmrg
232001e04c3fSmrguint32_t
232101e04c3fSmrgisl_surf_get_depth_format(const struct isl_device *dev,
232201e04c3fSmrg                          const struct isl_surf *surf)
232301e04c3fSmrg{
232401e04c3fSmrg   /* Support for separate stencil buffers began in gen5. Support for
232501e04c3fSmrg    * interleaved depthstencil buffers ceased in gen7. The intermediate gens,
232601e04c3fSmrg    * those that supported separate and interleaved stencil, were gen5 and
232701e04c3fSmrg    * gen6.
232801e04c3fSmrg    *
232901e04c3fSmrg    * For a list of all available formats, see the Sandybridge PRM >> Volume
233001e04c3fSmrg    * 2 Part 1: 3D/Media - 3D Pipeline >> 3DSTATE_DEPTH_BUFFER >> Surface
233101e04c3fSmrg    * Format (p321).
233201e04c3fSmrg    */
233301e04c3fSmrg
233401e04c3fSmrg   bool has_stencil = surf->usage & ISL_SURF_USAGE_STENCIL_BIT;
233501e04c3fSmrg
233601e04c3fSmrg   assert(surf->usage & ISL_SURF_USAGE_DEPTH_BIT);
233701e04c3fSmrg
233801e04c3fSmrg   if (has_stencil)
233901e04c3fSmrg      assert(ISL_DEV_GEN(dev) < 7);
234001e04c3fSmrg
234101e04c3fSmrg   switch (surf->format) {
234201e04c3fSmrg   default:
234301e04c3fSmrg      unreachable("bad isl depth format");
234401e04c3fSmrg   case ISL_FORMAT_R32_FLOAT_X8X24_TYPELESS:
234501e04c3fSmrg      assert(ISL_DEV_GEN(dev) < 7);
234601e04c3fSmrg      return 0; /* D32_FLOAT_S8X24_UINT */
234701e04c3fSmrg   case ISL_FORMAT_R32_FLOAT:
234801e04c3fSmrg      assert(!has_stencil);
234901e04c3fSmrg      return 1; /* D32_FLOAT */
235001e04c3fSmrg   case ISL_FORMAT_R24_UNORM_X8_TYPELESS:
235101e04c3fSmrg      if (has_stencil) {
235201e04c3fSmrg         assert(ISL_DEV_GEN(dev) < 7);
235301e04c3fSmrg         return 2; /* D24_UNORM_S8_UINT */
235401e04c3fSmrg      } else {
235501e04c3fSmrg         assert(ISL_DEV_GEN(dev) >= 5);
235601e04c3fSmrg         return 3; /* D24_UNORM_X8_UINT */
235701e04c3fSmrg      }
235801e04c3fSmrg   case ISL_FORMAT_R16_UNORM:
235901e04c3fSmrg      assert(!has_stencil);
236001e04c3fSmrg      return 5; /* D16_UNORM */
236101e04c3fSmrg   }
236201e04c3fSmrg}
236301e04c3fSmrg
236401e04c3fSmrgbool
236501e04c3fSmrgisl_swizzle_supports_rendering(const struct gen_device_info *devinfo,
236601e04c3fSmrg                               struct isl_swizzle swizzle)
236701e04c3fSmrg{
236801e04c3fSmrg   if (devinfo->is_haswell) {
236901e04c3fSmrg      /* From the Haswell PRM,
237001e04c3fSmrg       * RENDER_SURFACE_STATE::Shader Channel Select Red
237101e04c3fSmrg       *
237201e04c3fSmrg       *    "The Shader channel selects also define which shader channels are
237301e04c3fSmrg       *    written to which surface channel. If the Shader channel select is
237401e04c3fSmrg       *    SCS_ZERO or SCS_ONE then it is not written to the surface. If the
237501e04c3fSmrg       *    shader channel select is SCS_RED it is written to the surface red
237601e04c3fSmrg       *    channel and so on. If more than one shader channel select is set
237701e04c3fSmrg       *    to the same surface channel only the first shader channel in RGBA
237801e04c3fSmrg       *    order will be written."
237901e04c3fSmrg       */
238001e04c3fSmrg      return true;
238101e04c3fSmrg   } else if (devinfo->gen <= 7) {
238201e04c3fSmrg      /* Ivy Bridge and early doesn't have any swizzling */
238301e04c3fSmrg      return isl_swizzle_is_identity(swizzle);
238401e04c3fSmrg   } else {
238501e04c3fSmrg      /* From the Sky Lake PRM Vol. 2d,
238601e04c3fSmrg       * RENDER_SURFACE_STATE::Shader Channel Select Red
238701e04c3fSmrg       *
238801e04c3fSmrg       *    "For Render Target, Red, Green and Blue Shader Channel Selects
238901e04c3fSmrg       *    MUST be such that only valid components can be swapped i.e. only
239001e04c3fSmrg       *    change the order of components in the pixel. Any other values for
239101e04c3fSmrg       *    these Shader Channel Select fields are not valid for Render
239201e04c3fSmrg       *    Targets. This also means that there MUST not be multiple shader
239301e04c3fSmrg       *    channels mapped to the same RT channel."
239401e04c3fSmrg       *
239501e04c3fSmrg       * From the Sky Lake PRM Vol. 2d,
239601e04c3fSmrg       * RENDER_SURFACE_STATE::Shader Channel Select Alpha
239701e04c3fSmrg       *
239801e04c3fSmrg       *    "For Render Target, this field MUST be programmed to
239901e04c3fSmrg       *    value = SCS_ALPHA."
240001e04c3fSmrg       */
240101e04c3fSmrg      return (swizzle.r == ISL_CHANNEL_SELECT_RED ||
240201e04c3fSmrg              swizzle.r == ISL_CHANNEL_SELECT_GREEN ||
240301e04c3fSmrg              swizzle.r == ISL_CHANNEL_SELECT_BLUE) &&
240401e04c3fSmrg             (swizzle.g == ISL_CHANNEL_SELECT_RED ||
240501e04c3fSmrg              swizzle.g == ISL_CHANNEL_SELECT_GREEN ||
240601e04c3fSmrg              swizzle.g == ISL_CHANNEL_SELECT_BLUE) &&
240701e04c3fSmrg             (swizzle.b == ISL_CHANNEL_SELECT_RED ||
240801e04c3fSmrg              swizzle.b == ISL_CHANNEL_SELECT_GREEN ||
240901e04c3fSmrg              swizzle.b == ISL_CHANNEL_SELECT_BLUE) &&
241001e04c3fSmrg             swizzle.r != swizzle.g &&
241101e04c3fSmrg             swizzle.r != swizzle.b &&
241201e04c3fSmrg             swizzle.g != swizzle.b &&
241301e04c3fSmrg             swizzle.a == ISL_CHANNEL_SELECT_ALPHA;
241401e04c3fSmrg   }
241501e04c3fSmrg}
241601e04c3fSmrg
241701e04c3fSmrgstatic enum isl_channel_select
241801e04c3fSmrgswizzle_select(enum isl_channel_select chan, struct isl_swizzle swizzle)
241901e04c3fSmrg{
242001e04c3fSmrg   switch (chan) {
242101e04c3fSmrg   case ISL_CHANNEL_SELECT_ZERO:
242201e04c3fSmrg   case ISL_CHANNEL_SELECT_ONE:
242301e04c3fSmrg      return chan;
242401e04c3fSmrg   case ISL_CHANNEL_SELECT_RED:
242501e04c3fSmrg      return swizzle.r;
242601e04c3fSmrg   case ISL_CHANNEL_SELECT_GREEN:
242701e04c3fSmrg      return swizzle.g;
242801e04c3fSmrg   case ISL_CHANNEL_SELECT_BLUE:
242901e04c3fSmrg      return swizzle.b;
243001e04c3fSmrg   case ISL_CHANNEL_SELECT_ALPHA:
243101e04c3fSmrg      return swizzle.a;
243201e04c3fSmrg   default:
243301e04c3fSmrg      unreachable("Invalid swizzle component");
243401e04c3fSmrg   }
243501e04c3fSmrg}
243601e04c3fSmrg
243701e04c3fSmrg/**
243801e04c3fSmrg * Returns the single swizzle that is equivalent to applying the two given
243901e04c3fSmrg * swizzles in sequence.
244001e04c3fSmrg */
244101e04c3fSmrgstruct isl_swizzle
244201e04c3fSmrgisl_swizzle_compose(struct isl_swizzle first, struct isl_swizzle second)
244301e04c3fSmrg{
244401e04c3fSmrg   return (struct isl_swizzle) {
244501e04c3fSmrg      .r = swizzle_select(first.r, second),
244601e04c3fSmrg      .g = swizzle_select(first.g, second),
244701e04c3fSmrg      .b = swizzle_select(first.b, second),
244801e04c3fSmrg      .a = swizzle_select(first.a, second),
244901e04c3fSmrg   };
245001e04c3fSmrg}
245101e04c3fSmrg
245201e04c3fSmrg/**
245301e04c3fSmrg * Returns a swizzle that is the pseudo-inverse of this swizzle.
245401e04c3fSmrg */
245501e04c3fSmrgstruct isl_swizzle
245601e04c3fSmrgisl_swizzle_invert(struct isl_swizzle swizzle)
245701e04c3fSmrg{
245801e04c3fSmrg   /* Default to zero for channels which do not show up in the swizzle */
245901e04c3fSmrg   enum isl_channel_select chans[4] = {
246001e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
246101e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
246201e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
246301e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
246401e04c3fSmrg   };
246501e04c3fSmrg
246601e04c3fSmrg   /* We go in ABGR order so that, if there are any duplicates, the first one
246701e04c3fSmrg    * is taken if you look at it in RGBA order.  This is what Haswell hardware
246801e04c3fSmrg    * does for render target swizzles.
246901e04c3fSmrg    */
247001e04c3fSmrg   if ((unsigned)(swizzle.a - ISL_CHANNEL_SELECT_RED) < 4)
247101e04c3fSmrg      chans[swizzle.a - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_ALPHA;
247201e04c3fSmrg   if ((unsigned)(swizzle.b - ISL_CHANNEL_SELECT_RED) < 4)
247301e04c3fSmrg      chans[swizzle.b - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_BLUE;
247401e04c3fSmrg   if ((unsigned)(swizzle.g - ISL_CHANNEL_SELECT_RED) < 4)
247501e04c3fSmrg      chans[swizzle.g - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_GREEN;
247601e04c3fSmrg   if ((unsigned)(swizzle.r - ISL_CHANNEL_SELECT_RED) < 4)
247701e04c3fSmrg      chans[swizzle.r - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_RED;
247801e04c3fSmrg
247901e04c3fSmrg   return (struct isl_swizzle) { chans[0], chans[1], chans[2], chans[3] };
248001e04c3fSmrg}
2481