isl.c revision 7ec681f3
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"
317ec681f3Smrg#include "isl_gfx4.h"
327ec681f3Smrg#include "isl_gfx6.h"
337ec681f3Smrg#include "isl_gfx7.h"
347ec681f3Smrg#include "isl_gfx8.h"
357ec681f3Smrg#include "isl_gfx9.h"
367ec681f3Smrg#include "isl_gfx12.h"
3701e04c3fSmrg#include "isl_priv.h"
3801e04c3fSmrg
399f464c52Smayavoid
409f464c52Smayaisl_memcpy_linear_to_tiled(uint32_t xt1, uint32_t xt2,
419f464c52Smaya                           uint32_t yt1, uint32_t yt2,
429f464c52Smaya                           char *dst, const char *src,
439f464c52Smaya                           uint32_t dst_pitch, int32_t src_pitch,
449f464c52Smaya                           bool has_swizzling,
459f464c52Smaya                           enum isl_tiling tiling,
469f464c52Smaya                           isl_memcpy_type copy_type)
479f464c52Smaya{
489f464c52Smaya#ifdef USE_SSE41
499f464c52Smaya   if (copy_type == ISL_MEMCPY_STREAMING_LOAD) {
509f464c52Smaya      _isl_memcpy_linear_to_tiled_sse41(
519f464c52Smaya         xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
529f464c52Smaya         tiling, copy_type);
539f464c52Smaya      return;
549f464c52Smaya   }
559f464c52Smaya#endif
569f464c52Smaya
579f464c52Smaya   _isl_memcpy_linear_to_tiled(
589f464c52Smaya      xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
599f464c52Smaya      tiling, copy_type);
609f464c52Smaya}
619f464c52Smaya
629f464c52Smayavoid
639f464c52Smayaisl_memcpy_tiled_to_linear(uint32_t xt1, uint32_t xt2,
649f464c52Smaya                           uint32_t yt1, uint32_t yt2,
659f464c52Smaya                           char *dst, const char *src,
669f464c52Smaya                           int32_t dst_pitch, uint32_t src_pitch,
679f464c52Smaya                           bool has_swizzling,
689f464c52Smaya                           enum isl_tiling tiling,
699f464c52Smaya                           isl_memcpy_type copy_type)
709f464c52Smaya{
719f464c52Smaya#ifdef USE_SSE41
729f464c52Smaya   if (copy_type == ISL_MEMCPY_STREAMING_LOAD) {
739f464c52Smaya      _isl_memcpy_tiled_to_linear_sse41(
749f464c52Smaya         xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
759f464c52Smaya         tiling, copy_type);
769f464c52Smaya      return;
779f464c52Smaya   }
789f464c52Smaya#endif
799f464c52Smaya
809f464c52Smaya   _isl_memcpy_tiled_to_linear(
819f464c52Smaya      xt1, xt2, yt1, yt2, dst, src, dst_pitch, src_pitch, has_swizzling,
829f464c52Smaya      tiling, copy_type);
839f464c52Smaya}
849f464c52Smaya
8501e04c3fSmrgvoid PRINTFLIKE(3, 4) UNUSED
8601e04c3fSmrg__isl_finishme(const char *file, int line, const char *fmt, ...)
8701e04c3fSmrg{
8801e04c3fSmrg   va_list ap;
8901e04c3fSmrg   char buf[512];
9001e04c3fSmrg
9101e04c3fSmrg   va_start(ap, fmt);
9201e04c3fSmrg   vsnprintf(buf, sizeof(buf), fmt, ap);
9301e04c3fSmrg   va_end(ap);
9401e04c3fSmrg
9501e04c3fSmrg   fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buf);
9601e04c3fSmrg}
9701e04c3fSmrg
987ec681f3Smrgstatic void
997ec681f3Smrgisl_device_setup_mocs(struct isl_device *dev)
1007ec681f3Smrg{
1017ec681f3Smrg   if (dev->info->ver >= 12) {
1027ec681f3Smrg      if (dev->info->is_dg2) {
1037ec681f3Smrg         /* L3CC=WB; BSpec: 45101 */
1047ec681f3Smrg         dev->mocs.internal = 3 << 1;
1057ec681f3Smrg         dev->mocs.external = 3 << 1;
1067ec681f3Smrg      } else if (dev->info->is_dg1) {
1077ec681f3Smrg         /* L3CC=WB */
1087ec681f3Smrg         dev->mocs.internal = 5 << 1;
1097ec681f3Smrg         /* Displayables on DG1 are free to cache in L3 since L3 is transient
1107ec681f3Smrg          * and flushed at bottom of each submission.
1117ec681f3Smrg          */
1127ec681f3Smrg         dev->mocs.external = 5 << 1;
1137ec681f3Smrg      } else {
1147ec681f3Smrg         /* TC=1/LLC Only, LeCC=1/UC, LRUM=0, L3CC=3/WB */
1157ec681f3Smrg         dev->mocs.external = 61 << 1;
1167ec681f3Smrg         /* TC=LLC/eLLC, LeCC=WB, LRUM=3, L3CC=WB */
1177ec681f3Smrg         dev->mocs.internal = 2 << 1;
1187ec681f3Smrg
1197ec681f3Smrg         /* L1 - HDC:L1 + L3 + LLC */
1207ec681f3Smrg         dev->mocs.l1_hdc_l3_llc = 48 << 1;
1217ec681f3Smrg      }
1227ec681f3Smrg   } else if (dev->info->ver >= 9) {
1237ec681f3Smrg      /* TC=LLC/eLLC, LeCC=PTE, LRUM=3, L3CC=WB */
1247ec681f3Smrg      dev->mocs.external = 1 << 1;
1257ec681f3Smrg      /* TC=LLC/eLLC, LeCC=WB, LRUM=3, L3CC=WB */
1267ec681f3Smrg      dev->mocs.internal = 2 << 1;
1277ec681f3Smrg   } else if (dev->info->ver >= 8) {
1287ec681f3Smrg      /* MEMORY_OBJECT_CONTROL_STATE:
1297ec681f3Smrg       * .MemoryTypeLLCeLLCCacheabilityControl = UCwithFenceifcoherentcycle,
1307ec681f3Smrg       * .TargetCache = L3DefertoPATforLLCeLLCselection,
1317ec681f3Smrg       * .AgeforQUADLRU = 0
1327ec681f3Smrg       */
1337ec681f3Smrg      dev->mocs.external = 0x18;
1347ec681f3Smrg      /* MEMORY_OBJECT_CONTROL_STATE:
1357ec681f3Smrg       * .MemoryTypeLLCeLLCCacheabilityControl = WB,
1367ec681f3Smrg       * .TargetCache = L3DefertoPATforLLCeLLCselection,
1377ec681f3Smrg       * .AgeforQUADLRU = 0
1387ec681f3Smrg       */
1397ec681f3Smrg      dev->mocs.internal = 0x78;
1407ec681f3Smrg   } else if (dev->info->ver >= 7) {
1417ec681f3Smrg      if (dev->info->is_haswell) {
1427ec681f3Smrg         /* MEMORY_OBJECT_CONTROL_STATE:
1437ec681f3Smrg          * .LLCeLLCCacheabilityControlLLCCC             = 0,
1447ec681f3Smrg          * .L3CacheabilityControlL3CC                   = 1,
1457ec681f3Smrg          */
1467ec681f3Smrg         dev->mocs.internal = 1;
1477ec681f3Smrg         dev->mocs.external = 1;
1487ec681f3Smrg      } else {
1497ec681f3Smrg         /* MEMORY_OBJECT_CONTROL_STATE:
1507ec681f3Smrg          * .GraphicsDataTypeGFDT                        = 0,
1517ec681f3Smrg          * .LLCCacheabilityControlLLCCC                 = 0,
1527ec681f3Smrg          * .L3CacheabilityControlL3CC                   = 1,
1537ec681f3Smrg          */
1547ec681f3Smrg         dev->mocs.internal = 1;
1557ec681f3Smrg         dev->mocs.external = 1;
1567ec681f3Smrg      }
1577ec681f3Smrg   } else {
1587ec681f3Smrg      dev->mocs.internal = 0;
1597ec681f3Smrg      dev->mocs.external = 0;
1607ec681f3Smrg   }
1617ec681f3Smrg}
1627ec681f3Smrg
1637ec681f3Smrg/**
1647ec681f3Smrg * Return an appropriate MOCS entry for the given usage flags.
1657ec681f3Smrg */
1667ec681f3Smrguint32_t
1677ec681f3Smrgisl_mocs(const struct isl_device *dev, isl_surf_usage_flags_t usage,
1687ec681f3Smrg         bool external)
1697ec681f3Smrg{
1707ec681f3Smrg   if (external)
1717ec681f3Smrg      return dev->mocs.external;
1727ec681f3Smrg
1737ec681f3Smrg   if (dev->info->ver >= 12 && !dev->info->is_dg1) {
1747ec681f3Smrg      if (usage & ISL_SURF_USAGE_STAGING_BIT)
1757ec681f3Smrg         return dev->mocs.internal;
1767ec681f3Smrg
1777ec681f3Smrg      /* Using L1:HDC for storage buffers breaks Vulkan memory model
1787ec681f3Smrg       * tests that use shader atomics.  This isn't likely to work out,
1797ec681f3Smrg       * and we can't know a priori whether they'll be used.  So just
1807ec681f3Smrg       * continue with ordinary internal MOCS for now.
1817ec681f3Smrg       */
1827ec681f3Smrg      if (usage & ISL_SURF_USAGE_STORAGE_BIT)
1837ec681f3Smrg         return dev->mocs.internal;
1847ec681f3Smrg
1857ec681f3Smrg      if (usage & (ISL_SURF_USAGE_CONSTANT_BUFFER_BIT |
1867ec681f3Smrg                   ISL_SURF_USAGE_RENDER_TARGET_BIT |
1877ec681f3Smrg                   ISL_SURF_USAGE_TEXTURE_BIT))
1887ec681f3Smrg         return dev->mocs.l1_hdc_l3_llc;
1897ec681f3Smrg   }
1907ec681f3Smrg
1917ec681f3Smrg   return dev->mocs.internal;
1927ec681f3Smrg}
1937ec681f3Smrg
19401e04c3fSmrgvoid
19501e04c3fSmrgisl_device_init(struct isl_device *dev,
1967ec681f3Smrg                const struct intel_device_info *info,
19701e04c3fSmrg                bool has_bit6_swizzling)
19801e04c3fSmrg{
1997ec681f3Smrg   /* Gfx8+ don't have bit6 swizzling, ensure callsite is not confused. */
2007ec681f3Smrg   assert(!(has_bit6_swizzling && info->ver >= 8));
2019f464c52Smaya
20201e04c3fSmrg   dev->info = info;
2037ec681f3Smrg   dev->use_separate_stencil = ISL_GFX_VER(dev) >= 6;
20401e04c3fSmrg   dev->has_bit6_swizzling = has_bit6_swizzling;
20501e04c3fSmrg
20601e04c3fSmrg   /* The ISL_DEV macros may be defined in the CFLAGS, thus hardcoding some
20701e04c3fSmrg    * device properties at buildtime. Verify that the macros with the device
20801e04c3fSmrg    * properties chosen during runtime.
20901e04c3fSmrg    */
2107ec681f3Smrg   ISL_GFX_VER_SANITIZE(dev);
21101e04c3fSmrg   ISL_DEV_USE_SEPARATE_STENCIL_SANITIZE(dev);
21201e04c3fSmrg
21301e04c3fSmrg   /* Did we break hiz or stencil? */
21401e04c3fSmrg   if (ISL_DEV_USE_SEPARATE_STENCIL(dev))
21501e04c3fSmrg      assert(info->has_hiz_and_separate_stencil);
21601e04c3fSmrg   if (info->must_use_separate_stencil)
21701e04c3fSmrg      assert(ISL_DEV_USE_SEPARATE_STENCIL(dev));
21801e04c3fSmrg
21901e04c3fSmrg   dev->ss.size = RENDER_SURFACE_STATE_length(info) * 4;
22001e04c3fSmrg   dev->ss.align = isl_align(dev->ss.size, 32);
22101e04c3fSmrg
2229f464c52Smaya   dev->ss.clear_color_state_size =
2239f464c52Smaya      isl_align(CLEAR_COLOR_length(info) * 4, 64);
22401e04c3fSmrg   dev->ss.clear_color_state_offset =
22501e04c3fSmrg      RENDER_SURFACE_STATE_ClearValueAddress_start(info) / 32 * 4;
22601e04c3fSmrg
22701e04c3fSmrg   dev->ss.clear_value_size =
22801e04c3fSmrg      isl_align(RENDER_SURFACE_STATE_RedClearColor_bits(info) +
22901e04c3fSmrg                RENDER_SURFACE_STATE_GreenClearColor_bits(info) +
23001e04c3fSmrg                RENDER_SURFACE_STATE_BlueClearColor_bits(info) +
23101e04c3fSmrg                RENDER_SURFACE_STATE_AlphaClearColor_bits(info), 32) / 8;
23201e04c3fSmrg
23301e04c3fSmrg   dev->ss.clear_value_offset =
23401e04c3fSmrg      RENDER_SURFACE_STATE_RedClearColor_start(info) / 32 * 4;
23501e04c3fSmrg
23601e04c3fSmrg   assert(RENDER_SURFACE_STATE_SurfaceBaseAddress_start(info) % 8 == 0);
23701e04c3fSmrg   dev->ss.addr_offset =
23801e04c3fSmrg      RENDER_SURFACE_STATE_SurfaceBaseAddress_start(info) / 8;
23901e04c3fSmrg
24001e04c3fSmrg   /* The "Auxiliary Surface Base Address" field starts a bit higher up
24101e04c3fSmrg    * because the bottom 12 bits are used for other things.  Round down to
24201e04c3fSmrg    * the nearest dword before.
24301e04c3fSmrg    */
24401e04c3fSmrg   dev->ss.aux_addr_offset =
24501e04c3fSmrg      (RENDER_SURFACE_STATE_AuxiliarySurfaceBaseAddress_start(info) & ~31) / 8;
24601e04c3fSmrg
24701e04c3fSmrg   dev->ds.size = _3DSTATE_DEPTH_BUFFER_length(info) * 4;
24801e04c3fSmrg   assert(_3DSTATE_DEPTH_BUFFER_SurfaceBaseAddress_start(info) % 8 == 0);
24901e04c3fSmrg   dev->ds.depth_offset =
25001e04c3fSmrg      _3DSTATE_DEPTH_BUFFER_SurfaceBaseAddress_start(info) / 8;
25101e04c3fSmrg
25201e04c3fSmrg   if (dev->use_separate_stencil) {
25301e04c3fSmrg      dev->ds.size += _3DSTATE_STENCIL_BUFFER_length(info) * 4 +
25401e04c3fSmrg                      _3DSTATE_HIER_DEPTH_BUFFER_length(info) * 4 +
25501e04c3fSmrg                      _3DSTATE_CLEAR_PARAMS_length(info) * 4;
25601e04c3fSmrg
25701e04c3fSmrg      assert(_3DSTATE_STENCIL_BUFFER_SurfaceBaseAddress_start(info) % 8 == 0);
25801e04c3fSmrg      dev->ds.stencil_offset =
25901e04c3fSmrg         _3DSTATE_DEPTH_BUFFER_length(info) * 4 +
26001e04c3fSmrg         _3DSTATE_STENCIL_BUFFER_SurfaceBaseAddress_start(info) / 8;
26101e04c3fSmrg
26201e04c3fSmrg      assert(_3DSTATE_HIER_DEPTH_BUFFER_SurfaceBaseAddress_start(info) % 8 == 0);
26301e04c3fSmrg      dev->ds.hiz_offset =
26401e04c3fSmrg         _3DSTATE_DEPTH_BUFFER_length(info) * 4 +
26501e04c3fSmrg         _3DSTATE_STENCIL_BUFFER_length(info) * 4 +
26601e04c3fSmrg         _3DSTATE_HIER_DEPTH_BUFFER_SurfaceBaseAddress_start(info) / 8;
26701e04c3fSmrg   } else {
26801e04c3fSmrg      dev->ds.stencil_offset = 0;
26901e04c3fSmrg      dev->ds.hiz_offset = 0;
27001e04c3fSmrg   }
2717ec681f3Smrg
2727ec681f3Smrg   if (ISL_GFX_VER(dev) >= 7) {
2737ec681f3Smrg      /* From the IVB PRM, SURFACE_STATE::Height,
2747ec681f3Smrg       *
2757ec681f3Smrg       *    For typed buffer and structured buffer surfaces, the number
2767ec681f3Smrg       *    of entries in the buffer ranges from 1 to 2^27. For raw buffer
2777ec681f3Smrg       *    surfaces, the number of entries in the buffer is the number of bytes
2787ec681f3Smrg       *    which can range from 1 to 2^30.
2797ec681f3Smrg       *
2807ec681f3Smrg       * This limit is only concerned with raw buffers.
2817ec681f3Smrg       */
2827ec681f3Smrg      dev->max_buffer_size = 1ull << 30;
2837ec681f3Smrg   } else {
2847ec681f3Smrg      dev->max_buffer_size = 1ull << 27;
2857ec681f3Smrg   }
2867ec681f3Smrg
2877ec681f3Smrg   isl_device_setup_mocs(dev);
28801e04c3fSmrg}
28901e04c3fSmrg
29001e04c3fSmrg/**
29101e04c3fSmrg * @brief Query the set of multisamples supported by the device.
29201e04c3fSmrg *
29301e04c3fSmrg * This function always returns non-zero, as ISL_SAMPLE_COUNT_1_BIT is always
29401e04c3fSmrg * supported.
29501e04c3fSmrg */
29601e04c3fSmrgisl_sample_count_mask_t ATTRIBUTE_CONST
29701e04c3fSmrgisl_device_get_sample_counts(struct isl_device *dev)
29801e04c3fSmrg{
2997ec681f3Smrg   if (ISL_GFX_VER(dev) >= 9) {
30001e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
30101e04c3fSmrg             ISL_SAMPLE_COUNT_2_BIT |
30201e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT |
30301e04c3fSmrg             ISL_SAMPLE_COUNT_8_BIT |
30401e04c3fSmrg             ISL_SAMPLE_COUNT_16_BIT;
3057ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 8) {
30601e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
30701e04c3fSmrg             ISL_SAMPLE_COUNT_2_BIT |
30801e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT |
30901e04c3fSmrg             ISL_SAMPLE_COUNT_8_BIT;
3107ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 7) {
31101e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
31201e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT |
31301e04c3fSmrg             ISL_SAMPLE_COUNT_8_BIT;
3147ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 6) {
31501e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT |
31601e04c3fSmrg             ISL_SAMPLE_COUNT_4_BIT;
31701e04c3fSmrg   } else {
31801e04c3fSmrg      return ISL_SAMPLE_COUNT_1_BIT;
31901e04c3fSmrg   }
32001e04c3fSmrg}
32101e04c3fSmrg
32201e04c3fSmrg/**
3237ec681f3Smrg * Returns an isl_tile_info representation of the given isl_tiling when
3247ec681f3Smrg * combined when used in the given configuration.
3257ec681f3Smrg *
3267ec681f3Smrg * @param[in]  tiling      The tiling format to introspect
3277ec681f3Smrg * @param[in]  dim         The dimensionality of the surface being tiled
3287ec681f3Smrg * @param[in]  msaa_layout The layout of samples in the surface being tiled
3297ec681f3Smrg * @param[in]  format_bpb  The number of bits per surface element (block) for
3307ec681f3Smrg *                         the surface being tiled
3317ec681f3Smrg * @param[in]  samples     The samples in the surface being tiled
3327ec681f3Smrg * @param[out] tile_info   Return parameter for the tiling information
33301e04c3fSmrg */
3347ec681f3Smrgvoid
33501e04c3fSmrgisl_tiling_get_info(enum isl_tiling tiling,
3367ec681f3Smrg                    enum isl_surf_dim dim,
3377ec681f3Smrg                    enum isl_msaa_layout msaa_layout,
33801e04c3fSmrg                    uint32_t format_bpb,
3397ec681f3Smrg                    uint32_t samples,
34001e04c3fSmrg                    struct isl_tile_info *tile_info)
34101e04c3fSmrg{
34201e04c3fSmrg   const uint32_t bs = format_bpb / 8;
3437ec681f3Smrg   struct isl_extent4d logical_el;
3447ec681f3Smrg   struct isl_extent2d phys_B;
34501e04c3fSmrg
34601e04c3fSmrg   if (tiling != ISL_TILING_LINEAR && !isl_is_pow2(format_bpb)) {
34701e04c3fSmrg      /* It is possible to have non-power-of-two formats in a tiled buffer.
34801e04c3fSmrg       * The easiest way to handle this is to treat the tile as if it is three
34901e04c3fSmrg       * times as wide.  This way no pixel will ever cross a tile boundary.
3507ec681f3Smrg       * This really only works on a subset of tiling formats.
35101e04c3fSmrg       */
3527ec681f3Smrg      assert(tiling == ISL_TILING_X || tiling == ISL_TILING_Y0 ||
3537ec681f3Smrg             tiling == ISL_TILING_4);
35401e04c3fSmrg      assert(bs % 3 == 0 && isl_is_pow2(format_bpb / 3));
3557ec681f3Smrg      isl_tiling_get_info(tiling, dim, msaa_layout, format_bpb / 3, samples,
3567ec681f3Smrg                          tile_info);
35701e04c3fSmrg      return;
35801e04c3fSmrg   }
35901e04c3fSmrg
36001e04c3fSmrg   switch (tiling) {
36101e04c3fSmrg   case ISL_TILING_LINEAR:
36201e04c3fSmrg      assert(bs > 0);
3637ec681f3Smrg      logical_el = isl_extent4d(1, 1, 1, 1);
36401e04c3fSmrg      phys_B = isl_extent2d(bs, 1);
36501e04c3fSmrg      break;
36601e04c3fSmrg
36701e04c3fSmrg   case ISL_TILING_X:
36801e04c3fSmrg      assert(bs > 0);
3697ec681f3Smrg      logical_el = isl_extent4d(512 / bs, 8, 1, 1);
37001e04c3fSmrg      phys_B = isl_extent2d(512, 8);
37101e04c3fSmrg      break;
37201e04c3fSmrg
37301e04c3fSmrg   case ISL_TILING_Y0:
3747ec681f3Smrg   case ISL_TILING_4:
37501e04c3fSmrg      assert(bs > 0);
3767ec681f3Smrg      logical_el = isl_extent4d(128 / bs, 32, 1, 1);
37701e04c3fSmrg      phys_B = isl_extent2d(128, 32);
37801e04c3fSmrg      break;
37901e04c3fSmrg
38001e04c3fSmrg   case ISL_TILING_W:
38101e04c3fSmrg      assert(bs == 1);
3827ec681f3Smrg      logical_el = isl_extent4d(64, 64, 1, 1);
38301e04c3fSmrg      /* From the Broadwell PRM Vol 2d, RENDER_SURFACE_STATE::SurfacePitch:
38401e04c3fSmrg       *
38501e04c3fSmrg       *    "If the surface is a stencil buffer (and thus has Tile Mode set
38601e04c3fSmrg       *    to TILEMODE_WMAJOR), the pitch must be set to 2x the value
38701e04c3fSmrg       *    computed based on width, as the stencil buffer is stored with two
38801e04c3fSmrg       *    rows interleaved."
38901e04c3fSmrg       *
39001e04c3fSmrg       * This, together with the fact that stencil buffers are referred to as
39101e04c3fSmrg       * being Y-tiled in the PRMs for older hardware implies that the
39201e04c3fSmrg       * physical size of a W-tile is actually the same as for a Y-tile.
39301e04c3fSmrg       */
39401e04c3fSmrg      phys_B = isl_extent2d(128, 32);
39501e04c3fSmrg      break;
39601e04c3fSmrg
39701e04c3fSmrg   case ISL_TILING_Yf:
39801e04c3fSmrg   case ISL_TILING_Ys: {
39901e04c3fSmrg      bool is_Ys = tiling == ISL_TILING_Ys;
40001e04c3fSmrg
40101e04c3fSmrg      assert(bs > 0);
40201e04c3fSmrg      unsigned width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys));
40301e04c3fSmrg      unsigned height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys));
40401e04c3fSmrg
4057ec681f3Smrg      logical_el = isl_extent4d(width / bs, height, 1, 1);
40601e04c3fSmrg      phys_B = isl_extent2d(width, height);
40701e04c3fSmrg      break;
40801e04c3fSmrg   }
4097ec681f3Smrg   case ISL_TILING_64:
4107ec681f3Smrg      /* The tables below are taken from the "2D Surfaces" page in the Bspec
4117ec681f3Smrg       * which are formulated in terms of the Cv and Cu constants. This is
4127ec681f3Smrg       * different from the tables in the "Tile64 Format" page which should be
4137ec681f3Smrg       * equivalent but are usually in terms of pixels. Also note that Cv and
4147ec681f3Smrg       * Cu are HxW order to match the Bspec table, not WxH order like you
4157ec681f3Smrg       * might expect.
4167ec681f3Smrg       *
4177ec681f3Smrg       * From the Bspec's "Tile64 Format" page:
4187ec681f3Smrg       *
4197ec681f3Smrg       *    MSAA Depth/Stencil surface use IMS (Interleaved Multi Samples)
4207ec681f3Smrg       *    which means:
4217ec681f3Smrg       *
4227ec681f3Smrg       *    - Use the 1X MSAA (non-MSRT) version of the Tile64 equations and
4237ec681f3Smrg       *      let the client unit do the swizzling internally
4247ec681f3Smrg       *
4257ec681f3Smrg       * Surfaces using the IMS layout will use the mapping for 1x MSAA.
4267ec681f3Smrg       */
4277ec681f3Smrg#define tile_extent(bs, cv, cu, a) \
4287ec681f3Smrg      isl_extent4d((1 << cu) / bs, 1 << cv, 1, a)
4297ec681f3Smrg
4307ec681f3Smrg      /* Only 2D surfaces are handled. */
4317ec681f3Smrg      assert(dim == ISL_SURF_DIM_2D);
4327ec681f3Smrg
4337ec681f3Smrg      if (samples == 1 || msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED) {
4347ec681f3Smrg         switch (format_bpb) {
4357ec681f3Smrg         case 128: logical_el = tile_extent(bs, 6, 10, 1); break;
4367ec681f3Smrg         case  64: logical_el = tile_extent(bs, 6, 10, 1); break;
4377ec681f3Smrg         case  32: logical_el = tile_extent(bs, 7,  9, 1); break;
4387ec681f3Smrg         case  16: logical_el = tile_extent(bs, 7,  9, 1); break;
4397ec681f3Smrg         case   8: logical_el = tile_extent(bs, 8,  8, 1); break;
4407ec681f3Smrg         default: unreachable("Unsupported format size.");
4417ec681f3Smrg         }
4427ec681f3Smrg      } else if (samples == 2) {
4437ec681f3Smrg         switch (format_bpb) {
4447ec681f3Smrg         case 128: logical_el = tile_extent(bs, 6,  9, 2); break;
4457ec681f3Smrg         case  64: logical_el = tile_extent(bs, 6,  9, 2); break;
4467ec681f3Smrg         case  32: logical_el = tile_extent(bs, 7,  8, 2); break;
4477ec681f3Smrg         case  16: logical_el = tile_extent(bs, 7,  8, 2); break;
4487ec681f3Smrg         case   8: logical_el = tile_extent(bs, 8,  7, 2); break;
4497ec681f3Smrg         default: unreachable("Unsupported format size.");
4507ec681f3Smrg         }
4517ec681f3Smrg      } else {
4527ec681f3Smrg         switch (format_bpb) {
4537ec681f3Smrg         case 128: logical_el = tile_extent(bs, 5,  9, 4); break;
4547ec681f3Smrg         case  64: logical_el = tile_extent(bs, 5,  9, 4); break;
4557ec681f3Smrg         case  32: logical_el = tile_extent(bs, 6,  8, 4); break;
4567ec681f3Smrg         case  16: logical_el = tile_extent(bs, 6,  8, 4); break;
4577ec681f3Smrg         case   8: logical_el = tile_extent(bs, 7,  7, 4); break;
4587ec681f3Smrg         default: unreachable("Unsupported format size.");
4597ec681f3Smrg         }
4607ec681f3Smrg      }
4617ec681f3Smrg
4627ec681f3Smrg#undef tile_extent
4637ec681f3Smrg
4647ec681f3Smrg      phys_B.w = logical_el.w * bs;
4657ec681f3Smrg      phys_B.h = 64 * 1024 / phys_B.w;
4667ec681f3Smrg      break;
46701e04c3fSmrg
46801e04c3fSmrg   case ISL_TILING_HIZ:
46901e04c3fSmrg      /* HiZ buffers are required to have ISL_FORMAT_HIZ which is an 8x4
47001e04c3fSmrg       * 128bpb format.  The tiling has the same physical dimensions as
47101e04c3fSmrg       * Y-tiling but actually has two HiZ columns per Y-tiled column.
47201e04c3fSmrg       */
47301e04c3fSmrg      assert(bs == 16);
4747ec681f3Smrg      logical_el = isl_extent4d(16, 16, 1, 1);
47501e04c3fSmrg      phys_B = isl_extent2d(128, 32);
47601e04c3fSmrg      break;
47701e04c3fSmrg
47801e04c3fSmrg   case ISL_TILING_CCS:
47901e04c3fSmrg      /* CCS surfaces are required to have one of the GENX_CCS_* formats which
48001e04c3fSmrg       * have a block size of 1 or 2 bits per block and each CCS element
48101e04c3fSmrg       * corresponds to one cache-line pair in the main surface.  From the Sky
48201e04c3fSmrg       * Lake PRM Vol. 12 in the section on planes:
48301e04c3fSmrg       *
48401e04c3fSmrg       *    "The Color Control Surface (CCS) contains the compression status
48501e04c3fSmrg       *    of the cache-line pairs. The compression state of the cache-line
48601e04c3fSmrg       *    pair is specified by 2 bits in the CCS.  Each CCS cache-line
48701e04c3fSmrg       *    represents an area on the main surface of 16x16 sets of 128 byte
48801e04c3fSmrg       *    Y-tiled cache-line-pairs. CCS is always Y tiled."
48901e04c3fSmrg       *
49001e04c3fSmrg       * The CCS being Y-tiled implies that it's an 8x8 grid of cache-lines.
49101e04c3fSmrg       * Since each cache line corresponds to a 16x16 set of cache-line pairs,
49201e04c3fSmrg       * that yields total tile area of 128x128 cache-line pairs or CCS
49301e04c3fSmrg       * elements.  On older hardware, each CCS element is 1 bit and the tile
49401e04c3fSmrg       * is 128x256 elements.
49501e04c3fSmrg       */
49601e04c3fSmrg      assert(format_bpb == 1 || format_bpb == 2);
4977ec681f3Smrg      logical_el = isl_extent4d(128, 256 / format_bpb, 1, 1);
49801e04c3fSmrg      phys_B = isl_extent2d(128, 32);
49901e04c3fSmrg      break;
50001e04c3fSmrg
5017ec681f3Smrg   case ISL_TILING_GFX12_CCS:
5027ec681f3Smrg      /* From the Bspec, Gen Graphics > Gfx12 > Memory Data Formats > Memory
5037ec681f3Smrg       * Compression > Memory Compression - Gfx12:
5047ec681f3Smrg       *
5057ec681f3Smrg       *    4 bits of auxiliary plane data are required for 2 cachelines of
5067ec681f3Smrg       *    main surface data. This results in a single cacheline of auxiliary
5077ec681f3Smrg       *    plane data mapping to 4 4K pages of main surface data for the 4K
5087ec681f3Smrg       *    pages (tile Y ) and 1 64K Tile Ys page.
5097ec681f3Smrg       *
5107ec681f3Smrg       * The Y-tiled pairing bit of 9 shown in the table below that Bspec
5117ec681f3Smrg       * section expresses that the 2 cachelines of main surface data are
5127ec681f3Smrg       * horizontally adjacent.
5137ec681f3Smrg       *
5147ec681f3Smrg       * TODO: Handle Ys, Yf and their pairing bits.
5157ec681f3Smrg       *
5167ec681f3Smrg       * Therefore, each CCS cacheline represents a 512Bx32 row area and each
5177ec681f3Smrg       * element represents a 32Bx4 row area.
5187ec681f3Smrg       */
5197ec681f3Smrg      assert(format_bpb == 4);
5207ec681f3Smrg      logical_el = isl_extent4d(16, 8, 1, 1);
5217ec681f3Smrg      phys_B = isl_extent2d(64, 1);
5227ec681f3Smrg      break;
5237ec681f3Smrg
52401e04c3fSmrg   default:
52501e04c3fSmrg      unreachable("not reached");
52601e04c3fSmrg   } /* end switch */
52701e04c3fSmrg
52801e04c3fSmrg   *tile_info = (struct isl_tile_info) {
52901e04c3fSmrg      .tiling = tiling,
53001e04c3fSmrg      .format_bpb = format_bpb,
53101e04c3fSmrg      .logical_extent_el = logical_el,
53201e04c3fSmrg      .phys_extent_B = phys_B,
53301e04c3fSmrg   };
53401e04c3fSmrg}
53501e04c3fSmrg
53601e04c3fSmrgbool
53701e04c3fSmrgisl_color_value_is_zero(union isl_color_value value,
53801e04c3fSmrg                        enum isl_format format)
53901e04c3fSmrg{
54001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(format);
54101e04c3fSmrg
54201e04c3fSmrg#define RETURN_FALSE_IF_NOT_0(c, i) \
54301e04c3fSmrg   if (fmtl->channels.c.bits && value.u32[i] != 0) \
54401e04c3fSmrg      return false
54501e04c3fSmrg
54601e04c3fSmrg   RETURN_FALSE_IF_NOT_0(r, 0);
54701e04c3fSmrg   RETURN_FALSE_IF_NOT_0(g, 1);
54801e04c3fSmrg   RETURN_FALSE_IF_NOT_0(b, 2);
54901e04c3fSmrg   RETURN_FALSE_IF_NOT_0(a, 3);
55001e04c3fSmrg
55101e04c3fSmrg#undef RETURN_FALSE_IF_NOT_0
55201e04c3fSmrg
55301e04c3fSmrg   return true;
55401e04c3fSmrg}
55501e04c3fSmrg
55601e04c3fSmrgbool
55701e04c3fSmrgisl_color_value_is_zero_one(union isl_color_value value,
55801e04c3fSmrg                            enum isl_format format)
55901e04c3fSmrg{
56001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(format);
56101e04c3fSmrg
56201e04c3fSmrg#define RETURN_FALSE_IF_NOT_0_1(c, i, field) \
56301e04c3fSmrg   if (fmtl->channels.c.bits && value.field[i] != 0 && value.field[i] != 1) \
56401e04c3fSmrg      return false
56501e04c3fSmrg
56601e04c3fSmrg   if (isl_format_has_int_channel(format)) {
56701e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(r, 0, u32);
56801e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(g, 1, u32);
56901e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(b, 2, u32);
57001e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(a, 3, u32);
57101e04c3fSmrg   } else {
57201e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(r, 0, f32);
57301e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(g, 1, f32);
57401e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(b, 2, f32);
57501e04c3fSmrg      RETURN_FALSE_IF_NOT_0_1(a, 3, f32);
57601e04c3fSmrg   }
57701e04c3fSmrg
57801e04c3fSmrg#undef RETURN_FALSE_IF_NOT_0_1
57901e04c3fSmrg
58001e04c3fSmrg   return true;
58101e04c3fSmrg}
58201e04c3fSmrg
58301e04c3fSmrg/**
58401e04c3fSmrg * @param[out] tiling is set only on success
58501e04c3fSmrg */
58601e04c3fSmrgstatic bool
58701e04c3fSmrgisl_surf_choose_tiling(const struct isl_device *dev,
58801e04c3fSmrg                       const struct isl_surf_init_info *restrict info,
58901e04c3fSmrg                       enum isl_tiling *tiling)
59001e04c3fSmrg{
59101e04c3fSmrg   isl_tiling_flags_t tiling_flags = info->tiling_flags;
59201e04c3fSmrg
59301e04c3fSmrg   /* HiZ surfaces always use the HiZ tiling */
59401e04c3fSmrg   if (info->usage & ISL_SURF_USAGE_HIZ_BIT) {
59501e04c3fSmrg      assert(info->format == ISL_FORMAT_HIZ);
59601e04c3fSmrg      assert(tiling_flags == ISL_TILING_HIZ_BIT);
5977ec681f3Smrg      *tiling = isl_tiling_flag_to_enum(tiling_flags);
59801e04c3fSmrg      return true;
59901e04c3fSmrg   }
60001e04c3fSmrg
60101e04c3fSmrg   /* CCS surfaces always use the CCS tiling */
60201e04c3fSmrg   if (info->usage & ISL_SURF_USAGE_CCS_BIT) {
60301e04c3fSmrg      assert(isl_format_get_layout(info->format)->txc == ISL_TXC_CCS);
6047ec681f3Smrg      UNUSED bool ivb_ccs = ISL_GFX_VER(dev) < 12 &&
6057ec681f3Smrg                            tiling_flags == ISL_TILING_CCS_BIT;
6067ec681f3Smrg      UNUSED bool tgl_ccs = ISL_GFX_VER(dev) >= 12 &&
6077ec681f3Smrg                            tiling_flags == ISL_TILING_GFX12_CCS_BIT;
6087ec681f3Smrg      assert(ivb_ccs != tgl_ccs);
6097ec681f3Smrg      *tiling = isl_tiling_flag_to_enum(tiling_flags);
61001e04c3fSmrg      return true;
61101e04c3fSmrg   }
61201e04c3fSmrg
6137ec681f3Smrg   if (ISL_GFX_VERX10(dev) >= 125) {
6147ec681f3Smrg      isl_gfx125_filter_tiling(dev, info, &tiling_flags);
6157ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 6) {
6167ec681f3Smrg      isl_gfx6_filter_tiling(dev, info, &tiling_flags);
61701e04c3fSmrg   } else {
6187ec681f3Smrg      isl_gfx4_filter_tiling(dev, info, &tiling_flags);
61901e04c3fSmrg   }
62001e04c3fSmrg
62101e04c3fSmrg   #define CHOOSE(__tiling) \
62201e04c3fSmrg      do { \
62301e04c3fSmrg         if (tiling_flags & (1u << (__tiling))) { \
62401e04c3fSmrg            *tiling = (__tiling); \
62501e04c3fSmrg            return true; \
62601e04c3fSmrg          } \
62701e04c3fSmrg      } while (0)
62801e04c3fSmrg
62901e04c3fSmrg   /* Of the tiling modes remaining, choose the one that offers the best
63001e04c3fSmrg    * performance.
63101e04c3fSmrg    */
63201e04c3fSmrg
63301e04c3fSmrg   if (info->dim == ISL_SURF_DIM_1D) {
63401e04c3fSmrg      /* Prefer linear for 1D surfaces because they do not benefit from
63501e04c3fSmrg       * tiling. To the contrary, tiling leads to wasted memory and poor
63601e04c3fSmrg       * memory locality due to the swizzling and alignment restrictions
63701e04c3fSmrg       * required in tiled surfaces.
63801e04c3fSmrg       */
63901e04c3fSmrg      CHOOSE(ISL_TILING_LINEAR);
64001e04c3fSmrg   }
64101e04c3fSmrg
6427ec681f3Smrg   CHOOSE(ISL_TILING_4);
6437ec681f3Smrg   CHOOSE(ISL_TILING_64);
64401e04c3fSmrg   CHOOSE(ISL_TILING_Ys);
64501e04c3fSmrg   CHOOSE(ISL_TILING_Yf);
64601e04c3fSmrg   CHOOSE(ISL_TILING_Y0);
64701e04c3fSmrg   CHOOSE(ISL_TILING_X);
64801e04c3fSmrg   CHOOSE(ISL_TILING_W);
64901e04c3fSmrg   CHOOSE(ISL_TILING_LINEAR);
65001e04c3fSmrg
65101e04c3fSmrg   #undef CHOOSE
65201e04c3fSmrg
65301e04c3fSmrg   /* No tiling mode accomodates the inputs. */
65401e04c3fSmrg   return false;
65501e04c3fSmrg}
65601e04c3fSmrg
65701e04c3fSmrgstatic bool
65801e04c3fSmrgisl_choose_msaa_layout(const struct isl_device *dev,
65901e04c3fSmrg                 const struct isl_surf_init_info *info,
66001e04c3fSmrg                 enum isl_tiling tiling,
66101e04c3fSmrg                 enum isl_msaa_layout *msaa_layout)
66201e04c3fSmrg{
6637ec681f3Smrg   if (ISL_GFX_VER(dev) >= 8) {
6647ec681f3Smrg      return isl_gfx8_choose_msaa_layout(dev, info, tiling, msaa_layout);
6657ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 7) {
6667ec681f3Smrg      return isl_gfx7_choose_msaa_layout(dev, info, tiling, msaa_layout);
6677ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 6) {
6687ec681f3Smrg      return isl_gfx6_choose_msaa_layout(dev, info, tiling, msaa_layout);
66901e04c3fSmrg   } else {
6707ec681f3Smrg      return isl_gfx4_choose_msaa_layout(dev, info, tiling, msaa_layout);
67101e04c3fSmrg   }
67201e04c3fSmrg}
67301e04c3fSmrg
67401e04c3fSmrgstruct isl_extent2d
67501e04c3fSmrgisl_get_interleaved_msaa_px_size_sa(uint32_t samples)
67601e04c3fSmrg{
67701e04c3fSmrg   assert(isl_is_pow2(samples));
67801e04c3fSmrg
67901e04c3fSmrg   /* From the Broadwell PRM >> Volume 5: Memory Views >> Computing Mip Level
68001e04c3fSmrg    * Sizes (p133):
68101e04c3fSmrg    *
68201e04c3fSmrg    *    If the surface is multisampled and it is a depth or stencil surface
68301e04c3fSmrg    *    or Multisampled Surface StorageFormat in SURFACE_STATE is
68401e04c3fSmrg    *    MSFMT_DEPTH_STENCIL, W_L and H_L must be adjusted as follows before
68501e04c3fSmrg    *    proceeding: [...]
68601e04c3fSmrg    */
68701e04c3fSmrg   return (struct isl_extent2d) {
68801e04c3fSmrg      .width = 1 << ((ffs(samples) - 0) / 2),
68901e04c3fSmrg      .height = 1 << ((ffs(samples) - 1) / 2),
69001e04c3fSmrg   };
69101e04c3fSmrg}
69201e04c3fSmrg
69301e04c3fSmrgstatic void
69401e04c3fSmrgisl_msaa_interleaved_scale_px_to_sa(uint32_t samples,
69501e04c3fSmrg                                    uint32_t *width, uint32_t *height)
69601e04c3fSmrg{
69701e04c3fSmrg   const struct isl_extent2d px_size_sa =
69801e04c3fSmrg      isl_get_interleaved_msaa_px_size_sa(samples);
69901e04c3fSmrg
70001e04c3fSmrg   if (width)
70101e04c3fSmrg      *width = isl_align(*width, 2) * px_size_sa.width;
70201e04c3fSmrg   if (height)
70301e04c3fSmrg      *height = isl_align(*height, 2) * px_size_sa.height;
70401e04c3fSmrg}
70501e04c3fSmrg
70601e04c3fSmrgstatic enum isl_array_pitch_span
70701e04c3fSmrgisl_choose_array_pitch_span(const struct isl_device *dev,
70801e04c3fSmrg                            const struct isl_surf_init_info *restrict info,
70901e04c3fSmrg                            enum isl_dim_layout dim_layout,
71001e04c3fSmrg                            const struct isl_extent4d *phys_level0_sa)
71101e04c3fSmrg{
71201e04c3fSmrg   switch (dim_layout) {
7137ec681f3Smrg   case ISL_DIM_LAYOUT_GFX9_1D:
7147ec681f3Smrg   case ISL_DIM_LAYOUT_GFX4_2D:
7157ec681f3Smrg      if (ISL_GFX_VER(dev) >= 8) {
71601e04c3fSmrg         /* QPitch becomes programmable in Broadwell. So choose the
71701e04c3fSmrg          * most compact QPitch possible in order to conserve memory.
71801e04c3fSmrg          *
71901e04c3fSmrg          * From the Broadwell PRM >> Volume 2d: Command Reference: Structures
72001e04c3fSmrg          * >> RENDER_SURFACE_STATE Surface QPitch (p325):
72101e04c3fSmrg          *
72201e04c3fSmrg          *    - Software must ensure that this field is set to a value
72301e04c3fSmrg          *      sufficiently large such that the array slices in the surface
72401e04c3fSmrg          *      do not overlap. Refer to the Memory Data Formats section for
72501e04c3fSmrg          *      information on how surfaces are stored in memory.
72601e04c3fSmrg          *
72701e04c3fSmrg          *    - This field specifies the distance in rows between array
72801e04c3fSmrg          *      slices.  It is used only in the following cases:
72901e04c3fSmrg          *
73001e04c3fSmrg          *          - Surface Array is enabled OR
73101e04c3fSmrg          *          - Number of Mulitsamples is not NUMSAMPLES_1 and
73201e04c3fSmrg          *            Multisampled Surface Storage Format set to MSFMT_MSS OR
73301e04c3fSmrg          *          - Surface Type is SURFTYPE_CUBE
73401e04c3fSmrg          */
73501e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_COMPACT;
7367ec681f3Smrg      } else if (ISL_GFX_VER(dev) >= 7) {
73701e04c3fSmrg         /* Note that Ivybridge introduces
73801e04c3fSmrg          * RENDER_SURFACE_STATE.SurfaceArraySpacing, which provides the
73901e04c3fSmrg          * driver more control over the QPitch.
74001e04c3fSmrg          */
74101e04c3fSmrg
74201e04c3fSmrg         if (phys_level0_sa->array_len == 1) {
74301e04c3fSmrg            /* The hardware will never use the QPitch. So choose the most
74401e04c3fSmrg             * compact QPitch possible in order to conserve memory.
74501e04c3fSmrg             */
74601e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
74701e04c3fSmrg         }
74801e04c3fSmrg
74901e04c3fSmrg         if (isl_surf_usage_is_depth_or_stencil(info->usage) ||
75001e04c3fSmrg             (info->usage & ISL_SURF_USAGE_HIZ_BIT)) {
75101e04c3fSmrg            /* From the Ivybridge PRM >> Volume 1 Part 1: Graphics Core >>
75201e04c3fSmrg             * Section 6.18.4.7: Surface Arrays (p112):
75301e04c3fSmrg             *
75401e04c3fSmrg             *    If Surface Array Spacing is set to ARYSPC_FULL (note that
75501e04c3fSmrg             *    the depth buffer and stencil buffer have an implied value of
75601e04c3fSmrg             *    ARYSPC_FULL):
75701e04c3fSmrg             */
75801e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_FULL;
75901e04c3fSmrg         }
76001e04c3fSmrg
76101e04c3fSmrg         if (info->levels == 1) {
76201e04c3fSmrg            /* We are able to set RENDER_SURFACE_STATE.SurfaceArraySpacing
76301e04c3fSmrg             * to ARYSPC_LOD0.
76401e04c3fSmrg             */
76501e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
76601e04c3fSmrg         }
76701e04c3fSmrg
76801e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_FULL;
7697ec681f3Smrg      } else if ((ISL_GFX_VER(dev) == 5 || ISL_GFX_VER(dev) == 6) &&
77001e04c3fSmrg                 ISL_DEV_USE_SEPARATE_STENCIL(dev) &&
77101e04c3fSmrg                 isl_surf_usage_is_stencil(info->usage)) {
77201e04c3fSmrg         /* [ILK-SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
77301e04c3fSmrg          * Graphics Core >> Section 7.18.3.7: Surface Arrays:
77401e04c3fSmrg          *
77501e04c3fSmrg          *    The separate stencil buffer does not support mip mapping, thus
77601e04c3fSmrg          *    the storage for LODs other than LOD 0 is not needed.
77701e04c3fSmrg          */
77801e04c3fSmrg         assert(info->levels == 1);
77901e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_COMPACT;
78001e04c3fSmrg      } else {
7817ec681f3Smrg         if ((ISL_GFX_VER(dev) == 5 || ISL_GFX_VER(dev) == 6) &&
78201e04c3fSmrg             ISL_DEV_USE_SEPARATE_STENCIL(dev) &&
78301e04c3fSmrg             isl_surf_usage_is_stencil(info->usage)) {
78401e04c3fSmrg            /* [ILK-SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
78501e04c3fSmrg             * Graphics Core >> Section 7.18.3.7: Surface Arrays:
78601e04c3fSmrg             *
78701e04c3fSmrg             *    The separate stencil buffer does not support mip mapping,
78801e04c3fSmrg             *    thus the storage for LODs other than LOD 0 is not needed.
78901e04c3fSmrg             */
79001e04c3fSmrg            assert(info->levels == 1);
79101e04c3fSmrg            assert(phys_level0_sa->array_len == 1);
79201e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
79301e04c3fSmrg         }
79401e04c3fSmrg
79501e04c3fSmrg         if (phys_level0_sa->array_len == 1) {
79601e04c3fSmrg            /* The hardware will never use the QPitch. So choose the most
79701e04c3fSmrg             * compact QPitch possible in order to conserve memory.
79801e04c3fSmrg             */
79901e04c3fSmrg            return ISL_ARRAY_PITCH_SPAN_COMPACT;
80001e04c3fSmrg         }
80101e04c3fSmrg
80201e04c3fSmrg         return ISL_ARRAY_PITCH_SPAN_FULL;
80301e04c3fSmrg      }
80401e04c3fSmrg
8057ec681f3Smrg   case ISL_DIM_LAYOUT_GFX4_3D:
80601e04c3fSmrg      /* The hardware will never use the QPitch. So choose the most
80701e04c3fSmrg       * compact QPitch possible in order to conserve memory.
80801e04c3fSmrg       */
80901e04c3fSmrg      return ISL_ARRAY_PITCH_SPAN_COMPACT;
81001e04c3fSmrg
8117ec681f3Smrg   case ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ:
8127ec681f3Smrg      /* Each array image in the gfx6 stencil of HiZ surface is compact in the
81301e04c3fSmrg       * sense that every LOD is a compact array of the same size as LOD0.
81401e04c3fSmrg       */
81501e04c3fSmrg      return ISL_ARRAY_PITCH_SPAN_COMPACT;
81601e04c3fSmrg   }
81701e04c3fSmrg
81801e04c3fSmrg   unreachable("bad isl_dim_layout");
81901e04c3fSmrg   return ISL_ARRAY_PITCH_SPAN_FULL;
82001e04c3fSmrg}
82101e04c3fSmrg
82201e04c3fSmrgstatic void
82301e04c3fSmrgisl_choose_image_alignment_el(const struct isl_device *dev,
82401e04c3fSmrg                              const struct isl_surf_init_info *restrict info,
82501e04c3fSmrg                              enum isl_tiling tiling,
82601e04c3fSmrg                              enum isl_dim_layout dim_layout,
82701e04c3fSmrg                              enum isl_msaa_layout msaa_layout,
82801e04c3fSmrg                              struct isl_extent3d *image_align_el)
82901e04c3fSmrg{
83001e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
83101e04c3fSmrg   if (fmtl->txc == ISL_TXC_MCS) {
83201e04c3fSmrg      assert(tiling == ISL_TILING_Y0);
83301e04c3fSmrg
83401e04c3fSmrg      /*
83501e04c3fSmrg       * IvyBrigde PRM Vol 2, Part 1, "11.7 MCS Buffer for Render Target(s)":
83601e04c3fSmrg       *
83701e04c3fSmrg       * Height, width, and layout of MCS buffer in this case must match with
83801e04c3fSmrg       * Render Target height, width, and layout. MCS buffer is tiledY.
83901e04c3fSmrg       *
84001e04c3fSmrg       * To avoid wasting memory, choose the smallest alignment possible:
84101e04c3fSmrg       * HALIGN_4 and VALIGN_4.
84201e04c3fSmrg       */
84301e04c3fSmrg      *image_align_el = isl_extent3d(4, 4, 1);
84401e04c3fSmrg      return;
84501e04c3fSmrg   } else if (info->format == ISL_FORMAT_HIZ) {
8467ec681f3Smrg      assert(ISL_GFX_VER(dev) >= 6);
8477ec681f3Smrg      if (ISL_GFX_VER(dev) == 6) {
84801e04c3fSmrg         /* HiZ surfaces on Sandy Bridge are packed tightly. */
84901e04c3fSmrg         *image_align_el = isl_extent3d(1, 1, 1);
8507ec681f3Smrg      } else if (ISL_GFX_VER(dev) < 12) {
8517ec681f3Smrg         /* On gfx7+, HiZ surfaces are always aligned to 16x8 pixels in the
85201e04c3fSmrg          * primary surface which works out to 2x2 HiZ elments.
85301e04c3fSmrg          */
85401e04c3fSmrg         *image_align_el = isl_extent3d(2, 2, 1);
8557ec681f3Smrg      } else {
8567ec681f3Smrg         /* On gfx12+, HiZ surfaces are always aligned to 16x16 pixels in the
8577ec681f3Smrg          * primary surface which works out to 2x4 HiZ elments.
8587ec681f3Smrg          * TODO: Verify
8597ec681f3Smrg          */
8607ec681f3Smrg         *image_align_el = isl_extent3d(2, 4, 1);
86101e04c3fSmrg      }
86201e04c3fSmrg      return;
86301e04c3fSmrg   }
86401e04c3fSmrg
8657ec681f3Smrg   if (ISL_GFX_VERX10(dev) >= 125) {
8667ec681f3Smrg      isl_gfx125_choose_image_alignment_el(dev, info, tiling, dim_layout,
8677ec681f3Smrg                                           msaa_layout, image_align_el);
8687ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 12) {
8697ec681f3Smrg      isl_gfx12_choose_image_alignment_el(dev, info, tiling, dim_layout,
8707ec681f3Smrg                                          msaa_layout, image_align_el);
8717ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 9) {
8727ec681f3Smrg      isl_gfx9_choose_image_alignment_el(dev, info, tiling, dim_layout,
87301e04c3fSmrg                                         msaa_layout, image_align_el);
8747ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 8) {
8757ec681f3Smrg      isl_gfx8_choose_image_alignment_el(dev, info, tiling, dim_layout,
87601e04c3fSmrg                                         msaa_layout, image_align_el);
8777ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 7) {
8787ec681f3Smrg      isl_gfx7_choose_image_alignment_el(dev, info, tiling, dim_layout,
87901e04c3fSmrg                                          msaa_layout, image_align_el);
8807ec681f3Smrg   } else if (ISL_GFX_VER(dev) >= 6) {
8817ec681f3Smrg      isl_gfx6_choose_image_alignment_el(dev, info, tiling, dim_layout,
88201e04c3fSmrg                                         msaa_layout, image_align_el);
88301e04c3fSmrg   } else {
8847ec681f3Smrg      isl_gfx4_choose_image_alignment_el(dev, info, tiling, dim_layout,
88501e04c3fSmrg                                         msaa_layout, image_align_el);
88601e04c3fSmrg   }
88701e04c3fSmrg}
88801e04c3fSmrg
88901e04c3fSmrgstatic enum isl_dim_layout
89001e04c3fSmrgisl_surf_choose_dim_layout(const struct isl_device *dev,
89101e04c3fSmrg                           enum isl_surf_dim logical_dim,
89201e04c3fSmrg                           enum isl_tiling tiling,
89301e04c3fSmrg                           isl_surf_usage_flags_t usage)
89401e04c3fSmrg{
89501e04c3fSmrg   /* Sandy bridge needs a special layout for HiZ and stencil. */
8967ec681f3Smrg   if (ISL_GFX_VER(dev) == 6 &&
89701e04c3fSmrg       (tiling == ISL_TILING_W || tiling == ISL_TILING_HIZ))
8987ec681f3Smrg      return ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ;
89901e04c3fSmrg
9007ec681f3Smrg   if (ISL_GFX_VER(dev) >= 9) {
90101e04c3fSmrg      switch (logical_dim) {
90201e04c3fSmrg      case ISL_SURF_DIM_1D:
90301e04c3fSmrg         /* From the Sky Lake PRM Vol. 5, "1D Surfaces":
90401e04c3fSmrg          *
90501e04c3fSmrg          *    One-dimensional surfaces use a tiling mode of linear.
90601e04c3fSmrg          *    Technically, they are not tiled resources, but the Tiled
90701e04c3fSmrg          *    Resource Mode field in RENDER_SURFACE_STATE is still used to
90801e04c3fSmrg          *    indicate the alignment requirements for this linear surface
90901e04c3fSmrg          *    (See 1D Alignment requirements for how 4K and 64KB Tiled
91001e04c3fSmrg          *    Resource Modes impact alignment). Alternatively, a 1D surface
91101e04c3fSmrg          *    can be defined as a 2D tiled surface (e.g. TileY or TileX) with
91201e04c3fSmrg          *    a height of 0.
91301e04c3fSmrg          *
9147ec681f3Smrg          * In other words, ISL_DIM_LAYOUT_GFX9_1D is only used for linear
9157ec681f3Smrg          * surfaces and, for tiled surfaces, ISL_DIM_LAYOUT_GFX4_2D is used.
91601e04c3fSmrg          */
91701e04c3fSmrg         if (tiling == ISL_TILING_LINEAR)
9187ec681f3Smrg            return ISL_DIM_LAYOUT_GFX9_1D;
91901e04c3fSmrg         else
9207ec681f3Smrg            return ISL_DIM_LAYOUT_GFX4_2D;
92101e04c3fSmrg      case ISL_SURF_DIM_2D:
92201e04c3fSmrg      case ISL_SURF_DIM_3D:
9237ec681f3Smrg         return ISL_DIM_LAYOUT_GFX4_2D;
92401e04c3fSmrg      }
92501e04c3fSmrg   } else {
92601e04c3fSmrg      switch (logical_dim) {
92701e04c3fSmrg      case ISL_SURF_DIM_1D:
92801e04c3fSmrg      case ISL_SURF_DIM_2D:
92901e04c3fSmrg         /* From the G45 PRM Vol. 1a, "6.17.4.1 Hardware Cube Map Layout":
93001e04c3fSmrg          *
93101e04c3fSmrg          * The cube face textures are stored in the same way as 3D surfaces
93201e04c3fSmrg          * are stored (see section 6.17.5 for details).  For cube surfaces,
93301e04c3fSmrg          * however, the depth is equal to the number of faces (always 6) and
93401e04c3fSmrg          * is not reduced for each MIP.
93501e04c3fSmrg          */
9367ec681f3Smrg         if (ISL_GFX_VER(dev) == 4 && (usage & ISL_SURF_USAGE_CUBE_BIT))
9377ec681f3Smrg            return ISL_DIM_LAYOUT_GFX4_3D;
93801e04c3fSmrg
9397ec681f3Smrg         return ISL_DIM_LAYOUT_GFX4_2D;
94001e04c3fSmrg      case ISL_SURF_DIM_3D:
9417ec681f3Smrg         return ISL_DIM_LAYOUT_GFX4_3D;
94201e04c3fSmrg      }
94301e04c3fSmrg   }
94401e04c3fSmrg
94501e04c3fSmrg   unreachable("bad isl_surf_dim");
9467ec681f3Smrg   return ISL_DIM_LAYOUT_GFX4_2D;
94701e04c3fSmrg}
94801e04c3fSmrg
94901e04c3fSmrg/**
95001e04c3fSmrg * Calculate the physical extent of the surface's first level, in units of
9519f464c52Smaya * surface samples.
95201e04c3fSmrg */
95301e04c3fSmrgstatic void
95401e04c3fSmrgisl_calc_phys_level0_extent_sa(const struct isl_device *dev,
95501e04c3fSmrg                               const struct isl_surf_init_info *restrict info,
95601e04c3fSmrg                               enum isl_dim_layout dim_layout,
95701e04c3fSmrg                               enum isl_tiling tiling,
95801e04c3fSmrg                               enum isl_msaa_layout msaa_layout,
95901e04c3fSmrg                               struct isl_extent4d *phys_level0_sa)
96001e04c3fSmrg{
96101e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
96201e04c3fSmrg
9637ec681f3Smrg   if (isl_format_is_planar(info->format))
9647ec681f3Smrg      unreachable("Planar formats unsupported");
96501e04c3fSmrg
96601e04c3fSmrg   switch (info->dim) {
96701e04c3fSmrg   case ISL_SURF_DIM_1D:
96801e04c3fSmrg      assert(info->height == 1);
96901e04c3fSmrg      assert(info->depth == 1);
97001e04c3fSmrg      assert(info->samples == 1);
97101e04c3fSmrg
97201e04c3fSmrg      switch (dim_layout) {
9737ec681f3Smrg      case ISL_DIM_LAYOUT_GFX4_3D:
97401e04c3fSmrg         unreachable("bad isl_dim_layout");
97501e04c3fSmrg
9767ec681f3Smrg      case ISL_DIM_LAYOUT_GFX9_1D:
9777ec681f3Smrg      case ISL_DIM_LAYOUT_GFX4_2D:
9787ec681f3Smrg      case ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ:
97901e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
9809f464c52Smaya            .w = info->width,
9819f464c52Smaya            .h = 1,
98201e04c3fSmrg            .d = 1,
98301e04c3fSmrg            .a = info->array_len,
98401e04c3fSmrg         };
98501e04c3fSmrg         break;
98601e04c3fSmrg      }
98701e04c3fSmrg      break;
98801e04c3fSmrg
98901e04c3fSmrg   case ISL_SURF_DIM_2D:
9907ec681f3Smrg      if (ISL_GFX_VER(dev) == 4 && (info->usage & ISL_SURF_USAGE_CUBE_BIT))
9917ec681f3Smrg         assert(dim_layout == ISL_DIM_LAYOUT_GFX4_3D);
99201e04c3fSmrg      else
9937ec681f3Smrg         assert(dim_layout == ISL_DIM_LAYOUT_GFX4_2D ||
9947ec681f3Smrg                dim_layout == ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ);
99501e04c3fSmrg
99601e04c3fSmrg      if (tiling == ISL_TILING_Ys && info->samples > 1)
99701e04c3fSmrg         isl_finishme("%s:%s: multisample TileYs layout", __FILE__, __func__);
99801e04c3fSmrg
99901e04c3fSmrg      switch (msaa_layout) {
100001e04c3fSmrg      case ISL_MSAA_LAYOUT_NONE:
100101e04c3fSmrg         assert(info->depth == 1);
100201e04c3fSmrg         assert(info->samples == 1);
100301e04c3fSmrg
100401e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
10059f464c52Smaya            .w = info->width,
10069f464c52Smaya            .h = info->height,
100701e04c3fSmrg            .d = 1,
100801e04c3fSmrg            .a = info->array_len,
100901e04c3fSmrg         };
101001e04c3fSmrg         break;
101101e04c3fSmrg
101201e04c3fSmrg      case ISL_MSAA_LAYOUT_ARRAY:
101301e04c3fSmrg         assert(info->depth == 1);
101401e04c3fSmrg         assert(info->levels == 1);
101501e04c3fSmrg         assert(isl_format_supports_multisampling(dev->info, info->format));
101601e04c3fSmrg         assert(fmtl->bw == 1 && fmtl->bh == 1);
101701e04c3fSmrg
101801e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
101901e04c3fSmrg            .w = info->width,
102001e04c3fSmrg            .h = info->height,
102101e04c3fSmrg            .d = 1,
102201e04c3fSmrg            .a = info->array_len * info->samples,
102301e04c3fSmrg         };
102401e04c3fSmrg         break;
102501e04c3fSmrg
102601e04c3fSmrg      case ISL_MSAA_LAYOUT_INTERLEAVED:
102701e04c3fSmrg         assert(info->depth == 1);
102801e04c3fSmrg         assert(info->levels == 1);
102901e04c3fSmrg         assert(isl_format_supports_multisampling(dev->info, info->format));
103001e04c3fSmrg
103101e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
103201e04c3fSmrg            .w = info->width,
103301e04c3fSmrg            .h = info->height,
103401e04c3fSmrg            .d = 1,
103501e04c3fSmrg            .a = info->array_len,
103601e04c3fSmrg         };
103701e04c3fSmrg
103801e04c3fSmrg         isl_msaa_interleaved_scale_px_to_sa(info->samples,
103901e04c3fSmrg                                             &phys_level0_sa->w,
104001e04c3fSmrg                                             &phys_level0_sa->h);
104101e04c3fSmrg         break;
104201e04c3fSmrg      }
104301e04c3fSmrg      break;
104401e04c3fSmrg
104501e04c3fSmrg   case ISL_SURF_DIM_3D:
104601e04c3fSmrg      assert(info->array_len == 1);
104701e04c3fSmrg      assert(info->samples == 1);
104801e04c3fSmrg
104901e04c3fSmrg      if (fmtl->bd > 1) {
105001e04c3fSmrg         isl_finishme("%s:%s: compression block with depth > 1",
105101e04c3fSmrg                      __FILE__, __func__);
105201e04c3fSmrg      }
105301e04c3fSmrg
105401e04c3fSmrg      switch (dim_layout) {
10557ec681f3Smrg      case ISL_DIM_LAYOUT_GFX9_1D:
10567ec681f3Smrg      case ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ:
105701e04c3fSmrg         unreachable("bad isl_dim_layout");
105801e04c3fSmrg
10597ec681f3Smrg      case ISL_DIM_LAYOUT_GFX4_2D:
10607ec681f3Smrg         assert(ISL_GFX_VER(dev) >= 9);
106101e04c3fSmrg
106201e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
10639f464c52Smaya            .w = info->width,
10649f464c52Smaya            .h = info->height,
106501e04c3fSmrg            .d = 1,
106601e04c3fSmrg            .a = info->depth,
106701e04c3fSmrg         };
106801e04c3fSmrg         break;
106901e04c3fSmrg
10707ec681f3Smrg      case ISL_DIM_LAYOUT_GFX4_3D:
10717ec681f3Smrg         assert(ISL_GFX_VER(dev) < 9);
107201e04c3fSmrg         *phys_level0_sa = (struct isl_extent4d) {
10739f464c52Smaya            .w = info->width,
10749f464c52Smaya            .h = info->height,
107501e04c3fSmrg            .d = info->depth,
107601e04c3fSmrg            .a = 1,
107701e04c3fSmrg         };
107801e04c3fSmrg         break;
107901e04c3fSmrg      }
108001e04c3fSmrg      break;
108101e04c3fSmrg   }
108201e04c3fSmrg}
108301e04c3fSmrg
108401e04c3fSmrg/**
108501e04c3fSmrg * Calculate the pitch between physical array slices, in units of rows of
108601e04c3fSmrg * surface elements.
108701e04c3fSmrg */
108801e04c3fSmrgstatic uint32_t
10897ec681f3Smrgisl_calc_array_pitch_el_rows_gfx4_2d(
109001e04c3fSmrg      const struct isl_device *dev,
109101e04c3fSmrg      const struct isl_surf_init_info *restrict info,
109201e04c3fSmrg      const struct isl_tile_info *tile_info,
109301e04c3fSmrg      const struct isl_extent3d *image_align_sa,
109401e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
109501e04c3fSmrg      enum isl_array_pitch_span array_pitch_span,
109601e04c3fSmrg      const struct isl_extent2d *phys_slice0_sa)
109701e04c3fSmrg{
109801e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
109901e04c3fSmrg   uint32_t pitch_sa_rows = 0;
110001e04c3fSmrg
110101e04c3fSmrg   switch (array_pitch_span) {
110201e04c3fSmrg   case ISL_ARRAY_PITCH_SPAN_COMPACT:
110301e04c3fSmrg      pitch_sa_rows = isl_align_npot(phys_slice0_sa->h, image_align_sa->h);
110401e04c3fSmrg      break;
110501e04c3fSmrg   case ISL_ARRAY_PITCH_SPAN_FULL: {
110601e04c3fSmrg      /* The QPitch equation is found in the Broadwell PRM >> Volume 5:
110701e04c3fSmrg       * Memory Views >> Common Surface Formats >> Surface Layout >> 2D
110801e04c3fSmrg       * Surfaces >> Surface Arrays.
110901e04c3fSmrg       */
111001e04c3fSmrg      uint32_t H0_sa = phys_level0_sa->h;
111101e04c3fSmrg      uint32_t H1_sa = isl_minify(H0_sa, 1);
111201e04c3fSmrg
111301e04c3fSmrg      uint32_t h0_sa = isl_align_npot(H0_sa, image_align_sa->h);
111401e04c3fSmrg      uint32_t h1_sa = isl_align_npot(H1_sa, image_align_sa->h);
111501e04c3fSmrg
111601e04c3fSmrg      uint32_t m;
11177ec681f3Smrg      if (ISL_GFX_VER(dev) >= 7) {
111801e04c3fSmrg         /* The QPitch equation changed slightly in Ivybridge. */
111901e04c3fSmrg         m = 12;
112001e04c3fSmrg      } else {
112101e04c3fSmrg         m = 11;
112201e04c3fSmrg      }
112301e04c3fSmrg
112401e04c3fSmrg      pitch_sa_rows = h0_sa + h1_sa + (m * image_align_sa->h);
112501e04c3fSmrg
11267ec681f3Smrg      if (ISL_GFX_VER(dev) == 6 && info->samples > 1 &&
112701e04c3fSmrg          (info->height % 4 == 1)) {
112801e04c3fSmrg         /* [SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
112901e04c3fSmrg          * Graphics Core >> Section 7.18.3.7: Surface Arrays:
113001e04c3fSmrg          *
113101e04c3fSmrg          *    [SNB] Errata: Sampler MSAA Qpitch will be 4 greater than
113201e04c3fSmrg          *    the value calculated in the equation above , for every
113301e04c3fSmrg          *    other odd Surface Height starting from 1 i.e. 1,5,9,13.
113401e04c3fSmrg          *
113501e04c3fSmrg          * XXX(chadv): Is the errata natural corollary of the physical
113601e04c3fSmrg          * layout of interleaved samples?
113701e04c3fSmrg          */
113801e04c3fSmrg         pitch_sa_rows += 4;
113901e04c3fSmrg      }
114001e04c3fSmrg
114101e04c3fSmrg      pitch_sa_rows = isl_align_npot(pitch_sa_rows, fmtl->bh);
114201e04c3fSmrg      } /* end case */
114301e04c3fSmrg      break;
114401e04c3fSmrg   }
114501e04c3fSmrg
114601e04c3fSmrg   assert(pitch_sa_rows % fmtl->bh == 0);
114701e04c3fSmrg   uint32_t pitch_el_rows = pitch_sa_rows / fmtl->bh;
114801e04c3fSmrg
11497ec681f3Smrg   if (ISL_GFX_VER(dev) >= 9 && ISL_GFX_VER(dev) <= 11 &&
11507ec681f3Smrg       fmtl->txc == ISL_TXC_CCS) {
115101e04c3fSmrg      /*
115201e04c3fSmrg       * From the Sky Lake PRM Vol 7, "MCS Buffer for Render Target(s)" (p. 632):
115301e04c3fSmrg       *
115401e04c3fSmrg       *    "Mip-mapped and arrayed surfaces are supported with MCS buffer
115501e04c3fSmrg       *    layout with these alignments in the RT space: Horizontal
115601e04c3fSmrg       *    Alignment = 128 and Vertical Alignment = 64."
115701e04c3fSmrg       *
115801e04c3fSmrg       * From the Sky Lake PRM Vol. 2d, "RENDER_SURFACE_STATE" (p. 435):
115901e04c3fSmrg       *
116001e04c3fSmrg       *    "For non-multisampled render target's CCS auxiliary surface,
116101e04c3fSmrg       *    QPitch must be computed with Horizontal Alignment = 128 and
116201e04c3fSmrg       *    Surface Vertical Alignment = 256. These alignments are only for
116301e04c3fSmrg       *    CCS buffer and not for associated render target."
116401e04c3fSmrg       *
116501e04c3fSmrg       * The first restriction is already handled by isl_choose_image_alignment_el
116601e04c3fSmrg       * but the second restriction, which is an extension of the first, only
116701e04c3fSmrg       * applies to qpitch and must be applied here.
11687ec681f3Smrg       *
11697ec681f3Smrg       * The second restriction disappears on Gfx12.
117001e04c3fSmrg       */
117101e04c3fSmrg      assert(fmtl->bh == 4);
117201e04c3fSmrg      pitch_el_rows = isl_align(pitch_el_rows, 256 / 4);
117301e04c3fSmrg   }
117401e04c3fSmrg
11757ec681f3Smrg   if (ISL_GFX_VER(dev) >= 9 &&
117601e04c3fSmrg       info->dim == ISL_SURF_DIM_3D &&
117701e04c3fSmrg       tile_info->tiling != ISL_TILING_LINEAR) {
117801e04c3fSmrg      /* From the Skylake BSpec >> RENDER_SURFACE_STATE >> Surface QPitch:
117901e04c3fSmrg       *
118001e04c3fSmrg       *    Tile Mode != Linear: This field must be set to an integer multiple
118101e04c3fSmrg       *    of the tile height
118201e04c3fSmrg       */
118301e04c3fSmrg      pitch_el_rows = isl_align(pitch_el_rows, tile_info->logical_extent_el.height);
118401e04c3fSmrg   }
118501e04c3fSmrg
118601e04c3fSmrg   return pitch_el_rows;
118701e04c3fSmrg}
118801e04c3fSmrg
118901e04c3fSmrg/**
119001e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
11917ec681f3Smrg * ISL_DIM_LAYOUT_GFX4_2D.
119201e04c3fSmrg */
119301e04c3fSmrgstatic void
11947ec681f3Smrgisl_calc_phys_slice0_extent_sa_gfx4_2d(
119501e04c3fSmrg      const struct isl_device *dev,
119601e04c3fSmrg      const struct isl_surf_init_info *restrict info,
119701e04c3fSmrg      enum isl_msaa_layout msaa_layout,
119801e04c3fSmrg      const struct isl_extent3d *image_align_sa,
119901e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
120001e04c3fSmrg      struct isl_extent2d *phys_slice0_sa)
120101e04c3fSmrg{
120201e04c3fSmrg   assert(phys_level0_sa->depth == 1);
120301e04c3fSmrg
120401e04c3fSmrg   if (info->levels == 1) {
12059f464c52Smaya      /* Do not pad the surface to the image alignment.
120601e04c3fSmrg       *
120701e04c3fSmrg       * For tiled surfaces, using a reduced alignment here avoids wasting CPU
120801e04c3fSmrg       * cycles on the below mipmap layout caluclations. Reducing the
120901e04c3fSmrg       * alignment here is safe because we later align the row pitch and array
121001e04c3fSmrg       * pitch to the tile boundary. It is safe even for
121101e04c3fSmrg       * ISL_MSAA_LAYOUT_INTERLEAVED, because phys_level0_sa is already scaled
121201e04c3fSmrg       * to accomodate the interleaved samples.
121301e04c3fSmrg       *
121401e04c3fSmrg       * For linear surfaces, reducing the alignment here permits us to later
121501e04c3fSmrg       * choose an arbitrary, non-aligned row pitch. If the surface backs
121601e04c3fSmrg       * a VkBuffer, then an arbitrary pitch may be needed to accomodate
121701e04c3fSmrg       * VkBufferImageCopy::bufferRowLength.
121801e04c3fSmrg       */
121901e04c3fSmrg      *phys_slice0_sa = (struct isl_extent2d) {
12209f464c52Smaya         .w = phys_level0_sa->w,
12219f464c52Smaya         .h = phys_level0_sa->h,
122201e04c3fSmrg      };
122301e04c3fSmrg      return;
122401e04c3fSmrg   }
122501e04c3fSmrg
122601e04c3fSmrg   uint32_t slice_top_w = 0;
122701e04c3fSmrg   uint32_t slice_bottom_w = 0;
122801e04c3fSmrg   uint32_t slice_left_h = 0;
122901e04c3fSmrg   uint32_t slice_right_h = 0;
123001e04c3fSmrg
123101e04c3fSmrg   uint32_t W0 = phys_level0_sa->w;
123201e04c3fSmrg   uint32_t H0 = phys_level0_sa->h;
123301e04c3fSmrg
123401e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
123501e04c3fSmrg      uint32_t W = isl_minify(W0, l);
123601e04c3fSmrg      uint32_t H = isl_minify(H0, l);
123701e04c3fSmrg
123801e04c3fSmrg      uint32_t w = isl_align_npot(W, image_align_sa->w);
123901e04c3fSmrg      uint32_t h = isl_align_npot(H, image_align_sa->h);
124001e04c3fSmrg
124101e04c3fSmrg      if (l == 0) {
124201e04c3fSmrg         slice_top_w = w;
124301e04c3fSmrg         slice_left_h = h;
124401e04c3fSmrg         slice_right_h = h;
124501e04c3fSmrg      } else if (l == 1) {
124601e04c3fSmrg         slice_bottom_w = w;
124701e04c3fSmrg         slice_left_h += h;
124801e04c3fSmrg      } else if (l == 2) {
124901e04c3fSmrg         slice_bottom_w += w;
125001e04c3fSmrg         slice_right_h += h;
125101e04c3fSmrg      } else {
125201e04c3fSmrg         slice_right_h += h;
125301e04c3fSmrg      }
125401e04c3fSmrg   }
125501e04c3fSmrg
125601e04c3fSmrg   *phys_slice0_sa = (struct isl_extent2d) {
125701e04c3fSmrg      .w = MAX(slice_top_w, slice_bottom_w),
125801e04c3fSmrg      .h = MAX(slice_left_h, slice_right_h),
125901e04c3fSmrg   };
126001e04c3fSmrg}
126101e04c3fSmrg
126201e04c3fSmrgstatic void
12637ec681f3Smrgisl_calc_phys_total_extent_el_gfx4_2d(
126401e04c3fSmrg      const struct isl_device *dev,
126501e04c3fSmrg      const struct isl_surf_init_info *restrict info,
126601e04c3fSmrg      const struct isl_tile_info *tile_info,
126701e04c3fSmrg      enum isl_msaa_layout msaa_layout,
126801e04c3fSmrg      const struct isl_extent3d *image_align_sa,
126901e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
127001e04c3fSmrg      enum isl_array_pitch_span array_pitch_span,
127101e04c3fSmrg      uint32_t *array_pitch_el_rows,
12727ec681f3Smrg      struct isl_extent4d *phys_total_el)
127301e04c3fSmrg{
127401e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
127501e04c3fSmrg
127601e04c3fSmrg   struct isl_extent2d phys_slice0_sa;
12777ec681f3Smrg   isl_calc_phys_slice0_extent_sa_gfx4_2d(dev, info, msaa_layout,
127801e04c3fSmrg                                          image_align_sa, phys_level0_sa,
127901e04c3fSmrg                                          &phys_slice0_sa);
128001e04c3fSmrg   *array_pitch_el_rows =
12817ec681f3Smrg      isl_calc_array_pitch_el_rows_gfx4_2d(dev, info, tile_info,
128201e04c3fSmrg                                           image_align_sa, phys_level0_sa,
128301e04c3fSmrg                                           array_pitch_span,
128401e04c3fSmrg                                           &phys_slice0_sa);
12857ec681f3Smrg
12867ec681f3Smrg   if (tile_info->tiling == ISL_TILING_64) {
12877ec681f3Smrg      *phys_total_el = (struct isl_extent4d) {
12887ec681f3Smrg         .w = isl_align_div_npot(phys_slice0_sa.w, fmtl->bw),
12897ec681f3Smrg         .h = isl_align_div_npot(phys_slice0_sa.h, fmtl->bh),
12907ec681f3Smrg         .d = isl_align_div_npot(phys_level0_sa->d, fmtl->bd),
12917ec681f3Smrg         .a = phys_level0_sa->array_len,
12927ec681f3Smrg      };
12937ec681f3Smrg   } else {
12947ec681f3Smrg      *phys_total_el = (struct isl_extent4d) {
12957ec681f3Smrg         .w = isl_align_div_npot(phys_slice0_sa.w, fmtl->bw),
12967ec681f3Smrg         .h = *array_pitch_el_rows * (phys_level0_sa->array_len - 1) +
12977ec681f3Smrg              isl_align_div_npot(phys_slice0_sa.h, fmtl->bh),
12987ec681f3Smrg         .d = 1,
12997ec681f3Smrg         .a = 1,
13007ec681f3Smrg      };
13017ec681f3Smrg   }
130201e04c3fSmrg}
130301e04c3fSmrg
130401e04c3fSmrg/**
130501e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
13067ec681f3Smrg * ISL_DIM_LAYOUT_GFX4_3D.
130701e04c3fSmrg */
130801e04c3fSmrgstatic void
13097ec681f3Smrgisl_calc_phys_total_extent_el_gfx4_3d(
131001e04c3fSmrg      const struct isl_device *dev,
131101e04c3fSmrg      const struct isl_surf_init_info *restrict info,
131201e04c3fSmrg      const struct isl_extent3d *image_align_sa,
131301e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
131401e04c3fSmrg      uint32_t *array_pitch_el_rows,
13157ec681f3Smrg      struct isl_extent4d *phys_total_el)
131601e04c3fSmrg{
131701e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
131801e04c3fSmrg
131901e04c3fSmrg   assert(info->samples == 1);
132001e04c3fSmrg
132101e04c3fSmrg   if (info->dim != ISL_SURF_DIM_3D) {
132201e04c3fSmrg      /* From the G45 PRM Vol. 1a, "6.17.4.1 Hardware Cube Map Layout":
132301e04c3fSmrg       *
132401e04c3fSmrg       * The cube face textures are stored in the same way as 3D surfaces
132501e04c3fSmrg       * are stored (see section 6.17.5 for details).  For cube surfaces,
132601e04c3fSmrg       * however, the depth is equal to the number of faces (always 6) and
132701e04c3fSmrg       * is not reduced for each MIP.
132801e04c3fSmrg       */
13297ec681f3Smrg      assert(ISL_GFX_VER(dev) == 4);
133001e04c3fSmrg      assert(info->usage & ISL_SURF_USAGE_CUBE_BIT);
133101e04c3fSmrg      assert(phys_level0_sa->array_len == 6);
133201e04c3fSmrg   } else {
133301e04c3fSmrg      assert(phys_level0_sa->array_len == 1);
133401e04c3fSmrg   }
133501e04c3fSmrg
133601e04c3fSmrg   uint32_t total_w = 0;
133701e04c3fSmrg   uint32_t total_h = 0;
133801e04c3fSmrg
133901e04c3fSmrg   uint32_t W0 = phys_level0_sa->w;
134001e04c3fSmrg   uint32_t H0 = phys_level0_sa->h;
134101e04c3fSmrg   uint32_t D0 = phys_level0_sa->d;
134201e04c3fSmrg   uint32_t A0 = phys_level0_sa->a;
134301e04c3fSmrg
134401e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
134501e04c3fSmrg      uint32_t level_w = isl_align_npot(isl_minify(W0, l), image_align_sa->w);
134601e04c3fSmrg      uint32_t level_h = isl_align_npot(isl_minify(H0, l), image_align_sa->h);
134701e04c3fSmrg      uint32_t level_d = info->dim == ISL_SURF_DIM_3D ? isl_minify(D0, l) : A0;
134801e04c3fSmrg
134901e04c3fSmrg      uint32_t max_layers_horiz = MIN(level_d, 1u << l);
135001e04c3fSmrg      uint32_t max_layers_vert = isl_align(level_d, 1u << l) / (1u << l);
135101e04c3fSmrg
135201e04c3fSmrg      total_w = MAX(total_w, level_w * max_layers_horiz);
135301e04c3fSmrg      total_h += level_h * max_layers_vert;
135401e04c3fSmrg   }
135501e04c3fSmrg
13567ec681f3Smrg   /* GFX4_3D layouts don't really have an array pitch since each LOD has a
135701e04c3fSmrg    * different number of horizontal and vertical layers.  We have to set it
135801e04c3fSmrg    * to something, so at least make it true for LOD0.
135901e04c3fSmrg    */
136001e04c3fSmrg   *array_pitch_el_rows =
136101e04c3fSmrg      isl_align_npot(phys_level0_sa->h, image_align_sa->h) / fmtl->bw;
13627ec681f3Smrg   *phys_total_el = (struct isl_extent4d) {
136301e04c3fSmrg      .w = isl_assert_div(total_w, fmtl->bw),
136401e04c3fSmrg      .h = isl_assert_div(total_h, fmtl->bh),
13657ec681f3Smrg      .d = 1,
13667ec681f3Smrg      .a = 1,
136701e04c3fSmrg   };
136801e04c3fSmrg}
136901e04c3fSmrg
137001e04c3fSmrg/**
137101e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
13727ec681f3Smrg * ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ.
137301e04c3fSmrg */
137401e04c3fSmrgstatic void
13757ec681f3Smrgisl_calc_phys_total_extent_el_gfx6_stencil_hiz(
137601e04c3fSmrg      const struct isl_device *dev,
137701e04c3fSmrg      const struct isl_surf_init_info *restrict info,
137801e04c3fSmrg      const struct isl_tile_info *tile_info,
137901e04c3fSmrg      const struct isl_extent3d *image_align_sa,
138001e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
138101e04c3fSmrg      uint32_t *array_pitch_el_rows,
13827ec681f3Smrg      struct isl_extent4d *phys_total_el)
138301e04c3fSmrg{
138401e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
138501e04c3fSmrg
138601e04c3fSmrg   const struct isl_extent2d tile_extent_sa = {
138701e04c3fSmrg      .w = tile_info->logical_extent_el.w * fmtl->bw,
138801e04c3fSmrg      .h = tile_info->logical_extent_el.h * fmtl->bh,
138901e04c3fSmrg   };
139001e04c3fSmrg   /* Tile size is a multiple of image alignment */
139101e04c3fSmrg   assert(tile_extent_sa.w % image_align_sa->w == 0);
139201e04c3fSmrg   assert(tile_extent_sa.h % image_align_sa->h == 0);
139301e04c3fSmrg
139401e04c3fSmrg   const uint32_t W0 = phys_level0_sa->w;
139501e04c3fSmrg   const uint32_t H0 = phys_level0_sa->h;
139601e04c3fSmrg
139701e04c3fSmrg   /* Each image has the same height as LOD0 because the hardware thinks
139801e04c3fSmrg    * everything is LOD0
139901e04c3fSmrg    */
140001e04c3fSmrg   const uint32_t H = isl_align(H0, image_align_sa->h) * phys_level0_sa->a;
140101e04c3fSmrg
140201e04c3fSmrg   uint32_t total_top_w = 0;
140301e04c3fSmrg   uint32_t total_bottom_w = 0;
140401e04c3fSmrg   uint32_t total_h = 0;
140501e04c3fSmrg
140601e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
140701e04c3fSmrg      const uint32_t W = isl_minify(W0, l);
140801e04c3fSmrg
140901e04c3fSmrg      const uint32_t w = isl_align(W, tile_extent_sa.w);
141001e04c3fSmrg      const uint32_t h = isl_align(H, tile_extent_sa.h);
141101e04c3fSmrg
141201e04c3fSmrg      if (l == 0) {
141301e04c3fSmrg         total_top_w = w;
141401e04c3fSmrg         total_h = h;
141501e04c3fSmrg      } else if (l == 1) {
141601e04c3fSmrg         total_bottom_w = w;
141701e04c3fSmrg         total_h += h;
141801e04c3fSmrg      } else {
141901e04c3fSmrg         total_bottom_w += w;
142001e04c3fSmrg      }
142101e04c3fSmrg   }
142201e04c3fSmrg
142301e04c3fSmrg   *array_pitch_el_rows =
142401e04c3fSmrg      isl_assert_div(isl_align(H0, image_align_sa->h), fmtl->bh);
14257ec681f3Smrg   *phys_total_el = (struct isl_extent4d) {
142601e04c3fSmrg      .w = isl_assert_div(MAX(total_top_w, total_bottom_w), fmtl->bw),
142701e04c3fSmrg      .h = isl_assert_div(total_h, fmtl->bh),
14287ec681f3Smrg      .d = 1,
14297ec681f3Smrg      .a = 1,
143001e04c3fSmrg   };
143101e04c3fSmrg}
143201e04c3fSmrg
143301e04c3fSmrg/**
143401e04c3fSmrg * A variant of isl_calc_phys_slice0_extent_sa() specific to
14357ec681f3Smrg * ISL_DIM_LAYOUT_GFX9_1D.
143601e04c3fSmrg */
143701e04c3fSmrgstatic void
14387ec681f3Smrgisl_calc_phys_total_extent_el_gfx9_1d(
143901e04c3fSmrg      const struct isl_device *dev,
144001e04c3fSmrg      const struct isl_surf_init_info *restrict info,
144101e04c3fSmrg      const struct isl_extent3d *image_align_sa,
144201e04c3fSmrg      const struct isl_extent4d *phys_level0_sa,
144301e04c3fSmrg      uint32_t *array_pitch_el_rows,
14447ec681f3Smrg      struct isl_extent4d *phys_total_el)
144501e04c3fSmrg{
14467ec681f3Smrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
144701e04c3fSmrg
14489f464c52Smaya   assert(phys_level0_sa->height == 1);
144901e04c3fSmrg   assert(phys_level0_sa->depth == 1);
145001e04c3fSmrg   assert(info->samples == 1);
145101e04c3fSmrg   assert(image_align_sa->w >= fmtl->bw);
145201e04c3fSmrg
145301e04c3fSmrg   uint32_t slice_w = 0;
145401e04c3fSmrg   const uint32_t W0 = phys_level0_sa->w;
145501e04c3fSmrg
145601e04c3fSmrg   for (uint32_t l = 0; l < info->levels; ++l) {
145701e04c3fSmrg      uint32_t W = isl_minify(W0, l);
145801e04c3fSmrg      uint32_t w = isl_align_npot(W, image_align_sa->w);
145901e04c3fSmrg
146001e04c3fSmrg      slice_w += w;
146101e04c3fSmrg   }
146201e04c3fSmrg
146301e04c3fSmrg   *array_pitch_el_rows = 1;
14647ec681f3Smrg   *phys_total_el = (struct isl_extent4d) {
146501e04c3fSmrg      .w = isl_assert_div(slice_w, fmtl->bw),
146601e04c3fSmrg      .h = phys_level0_sa->array_len,
14677ec681f3Smrg      .d = 1,
14687ec681f3Smrg      .a = 1,
146901e04c3fSmrg   };
147001e04c3fSmrg}
147101e04c3fSmrg
147201e04c3fSmrg/**
147301e04c3fSmrg * Calculate the two-dimensional total physical extent of the surface, in
147401e04c3fSmrg * units of surface elements.
147501e04c3fSmrg */
147601e04c3fSmrgstatic void
147701e04c3fSmrgisl_calc_phys_total_extent_el(const struct isl_device *dev,
147801e04c3fSmrg                              const struct isl_surf_init_info *restrict info,
147901e04c3fSmrg                              const struct isl_tile_info *tile_info,
148001e04c3fSmrg                              enum isl_dim_layout dim_layout,
148101e04c3fSmrg                              enum isl_msaa_layout msaa_layout,
148201e04c3fSmrg                              const struct isl_extent3d *image_align_sa,
148301e04c3fSmrg                              const struct isl_extent4d *phys_level0_sa,
148401e04c3fSmrg                              enum isl_array_pitch_span array_pitch_span,
148501e04c3fSmrg                              uint32_t *array_pitch_el_rows,
14867ec681f3Smrg                              struct isl_extent4d *phys_total_el)
148701e04c3fSmrg{
148801e04c3fSmrg   switch (dim_layout) {
14897ec681f3Smrg   case ISL_DIM_LAYOUT_GFX9_1D:
149001e04c3fSmrg      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
14917ec681f3Smrg      isl_calc_phys_total_extent_el_gfx9_1d(dev, info,
149201e04c3fSmrg                                            image_align_sa, phys_level0_sa,
149301e04c3fSmrg                                            array_pitch_el_rows,
14947ec681f3Smrg                                            phys_total_el);
149501e04c3fSmrg      return;
14967ec681f3Smrg   case ISL_DIM_LAYOUT_GFX4_2D:
14977ec681f3Smrg      isl_calc_phys_total_extent_el_gfx4_2d(dev, info, tile_info, msaa_layout,
149801e04c3fSmrg                                            image_align_sa, phys_level0_sa,
149901e04c3fSmrg                                            array_pitch_span,
150001e04c3fSmrg                                            array_pitch_el_rows,
15017ec681f3Smrg                                            phys_total_el);
150201e04c3fSmrg      return;
15037ec681f3Smrg   case ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ:
150401e04c3fSmrg      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
15057ec681f3Smrg      isl_calc_phys_total_extent_el_gfx6_stencil_hiz(dev, info, tile_info,
150601e04c3fSmrg                                                     image_align_sa,
150701e04c3fSmrg                                                     phys_level0_sa,
150801e04c3fSmrg                                                     array_pitch_el_rows,
15097ec681f3Smrg                                                     phys_total_el);
151001e04c3fSmrg      return;
15117ec681f3Smrg   case ISL_DIM_LAYOUT_GFX4_3D:
151201e04c3fSmrg      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
15137ec681f3Smrg      isl_calc_phys_total_extent_el_gfx4_3d(dev, info,
151401e04c3fSmrg                                            image_align_sa, phys_level0_sa,
151501e04c3fSmrg                                            array_pitch_el_rows,
15167ec681f3Smrg                                            phys_total_el);
151701e04c3fSmrg      return;
151801e04c3fSmrg   }
15197ec681f3Smrg
15207ec681f3Smrg   unreachable("invalid value for dim_layout");
152101e04c3fSmrg}
152201e04c3fSmrg
152301e04c3fSmrgstatic uint32_t
15247ec681f3Smrgisl_calc_row_pitch_alignment(const struct isl_device *dev,
15257ec681f3Smrg                             const struct isl_surf_init_info *surf_info,
152601e04c3fSmrg                             const struct isl_tile_info *tile_info)
152701e04c3fSmrg{
15287ec681f3Smrg   if (tile_info->tiling != ISL_TILING_LINEAR) {
15297ec681f3Smrg      /* According to BSpec: 44930, Gfx12's CCS-compressed surface pitches must
15307ec681f3Smrg       * be 512B-aligned. CCS is only support on Y tilings.
15317ec681f3Smrg       *
15327ec681f3Smrg       * Only consider 512B alignment when :
15337ec681f3Smrg       *    - AUX is not explicitly disabled
15347ec681f3Smrg       *    - the caller has specified no pitch
15357ec681f3Smrg       *
15367ec681f3Smrg       * isl_surf_get_ccs_surf() will check that the main surface alignment
15377ec681f3Smrg       * matches CCS expectations.
15387ec681f3Smrg       */
15397ec681f3Smrg      if (ISL_GFX_VER(dev) >= 12 &&
15407ec681f3Smrg          isl_format_supports_ccs_e(dev->info, surf_info->format) &&
15417ec681f3Smrg          tile_info->tiling != ISL_TILING_X &&
15427ec681f3Smrg          !(surf_info->usage & ISL_SURF_USAGE_DISABLE_AUX_BIT) &&
15437ec681f3Smrg          surf_info->row_pitch_B == 0) {
15447ec681f3Smrg         return isl_align(tile_info->phys_extent_B.width, 512);
15457ec681f3Smrg      }
15467ec681f3Smrg
154701e04c3fSmrg      return tile_info->phys_extent_B.width;
15487ec681f3Smrg   }
154901e04c3fSmrg
155001e04c3fSmrg   /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
155101e04c3fSmrg    * RENDER_SURFACE_STATE Surface Pitch (p349):
155201e04c3fSmrg    *
155301e04c3fSmrg    *    - For linear render target surfaces and surfaces accessed with the
155401e04c3fSmrg    *      typed data port messages, the pitch must be a multiple of the
155501e04c3fSmrg    *      element size for non-YUV surface formats.  Pitch must be
155601e04c3fSmrg    *      a multiple of 2 * element size for YUV surface formats.
155701e04c3fSmrg    *
155801e04c3fSmrg    *    - [Requirements for SURFTYPE_BUFFER and SURFTYPE_STRBUF, which we
155901e04c3fSmrg    *      ignore because isl doesn't do buffers.]
156001e04c3fSmrg    *
156101e04c3fSmrg    *    - For other linear surfaces, the pitch can be any multiple of
156201e04c3fSmrg    *      bytes.
156301e04c3fSmrg    */
156401e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf_info->format);
156501e04c3fSmrg   const uint32_t bs = fmtl->bpb / 8;
15667ec681f3Smrg   uint32_t alignment;
156701e04c3fSmrg
156801e04c3fSmrg   if (surf_info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
156901e04c3fSmrg      if (isl_format_is_yuv(surf_info->format)) {
15707ec681f3Smrg         alignment = 2 * bs;
157101e04c3fSmrg      } else  {
15727ec681f3Smrg         alignment = bs;
157301e04c3fSmrg      }
15747ec681f3Smrg   } else {
15757ec681f3Smrg      alignment = 1;
157601e04c3fSmrg   }
157701e04c3fSmrg
15787ec681f3Smrg   /* From the Broadwell PRM >> Volume 2c: Command Reference: Registers >>
15797ec681f3Smrg    * PRI_STRIDE Stride (p1254):
15807ec681f3Smrg    *
15817ec681f3Smrg    *    "When using linear memory, this must be at least 64 byte aligned."
15827ec681f3Smrg    *
15837ec681f3Smrg    * However, when displaying on NVIDIA and recent AMD GPUs via PRIME,
15847ec681f3Smrg    * we need a larger pitch of 256 bytes.
15857ec681f3Smrg    *
15867ec681f3Smrg    * If the ISL caller didn't specify a row_pitch_B, then we should assume
15877ec681f3Smrg    * the NVIDIA/AMD requirements. Otherwise, if we have a specified
15887ec681f3Smrg    * row_pitch_B, this is probably because the caller is trying to import a
15897ec681f3Smrg    * buffer. In that case we limit the minimum row pitch to the Intel HW
15907ec681f3Smrg    * requirement.
15917ec681f3Smrg    */
15927ec681f3Smrg   if (surf_info->usage & ISL_SURF_USAGE_DISPLAY_BIT) {
15937ec681f3Smrg      if (surf_info->row_pitch_B == 0)
15947ec681f3Smrg         alignment = isl_align(alignment, 256);
15957ec681f3Smrg      else
15967ec681f3Smrg         alignment = isl_align(alignment, 64);
15977ec681f3Smrg   }
15987ec681f3Smrg
15997ec681f3Smrg   return alignment;
160001e04c3fSmrg}
160101e04c3fSmrg
160201e04c3fSmrgstatic uint32_t
160301e04c3fSmrgisl_calc_linear_min_row_pitch(const struct isl_device *dev,
160401e04c3fSmrg                              const struct isl_surf_init_info *info,
16057ec681f3Smrg                              const struct isl_extent4d *phys_total_el,
160601e04c3fSmrg                              uint32_t alignment_B)
160701e04c3fSmrg{
160801e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
160901e04c3fSmrg   const uint32_t bs = fmtl->bpb / 8;
161001e04c3fSmrg
161101e04c3fSmrg   return isl_align_npot(bs * phys_total_el->w, alignment_B);
161201e04c3fSmrg}
161301e04c3fSmrg
161401e04c3fSmrgstatic uint32_t
161501e04c3fSmrgisl_calc_tiled_min_row_pitch(const struct isl_device *dev,
161601e04c3fSmrg                             const struct isl_surf_init_info *surf_info,
161701e04c3fSmrg                             const struct isl_tile_info *tile_info,
16187ec681f3Smrg                             const struct isl_extent4d *phys_total_el,
161901e04c3fSmrg                             uint32_t alignment_B)
162001e04c3fSmrg{
162101e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf_info->format);
162201e04c3fSmrg
162301e04c3fSmrg   assert(fmtl->bpb % tile_info->format_bpb == 0);
162401e04c3fSmrg
162501e04c3fSmrg   const uint32_t tile_el_scale = fmtl->bpb / tile_info->format_bpb;
162601e04c3fSmrg   const uint32_t total_w_tl =
162701e04c3fSmrg      isl_align_div(phys_total_el->w * tile_el_scale,
162801e04c3fSmrg                    tile_info->logical_extent_el.width);
162901e04c3fSmrg
16307ec681f3Smrg   /* In some cases the alignment of the pitch might be > to the tile size
16317ec681f3Smrg    * (for example Gfx12 CCS requires 512B alignment while the tile's width
16327ec681f3Smrg    * can be 128B), so align the row pitch to the alignment.
16337ec681f3Smrg    */
16347ec681f3Smrg   assert(alignment_B >= tile_info->phys_extent_B.width);
16357ec681f3Smrg   return isl_align(total_w_tl * tile_info->phys_extent_B.width, alignment_B);
163601e04c3fSmrg}
163701e04c3fSmrg
163801e04c3fSmrgstatic uint32_t
163901e04c3fSmrgisl_calc_min_row_pitch(const struct isl_device *dev,
164001e04c3fSmrg                       const struct isl_surf_init_info *surf_info,
164101e04c3fSmrg                       const struct isl_tile_info *tile_info,
16427ec681f3Smrg                       const struct isl_extent4d *phys_total_el,
164301e04c3fSmrg                       uint32_t alignment_B)
164401e04c3fSmrg{
164501e04c3fSmrg   if (tile_info->tiling == ISL_TILING_LINEAR) {
164601e04c3fSmrg      return isl_calc_linear_min_row_pitch(dev, surf_info, phys_total_el,
164701e04c3fSmrg                                           alignment_B);
164801e04c3fSmrg   } else {
164901e04c3fSmrg      return isl_calc_tiled_min_row_pitch(dev, surf_info, tile_info,
165001e04c3fSmrg                                          phys_total_el, alignment_B);
165101e04c3fSmrg   }
165201e04c3fSmrg}
165301e04c3fSmrg
165401e04c3fSmrg/**
165501e04c3fSmrg * Is `pitch` in the valid range for a hardware bitfield, if the bitfield's
165601e04c3fSmrg * size is `bits` bits?
165701e04c3fSmrg *
165801e04c3fSmrg * Hardware pitch fields are offset by 1. For example, if the size of
165901e04c3fSmrg * RENDER_SURFACE_STATE::SurfacePitch is B bits, then the range of valid
166001e04c3fSmrg * pitches is [1, 2^b] inclusive.  If the surface pitch is N, then
166101e04c3fSmrg * RENDER_SURFACE_STATE::SurfacePitch must be set to N-1.
166201e04c3fSmrg */
166301e04c3fSmrgstatic bool
166401e04c3fSmrgpitch_in_range(uint32_t n, uint32_t bits)
166501e04c3fSmrg{
166601e04c3fSmrg   assert(n != 0);
166701e04c3fSmrg   return likely(bits != 0 && 1 <= n && n <= (1 << bits));
166801e04c3fSmrg}
166901e04c3fSmrg
167001e04c3fSmrgstatic bool
167101e04c3fSmrgisl_calc_row_pitch(const struct isl_device *dev,
167201e04c3fSmrg                   const struct isl_surf_init_info *surf_info,
167301e04c3fSmrg                   const struct isl_tile_info *tile_info,
167401e04c3fSmrg                   enum isl_dim_layout dim_layout,
16757ec681f3Smrg                   const struct isl_extent4d *phys_total_el,
167601e04c3fSmrg                   uint32_t *out_row_pitch_B)
167701e04c3fSmrg{
167801e04c3fSmrg   uint32_t alignment_B =
16797ec681f3Smrg      isl_calc_row_pitch_alignment(dev, surf_info, tile_info);
168001e04c3fSmrg
168101e04c3fSmrg   const uint32_t min_row_pitch_B =
168201e04c3fSmrg      isl_calc_min_row_pitch(dev, surf_info, tile_info, phys_total_el,
168301e04c3fSmrg                             alignment_B);
168401e04c3fSmrg
168501e04c3fSmrg   if (surf_info->row_pitch_B != 0) {
16867ec681f3Smrg      if (surf_info->row_pitch_B < min_row_pitch_B)
168701e04c3fSmrg         return false;
168801e04c3fSmrg
16897ec681f3Smrg      if (surf_info->row_pitch_B % alignment_B != 0)
169001e04c3fSmrg         return false;
169101e04c3fSmrg   }
169201e04c3fSmrg
16937ec681f3Smrg   const uint32_t row_pitch_B =
16947ec681f3Smrg      surf_info->row_pitch_B != 0 ? surf_info->row_pitch_B : min_row_pitch_B;
16957ec681f3Smrg
169601e04c3fSmrg   const uint32_t row_pitch_tl = row_pitch_B / tile_info->phys_extent_B.width;
169701e04c3fSmrg
169801e04c3fSmrg   if (row_pitch_B == 0)
169901e04c3fSmrg      return false;
170001e04c3fSmrg
17017ec681f3Smrg   if (dim_layout == ISL_DIM_LAYOUT_GFX9_1D) {
170201e04c3fSmrg      /* SurfacePitch is ignored for this layout. */
170301e04c3fSmrg      goto done;
170401e04c3fSmrg   }
170501e04c3fSmrg
170601e04c3fSmrg   if ((surf_info->usage & (ISL_SURF_USAGE_RENDER_TARGET_BIT |
170701e04c3fSmrg                            ISL_SURF_USAGE_TEXTURE_BIT |
170801e04c3fSmrg                            ISL_SURF_USAGE_STORAGE_BIT)) &&
170901e04c3fSmrg       !pitch_in_range(row_pitch_B, RENDER_SURFACE_STATE_SurfacePitch_bits(dev->info)))
171001e04c3fSmrg      return false;
171101e04c3fSmrg
171201e04c3fSmrg   if ((surf_info->usage & (ISL_SURF_USAGE_CCS_BIT |
171301e04c3fSmrg                            ISL_SURF_USAGE_MCS_BIT)) &&
171401e04c3fSmrg       !pitch_in_range(row_pitch_tl, RENDER_SURFACE_STATE_AuxiliarySurfacePitch_bits(dev->info)))
171501e04c3fSmrg      return false;
171601e04c3fSmrg
171701e04c3fSmrg   if ((surf_info->usage & ISL_SURF_USAGE_DEPTH_BIT) &&
171801e04c3fSmrg       !pitch_in_range(row_pitch_B, _3DSTATE_DEPTH_BUFFER_SurfacePitch_bits(dev->info)))
171901e04c3fSmrg      return false;
172001e04c3fSmrg
172101e04c3fSmrg   if ((surf_info->usage & ISL_SURF_USAGE_HIZ_BIT) &&
172201e04c3fSmrg       !pitch_in_range(row_pitch_B, _3DSTATE_HIER_DEPTH_BUFFER_SurfacePitch_bits(dev->info)))
172301e04c3fSmrg      return false;
172401e04c3fSmrg
172501e04c3fSmrg   const uint32_t stencil_pitch_bits = dev->use_separate_stencil ?
172601e04c3fSmrg      _3DSTATE_STENCIL_BUFFER_SurfacePitch_bits(dev->info) :
172701e04c3fSmrg      _3DSTATE_DEPTH_BUFFER_SurfacePitch_bits(dev->info);
172801e04c3fSmrg
172901e04c3fSmrg   if ((surf_info->usage & ISL_SURF_USAGE_STENCIL_BIT) &&
173001e04c3fSmrg       !pitch_in_range(row_pitch_B, stencil_pitch_bits))
173101e04c3fSmrg      return false;
173201e04c3fSmrg
173301e04c3fSmrg done:
173401e04c3fSmrg   *out_row_pitch_B = row_pitch_B;
173501e04c3fSmrg   return true;
173601e04c3fSmrg}
173701e04c3fSmrg
173801e04c3fSmrgbool
173901e04c3fSmrgisl_surf_init_s(const struct isl_device *dev,
174001e04c3fSmrg                struct isl_surf *surf,
174101e04c3fSmrg                const struct isl_surf_init_info *restrict info)
174201e04c3fSmrg{
174301e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
174401e04c3fSmrg
174501e04c3fSmrg   const struct isl_extent4d logical_level0_px = {
174601e04c3fSmrg      .w = info->width,
174701e04c3fSmrg      .h = info->height,
174801e04c3fSmrg      .d = info->depth,
174901e04c3fSmrg      .a = info->array_len,
175001e04c3fSmrg   };
175101e04c3fSmrg
175201e04c3fSmrg   enum isl_tiling tiling;
175301e04c3fSmrg   if (!isl_surf_choose_tiling(dev, info, &tiling))
175401e04c3fSmrg      return false;
175501e04c3fSmrg
175601e04c3fSmrg   const enum isl_dim_layout dim_layout =
175701e04c3fSmrg      isl_surf_choose_dim_layout(dev, info->dim, tiling, info->usage);
175801e04c3fSmrg
175901e04c3fSmrg   enum isl_msaa_layout msaa_layout;
176001e04c3fSmrg   if (!isl_choose_msaa_layout(dev, info, tiling, &msaa_layout))
176101e04c3fSmrg       return false;
176201e04c3fSmrg
17637ec681f3Smrg   struct isl_tile_info tile_info;
17647ec681f3Smrg   isl_tiling_get_info(tiling, info->dim, msaa_layout, fmtl->bpb,
17657ec681f3Smrg                       info->samples, &tile_info);
17667ec681f3Smrg
176701e04c3fSmrg   struct isl_extent3d image_align_el;
176801e04c3fSmrg   isl_choose_image_alignment_el(dev, info, tiling, dim_layout, msaa_layout,
176901e04c3fSmrg                                 &image_align_el);
177001e04c3fSmrg
177101e04c3fSmrg   struct isl_extent3d image_align_sa =
177201e04c3fSmrg      isl_extent3d_el_to_sa(info->format, image_align_el);
177301e04c3fSmrg
177401e04c3fSmrg   struct isl_extent4d phys_level0_sa;
177501e04c3fSmrg   isl_calc_phys_level0_extent_sa(dev, info, dim_layout, tiling, msaa_layout,
177601e04c3fSmrg                                  &phys_level0_sa);
177701e04c3fSmrg
177801e04c3fSmrg   enum isl_array_pitch_span array_pitch_span =
177901e04c3fSmrg      isl_choose_array_pitch_span(dev, info, dim_layout, &phys_level0_sa);
178001e04c3fSmrg
178101e04c3fSmrg   uint32_t array_pitch_el_rows;
17827ec681f3Smrg   struct isl_extent4d phys_total_el;
178301e04c3fSmrg   isl_calc_phys_total_extent_el(dev, info, &tile_info,
178401e04c3fSmrg                                 dim_layout, msaa_layout,
178501e04c3fSmrg                                 &image_align_sa, &phys_level0_sa,
178601e04c3fSmrg                                 array_pitch_span, &array_pitch_el_rows,
178701e04c3fSmrg                                 &phys_total_el);
178801e04c3fSmrg
178901e04c3fSmrg   uint32_t row_pitch_B;
179001e04c3fSmrg   if (!isl_calc_row_pitch(dev, info, &tile_info, dim_layout,
179101e04c3fSmrg                           &phys_total_el, &row_pitch_B))
179201e04c3fSmrg      return false;
179301e04c3fSmrg
179401e04c3fSmrg   uint32_t base_alignment_B;
179501e04c3fSmrg   uint64_t size_B;
179601e04c3fSmrg   if (tiling == ISL_TILING_LINEAR) {
17977ec681f3Smrg      /* LINEAR tiling has no concept of intra-tile arrays */
17987ec681f3Smrg      assert(phys_total_el.d == 1 && phys_total_el.a == 1);
17997ec681f3Smrg
180001e04c3fSmrg      size_B = (uint64_t) row_pitch_B * phys_total_el.h;
180101e04c3fSmrg
180201e04c3fSmrg      /* From the Broadwell PRM Vol 2d, RENDER_SURFACE_STATE::SurfaceBaseAddress:
180301e04c3fSmrg       *
180401e04c3fSmrg       *    "The Base Address for linear render target surfaces and surfaces
180501e04c3fSmrg       *    accessed with the typed surface read/write data port messages must
180601e04c3fSmrg       *    be element-size aligned, for non-YUV surface formats, or a
180701e04c3fSmrg       *    multiple of 2 element-sizes for YUV surface formats. Other linear
180801e04c3fSmrg       *    surfaces have no alignment requirements (byte alignment is
180901e04c3fSmrg       *    sufficient.)"
181001e04c3fSmrg       */
181101e04c3fSmrg      base_alignment_B = MAX(1, info->min_alignment_B);
181201e04c3fSmrg      if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
181301e04c3fSmrg         if (isl_format_is_yuv(info->format)) {
181401e04c3fSmrg            base_alignment_B = MAX(base_alignment_B, fmtl->bpb / 4);
181501e04c3fSmrg         } else {
181601e04c3fSmrg            base_alignment_B = MAX(base_alignment_B, fmtl->bpb / 8);
181701e04c3fSmrg         }
181801e04c3fSmrg      }
181901e04c3fSmrg      base_alignment_B = isl_round_up_to_power_of_two(base_alignment_B);
18209f464c52Smaya
18219f464c52Smaya      /* From the Skylake PRM Vol 2c, PLANE_STRIDE::Stride:
18229f464c52Smaya       *
18239f464c52Smaya       *     "For Linear memory, this field specifies the stride in chunks of
18249f464c52Smaya       *     64 bytes (1 cache line)."
18259f464c52Smaya       */
18269f464c52Smaya      if (isl_surf_usage_is_display(info->usage))
18279f464c52Smaya         base_alignment_B = MAX(base_alignment_B, 64);
182801e04c3fSmrg   } else {
18297ec681f3Smrg      /* Pitches must make sense with the tiling */
18307ec681f3Smrg      assert(row_pitch_B % tile_info.phys_extent_B.width == 0);
18317ec681f3Smrg
18327ec681f3Smrg      uint32_t array_slices, array_pitch_tl_rows;
18337ec681f3Smrg      if (phys_total_el.d > 1) {
18347ec681f3Smrg         assert(phys_total_el.a == 1);
18357ec681f3Smrg         array_pitch_tl_rows = isl_assert_div(array_pitch_el_rows,
18367ec681f3Smrg                                              tile_info.logical_extent_el.h);
18377ec681f3Smrg         array_slices = isl_align_div(phys_total_el.d,
18387ec681f3Smrg                                      tile_info.logical_extent_el.d);
18397ec681f3Smrg      } else if (phys_total_el.a > 1) {
18407ec681f3Smrg         assert(phys_total_el.d == 1);
18417ec681f3Smrg         array_pitch_tl_rows = isl_assert_div(array_pitch_el_rows,
18427ec681f3Smrg                                              tile_info.logical_extent_el.h);
18437ec681f3Smrg         array_slices = isl_align_div(phys_total_el.a,
18447ec681f3Smrg                                      tile_info.logical_extent_el.a);
18457ec681f3Smrg      } else {
18467ec681f3Smrg         assert(phys_total_el.d == 1 && phys_total_el.a == 1);
18477ec681f3Smrg         array_pitch_tl_rows = 0;
18487ec681f3Smrg         array_slices = 1;
18497ec681f3Smrg      }
18507ec681f3Smrg
185101e04c3fSmrg      const uint32_t total_h_tl =
18527ec681f3Smrg         (array_slices - 1) * array_pitch_tl_rows +
185301e04c3fSmrg         isl_align_div(phys_total_el.h, tile_info.logical_extent_el.height);
185401e04c3fSmrg
185501e04c3fSmrg      size_B = (uint64_t) total_h_tl * tile_info.phys_extent_B.height * row_pitch_B;
185601e04c3fSmrg
185701e04c3fSmrg      const uint32_t tile_size_B = tile_info.phys_extent_B.width *
185801e04c3fSmrg                                   tile_info.phys_extent_B.height;
185901e04c3fSmrg      assert(isl_is_pow2(info->min_alignment_B) && isl_is_pow2(tile_size_B));
186001e04c3fSmrg      base_alignment_B = MAX(info->min_alignment_B, tile_size_B);
18617ec681f3Smrg
18627ec681f3Smrg      /* The diagram in the Bspec section Memory Compression - Gfx12, shows
18637ec681f3Smrg       * that the CCS is indexed in 256B chunks. However, the
18647ec681f3Smrg       * PLANE_AUX_DIST::Auxiliary Surface Distance field is in units of 4K
18657ec681f3Smrg       * pages. We currently don't assign the usage field like we do for main
18667ec681f3Smrg       * surfaces, so just use 4K for now.
18677ec681f3Smrg       */
18687ec681f3Smrg      if (tiling == ISL_TILING_GFX12_CCS)
18697ec681f3Smrg         base_alignment_B = MAX(base_alignment_B, 4096);
18707ec681f3Smrg
18717ec681f3Smrg      /* Gfx12+ requires that images be 64K-aligned if they're going to used
18727ec681f3Smrg       * with CCS.  This is because the Aux translation table maps main
18737ec681f3Smrg       * surface addresses to aux addresses at a 64K (in the main surface)
18747ec681f3Smrg       * granularity.  Because we don't know for sure in ISL if a surface will
18757ec681f3Smrg       * use CCS, we have to guess based on the DISABLE_AUX usage bit.  The
18767ec681f3Smrg       * one thing we do know is that we haven't enable CCS on linear images
18777ec681f3Smrg       * yet so we can avoid the extra alignment there.
18787ec681f3Smrg       */
18797ec681f3Smrg      if (ISL_GFX_VER(dev) >= 12 &&
18807ec681f3Smrg          !(info->usage & ISL_SURF_USAGE_DISABLE_AUX_BIT)) {
18817ec681f3Smrg         base_alignment_B = MAX(base_alignment_B, 64 * 1024);
18827ec681f3Smrg      }
188301e04c3fSmrg   }
188401e04c3fSmrg
18857ec681f3Smrg   if (ISL_GFX_VER(dev) < 9) {
188601e04c3fSmrg      /* From the Broadwell PRM Vol 5, Surface Layout:
188701e04c3fSmrg       *
188801e04c3fSmrg       *    "In addition to restrictions on maximum height, width, and depth,
188901e04c3fSmrg       *     surfaces are also restricted to a maximum size in bytes. This
189001e04c3fSmrg       *     maximum is 2 GB for all products and all surface types."
189101e04c3fSmrg       *
18927ec681f3Smrg       * This comment is applicable to all Pre-gfx9 platforms.
189301e04c3fSmrg       */
189401e04c3fSmrg      if (size_B > (uint64_t) 1 << 31)
189501e04c3fSmrg         return false;
18967ec681f3Smrg   } else if (ISL_GFX_VER(dev) < 11) {
189701e04c3fSmrg      /* From the Skylake PRM Vol 5, Maximum Surface Size in Bytes:
189801e04c3fSmrg       *    "In addition to restrictions on maximum height, width, and depth,
189901e04c3fSmrg       *     surfaces are also restricted to a maximum size of 2^38 bytes.
190001e04c3fSmrg       *     All pixels within the surface must be contained within 2^38 bytes
190101e04c3fSmrg       *     of the base address."
190201e04c3fSmrg       */
190301e04c3fSmrg      if (size_B > (uint64_t) 1 << 38)
190401e04c3fSmrg         return false;
190501e04c3fSmrg   } else {
19067ec681f3Smrg      /* gfx11+ platforms raised this limit to 2^44 bytes. */
190701e04c3fSmrg      if (size_B > (uint64_t) 1 << 44)
190801e04c3fSmrg         return false;
190901e04c3fSmrg   }
191001e04c3fSmrg
191101e04c3fSmrg   *surf = (struct isl_surf) {
191201e04c3fSmrg      .dim = info->dim,
191301e04c3fSmrg      .dim_layout = dim_layout,
191401e04c3fSmrg      .msaa_layout = msaa_layout,
191501e04c3fSmrg      .tiling = tiling,
191601e04c3fSmrg      .format = info->format,
191701e04c3fSmrg
191801e04c3fSmrg      .levels = info->levels,
191901e04c3fSmrg      .samples = info->samples,
192001e04c3fSmrg
192101e04c3fSmrg      .image_alignment_el = image_align_el,
192201e04c3fSmrg      .logical_level0_px = logical_level0_px,
192301e04c3fSmrg      .phys_level0_sa = phys_level0_sa,
192401e04c3fSmrg
192501e04c3fSmrg      .size_B = size_B,
192601e04c3fSmrg      .alignment_B = base_alignment_B,
192701e04c3fSmrg      .row_pitch_B = row_pitch_B,
192801e04c3fSmrg      .array_pitch_el_rows = array_pitch_el_rows,
192901e04c3fSmrg      .array_pitch_span = array_pitch_span,
193001e04c3fSmrg
193101e04c3fSmrg      .usage = info->usage,
193201e04c3fSmrg   };
193301e04c3fSmrg
193401e04c3fSmrg   return true;
193501e04c3fSmrg}
193601e04c3fSmrg
193701e04c3fSmrgvoid
193801e04c3fSmrgisl_surf_get_tile_info(const struct isl_surf *surf,
193901e04c3fSmrg                       struct isl_tile_info *tile_info)
194001e04c3fSmrg{
194101e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
19427ec681f3Smrg   isl_tiling_get_info(surf->tiling, surf->dim, surf->msaa_layout, fmtl->bpb,
19437ec681f3Smrg                       surf->samples, tile_info);
194401e04c3fSmrg}
194501e04c3fSmrg
194601e04c3fSmrgbool
194701e04c3fSmrgisl_surf_get_hiz_surf(const struct isl_device *dev,
194801e04c3fSmrg                      const struct isl_surf *surf,
194901e04c3fSmrg                      struct isl_surf *hiz_surf)
195001e04c3fSmrg{
19517ec681f3Smrg   assert(ISL_GFX_VER(dev) >= 5 && ISL_DEV_USE_SEPARATE_STENCIL(dev));
19527ec681f3Smrg
19537ec681f3Smrg   if (!isl_surf_usage_is_depth(surf->usage))
19547ec681f3Smrg      return false;
19557ec681f3Smrg
19567ec681f3Smrg   /* HiZ only works with Y-tiled depth buffers */
19577ec681f3Smrg   if (!isl_tiling_is_any_y(surf->tiling))
19587ec681f3Smrg      return false;
19597ec681f3Smrg
19607ec681f3Smrg   /* On SNB+, compressed depth buffers cannot be interleaved with stencil. */
19617ec681f3Smrg   switch (surf->format) {
19627ec681f3Smrg   case ISL_FORMAT_R24_UNORM_X8_TYPELESS:
19637ec681f3Smrg      if (isl_surf_usage_is_depth_and_stencil(surf->usage)) {
19647ec681f3Smrg         assert(ISL_GFX_VER(dev) == 5);
19657ec681f3Smrg         unreachable("This should work, but is untested");
19667ec681f3Smrg      }
19677ec681f3Smrg      FALLTHROUGH;
19687ec681f3Smrg   case ISL_FORMAT_R16_UNORM:
19697ec681f3Smrg   case ISL_FORMAT_R32_FLOAT:
19707ec681f3Smrg      break;
19717ec681f3Smrg   case ISL_FORMAT_R32_FLOAT_X8X24_TYPELESS:
19727ec681f3Smrg      if (ISL_GFX_VER(dev) == 5) {
19737ec681f3Smrg         assert(isl_surf_usage_is_depth_and_stencil(surf->usage));
19747ec681f3Smrg         unreachable("This should work, but is untested");
19757ec681f3Smrg      }
19767ec681f3Smrg      FALLTHROUGH;
19777ec681f3Smrg   default:
19787ec681f3Smrg      return false;
19797ec681f3Smrg   }
198001e04c3fSmrg
198101e04c3fSmrg   /* Multisampled depth is always interleaved */
198201e04c3fSmrg   assert(surf->msaa_layout == ISL_MSAA_LAYOUT_NONE ||
198301e04c3fSmrg          surf->msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED);
198401e04c3fSmrg
198501e04c3fSmrg   /* From the Broadwell PRM Vol. 7, "Hierarchical Depth Buffer":
198601e04c3fSmrg    *
198701e04c3fSmrg    *    "The Surface Type, Height, Width, Depth, Minimum Array Element, Render
198801e04c3fSmrg    *    Target View Extent, and Depth Coordinate Offset X/Y of the
198901e04c3fSmrg    *    hierarchical depth buffer are inherited from the depth buffer. The
199001e04c3fSmrg    *    height and width of the hierarchical depth buffer that must be
199101e04c3fSmrg    *    allocated are computed by the following formulas, where HZ is the
199201e04c3fSmrg    *    hierarchical depth buffer and Z is the depth buffer. The Z_Height,
199301e04c3fSmrg    *    Z_Width, and Z_Depth values given in these formulas are those present
199401e04c3fSmrg    *    in 3DSTATE_DEPTH_BUFFER incremented by one.
199501e04c3fSmrg    *
199601e04c3fSmrg    *    "The value of Z_Height and Z_Width must each be multiplied by 2 before
199701e04c3fSmrg    *    being applied to the table below if Number of Multisamples is set to
199801e04c3fSmrg    *    NUMSAMPLES_4. The value of Z_Height must be multiplied by 2 and
199901e04c3fSmrg    *    Z_Width must be multiplied by 4 before being applied to the table
200001e04c3fSmrg    *    below if Number of Multisamples is set to NUMSAMPLES_8."
200101e04c3fSmrg    *
200201e04c3fSmrg    * In the Sky Lake PRM, the second paragraph is replaced with this:
200301e04c3fSmrg    *
200401e04c3fSmrg    *    "The Z_Height and Z_Width values must equal those present in
200501e04c3fSmrg    *    3DSTATE_DEPTH_BUFFER incremented by one."
200601e04c3fSmrg    *
200701e04c3fSmrg    * In other words, on Sandy Bridge through Broadwell, each 128-bit HiZ
200801e04c3fSmrg    * block corresponds to a region of 8x4 samples in the primary depth
200901e04c3fSmrg    * surface.  On Sky Lake, on the other hand, each HiZ block corresponds to
201001e04c3fSmrg    * a region of 8x4 pixels in the primary depth surface regardless of the
201101e04c3fSmrg    * number of samples.  The dimensions of a HiZ block in both pixels and
201201e04c3fSmrg    * samples are given in the table below:
201301e04c3fSmrg    *
201401e04c3fSmrg    *                    | SNB - BDW |     SKL+
201501e04c3fSmrg    *              ------+-----------+-------------
201601e04c3fSmrg    *                1x  |  8 x 4 sa |   8 x 4 sa
201701e04c3fSmrg    *               MSAA |  8 x 4 px |   8 x 4 px
201801e04c3fSmrg    *              ------+-----------+-------------
201901e04c3fSmrg    *                2x  |  8 x 4 sa |  16 x 4 sa
202001e04c3fSmrg    *               MSAA |  4 x 4 px |   8 x 4 px
202101e04c3fSmrg    *              ------+-----------+-------------
202201e04c3fSmrg    *                4x  |  8 x 4 sa |  16 x 8 sa
202301e04c3fSmrg    *               MSAA |  4 x 2 px |   8 x 4 px
202401e04c3fSmrg    *              ------+-----------+-------------
202501e04c3fSmrg    *                8x  |  8 x 4 sa |  32 x 8 sa
202601e04c3fSmrg    *               MSAA |  2 x 2 px |   8 x 4 px
202701e04c3fSmrg    *              ------+-----------+-------------
202801e04c3fSmrg    *               16x  |    N/A    | 32 x 16 sa
202901e04c3fSmrg    *               MSAA |    N/A    |  8 x  4 px
203001e04c3fSmrg    *              ------+-----------+-------------
203101e04c3fSmrg    *
203201e04c3fSmrg    * There are a number of different ways that this discrepency could be
203301e04c3fSmrg    * handled.  The way we have chosen is to simply make MSAA HiZ have the
203401e04c3fSmrg    * same number of samples as the parent surface pre-Sky Lake and always be
203501e04c3fSmrg    * single-sampled on Sky Lake and above.  Since the block sizes of
203601e04c3fSmrg    * compressed formats are given in samples, this neatly handles everything
203701e04c3fSmrg    * without the need for additional HiZ formats with different block sizes
203801e04c3fSmrg    * on SKL+.
203901e04c3fSmrg    */
20407ec681f3Smrg   const unsigned samples = ISL_GFX_VER(dev) >= 9 ? 1 : surf->samples;
204101e04c3fSmrg
204201e04c3fSmrg   return isl_surf_init(dev, hiz_surf,
204301e04c3fSmrg                        .dim = surf->dim,
204401e04c3fSmrg                        .format = ISL_FORMAT_HIZ,
204501e04c3fSmrg                        .width = surf->logical_level0_px.width,
204601e04c3fSmrg                        .height = surf->logical_level0_px.height,
204701e04c3fSmrg                        .depth = surf->logical_level0_px.depth,
204801e04c3fSmrg                        .levels = surf->levels,
204901e04c3fSmrg                        .array_len = surf->logical_level0_px.array_len,
205001e04c3fSmrg                        .samples = samples,
205101e04c3fSmrg                        .usage = ISL_SURF_USAGE_HIZ_BIT,
205201e04c3fSmrg                        .tiling_flags = ISL_TILING_HIZ_BIT);
205301e04c3fSmrg}
205401e04c3fSmrg
205501e04c3fSmrgbool
205601e04c3fSmrgisl_surf_get_mcs_surf(const struct isl_device *dev,
205701e04c3fSmrg                      const struct isl_surf *surf,
205801e04c3fSmrg                      struct isl_surf *mcs_surf)
205901e04c3fSmrg{
206001e04c3fSmrg   /* It must be multisampled with an array layout */
20617ec681f3Smrg   if (surf->msaa_layout != ISL_MSAA_LAYOUT_ARRAY)
20627ec681f3Smrg      return false;
20637ec681f3Smrg
20647ec681f3Smrg   if (mcs_surf->size_B > 0)
20657ec681f3Smrg      return false;
206601e04c3fSmrg
206701e04c3fSmrg   /* The following are true of all multisampled surfaces */
20687ec681f3Smrg   assert(surf->samples > 1);
206901e04c3fSmrg   assert(surf->dim == ISL_SURF_DIM_2D);
207001e04c3fSmrg   assert(surf->levels == 1);
207101e04c3fSmrg   assert(surf->logical_level0_px.depth == 1);
207201e04c3fSmrg
20737ec681f3Smrg   /* From the Ivy Bridge PRM, Vol4 Part1 p77 ("MCS Enable"):
20747ec681f3Smrg    *
20757ec681f3Smrg    *   This field must be set to 0 for all SINT MSRTs when all RT channels
20767ec681f3Smrg    *   are not written
20777ec681f3Smrg    *
20787ec681f3Smrg    * In practice this means that we have to disable MCS for all signed
20797ec681f3Smrg    * integer MSAA buffers.  The alternative, to disable MCS only when one
20807ec681f3Smrg    * of the render target channels is disabled, is impractical because it
20817ec681f3Smrg    * would require converting between CMS and UMS MSAA layouts on the fly,
20827ec681f3Smrg    * which is expensive.
20837ec681f3Smrg    */
20847ec681f3Smrg   if (ISL_GFX_VER(dev) == 7 && isl_format_has_sint_channel(surf->format))
20857ec681f3Smrg      return false;
20867ec681f3Smrg
208701e04c3fSmrg   /* The "Auxiliary Surface Pitch" field in RENDER_SURFACE_STATE is only 9
208801e04c3fSmrg    * bits which means the maximum pitch of a compression surface is 512
208901e04c3fSmrg    * tiles or 64KB (since MCS is always Y-tiled).  Since a 16x MCS buffer is
209001e04c3fSmrg    * 64bpp, this gives us a maximum width of 8192 pixels.  We can create
209101e04c3fSmrg    * larger multisampled surfaces, we just can't compress them.   For 2x, 4x,
209201e04c3fSmrg    * and 8x, we have enough room for the full 16k supported by the hardware.
209301e04c3fSmrg    */
209401e04c3fSmrg   if (surf->samples == 16 && surf->logical_level0_px.width > 8192)
209501e04c3fSmrg      return false;
209601e04c3fSmrg
209701e04c3fSmrg   enum isl_format mcs_format;
209801e04c3fSmrg   switch (surf->samples) {
209901e04c3fSmrg   case 2:  mcs_format = ISL_FORMAT_MCS_2X;  break;
210001e04c3fSmrg   case 4:  mcs_format = ISL_FORMAT_MCS_4X;  break;
210101e04c3fSmrg   case 8:  mcs_format = ISL_FORMAT_MCS_8X;  break;
210201e04c3fSmrg   case 16: mcs_format = ISL_FORMAT_MCS_16X; break;
210301e04c3fSmrg   default:
210401e04c3fSmrg      unreachable("Invalid sample count");
210501e04c3fSmrg   }
210601e04c3fSmrg
210701e04c3fSmrg   return isl_surf_init(dev, mcs_surf,
210801e04c3fSmrg                        .dim = ISL_SURF_DIM_2D,
210901e04c3fSmrg                        .format = mcs_format,
211001e04c3fSmrg                        .width = surf->logical_level0_px.width,
211101e04c3fSmrg                        .height = surf->logical_level0_px.height,
211201e04c3fSmrg                        .depth = 1,
211301e04c3fSmrg                        .levels = 1,
211401e04c3fSmrg                        .array_len = surf->logical_level0_px.array_len,
211501e04c3fSmrg                        .samples = 1, /* MCS surfaces are really single-sampled */
211601e04c3fSmrg                        .usage = ISL_SURF_USAGE_MCS_BIT,
211701e04c3fSmrg                        .tiling_flags = ISL_TILING_Y0_BIT);
211801e04c3fSmrg}
211901e04c3fSmrg
212001e04c3fSmrgbool
21217ec681f3Smrgisl_surf_supports_ccs(const struct isl_device *dev,
212201e04c3fSmrg                      const struct isl_surf *surf,
21237ec681f3Smrg                      const struct isl_surf *hiz_or_mcs_surf)
212401e04c3fSmrg{
21257ec681f3Smrg   /* CCS support does not exist prior to Gfx7 */
21267ec681f3Smrg   if (ISL_GFX_VER(dev) <= 6)
21277ec681f3Smrg      return false;
21287ec681f3Smrg
21297ec681f3Smrg   /* Wa_22011186057: Disable compression on ADL-P A0 */
21307ec681f3Smrg   if (dev->info->is_alderlake && dev->info->gt == 2 &&
21317ec681f3Smrg       dev->info->revision == 0)
21327ec681f3Smrg      return false;
213301e04c3fSmrg
213401e04c3fSmrg   if (surf->usage & ISL_SURF_USAGE_DISABLE_AUX_BIT)
213501e04c3fSmrg      return false;
213601e04c3fSmrg
21377ec681f3Smrg   if (isl_format_is_compressed(surf->format))
213801e04c3fSmrg      return false;
213901e04c3fSmrg
21407ec681f3Smrg   if (!isl_is_pow2(isl_format_get_layout(surf->format)->bpb))
21417ec681f3Smrg      return false;
21427ec681f3Smrg
21437ec681f3Smrg   /* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render
21447ec681f3Smrg    * Target(s)", beneath the "Fast Color Clear" bullet (p326):
21457ec681f3Smrg    *
21467ec681f3Smrg    *     - Support is limited to tiled render targets.
21477ec681f3Smrg    *
21487ec681f3Smrg    * From the Skylake documentation, it is made clear that X-tiling is no
21497ec681f3Smrg    * longer supported:
21507ec681f3Smrg    *
21517ec681f3Smrg    *     - MCS and Lossless compression is supported for
21527ec681f3Smrg    *       TiledY/TileYs/TileYf non-MSRTs only.
215301e04c3fSmrg    *
21547ec681f3Smrg    * From the BSpec (44930) for Gfx12:
215501e04c3fSmrg    *
21567ec681f3Smrg    *    Linear CCS is only allowed for Untyped Buffers but only via HDC
21577ec681f3Smrg    *    Data-Port messages.
21587ec681f3Smrg    *
21597ec681f3Smrg    * We never use untyped messages on surfaces created by ISL on Gfx9+ so
21607ec681f3Smrg    * this means linear is out on Gfx12+ as well.
216101e04c3fSmrg    */
21627ec681f3Smrg   if (surf->tiling == ISL_TILING_LINEAR)
216301e04c3fSmrg      return false;
216401e04c3fSmrg
21657ec681f3Smrg   if (ISL_GFX_VER(dev) >= 12) {
21667ec681f3Smrg      if (isl_surf_usage_is_stencil(surf->usage)) {
21677ec681f3Smrg         /* HiZ and MCS aren't allowed with stencil */
21687ec681f3Smrg         assert(hiz_or_mcs_surf == NULL || hiz_or_mcs_surf->size_B == 0);
21697ec681f3Smrg
21707ec681f3Smrg         /* Multi-sampled stencil cannot have CCS */
21717ec681f3Smrg         if (surf->samples > 1)
21727ec681f3Smrg            return false;
21737ec681f3Smrg      } else if (isl_surf_usage_is_depth(surf->usage)) {
21747ec681f3Smrg         const struct isl_surf *hiz_surf = hiz_or_mcs_surf;
21757ec681f3Smrg
21767ec681f3Smrg         /* With depth surfaces, HIZ is required for CCS. */
21777ec681f3Smrg         if (hiz_surf == NULL || hiz_surf->size_B == 0)
21787ec681f3Smrg            return false;
21797ec681f3Smrg
21807ec681f3Smrg         assert(hiz_surf->usage & ISL_SURF_USAGE_HIZ_BIT);
21817ec681f3Smrg         assert(hiz_surf->tiling == ISL_TILING_HIZ);
21827ec681f3Smrg         assert(hiz_surf->format == ISL_FORMAT_HIZ);
21837ec681f3Smrg      } else if (surf->samples > 1) {
21847ec681f3Smrg         const struct isl_surf *mcs_surf = hiz_or_mcs_surf;
21857ec681f3Smrg
21867ec681f3Smrg         /* With multisampled color, CCS requires MCS */
21877ec681f3Smrg         if (mcs_surf == NULL || mcs_surf->size_B == 0)
21887ec681f3Smrg            return false;
21897ec681f3Smrg
21907ec681f3Smrg         assert(mcs_surf->usage & ISL_SURF_USAGE_MCS_BIT);
21917ec681f3Smrg         assert(isl_tiling_is_any_y(mcs_surf->tiling));
21927ec681f3Smrg         assert(isl_format_is_mcs(mcs_surf->format));
21937ec681f3Smrg      } else {
21947ec681f3Smrg         /* Single-sampled color can't have MCS or HiZ */
21957ec681f3Smrg         assert(hiz_or_mcs_surf == NULL || hiz_or_mcs_surf->size_B == 0);
21967ec681f3Smrg      }
219701e04c3fSmrg
21987ec681f3Smrg      /* On Gfx12, all CCS-compressed surface pitches must be multiples of
21997ec681f3Smrg       * 512B.
22007ec681f3Smrg       */
22017ec681f3Smrg      if (surf->row_pitch_B % 512 != 0)
220201e04c3fSmrg         return false;
220301e04c3fSmrg
22047ec681f3Smrg      /* According to Wa_1406738321, 3D textures need a blit to a new
22057ec681f3Smrg       * surface in order to perform a resolve. For now, just disable CCS.
22067ec681f3Smrg       */
22077ec681f3Smrg      if (surf->dim == ISL_SURF_DIM_3D) {
22087ec681f3Smrg         isl_finishme("%s:%s: CCS for 3D textures is disabled, but a workaround"
22097ec681f3Smrg                      " is available.", __FILE__, __func__);
221001e04c3fSmrg         return false;
221101e04c3fSmrg      }
22127ec681f3Smrg
22137ec681f3Smrg      /* Wa_1207137018
22147ec681f3Smrg       *
22157ec681f3Smrg       * TODO: implement following workaround currently covered by the
22167ec681f3Smrg       * restriction above. If following conditions are met:
22177ec681f3Smrg       *
22187ec681f3Smrg       *    - RENDER_SURFACE_STATE.Surface Type == 3D
22197ec681f3Smrg       *    - RENDER_SURFACE_STATE.Auxiliary Surface Mode != AUX_NONE
22207ec681f3Smrg       *    - RENDER_SURFACE_STATE.Tiled ResourceMode is TYF or TYS
22217ec681f3Smrg       *
22227ec681f3Smrg       * Set the value of RENDER_SURFACE_STATE.Mip Tail Start LOD to a mip
22237ec681f3Smrg       * that larger than those present in the surface (i.e. 15)
22247ec681f3Smrg       */
22257ec681f3Smrg
22267ec681f3Smrg      /* TODO: Handle the other tiling formats */
22277ec681f3Smrg      if (surf->tiling != ISL_TILING_Y0)
222801e04c3fSmrg         return false;
22297ec681f3Smrg   } else {
22307ec681f3Smrg      /* ISL_GFX_VER(dev) < 12 */
22317ec681f3Smrg      if (surf->samples > 1)
22327ec681f3Smrg         return false;
22337ec681f3Smrg
22347ec681f3Smrg      /* CCS is only for color images on Gfx7-11 */
22357ec681f3Smrg      if (isl_surf_usage_is_depth_or_stencil(surf->usage))
22367ec681f3Smrg         return false;
22377ec681f3Smrg
22387ec681f3Smrg      /* We're single-sampled color so having HiZ or MCS makes no sense */
22397ec681f3Smrg      assert(hiz_or_mcs_surf == NULL || hiz_or_mcs_surf->size_B == 0);
22407ec681f3Smrg
22417ec681f3Smrg      /* The PRM doesn't say this explicitly, but fast-clears don't appear to
22427ec681f3Smrg       * work for 3D textures until gfx9 where the layout of 3D textures
22437ec681f3Smrg       * changes to match 2D array textures.
22447ec681f3Smrg       */
22457ec681f3Smrg      if (ISL_GFX_VER(dev) <= 8 && surf->dim != ISL_SURF_DIM_2D)
22467ec681f3Smrg         return false;
22477ec681f3Smrg
22487ec681f3Smrg      /* From the HSW PRM Volume 7: 3D-Media-GPGPU, page 652 (Color Clear of
22497ec681f3Smrg       * Non-MultiSampler Render Target Restrictions):
22507ec681f3Smrg       *
22517ec681f3Smrg       *    "Support is for non-mip-mapped and non-array surface types only."
22527ec681f3Smrg       *
22537ec681f3Smrg       * This restriction is lifted on gfx8+.  Technically, it may be possible
22547ec681f3Smrg       * to create a CCS for an arrayed or mipmapped image and only enable
22557ec681f3Smrg       * CCS_D when rendering to the base slice.  However, there is no
22567ec681f3Smrg       * documentation tell us what the hardware would do in that case or what
22577ec681f3Smrg       * it does if you walk off the bases slice.  (Does it ignore CCS or does
22587ec681f3Smrg       * it start scribbling over random memory?)  We play it safe and just
22597ec681f3Smrg       * follow the docs and don't allow CCS_D for arrayed or mip-mapped
22607ec681f3Smrg       * surfaces.
22617ec681f3Smrg       */
22627ec681f3Smrg      if (ISL_GFX_VER(dev) <= 7 &&
22637ec681f3Smrg          (surf->levels > 1 || surf->logical_level0_px.array_len > 1))
22647ec681f3Smrg         return false;
22657ec681f3Smrg
22667ec681f3Smrg      /* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render
22677ec681f3Smrg       * Target(s)", beneath the "Fast Color Clear" bullet (p326):
22687ec681f3Smrg       *
22697ec681f3Smrg       *     - MCS buffer for non-MSRT is supported only for RT formats 32bpp,
22707ec681f3Smrg       *       64bpp, and 128bpp.
22717ec681f3Smrg       */
22727ec681f3Smrg      if (isl_format_get_layout(surf->format)->bpb < 32)
22737ec681f3Smrg         return false;
22747ec681f3Smrg
22757ec681f3Smrg      /* From the Skylake documentation, it is made clear that X-tiling is no
22767ec681f3Smrg       * longer supported:
22777ec681f3Smrg       *
22787ec681f3Smrg       *     - MCS and Lossless compression is supported for
22797ec681f3Smrg       *     TiledY/TileYs/TileYf non-MSRTs only.
22807ec681f3Smrg       */
22817ec681f3Smrg      if (ISL_GFX_VER(dev) >= 9 && !isl_tiling_is_any_y(surf->tiling))
22827ec681f3Smrg         return false;
22837ec681f3Smrg   }
22847ec681f3Smrg
22857ec681f3Smrg   return true;
22867ec681f3Smrg}
22877ec681f3Smrg
22887ec681f3Smrgbool
22897ec681f3Smrgisl_surf_get_ccs_surf(const struct isl_device *dev,
22907ec681f3Smrg                      const struct isl_surf *surf,
22917ec681f3Smrg                      const struct isl_surf *hiz_or_mcs_surf,
22927ec681f3Smrg                      struct isl_surf *ccs_surf,
22937ec681f3Smrg                      uint32_t row_pitch_B)
22947ec681f3Smrg{
22957ec681f3Smrg   if (!isl_surf_supports_ccs(dev, surf, hiz_or_mcs_surf))
22967ec681f3Smrg      return false;
22977ec681f3Smrg
22987ec681f3Smrg   if (ISL_GFX_VER(dev) >= 12) {
22997ec681f3Smrg      enum isl_format ccs_format;
230001e04c3fSmrg      switch (isl_format_get_layout(surf->format)->bpb) {
23017ec681f3Smrg      case 8:     ccs_format = ISL_FORMAT_GFX12_CCS_8BPP_Y0;    break;
23027ec681f3Smrg      case 16:    ccs_format = ISL_FORMAT_GFX12_CCS_16BPP_Y0;   break;
23037ec681f3Smrg      case 32:    ccs_format = ISL_FORMAT_GFX12_CCS_32BPP_Y0;   break;
23047ec681f3Smrg      case 64:    ccs_format = ISL_FORMAT_GFX12_CCS_64BPP_Y0;   break;
23057ec681f3Smrg      case 128:   ccs_format = ISL_FORMAT_GFX12_CCS_128BPP_Y0;  break;
230601e04c3fSmrg      default:
230701e04c3fSmrg         return false;
230801e04c3fSmrg      }
23097ec681f3Smrg
23107ec681f3Smrg      /* On Gfx12, the CCS is a scaled-down version of the main surface. We
23117ec681f3Smrg       * model this as the CCS compressing a 2D-view of the entire surface.
23127ec681f3Smrg       */
23137ec681f3Smrg      const bool ok =
23147ec681f3Smrg         isl_surf_init(dev, ccs_surf,
23157ec681f3Smrg                       .dim = ISL_SURF_DIM_2D,
23167ec681f3Smrg                       .format = ccs_format,
23177ec681f3Smrg                       .width = isl_surf_get_row_pitch_el(surf),
23187ec681f3Smrg                       .height = surf->size_B / surf->row_pitch_B,
23197ec681f3Smrg                       .depth = 1,
23207ec681f3Smrg                       .levels = 1,
23217ec681f3Smrg                       .array_len = 1,
23227ec681f3Smrg                       .samples = 1,
23237ec681f3Smrg                       .row_pitch_B = row_pitch_B,
23247ec681f3Smrg                       .usage = ISL_SURF_USAGE_CCS_BIT,
23257ec681f3Smrg                       .tiling_flags = ISL_TILING_GFX12_CCS_BIT);
23267ec681f3Smrg      assert(!ok || ccs_surf->size_B == surf->size_B / 256);
23277ec681f3Smrg      return ok;
232801e04c3fSmrg   } else {
23297ec681f3Smrg      enum isl_format ccs_format;
23307ec681f3Smrg      if (ISL_GFX_VER(dev) >= 9) {
23317ec681f3Smrg         switch (isl_format_get_layout(surf->format)->bpb) {
23327ec681f3Smrg         case 32:    ccs_format = ISL_FORMAT_GFX9_CCS_32BPP;   break;
23337ec681f3Smrg         case 64:    ccs_format = ISL_FORMAT_GFX9_CCS_64BPP;   break;
23347ec681f3Smrg         case 128:   ccs_format = ISL_FORMAT_GFX9_CCS_128BPP;  break;
23357ec681f3Smrg         default:    unreachable("Unsupported CCS format");
23367ec681f3Smrg            return false;
23377ec681f3Smrg         }
23387ec681f3Smrg      } else if (surf->tiling == ISL_TILING_Y0) {
23397ec681f3Smrg         switch (isl_format_get_layout(surf->format)->bpb) {
23407ec681f3Smrg         case 32:    ccs_format = ISL_FORMAT_GFX7_CCS_32BPP_Y;    break;
23417ec681f3Smrg         case 64:    ccs_format = ISL_FORMAT_GFX7_CCS_64BPP_Y;    break;
23427ec681f3Smrg         case 128:   ccs_format = ISL_FORMAT_GFX7_CCS_128BPP_Y;   break;
23437ec681f3Smrg         default:    unreachable("Unsupported CCS format");
23447ec681f3Smrg         }
23457ec681f3Smrg      } else if (surf->tiling == ISL_TILING_X) {
23467ec681f3Smrg         switch (isl_format_get_layout(surf->format)->bpb) {
23477ec681f3Smrg         case 32:    ccs_format = ISL_FORMAT_GFX7_CCS_32BPP_X;    break;
23487ec681f3Smrg         case 64:    ccs_format = ISL_FORMAT_GFX7_CCS_64BPP_X;    break;
23497ec681f3Smrg         case 128:   ccs_format = ISL_FORMAT_GFX7_CCS_128BPP_X;   break;
23507ec681f3Smrg         default:    unreachable("Unsupported CCS format");
23517ec681f3Smrg         }
23527ec681f3Smrg      } else {
23537ec681f3Smrg         unreachable("Invalid tiling format");
23547ec681f3Smrg      }
235501e04c3fSmrg
23567ec681f3Smrg      return isl_surf_init(dev, ccs_surf,
23577ec681f3Smrg                           .dim = surf->dim,
23587ec681f3Smrg                           .format = ccs_format,
23597ec681f3Smrg                           .width = surf->logical_level0_px.width,
23607ec681f3Smrg                           .height = surf->logical_level0_px.height,
23617ec681f3Smrg                           .depth = surf->logical_level0_px.depth,
23627ec681f3Smrg                           .levels = surf->levels,
23637ec681f3Smrg                           .array_len = surf->logical_level0_px.array_len,
23647ec681f3Smrg                           .samples = 1,
23657ec681f3Smrg                           .row_pitch_B = row_pitch_B,
23667ec681f3Smrg                           .usage = ISL_SURF_USAGE_CCS_BIT,
23677ec681f3Smrg                           .tiling_flags = ISL_TILING_CCS_BIT);
23687ec681f3Smrg   }
236901e04c3fSmrg}
237001e04c3fSmrg
237101e04c3fSmrg#define isl_genX_call(dev, func, ...)              \
23727ec681f3Smrg   switch (ISL_GFX_VERX10(dev)) {                  \
23737ec681f3Smrg   case 40:                                        \
23747ec681f3Smrg      isl_gfx4_##func(__VA_ARGS__);                \
237501e04c3fSmrg      break;                                       \
23767ec681f3Smrg   case 45:                                        \
23777ec681f3Smrg      /* G45 surface state is the same as gfx5 */  \
23787ec681f3Smrg   case 50:                                        \
23797ec681f3Smrg      isl_gfx5_##func(__VA_ARGS__);                \
238001e04c3fSmrg      break;                                       \
23817ec681f3Smrg   case 60:                                        \
23827ec681f3Smrg      isl_gfx6_##func(__VA_ARGS__);                \
238301e04c3fSmrg      break;                                       \
23847ec681f3Smrg   case 70:                                        \
23857ec681f3Smrg      isl_gfx7_##func(__VA_ARGS__);                \
238601e04c3fSmrg      break;                                       \
23877ec681f3Smrg   case 75:                                        \
23887ec681f3Smrg      isl_gfx75_##func(__VA_ARGS__);               \
238901e04c3fSmrg      break;                                       \
23907ec681f3Smrg   case 80:                                        \
23917ec681f3Smrg      isl_gfx8_##func(__VA_ARGS__);                \
239201e04c3fSmrg      break;                                       \
23937ec681f3Smrg   case 90:                                        \
23947ec681f3Smrg      isl_gfx9_##func(__VA_ARGS__);                \
239501e04c3fSmrg      break;                                       \
23967ec681f3Smrg   case 110:                                       \
23977ec681f3Smrg      isl_gfx11_##func(__VA_ARGS__);               \
23987ec681f3Smrg      break;                                       \
23997ec681f3Smrg   case 120:                                       \
24007ec681f3Smrg      isl_gfx12_##func(__VA_ARGS__);               \
24017ec681f3Smrg      break;                                       \
24027ec681f3Smrg   case 125:                                       \
24037ec681f3Smrg      isl_gfx125_##func(__VA_ARGS__);              \
240401e04c3fSmrg      break;                                       \
240501e04c3fSmrg   default:                                        \
240601e04c3fSmrg      assert(!"Unknown hardware generation");      \
240701e04c3fSmrg   }
240801e04c3fSmrg
240901e04c3fSmrgvoid
241001e04c3fSmrgisl_surf_fill_state_s(const struct isl_device *dev, void *state,
241101e04c3fSmrg                      const struct isl_surf_fill_state_info *restrict info)
241201e04c3fSmrg{
241301e04c3fSmrg#ifndef NDEBUG
241401e04c3fSmrg   isl_surf_usage_flags_t _base_usage =
241501e04c3fSmrg      info->view->usage & (ISL_SURF_USAGE_RENDER_TARGET_BIT |
241601e04c3fSmrg                           ISL_SURF_USAGE_TEXTURE_BIT |
241701e04c3fSmrg                           ISL_SURF_USAGE_STORAGE_BIT);
241801e04c3fSmrg   /* They may only specify one of the above bits at a time */
241901e04c3fSmrg   assert(__builtin_popcount(_base_usage) == 1);
242001e04c3fSmrg   /* The only other allowed bit is ISL_SURF_USAGE_CUBE_BIT */
242101e04c3fSmrg   assert((info->view->usage & ~ISL_SURF_USAGE_CUBE_BIT) == _base_usage);
242201e04c3fSmrg#endif
242301e04c3fSmrg
242401e04c3fSmrg   if (info->surf->dim == ISL_SURF_DIM_3D) {
242501e04c3fSmrg      assert(info->view->base_array_layer + info->view->array_len <=
242601e04c3fSmrg             info->surf->logical_level0_px.depth);
242701e04c3fSmrg   } else {
242801e04c3fSmrg      assert(info->view->base_array_layer + info->view->array_len <=
242901e04c3fSmrg             info->surf->logical_level0_px.array_len);
243001e04c3fSmrg   }
243101e04c3fSmrg
243201e04c3fSmrg   isl_genX_call(dev, surf_fill_state_s, dev, state, info);
243301e04c3fSmrg}
243401e04c3fSmrg
243501e04c3fSmrgvoid
243601e04c3fSmrgisl_buffer_fill_state_s(const struct isl_device *dev, void *state,
243701e04c3fSmrg                        const struct isl_buffer_fill_state_info *restrict info)
243801e04c3fSmrg{
24397ec681f3Smrg   isl_genX_call(dev, buffer_fill_state_s, dev, state, info);
244001e04c3fSmrg}
244101e04c3fSmrg
244201e04c3fSmrgvoid
24437ec681f3Smrgisl_null_fill_state_s(const struct isl_device *dev, void *state,
24447ec681f3Smrg                      const struct isl_null_fill_state_info *restrict info)
244501e04c3fSmrg{
24467ec681f3Smrg   isl_genX_call(dev, null_fill_state, state, info);
244701e04c3fSmrg}
244801e04c3fSmrg
244901e04c3fSmrgvoid
245001e04c3fSmrgisl_emit_depth_stencil_hiz_s(const struct isl_device *dev, void *batch,
245101e04c3fSmrg                             const struct isl_depth_stencil_hiz_emit_info *restrict info)
245201e04c3fSmrg{
245301e04c3fSmrg   if (info->depth_surf && info->stencil_surf) {
245401e04c3fSmrg      if (!dev->info->has_hiz_and_separate_stencil) {
245501e04c3fSmrg         assert(info->depth_surf == info->stencil_surf);
245601e04c3fSmrg         assert(info->depth_address == info->stencil_address);
245701e04c3fSmrg      }
245801e04c3fSmrg      assert(info->depth_surf->dim == info->stencil_surf->dim);
245901e04c3fSmrg   }
246001e04c3fSmrg
246101e04c3fSmrg   if (info->depth_surf) {
246201e04c3fSmrg      assert((info->depth_surf->usage & ISL_SURF_USAGE_DEPTH_BIT));
246301e04c3fSmrg      if (info->depth_surf->dim == ISL_SURF_DIM_3D) {
246401e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
246501e04c3fSmrg                info->depth_surf->logical_level0_px.depth);
246601e04c3fSmrg      } else {
246701e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
246801e04c3fSmrg                info->depth_surf->logical_level0_px.array_len);
246901e04c3fSmrg      }
247001e04c3fSmrg   }
247101e04c3fSmrg
247201e04c3fSmrg   if (info->stencil_surf) {
247301e04c3fSmrg      assert((info->stencil_surf->usage & ISL_SURF_USAGE_STENCIL_BIT));
247401e04c3fSmrg      if (info->stencil_surf->dim == ISL_SURF_DIM_3D) {
247501e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
247601e04c3fSmrg                info->stencil_surf->logical_level0_px.depth);
247701e04c3fSmrg      } else {
247801e04c3fSmrg         assert(info->view->base_array_layer + info->view->array_len <=
247901e04c3fSmrg                info->stencil_surf->logical_level0_px.array_len);
248001e04c3fSmrg      }
248101e04c3fSmrg   }
248201e04c3fSmrg
248301e04c3fSmrg   isl_genX_call(dev, emit_depth_stencil_hiz_s, dev, batch, info);
248401e04c3fSmrg}
248501e04c3fSmrg
248601e04c3fSmrg/**
248701e04c3fSmrg * A variant of isl_surf_get_image_offset_sa() specific to
24887ec681f3Smrg * ISL_DIM_LAYOUT_GFX4_2D.
248901e04c3fSmrg */
249001e04c3fSmrgstatic void
24917ec681f3Smrgget_image_offset_sa_gfx4_2d(const struct isl_surf *surf,
249201e04c3fSmrg                            uint32_t level, uint32_t logical_array_layer,
249301e04c3fSmrg                            uint32_t *x_offset_sa,
249401e04c3fSmrg                            uint32_t *y_offset_sa)
249501e04c3fSmrg{
249601e04c3fSmrg   assert(level < surf->levels);
249701e04c3fSmrg   if (surf->dim == ISL_SURF_DIM_3D)
249801e04c3fSmrg      assert(logical_array_layer < surf->logical_level0_px.depth);
249901e04c3fSmrg   else
250001e04c3fSmrg      assert(logical_array_layer < surf->logical_level0_px.array_len);
250101e04c3fSmrg
250201e04c3fSmrg   const struct isl_extent3d image_align_sa =
250301e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
250401e04c3fSmrg
250501e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.width;
250601e04c3fSmrg   const uint32_t H0 = surf->phys_level0_sa.height;
250701e04c3fSmrg
250801e04c3fSmrg   const uint32_t phys_layer = logical_array_layer *
250901e04c3fSmrg      (surf->msaa_layout == ISL_MSAA_LAYOUT_ARRAY ? surf->samples : 1);
251001e04c3fSmrg
251101e04c3fSmrg   uint32_t x = 0;
251201e04c3fSmrg   uint32_t y = phys_layer * isl_surf_get_array_pitch_sa_rows(surf);
251301e04c3fSmrg
251401e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
251501e04c3fSmrg      if (l == 1) {
251601e04c3fSmrg         uint32_t W = isl_minify(W0, l);
251701e04c3fSmrg         x += isl_align_npot(W, image_align_sa.w);
251801e04c3fSmrg      } else {
251901e04c3fSmrg         uint32_t H = isl_minify(H0, l);
252001e04c3fSmrg         y += isl_align_npot(H, image_align_sa.h);
252101e04c3fSmrg      }
252201e04c3fSmrg   }
252301e04c3fSmrg
252401e04c3fSmrg   *x_offset_sa = x;
252501e04c3fSmrg   *y_offset_sa = y;
252601e04c3fSmrg}
252701e04c3fSmrg
252801e04c3fSmrg/**
252901e04c3fSmrg * A variant of isl_surf_get_image_offset_sa() specific to
25307ec681f3Smrg * ISL_DIM_LAYOUT_GFX4_3D.
253101e04c3fSmrg */
253201e04c3fSmrgstatic void
25337ec681f3Smrgget_image_offset_sa_gfx4_3d(const struct isl_surf *surf,
253401e04c3fSmrg                            uint32_t level, uint32_t logical_z_offset_px,
253501e04c3fSmrg                            uint32_t *x_offset_sa,
253601e04c3fSmrg                            uint32_t *y_offset_sa)
253701e04c3fSmrg{
253801e04c3fSmrg   assert(level < surf->levels);
253901e04c3fSmrg   if (surf->dim == ISL_SURF_DIM_3D) {
254001e04c3fSmrg      assert(surf->phys_level0_sa.array_len == 1);
254101e04c3fSmrg      assert(logical_z_offset_px < isl_minify(surf->phys_level0_sa.depth, level));
254201e04c3fSmrg   } else {
254301e04c3fSmrg      assert(surf->dim == ISL_SURF_DIM_2D);
254401e04c3fSmrg      assert(surf->usage & ISL_SURF_USAGE_CUBE_BIT);
254501e04c3fSmrg      assert(surf->phys_level0_sa.array_len == 6);
254601e04c3fSmrg      assert(logical_z_offset_px < surf->phys_level0_sa.array_len);
254701e04c3fSmrg   }
254801e04c3fSmrg
254901e04c3fSmrg   const struct isl_extent3d image_align_sa =
255001e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
255101e04c3fSmrg
255201e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.width;
255301e04c3fSmrg   const uint32_t H0 = surf->phys_level0_sa.height;
255401e04c3fSmrg   const uint32_t D0 = surf->phys_level0_sa.depth;
255501e04c3fSmrg   const uint32_t AL = surf->phys_level0_sa.array_len;
255601e04c3fSmrg
255701e04c3fSmrg   uint32_t x = 0;
255801e04c3fSmrg   uint32_t y = 0;
255901e04c3fSmrg
256001e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
256101e04c3fSmrg      const uint32_t level_h = isl_align_npot(isl_minify(H0, l), image_align_sa.h);
256201e04c3fSmrg      const uint32_t level_d =
256301e04c3fSmrg         isl_align_npot(surf->dim == ISL_SURF_DIM_3D ? isl_minify(D0, l) : AL,
256401e04c3fSmrg                        image_align_sa.d);
256501e04c3fSmrg      const uint32_t max_layers_vert = isl_align(level_d, 1u << l) / (1u << l);
256601e04c3fSmrg
256701e04c3fSmrg      y += level_h * max_layers_vert;
256801e04c3fSmrg   }
256901e04c3fSmrg
257001e04c3fSmrg   const uint32_t level_w = isl_align_npot(isl_minify(W0, level), image_align_sa.w);
257101e04c3fSmrg   const uint32_t level_h = isl_align_npot(isl_minify(H0, level), image_align_sa.h);
257201e04c3fSmrg   const uint32_t level_d =
257301e04c3fSmrg      isl_align_npot(surf->dim == ISL_SURF_DIM_3D ? isl_minify(D0, level) : AL,
257401e04c3fSmrg                     image_align_sa.d);
257501e04c3fSmrg
257601e04c3fSmrg   const uint32_t max_layers_horiz = MIN(level_d, 1u << level);
257701e04c3fSmrg
257801e04c3fSmrg   x += level_w * (logical_z_offset_px % max_layers_horiz);
257901e04c3fSmrg   y += level_h * (logical_z_offset_px / max_layers_horiz);
258001e04c3fSmrg
258101e04c3fSmrg   *x_offset_sa = x;
258201e04c3fSmrg   *y_offset_sa = y;
258301e04c3fSmrg}
258401e04c3fSmrg
258501e04c3fSmrgstatic void
25867ec681f3Smrgget_image_offset_sa_gfx6_stencil_hiz(const struct isl_surf *surf,
258701e04c3fSmrg                                     uint32_t level,
258801e04c3fSmrg                                     uint32_t logical_array_layer,
258901e04c3fSmrg                                     uint32_t *x_offset_sa,
259001e04c3fSmrg                                     uint32_t *y_offset_sa)
259101e04c3fSmrg{
259201e04c3fSmrg   assert(level < surf->levels);
259301e04c3fSmrg   assert(surf->logical_level0_px.depth == 1);
259401e04c3fSmrg   assert(logical_array_layer < surf->logical_level0_px.array_len);
259501e04c3fSmrg
259601e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
259701e04c3fSmrg
259801e04c3fSmrg   const struct isl_extent3d image_align_sa =
259901e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
260001e04c3fSmrg
260101e04c3fSmrg   struct isl_tile_info tile_info;
26027ec681f3Smrg   isl_surf_get_tile_info(surf, &tile_info);
260301e04c3fSmrg   const struct isl_extent2d tile_extent_sa = {
260401e04c3fSmrg      .w = tile_info.logical_extent_el.w * fmtl->bw,
260501e04c3fSmrg      .h = tile_info.logical_extent_el.h * fmtl->bh,
260601e04c3fSmrg   };
260701e04c3fSmrg   /* Tile size is a multiple of image alignment */
260801e04c3fSmrg   assert(tile_extent_sa.w % image_align_sa.w == 0);
260901e04c3fSmrg   assert(tile_extent_sa.h % image_align_sa.h == 0);
261001e04c3fSmrg
261101e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.w;
261201e04c3fSmrg   const uint32_t H0 = surf->phys_level0_sa.h;
261301e04c3fSmrg
261401e04c3fSmrg   /* Each image has the same height as LOD0 because the hardware thinks
261501e04c3fSmrg    * everything is LOD0
261601e04c3fSmrg    */
261701e04c3fSmrg   const uint32_t H = isl_align(H0, image_align_sa.h);
261801e04c3fSmrg
261901e04c3fSmrg   /* Quick sanity check for consistency */
262001e04c3fSmrg   if (surf->phys_level0_sa.array_len > 1)
262101e04c3fSmrg      assert(surf->array_pitch_el_rows == isl_assert_div(H, fmtl->bh));
262201e04c3fSmrg
262301e04c3fSmrg   uint32_t x = 0, y = 0;
262401e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
262501e04c3fSmrg      const uint32_t W = isl_minify(W0, l);
262601e04c3fSmrg
262701e04c3fSmrg      const uint32_t w = isl_align(W, tile_extent_sa.w);
262801e04c3fSmrg      const uint32_t h = isl_align(H * surf->phys_level0_sa.a,
262901e04c3fSmrg                                   tile_extent_sa.h);
263001e04c3fSmrg
263101e04c3fSmrg      if (l == 0) {
263201e04c3fSmrg         y += h;
263301e04c3fSmrg      } else {
263401e04c3fSmrg         x += w;
263501e04c3fSmrg      }
263601e04c3fSmrg   }
263701e04c3fSmrg
263801e04c3fSmrg   y += H * logical_array_layer;
263901e04c3fSmrg
264001e04c3fSmrg   *x_offset_sa = x;
264101e04c3fSmrg   *y_offset_sa = y;
264201e04c3fSmrg}
264301e04c3fSmrg
264401e04c3fSmrg/**
264501e04c3fSmrg * A variant of isl_surf_get_image_offset_sa() specific to
26467ec681f3Smrg * ISL_DIM_LAYOUT_GFX9_1D.
264701e04c3fSmrg */
264801e04c3fSmrgstatic void
26497ec681f3Smrgget_image_offset_sa_gfx9_1d(const struct isl_surf *surf,
265001e04c3fSmrg                            uint32_t level, uint32_t layer,
265101e04c3fSmrg                            uint32_t *x_offset_sa,
265201e04c3fSmrg                            uint32_t *y_offset_sa)
265301e04c3fSmrg{
265401e04c3fSmrg   assert(level < surf->levels);
265501e04c3fSmrg   assert(layer < surf->phys_level0_sa.array_len);
265601e04c3fSmrg   assert(surf->phys_level0_sa.height == 1);
265701e04c3fSmrg   assert(surf->phys_level0_sa.depth == 1);
265801e04c3fSmrg   assert(surf->samples == 1);
265901e04c3fSmrg
266001e04c3fSmrg   const uint32_t W0 = surf->phys_level0_sa.width;
266101e04c3fSmrg   const struct isl_extent3d image_align_sa =
266201e04c3fSmrg      isl_surf_get_image_alignment_sa(surf);
266301e04c3fSmrg
266401e04c3fSmrg   uint32_t x = 0;
266501e04c3fSmrg
266601e04c3fSmrg   for (uint32_t l = 0; l < level; ++l) {
266701e04c3fSmrg      uint32_t W = isl_minify(W0, l);
266801e04c3fSmrg      uint32_t w = isl_align_npot(W, image_align_sa.w);
266901e04c3fSmrg
267001e04c3fSmrg      x += w;
267101e04c3fSmrg   }
267201e04c3fSmrg
267301e04c3fSmrg   *x_offset_sa = x;
267401e04c3fSmrg   *y_offset_sa = layer * isl_surf_get_array_pitch_sa_rows(surf);
267501e04c3fSmrg}
267601e04c3fSmrg
267701e04c3fSmrg/**
267801e04c3fSmrg * Calculate the offset, in units of surface samples, to a subimage in the
267901e04c3fSmrg * surface.
268001e04c3fSmrg *
268101e04c3fSmrg * @invariant level < surface levels
268201e04c3fSmrg * @invariant logical_array_layer < logical array length of surface
268301e04c3fSmrg * @invariant logical_z_offset_px < logical depth of surface at level
268401e04c3fSmrg */
268501e04c3fSmrgvoid
268601e04c3fSmrgisl_surf_get_image_offset_sa(const struct isl_surf *surf,
268701e04c3fSmrg                             uint32_t level,
268801e04c3fSmrg                             uint32_t logical_array_layer,
268901e04c3fSmrg                             uint32_t logical_z_offset_px,
269001e04c3fSmrg                             uint32_t *x_offset_sa,
26917ec681f3Smrg                             uint32_t *y_offset_sa,
26927ec681f3Smrg                             uint32_t *z_offset_sa,
26937ec681f3Smrg                             uint32_t *array_offset)
269401e04c3fSmrg{
269501e04c3fSmrg   assert(level < surf->levels);
269601e04c3fSmrg   assert(logical_array_layer < surf->logical_level0_px.array_len);
269701e04c3fSmrg   assert(logical_z_offset_px
269801e04c3fSmrg          < isl_minify(surf->logical_level0_px.depth, level));
269901e04c3fSmrg
270001e04c3fSmrg   switch (surf->dim_layout) {
27017ec681f3Smrg   case ISL_DIM_LAYOUT_GFX9_1D:
27027ec681f3Smrg      get_image_offset_sa_gfx9_1d(surf, level, logical_array_layer,
270301e04c3fSmrg                                  x_offset_sa, y_offset_sa);
27047ec681f3Smrg      *z_offset_sa = 0;
27057ec681f3Smrg      *array_offset = 0;
270601e04c3fSmrg      break;
27077ec681f3Smrg   case ISL_DIM_LAYOUT_GFX4_2D:
27087ec681f3Smrg      get_image_offset_sa_gfx4_2d(surf, level, logical_array_layer
270901e04c3fSmrg                                  + logical_z_offset_px,
271001e04c3fSmrg                                  x_offset_sa, y_offset_sa);
27117ec681f3Smrg      *z_offset_sa = 0;
27127ec681f3Smrg      *array_offset = 0;
271301e04c3fSmrg      break;
27147ec681f3Smrg   case ISL_DIM_LAYOUT_GFX4_3D:
27157ec681f3Smrg      get_image_offset_sa_gfx4_3d(surf, level, logical_array_layer +
271601e04c3fSmrg                                  logical_z_offset_px,
271701e04c3fSmrg                                  x_offset_sa, y_offset_sa);
27187ec681f3Smrg      *z_offset_sa = 0;
27197ec681f3Smrg      *array_offset = 0;
272001e04c3fSmrg      break;
27217ec681f3Smrg   case ISL_DIM_LAYOUT_GFX6_STENCIL_HIZ:
27227ec681f3Smrg      get_image_offset_sa_gfx6_stencil_hiz(surf, level, logical_array_layer +
272301e04c3fSmrg                                           logical_z_offset_px,
272401e04c3fSmrg                                           x_offset_sa, y_offset_sa);
27257ec681f3Smrg      *z_offset_sa = 0;
27267ec681f3Smrg      *array_offset = 0;
272701e04c3fSmrg      break;
272801e04c3fSmrg
272901e04c3fSmrg   default:
273001e04c3fSmrg      unreachable("not reached");
273101e04c3fSmrg   }
273201e04c3fSmrg}
273301e04c3fSmrg
273401e04c3fSmrgvoid
273501e04c3fSmrgisl_surf_get_image_offset_el(const struct isl_surf *surf,
273601e04c3fSmrg                             uint32_t level,
273701e04c3fSmrg                             uint32_t logical_array_layer,
273801e04c3fSmrg                             uint32_t logical_z_offset_px,
273901e04c3fSmrg                             uint32_t *x_offset_el,
27407ec681f3Smrg                             uint32_t *y_offset_el,
27417ec681f3Smrg                             uint32_t *z_offset_el,
27427ec681f3Smrg                             uint32_t *array_offset)
274301e04c3fSmrg{
274401e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
274501e04c3fSmrg
274601e04c3fSmrg   assert(level < surf->levels);
274701e04c3fSmrg   assert(logical_array_layer < surf->logical_level0_px.array_len);
274801e04c3fSmrg   assert(logical_z_offset_px
274901e04c3fSmrg          < isl_minify(surf->logical_level0_px.depth, level));
275001e04c3fSmrg
27517ec681f3Smrg   uint32_t x_offset_sa, y_offset_sa, z_offset_sa;
275201e04c3fSmrg   isl_surf_get_image_offset_sa(surf, level,
275301e04c3fSmrg                                logical_array_layer,
275401e04c3fSmrg                                logical_z_offset_px,
275501e04c3fSmrg                                &x_offset_sa,
27567ec681f3Smrg                                &y_offset_sa,
27577ec681f3Smrg                                &z_offset_sa,
27587ec681f3Smrg                                array_offset);
275901e04c3fSmrg
276001e04c3fSmrg   *x_offset_el = x_offset_sa / fmtl->bw;
276101e04c3fSmrg   *y_offset_el = y_offset_sa / fmtl->bh;
27627ec681f3Smrg   *z_offset_el = z_offset_sa / fmtl->bd;
276301e04c3fSmrg}
276401e04c3fSmrg
276501e04c3fSmrgvoid
276601e04c3fSmrgisl_surf_get_image_offset_B_tile_sa(const struct isl_surf *surf,
276701e04c3fSmrg                                    uint32_t level,
276801e04c3fSmrg                                    uint32_t logical_array_layer,
276901e04c3fSmrg                                    uint32_t logical_z_offset_px,
27707ec681f3Smrg                                    uint64_t *offset_B,
277101e04c3fSmrg                                    uint32_t *x_offset_sa,
277201e04c3fSmrg                                    uint32_t *y_offset_sa)
277301e04c3fSmrg{
277401e04c3fSmrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
277501e04c3fSmrg
277601e04c3fSmrg   uint32_t x_offset_el, y_offset_el;
27777ec681f3Smrg   isl_surf_get_image_offset_B_tile_el(surf, level,
27787ec681f3Smrg                                       logical_array_layer,
27797ec681f3Smrg                                       logical_z_offset_px,
27807ec681f3Smrg                                       offset_B,
27817ec681f3Smrg                                       &x_offset_el,
27827ec681f3Smrg                                       &y_offset_el);
278301e04c3fSmrg
278401e04c3fSmrg   if (x_offset_sa) {
278501e04c3fSmrg      *x_offset_sa = x_offset_el * fmtl->bw;
278601e04c3fSmrg   } else {
278701e04c3fSmrg      assert(x_offset_el == 0);
278801e04c3fSmrg   }
278901e04c3fSmrg
279001e04c3fSmrg   if (y_offset_sa) {
279101e04c3fSmrg      *y_offset_sa = y_offset_el * fmtl->bh;
279201e04c3fSmrg   } else {
279301e04c3fSmrg      assert(y_offset_el == 0);
279401e04c3fSmrg   }
279501e04c3fSmrg}
279601e04c3fSmrg
27977ec681f3Smrgvoid
27987ec681f3Smrgisl_surf_get_image_offset_B_tile_el(const struct isl_surf *surf,
27997ec681f3Smrg                                    uint32_t level,
28007ec681f3Smrg                                    uint32_t logical_array_layer,
28017ec681f3Smrg                                    uint32_t logical_z_offset_px,
28027ec681f3Smrg                                    uint64_t *offset_B,
28037ec681f3Smrg                                    uint32_t *x_offset_el,
28047ec681f3Smrg                                    uint32_t *y_offset_el)
28057ec681f3Smrg{
28067ec681f3Smrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
28077ec681f3Smrg
28087ec681f3Smrg   uint32_t total_x_offset_el, total_y_offset_el;
28097ec681f3Smrg   uint32_t total_z_offset_el, total_array_offset;
28107ec681f3Smrg   isl_surf_get_image_offset_el(surf, level, logical_array_layer,
28117ec681f3Smrg                                logical_z_offset_px,
28127ec681f3Smrg                                &total_x_offset_el,
28137ec681f3Smrg                                &total_y_offset_el,
28147ec681f3Smrg                                &total_z_offset_el,
28157ec681f3Smrg                                &total_array_offset);
28167ec681f3Smrg
28177ec681f3Smrg   uint32_t z_offset_el, array_offset;
28187ec681f3Smrg   isl_tiling_get_intratile_offset_el(surf->tiling, surf->dim,
28197ec681f3Smrg                                      surf->msaa_layout, fmtl->bpb,
28207ec681f3Smrg                                      surf->samples,
28217ec681f3Smrg                                      surf->row_pitch_B,
28227ec681f3Smrg                                      surf->array_pitch_el_rows,
28237ec681f3Smrg                                      total_x_offset_el,
28247ec681f3Smrg                                      total_y_offset_el,
28257ec681f3Smrg                                      total_z_offset_el,
28267ec681f3Smrg                                      total_array_offset,
28277ec681f3Smrg                                      offset_B,
28287ec681f3Smrg                                      x_offset_el,
28297ec681f3Smrg                                      y_offset_el,
28307ec681f3Smrg                                      &z_offset_el,
28317ec681f3Smrg                                      &array_offset);
28327ec681f3Smrg   assert(z_offset_el == 0);
28337ec681f3Smrg   assert(array_offset == 0);
28347ec681f3Smrg}
28357ec681f3Smrg
28367ec681f3Smrgvoid
28377ec681f3Smrgisl_surf_get_image_range_B_tile(const struct isl_surf *surf,
28387ec681f3Smrg                                uint32_t level,
28397ec681f3Smrg                                uint32_t logical_array_layer,
28407ec681f3Smrg                                uint32_t logical_z_offset_px,
28417ec681f3Smrg                                uint64_t *start_tile_B,
28427ec681f3Smrg                                uint64_t *end_tile_B)
28437ec681f3Smrg{
28447ec681f3Smrg   uint32_t start_x_offset_el, start_y_offset_el;
28457ec681f3Smrg   uint32_t start_z_offset_el, start_array_slice;
28467ec681f3Smrg   isl_surf_get_image_offset_el(surf, level, logical_array_layer,
28477ec681f3Smrg                                logical_z_offset_px,
28487ec681f3Smrg                                &start_x_offset_el,
28497ec681f3Smrg                                &start_y_offset_el,
28507ec681f3Smrg                                &start_z_offset_el,
28517ec681f3Smrg                                &start_array_slice);
28527ec681f3Smrg
28537ec681f3Smrg   /* Compute the size of the subimage in surface elements */
28547ec681f3Smrg   const uint32_t subimage_w_sa = isl_minify(surf->phys_level0_sa.w, level);
28557ec681f3Smrg   const uint32_t subimage_h_sa = isl_minify(surf->phys_level0_sa.h, level);
28567ec681f3Smrg   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
28577ec681f3Smrg   const uint32_t subimage_w_el = isl_align_div_npot(subimage_w_sa, fmtl->bw);
28587ec681f3Smrg   const uint32_t subimage_h_el = isl_align_div_npot(subimage_h_sa, fmtl->bh);
28597ec681f3Smrg
28607ec681f3Smrg   /* Find the last pixel */
28617ec681f3Smrg   uint32_t end_x_offset_el = start_x_offset_el + subimage_w_el - 1;
28627ec681f3Smrg   uint32_t end_y_offset_el = start_y_offset_el + subimage_h_el - 1;
28637ec681f3Smrg
28647ec681f3Smrg   /* We only consider one Z or array slice */
28657ec681f3Smrg   const uint32_t end_z_offset_el = start_z_offset_el;
28667ec681f3Smrg   const uint32_t end_array_slice = start_array_slice;
28677ec681f3Smrg
28687ec681f3Smrg   UNUSED uint32_t x_offset_el, y_offset_el, z_offset_el, array_slice;
28697ec681f3Smrg   isl_tiling_get_intratile_offset_el(surf->tiling, surf->dim,
28707ec681f3Smrg                                      surf->msaa_layout, fmtl->bpb,
28717ec681f3Smrg                                      surf->samples,
28727ec681f3Smrg                                      surf->row_pitch_B,
28737ec681f3Smrg                                      surf->array_pitch_el_rows,
28747ec681f3Smrg                                      start_x_offset_el,
28757ec681f3Smrg                                      start_y_offset_el,
28767ec681f3Smrg                                      start_z_offset_el,
28777ec681f3Smrg                                      start_array_slice,
28787ec681f3Smrg                                      start_tile_B,
28797ec681f3Smrg                                      &x_offset_el,
28807ec681f3Smrg                                      &y_offset_el,
28817ec681f3Smrg                                      &z_offset_el,
28827ec681f3Smrg                                      &array_slice);
28837ec681f3Smrg
28847ec681f3Smrg   isl_tiling_get_intratile_offset_el(surf->tiling, surf->dim,
28857ec681f3Smrg                                      surf->msaa_layout, fmtl->bpb,
28867ec681f3Smrg                                      surf->samples,
28877ec681f3Smrg                                      surf->row_pitch_B,
28887ec681f3Smrg                                      surf->array_pitch_el_rows,
28897ec681f3Smrg                                      end_x_offset_el,
28907ec681f3Smrg                                      end_y_offset_el,
28917ec681f3Smrg                                      end_z_offset_el,
28927ec681f3Smrg                                      end_array_slice,
28937ec681f3Smrg                                      end_tile_B,
28947ec681f3Smrg                                      &x_offset_el,
28957ec681f3Smrg                                      &y_offset_el,
28967ec681f3Smrg                                      &z_offset_el,
28977ec681f3Smrg                                      &array_slice);
28987ec681f3Smrg
28997ec681f3Smrg   /* We want the range we return to be exclusive but the tile containing the
29007ec681f3Smrg    * last pixel (what we just calculated) is inclusive.  Add one.
29017ec681f3Smrg    */
29027ec681f3Smrg   (*end_tile_B)++;
29037ec681f3Smrg
29047ec681f3Smrg   assert(*end_tile_B <= surf->size_B);
29057ec681f3Smrg}
29067ec681f3Smrg
290701e04c3fSmrgvoid
290801e04c3fSmrgisl_surf_get_image_surf(const struct isl_device *dev,
290901e04c3fSmrg                        const struct isl_surf *surf,
291001e04c3fSmrg                        uint32_t level,
291101e04c3fSmrg                        uint32_t logical_array_layer,
291201e04c3fSmrg                        uint32_t logical_z_offset_px,
291301e04c3fSmrg                        struct isl_surf *image_surf,
29147ec681f3Smrg                        uint64_t *offset_B,
291501e04c3fSmrg                        uint32_t *x_offset_sa,
291601e04c3fSmrg                        uint32_t *y_offset_sa)
291701e04c3fSmrg{
291801e04c3fSmrg   isl_surf_get_image_offset_B_tile_sa(surf,
291901e04c3fSmrg                                       level,
292001e04c3fSmrg                                       logical_array_layer,
292101e04c3fSmrg                                       logical_z_offset_px,
292201e04c3fSmrg                                       offset_B,
292301e04c3fSmrg                                       x_offset_sa,
292401e04c3fSmrg                                       y_offset_sa);
292501e04c3fSmrg
292601e04c3fSmrg   /* Even for cube maps there will be only single face, therefore drop the
292701e04c3fSmrg    * corresponding flag if present.
292801e04c3fSmrg    */
292901e04c3fSmrg   const isl_surf_usage_flags_t usage =
293001e04c3fSmrg      surf->usage & (~ISL_SURF_USAGE_CUBE_BIT);
293101e04c3fSmrg
293201e04c3fSmrg   bool ok UNUSED;
293301e04c3fSmrg   ok = isl_surf_init(dev, image_surf,
293401e04c3fSmrg                      .dim = ISL_SURF_DIM_2D,
293501e04c3fSmrg                      .format = surf->format,
293601e04c3fSmrg                      .width = isl_minify(surf->logical_level0_px.w, level),
293701e04c3fSmrg                      .height = isl_minify(surf->logical_level0_px.h, level),
293801e04c3fSmrg                      .depth = 1,
293901e04c3fSmrg                      .levels = 1,
294001e04c3fSmrg                      .array_len = 1,
294101e04c3fSmrg                      .samples = surf->samples,
294201e04c3fSmrg                      .row_pitch_B = surf->row_pitch_B,
294301e04c3fSmrg                      .usage = usage,
294401e04c3fSmrg                      .tiling_flags = (1 << surf->tiling));
294501e04c3fSmrg   assert(ok);
294601e04c3fSmrg}
294701e04c3fSmrg
29487ec681f3Smrgbool
29497ec681f3Smrgisl_surf_get_uncompressed_surf(const struct isl_device *dev,
29507ec681f3Smrg                               const struct isl_surf *surf,
29517ec681f3Smrg                               const struct isl_view *view,
29527ec681f3Smrg                               struct isl_surf *ucompr_surf,
29537ec681f3Smrg                               struct isl_view *ucompr_view,
29547ec681f3Smrg                               uint64_t *offset_B,
29557ec681f3Smrg                               uint32_t *x_offset_el,
29567ec681f3Smrg                               uint32_t *y_offset_el)
29577ec681f3Smrg{
29587ec681f3Smrg   const struct isl_format_layout *fmtl =
29597ec681f3Smrg      isl_format_get_layout(surf->format);
29607ec681f3Smrg   const enum isl_format view_format = view->format;
29617ec681f3Smrg
29627ec681f3Smrg   assert(fmtl->bw > 1 || fmtl->bh > 1 || fmtl->bd > 1);
29637ec681f3Smrg   assert(isl_format_is_compressed(surf->format));
29647ec681f3Smrg   assert(!isl_format_is_compressed(view->format));
29657ec681f3Smrg   assert(isl_format_get_layout(view->format)->bpb == fmtl->bpb);
29667ec681f3Smrg   assert(view->levels == 1);
29677ec681f3Smrg
29687ec681f3Smrg   const uint32_t view_width_px =
29697ec681f3Smrg      isl_minify(surf->logical_level0_px.width, view->base_level);
29707ec681f3Smrg   const uint32_t view_height_px =
29717ec681f3Smrg      isl_minify(surf->logical_level0_px.height, view->base_level);
29727ec681f3Smrg
29737ec681f3Smrg   assert(surf->samples == 1);
29747ec681f3Smrg   const uint32_t view_width_el = isl_align_div_npot(view_width_px, fmtl->bw);
29757ec681f3Smrg   const uint32_t view_height_el = isl_align_div_npot(view_height_px, fmtl->bh);
29767ec681f3Smrg
29777ec681f3Smrg   /* If we ever enable 3D block formats, we'll need to re-think this */
29787ec681f3Smrg   assert(fmtl->bd == 1);
29797ec681f3Smrg
29807ec681f3Smrg   if (view->array_len > 1) {
29817ec681f3Smrg      /* The Skylake PRM Vol. 2d, "RENDER_SURFACE_STATE::X Offset" says:
29827ec681f3Smrg       *
29837ec681f3Smrg       *    "If Surface Array is enabled, this field must be zero."
29847ec681f3Smrg       *
29857ec681f3Smrg       * The PRMs for other hardware have similar text.  This is also tricky
29867ec681f3Smrg       * to handle with things like BLORP's SW offsetting because the
29877ec681f3Smrg       * increased surface size required for the offset may result in an image
29887ec681f3Smrg       * height greater than qpitch.
29897ec681f3Smrg       */
29907ec681f3Smrg      if (view->base_level > 0)
29917ec681f3Smrg         return false;
29927ec681f3Smrg
29937ec681f3Smrg      /* On Haswell and earlier, RENDER_SURFACE_STATE doesn't have a QPitch
29947ec681f3Smrg       * field; it only has "array pitch span" which means the QPitch is
29957ec681f3Smrg       * automatically calculated.  Since we're smashing the surface format
29967ec681f3Smrg       * (block formats are subtly different) and the number of miplevels,
29977ec681f3Smrg       * that calculation will get thrown off.  This means we can't do arrays
29987ec681f3Smrg       * even at LOD0
29997ec681f3Smrg       *
30007ec681f3Smrg       * On Broadwell, we do have a QPitch field which we can control.
30017ec681f3Smrg       * However, HALIGN and VALIGN are specified in pixels and are
30027ec681f3Smrg       * hard-coded to align to exactly the block size of the compressed
30037ec681f3Smrg       * texture.  This means that, when reinterpreted as a non-compressed
30047ec681f3Smrg       * the QPitch may be anything but the HW requires it to be properly
30057ec681f3Smrg       * aligned.
30067ec681f3Smrg       */
30077ec681f3Smrg      if (ISL_GFX_VER(dev) < 9)
30087ec681f3Smrg         return false;
30097ec681f3Smrg
30107ec681f3Smrg      *ucompr_surf = *surf;
30117ec681f3Smrg      ucompr_surf->levels = 1;
30127ec681f3Smrg      ucompr_surf->format = view_format;
30137ec681f3Smrg
30147ec681f3Smrg      /* We're making an uncompressed view here.  The image dimensions
30157ec681f3Smrg       * need to be scaled down by the block size.
30167ec681f3Smrg       */
30177ec681f3Smrg      assert(ucompr_surf->logical_level0_px.width == view_width_px);
30187ec681f3Smrg      assert(ucompr_surf->logical_level0_px.height == view_height_px);
30197ec681f3Smrg      ucompr_surf->logical_level0_px.width = view_width_el;
30207ec681f3Smrg      ucompr_surf->logical_level0_px.height = view_height_el;
30217ec681f3Smrg      ucompr_surf->phys_level0_sa = isl_surf_get_phys_level0_el(surf);
30227ec681f3Smrg
30237ec681f3Smrg      /* The surface mostly stays as-is; there is no offset */
30247ec681f3Smrg      *offset_B = 0;
30257ec681f3Smrg      *x_offset_el = 0;
30267ec681f3Smrg      *y_offset_el = 0;
30277ec681f3Smrg
30287ec681f3Smrg      /* The view remains the same */
30297ec681f3Smrg      *ucompr_view = *view;
30307ec681f3Smrg   } else {
30317ec681f3Smrg      /* If only one array slice is requested, directly offset to that slice.
30327ec681f3Smrg       * We could, in theory, still use arrays in some cases but BLORP isn't
30337ec681f3Smrg       * prepared for this and everyone who calls this function should be
30347ec681f3Smrg       * prepared to handle an X/Y offset.
30357ec681f3Smrg       */
30367ec681f3Smrg      isl_surf_get_image_offset_B_tile_el(surf,
30377ec681f3Smrg                                          view->base_level,
30387ec681f3Smrg                                          surf->dim == ISL_SURF_DIM_3D ?
30397ec681f3Smrg                                             0 : view->base_array_layer,
30407ec681f3Smrg                                          surf->dim == ISL_SURF_DIM_3D ?
30417ec681f3Smrg                                             view->base_array_layer : 0,
30427ec681f3Smrg                                          offset_B,
30437ec681f3Smrg                                          x_offset_el,
30447ec681f3Smrg                                          y_offset_el);
30457ec681f3Smrg
30467ec681f3Smrg      /* Even for cube maps there will be only single face, therefore drop the
30477ec681f3Smrg       * corresponding flag if present.
30487ec681f3Smrg       */
30497ec681f3Smrg      const isl_surf_usage_flags_t usage =
30507ec681f3Smrg         surf->usage & (~ISL_SURF_USAGE_CUBE_BIT);
30517ec681f3Smrg
30527ec681f3Smrg      bool ok UNUSED;
30537ec681f3Smrg      ok = isl_surf_init(dev, ucompr_surf,
30547ec681f3Smrg                         .dim = ISL_SURF_DIM_2D,
30557ec681f3Smrg                         .format = view_format,
30567ec681f3Smrg                         .width = view_width_el,
30577ec681f3Smrg                         .height = view_height_el,
30587ec681f3Smrg                         .depth = 1,
30597ec681f3Smrg                         .levels = 1,
30607ec681f3Smrg                         .array_len = 1,
30617ec681f3Smrg                         .samples = 1,
30627ec681f3Smrg                         .row_pitch_B = surf->row_pitch_B,
30637ec681f3Smrg                         .usage = usage,
30647ec681f3Smrg                         .tiling_flags = (1 << surf->tiling));
30657ec681f3Smrg      assert(ok);
30667ec681f3Smrg
30677ec681f3Smrg      /* The newly created image represents the one subimage we're
30687ec681f3Smrg       * referencing with this view so it only has one array slice and
30697ec681f3Smrg       * miplevel.
30707ec681f3Smrg       */
30717ec681f3Smrg      *ucompr_view = *view;
30727ec681f3Smrg      ucompr_view->base_array_layer = 0;
30737ec681f3Smrg      ucompr_view->base_level = 0;
30747ec681f3Smrg   }
30757ec681f3Smrg
30767ec681f3Smrg   return true;
30777ec681f3Smrg}
30787ec681f3Smrg
307901e04c3fSmrgvoid
308001e04c3fSmrgisl_tiling_get_intratile_offset_el(enum isl_tiling tiling,
30817ec681f3Smrg                                   enum isl_surf_dim dim,
30827ec681f3Smrg                                   enum isl_msaa_layout msaa_layout,
308301e04c3fSmrg                                   uint32_t bpb,
30847ec681f3Smrg                                   uint32_t samples,
308501e04c3fSmrg                                   uint32_t row_pitch_B,
30867ec681f3Smrg                                   uint32_t array_pitch_el_rows,
308701e04c3fSmrg                                   uint32_t total_x_offset_el,
308801e04c3fSmrg                                   uint32_t total_y_offset_el,
30897ec681f3Smrg                                   uint32_t total_z_offset_el,
30907ec681f3Smrg                                   uint32_t total_array_offset,
30917ec681f3Smrg                                   uint64_t *tile_offset_B,
309201e04c3fSmrg                                   uint32_t *x_offset_el,
30937ec681f3Smrg                                   uint32_t *y_offset_el,
30947ec681f3Smrg                                   uint32_t *z_offset_el,
30957ec681f3Smrg                                   uint32_t *array_offset)
309601e04c3fSmrg{
309701e04c3fSmrg   if (tiling == ISL_TILING_LINEAR) {
309801e04c3fSmrg      assert(bpb % 8 == 0);
30997ec681f3Smrg      assert(samples == 1);
31007ec681f3Smrg      assert(total_z_offset_el == 0 && total_array_offset == 0);
31017ec681f3Smrg      *tile_offset_B = (uint64_t)total_y_offset_el * row_pitch_B +
31027ec681f3Smrg                       (uint64_t)total_x_offset_el * (bpb / 8);
310301e04c3fSmrg      *x_offset_el = 0;
310401e04c3fSmrg      *y_offset_el = 0;
31057ec681f3Smrg      *z_offset_el = 0;
31067ec681f3Smrg      *array_offset = 0;
310701e04c3fSmrg      return;
310801e04c3fSmrg   }
310901e04c3fSmrg
311001e04c3fSmrg   struct isl_tile_info tile_info;
31117ec681f3Smrg   isl_tiling_get_info(tiling, dim, msaa_layout, bpb, samples, &tile_info);
311201e04c3fSmrg
31137ec681f3Smrg   /* Pitches must make sense with the tiling */
311401e04c3fSmrg   assert(row_pitch_B % tile_info.phys_extent_B.width == 0);
31157ec681f3Smrg   if (tile_info.logical_extent_el.d > 1 || tile_info.logical_extent_el.a > 1)
31167ec681f3Smrg      assert(array_pitch_el_rows % tile_info.logical_extent_el.h == 0);
311701e04c3fSmrg
311801e04c3fSmrg   /* For non-power-of-two formats, we need the address to be both tile and
311901e04c3fSmrg    * element-aligned.  The easiest way to achieve this is to work with a tile
312001e04c3fSmrg    * that is three times as wide as the regular tile.
312101e04c3fSmrg    *
312201e04c3fSmrg    * The tile info returned by get_tile_info has a logical size that is an
312301e04c3fSmrg    * integer number of tile_info.format_bpb size elements.  To scale the
312401e04c3fSmrg    * tile, we scale up the physical width and then treat the logical tile
312501e04c3fSmrg    * size as if it has bpb size elements.
312601e04c3fSmrg    */
312701e04c3fSmrg   const uint32_t tile_el_scale = bpb / tile_info.format_bpb;
312801e04c3fSmrg   tile_info.phys_extent_B.width *= tile_el_scale;
312901e04c3fSmrg
313001e04c3fSmrg   /* Compute the offset into the tile */
313101e04c3fSmrg   *x_offset_el = total_x_offset_el % tile_info.logical_extent_el.w;
313201e04c3fSmrg   *y_offset_el = total_y_offset_el % tile_info.logical_extent_el.h;
31337ec681f3Smrg   *z_offset_el = total_z_offset_el % tile_info.logical_extent_el.d;
31347ec681f3Smrg   *array_offset = total_array_offset % tile_info.logical_extent_el.a;
313501e04c3fSmrg
313601e04c3fSmrg   /* Compute the offset of the tile in units of whole tiles */
313701e04c3fSmrg   uint32_t x_offset_tl = total_x_offset_el / tile_info.logical_extent_el.w;
313801e04c3fSmrg   uint32_t y_offset_tl = total_y_offset_el / tile_info.logical_extent_el.h;
31397ec681f3Smrg   uint32_t z_offset_tl = total_z_offset_el / tile_info.logical_extent_el.d;
31407ec681f3Smrg   uint32_t a_offset_tl = total_array_offset / tile_info.logical_extent_el.a;
31417ec681f3Smrg
31427ec681f3Smrg   /* Compute an array pitch in number of tiles */
31437ec681f3Smrg   uint32_t array_pitch_tl_rows =
31447ec681f3Smrg      array_pitch_el_rows / tile_info.logical_extent_el.h;
314501e04c3fSmrg
31467ec681f3Smrg   /* Add the Z and array offset to the Y offset to get a 2D offset */
31477ec681f3Smrg   y_offset_tl += (z_offset_tl + a_offset_tl) * array_pitch_tl_rows;
31487ec681f3Smrg
31497ec681f3Smrg   *tile_offset_B =
31507ec681f3Smrg      (uint64_t)y_offset_tl * tile_info.phys_extent_B.h * row_pitch_B +
31517ec681f3Smrg      (uint64_t)x_offset_tl * tile_info.phys_extent_B.h * tile_info.phys_extent_B.w;
315201e04c3fSmrg}
315301e04c3fSmrg
315401e04c3fSmrguint32_t
315501e04c3fSmrgisl_surf_get_depth_format(const struct isl_device *dev,
315601e04c3fSmrg                          const struct isl_surf *surf)
315701e04c3fSmrg{
31587ec681f3Smrg   /* Support for separate stencil buffers began in gfx5. Support for
31597ec681f3Smrg    * interleaved depthstencil buffers ceased in gfx7. The intermediate gens,
31607ec681f3Smrg    * those that supported separate and interleaved stencil, were gfx5 and
31617ec681f3Smrg    * gfx6.
316201e04c3fSmrg    *
316301e04c3fSmrg    * For a list of all available formats, see the Sandybridge PRM >> Volume
316401e04c3fSmrg    * 2 Part 1: 3D/Media - 3D Pipeline >> 3DSTATE_DEPTH_BUFFER >> Surface
316501e04c3fSmrg    * Format (p321).
316601e04c3fSmrg    */
316701e04c3fSmrg
316801e04c3fSmrg   bool has_stencil = surf->usage & ISL_SURF_USAGE_STENCIL_BIT;
316901e04c3fSmrg
317001e04c3fSmrg   assert(surf->usage & ISL_SURF_USAGE_DEPTH_BIT);
317101e04c3fSmrg
317201e04c3fSmrg   if (has_stencil)
31737ec681f3Smrg      assert(ISL_GFX_VER(dev) < 7);
317401e04c3fSmrg
317501e04c3fSmrg   switch (surf->format) {
317601e04c3fSmrg   default:
317701e04c3fSmrg      unreachable("bad isl depth format");
317801e04c3fSmrg   case ISL_FORMAT_R32_FLOAT_X8X24_TYPELESS:
31797ec681f3Smrg      assert(ISL_GFX_VER(dev) < 7);
318001e04c3fSmrg      return 0; /* D32_FLOAT_S8X24_UINT */
318101e04c3fSmrg   case ISL_FORMAT_R32_FLOAT:
318201e04c3fSmrg      assert(!has_stencil);
318301e04c3fSmrg      return 1; /* D32_FLOAT */
318401e04c3fSmrg   case ISL_FORMAT_R24_UNORM_X8_TYPELESS:
318501e04c3fSmrg      if (has_stencil) {
31867ec681f3Smrg         assert(ISL_GFX_VER(dev) < 7);
318701e04c3fSmrg         return 2; /* D24_UNORM_S8_UINT */
318801e04c3fSmrg      } else {
31897ec681f3Smrg         assert(ISL_GFX_VER(dev) >= 5);
319001e04c3fSmrg         return 3; /* D24_UNORM_X8_UINT */
319101e04c3fSmrg      }
319201e04c3fSmrg   case ISL_FORMAT_R16_UNORM:
319301e04c3fSmrg      assert(!has_stencil);
319401e04c3fSmrg      return 5; /* D16_UNORM */
319501e04c3fSmrg   }
319601e04c3fSmrg}
319701e04c3fSmrg
319801e04c3fSmrgbool
31997ec681f3Smrgisl_swizzle_supports_rendering(const struct intel_device_info *devinfo,
320001e04c3fSmrg                               struct isl_swizzle swizzle)
320101e04c3fSmrg{
320201e04c3fSmrg   if (devinfo->is_haswell) {
320301e04c3fSmrg      /* From the Haswell PRM,
320401e04c3fSmrg       * RENDER_SURFACE_STATE::Shader Channel Select Red
320501e04c3fSmrg       *
320601e04c3fSmrg       *    "The Shader channel selects also define which shader channels are
320701e04c3fSmrg       *    written to which surface channel. If the Shader channel select is
320801e04c3fSmrg       *    SCS_ZERO or SCS_ONE then it is not written to the surface. If the
320901e04c3fSmrg       *    shader channel select is SCS_RED it is written to the surface red
321001e04c3fSmrg       *    channel and so on. If more than one shader channel select is set
321101e04c3fSmrg       *    to the same surface channel only the first shader channel in RGBA
321201e04c3fSmrg       *    order will be written."
321301e04c3fSmrg       */
321401e04c3fSmrg      return true;
32157ec681f3Smrg   } else if (devinfo->ver <= 7) {
321601e04c3fSmrg      /* Ivy Bridge and early doesn't have any swizzling */
321701e04c3fSmrg      return isl_swizzle_is_identity(swizzle);
321801e04c3fSmrg   } else {
321901e04c3fSmrg      /* From the Sky Lake PRM Vol. 2d,
322001e04c3fSmrg       * RENDER_SURFACE_STATE::Shader Channel Select Red
322101e04c3fSmrg       *
322201e04c3fSmrg       *    "For Render Target, Red, Green and Blue Shader Channel Selects
322301e04c3fSmrg       *    MUST be such that only valid components can be swapped i.e. only
322401e04c3fSmrg       *    change the order of components in the pixel. Any other values for
322501e04c3fSmrg       *    these Shader Channel Select fields are not valid for Render
322601e04c3fSmrg       *    Targets. This also means that there MUST not be multiple shader
322701e04c3fSmrg       *    channels mapped to the same RT channel."
322801e04c3fSmrg       *
322901e04c3fSmrg       * From the Sky Lake PRM Vol. 2d,
323001e04c3fSmrg       * RENDER_SURFACE_STATE::Shader Channel Select Alpha
323101e04c3fSmrg       *
323201e04c3fSmrg       *    "For Render Target, this field MUST be programmed to
323301e04c3fSmrg       *    value = SCS_ALPHA."
323401e04c3fSmrg       */
323501e04c3fSmrg      return (swizzle.r == ISL_CHANNEL_SELECT_RED ||
323601e04c3fSmrg              swizzle.r == ISL_CHANNEL_SELECT_GREEN ||
323701e04c3fSmrg              swizzle.r == ISL_CHANNEL_SELECT_BLUE) &&
323801e04c3fSmrg             (swizzle.g == ISL_CHANNEL_SELECT_RED ||
323901e04c3fSmrg              swizzle.g == ISL_CHANNEL_SELECT_GREEN ||
324001e04c3fSmrg              swizzle.g == ISL_CHANNEL_SELECT_BLUE) &&
324101e04c3fSmrg             (swizzle.b == ISL_CHANNEL_SELECT_RED ||
324201e04c3fSmrg              swizzle.b == ISL_CHANNEL_SELECT_GREEN ||
324301e04c3fSmrg              swizzle.b == ISL_CHANNEL_SELECT_BLUE) &&
324401e04c3fSmrg             swizzle.r != swizzle.g &&
324501e04c3fSmrg             swizzle.r != swizzle.b &&
324601e04c3fSmrg             swizzle.g != swizzle.b &&
324701e04c3fSmrg             swizzle.a == ISL_CHANNEL_SELECT_ALPHA;
324801e04c3fSmrg   }
324901e04c3fSmrg}
325001e04c3fSmrg
325101e04c3fSmrgstatic enum isl_channel_select
325201e04c3fSmrgswizzle_select(enum isl_channel_select chan, struct isl_swizzle swizzle)
325301e04c3fSmrg{
325401e04c3fSmrg   switch (chan) {
325501e04c3fSmrg   case ISL_CHANNEL_SELECT_ZERO:
325601e04c3fSmrg   case ISL_CHANNEL_SELECT_ONE:
325701e04c3fSmrg      return chan;
325801e04c3fSmrg   case ISL_CHANNEL_SELECT_RED:
325901e04c3fSmrg      return swizzle.r;
326001e04c3fSmrg   case ISL_CHANNEL_SELECT_GREEN:
326101e04c3fSmrg      return swizzle.g;
326201e04c3fSmrg   case ISL_CHANNEL_SELECT_BLUE:
326301e04c3fSmrg      return swizzle.b;
326401e04c3fSmrg   case ISL_CHANNEL_SELECT_ALPHA:
326501e04c3fSmrg      return swizzle.a;
326601e04c3fSmrg   default:
326701e04c3fSmrg      unreachable("Invalid swizzle component");
326801e04c3fSmrg   }
326901e04c3fSmrg}
327001e04c3fSmrg
327101e04c3fSmrg/**
327201e04c3fSmrg * Returns the single swizzle that is equivalent to applying the two given
327301e04c3fSmrg * swizzles in sequence.
327401e04c3fSmrg */
327501e04c3fSmrgstruct isl_swizzle
327601e04c3fSmrgisl_swizzle_compose(struct isl_swizzle first, struct isl_swizzle second)
327701e04c3fSmrg{
327801e04c3fSmrg   return (struct isl_swizzle) {
327901e04c3fSmrg      .r = swizzle_select(first.r, second),
328001e04c3fSmrg      .g = swizzle_select(first.g, second),
328101e04c3fSmrg      .b = swizzle_select(first.b, second),
328201e04c3fSmrg      .a = swizzle_select(first.a, second),
328301e04c3fSmrg   };
328401e04c3fSmrg}
328501e04c3fSmrg
328601e04c3fSmrg/**
328701e04c3fSmrg * Returns a swizzle that is the pseudo-inverse of this swizzle.
328801e04c3fSmrg */
328901e04c3fSmrgstruct isl_swizzle
329001e04c3fSmrgisl_swizzle_invert(struct isl_swizzle swizzle)
329101e04c3fSmrg{
329201e04c3fSmrg   /* Default to zero for channels which do not show up in the swizzle */
329301e04c3fSmrg   enum isl_channel_select chans[4] = {
329401e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
329501e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
329601e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
329701e04c3fSmrg      ISL_CHANNEL_SELECT_ZERO,
329801e04c3fSmrg   };
329901e04c3fSmrg
330001e04c3fSmrg   /* We go in ABGR order so that, if there are any duplicates, the first one
330101e04c3fSmrg    * is taken if you look at it in RGBA order.  This is what Haswell hardware
330201e04c3fSmrg    * does for render target swizzles.
330301e04c3fSmrg    */
330401e04c3fSmrg   if ((unsigned)(swizzle.a - ISL_CHANNEL_SELECT_RED) < 4)
330501e04c3fSmrg      chans[swizzle.a - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_ALPHA;
330601e04c3fSmrg   if ((unsigned)(swizzle.b - ISL_CHANNEL_SELECT_RED) < 4)
330701e04c3fSmrg      chans[swizzle.b - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_BLUE;
330801e04c3fSmrg   if ((unsigned)(swizzle.g - ISL_CHANNEL_SELECT_RED) < 4)
330901e04c3fSmrg      chans[swizzle.g - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_GREEN;
331001e04c3fSmrg   if ((unsigned)(swizzle.r - ISL_CHANNEL_SELECT_RED) < 4)
331101e04c3fSmrg      chans[swizzle.r - ISL_CHANNEL_SELECT_RED] = ISL_CHANNEL_SELECT_RED;
331201e04c3fSmrg
331301e04c3fSmrg   return (struct isl_swizzle) { chans[0], chans[1], chans[2], chans[3] };
331401e04c3fSmrg}
33157ec681f3Smrg
33167ec681f3Smrg/** Applies an inverse swizzle to a color value */
33177ec681f3Smrgunion isl_color_value
33187ec681f3Smrgisl_color_value_swizzle_inv(union isl_color_value src,
33197ec681f3Smrg                            struct isl_swizzle swizzle)
33207ec681f3Smrg{
33217ec681f3Smrg   union isl_color_value dst = { .u32 = { 0, } };
33227ec681f3Smrg
33237ec681f3Smrg   /* We assign colors in ABGR order so that the first one will be taken in
33247ec681f3Smrg    * RGBA precedence order.  According to the PRM docs for shader channel
33257ec681f3Smrg    * select, this matches Haswell hardware behavior.
33267ec681f3Smrg    */
33277ec681f3Smrg   if ((unsigned)(swizzle.a - ISL_CHANNEL_SELECT_RED) < 4)
33287ec681f3Smrg      dst.u32[swizzle.a - ISL_CHANNEL_SELECT_RED] = src.u32[3];
33297ec681f3Smrg   if ((unsigned)(swizzle.b - ISL_CHANNEL_SELECT_RED) < 4)
33307ec681f3Smrg      dst.u32[swizzle.b - ISL_CHANNEL_SELECT_RED] = src.u32[2];
33317ec681f3Smrg   if ((unsigned)(swizzle.g - ISL_CHANNEL_SELECT_RED) < 4)
33327ec681f3Smrg      dst.u32[swizzle.g - ISL_CHANNEL_SELECT_RED] = src.u32[1];
33337ec681f3Smrg   if ((unsigned)(swizzle.r - ISL_CHANNEL_SELECT_RED) < 4)
33347ec681f3Smrg      dst.u32[swizzle.r - ISL_CHANNEL_SELECT_RED] = src.u32[0];
33357ec681f3Smrg
33367ec681f3Smrg   return dst;
33377ec681f3Smrg}
33387ec681f3Smrg
33397ec681f3Smrguint8_t
33407ec681f3Smrgisl_format_get_aux_map_encoding(enum isl_format format)
33417ec681f3Smrg{
33427ec681f3Smrg   switch(format) {
33437ec681f3Smrg   case ISL_FORMAT_R32G32B32A32_FLOAT: return 0x11;
33447ec681f3Smrg   case ISL_FORMAT_R32G32B32X32_FLOAT: return 0x11;
33457ec681f3Smrg   case ISL_FORMAT_R32G32B32A32_SINT: return 0x12;
33467ec681f3Smrg   case ISL_FORMAT_R32G32B32A32_UINT: return 0x13;
33477ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_UNORM: return 0x14;
33487ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_SNORM: return 0x15;
33497ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_SINT: return 0x16;
33507ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_UINT: return 0x17;
33517ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_FLOAT: return 0x10;
33527ec681f3Smrg   case ISL_FORMAT_R16G16B16X16_FLOAT: return 0x10;
33537ec681f3Smrg   case ISL_FORMAT_R32G32_FLOAT: return 0x11;
33547ec681f3Smrg   case ISL_FORMAT_R32G32_SINT: return 0x12;
33557ec681f3Smrg   case ISL_FORMAT_R32G32_UINT: return 0x13;
33567ec681f3Smrg   case ISL_FORMAT_B8G8R8A8_UNORM: return 0xA;
33577ec681f3Smrg   case ISL_FORMAT_B8G8R8X8_UNORM: return 0xA;
33587ec681f3Smrg   case ISL_FORMAT_B8G8R8A8_UNORM_SRGB: return 0xA;
33597ec681f3Smrg   case ISL_FORMAT_B8G8R8X8_UNORM_SRGB: return 0xA;
33607ec681f3Smrg   case ISL_FORMAT_R10G10B10A2_UNORM: return 0x18;
33617ec681f3Smrg   case ISL_FORMAT_R10G10B10A2_UNORM_SRGB: return 0x18;
33627ec681f3Smrg   case ISL_FORMAT_R10G10B10_FLOAT_A2_UNORM: return 0x19;
33637ec681f3Smrg   case ISL_FORMAT_R10G10B10A2_UINT: return 0x1A;
33647ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_UNORM: return 0xA;
33657ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_UNORM_SRGB: return 0xA;
33667ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_SNORM: return 0x1B;
33677ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_SINT: return 0x1C;
33687ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_UINT: return 0x1D;
33697ec681f3Smrg   case ISL_FORMAT_R16G16_UNORM: return 0x14;
33707ec681f3Smrg   case ISL_FORMAT_R16G16_SNORM: return 0x15;
33717ec681f3Smrg   case ISL_FORMAT_R16G16_SINT: return 0x16;
33727ec681f3Smrg   case ISL_FORMAT_R16G16_UINT: return 0x17;
33737ec681f3Smrg   case ISL_FORMAT_R16G16_FLOAT: return 0x10;
33747ec681f3Smrg   case ISL_FORMAT_B10G10R10A2_UNORM: return 0x18;
33757ec681f3Smrg   case ISL_FORMAT_B10G10R10A2_UNORM_SRGB: return 0x18;
33767ec681f3Smrg   case ISL_FORMAT_R11G11B10_FLOAT: return 0x1E;
33777ec681f3Smrg   case ISL_FORMAT_R32_SINT: return 0x12;
33787ec681f3Smrg   case ISL_FORMAT_R32_UINT: return 0x13;
33797ec681f3Smrg   case ISL_FORMAT_R32_FLOAT: return 0x11;
33807ec681f3Smrg   case ISL_FORMAT_R24_UNORM_X8_TYPELESS: return 0x13;
33817ec681f3Smrg   case ISL_FORMAT_B5G6R5_UNORM: return 0xA;
33827ec681f3Smrg   case ISL_FORMAT_B5G6R5_UNORM_SRGB: return 0xA;
33837ec681f3Smrg   case ISL_FORMAT_B5G5R5A1_UNORM: return 0xA;
33847ec681f3Smrg   case ISL_FORMAT_B5G5R5A1_UNORM_SRGB: return 0xA;
33857ec681f3Smrg   case ISL_FORMAT_B4G4R4A4_UNORM: return 0xA;
33867ec681f3Smrg   case ISL_FORMAT_B4G4R4A4_UNORM_SRGB: return 0xA;
33877ec681f3Smrg   case ISL_FORMAT_R8G8_UNORM: return 0xA;
33887ec681f3Smrg   case ISL_FORMAT_R8G8_SNORM: return 0x1B;
33897ec681f3Smrg   case ISL_FORMAT_R8G8_SINT: return 0x1C;
33907ec681f3Smrg   case ISL_FORMAT_R8G8_UINT: return 0x1D;
33917ec681f3Smrg   case ISL_FORMAT_R16_UNORM: return 0x14;
33927ec681f3Smrg   case ISL_FORMAT_R16_SNORM: return 0x15;
33937ec681f3Smrg   case ISL_FORMAT_R16_SINT: return 0x16;
33947ec681f3Smrg   case ISL_FORMAT_R16_UINT: return 0x17;
33957ec681f3Smrg   case ISL_FORMAT_R16_FLOAT: return 0x10;
33967ec681f3Smrg   case ISL_FORMAT_B5G5R5X1_UNORM: return 0xA;
33977ec681f3Smrg   case ISL_FORMAT_B5G5R5X1_UNORM_SRGB: return 0xA;
33987ec681f3Smrg   case ISL_FORMAT_A1B5G5R5_UNORM: return 0xA;
33997ec681f3Smrg   case ISL_FORMAT_A4B4G4R4_UNORM: return 0xA;
34007ec681f3Smrg   case ISL_FORMAT_R8_UNORM: return 0xA;
34017ec681f3Smrg   case ISL_FORMAT_R8_SNORM: return 0x1B;
34027ec681f3Smrg   case ISL_FORMAT_R8_SINT: return 0x1C;
34037ec681f3Smrg   case ISL_FORMAT_R8_UINT: return 0x1D;
34047ec681f3Smrg   case ISL_FORMAT_A8_UNORM: return 0xA;
34057ec681f3Smrg   case ISL_FORMAT_PLANAR_420_8: return 0xF;
34067ec681f3Smrg   case ISL_FORMAT_PLANAR_420_10: return 0x7;
34077ec681f3Smrg   case ISL_FORMAT_PLANAR_420_12: return 0x8;
34087ec681f3Smrg   case ISL_FORMAT_PLANAR_420_16: return 0x8;
34097ec681f3Smrg   case ISL_FORMAT_YCRCB_NORMAL: return 0x3;
34107ec681f3Smrg   case ISL_FORMAT_YCRCB_SWAPY: return 0xB;
34117ec681f3Smrg   default:
34127ec681f3Smrg      unreachable("Unsupported aux-map format!");
34137ec681f3Smrg      return 0;
34147ec681f3Smrg   }
34157ec681f3Smrg}
34167ec681f3Smrg
34177ec681f3Smrg/*
34187ec681f3Smrg * Returns compression format encoding for Unified Lossless Compression
34197ec681f3Smrg */
34207ec681f3Smrguint8_t
34217ec681f3Smrgisl_get_render_compression_format(enum isl_format format)
34227ec681f3Smrg{
34237ec681f3Smrg   /* From the Bspec, Enumeration_RenderCompressionFormat section (53726): */
34247ec681f3Smrg   switch(format) {
34257ec681f3Smrg   case ISL_FORMAT_R32G32B32A32_FLOAT:
34267ec681f3Smrg   case ISL_FORMAT_R32G32B32X32_FLOAT:
34277ec681f3Smrg   case ISL_FORMAT_R32G32B32A32_SINT:
34287ec681f3Smrg      return 0x0;
34297ec681f3Smrg   case ISL_FORMAT_R32G32B32A32_UINT:
34307ec681f3Smrg      return 0x1;
34317ec681f3Smrg   case ISL_FORMAT_R32G32_FLOAT:
34327ec681f3Smrg   case ISL_FORMAT_R32G32_SINT:
34337ec681f3Smrg      return 0x2;
34347ec681f3Smrg   case ISL_FORMAT_R32G32_UINT:
34357ec681f3Smrg      return 0x3;
34367ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_UNORM:
34377ec681f3Smrg   case ISL_FORMAT_R16G16B16X16_UNORM:
34387ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_UINT:
34397ec681f3Smrg      return 0x4;
34407ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_SNORM:
34417ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_SINT:
34427ec681f3Smrg   case ISL_FORMAT_R16G16B16A16_FLOAT:
34437ec681f3Smrg   case ISL_FORMAT_R16G16B16X16_FLOAT:
34447ec681f3Smrg      return 0x5;
34457ec681f3Smrg   case ISL_FORMAT_R16G16_UNORM:
34467ec681f3Smrg   case ISL_FORMAT_R16G16_UINT:
34477ec681f3Smrg      return 0x6;
34487ec681f3Smrg   case ISL_FORMAT_R16G16_SNORM:
34497ec681f3Smrg   case ISL_FORMAT_R16G16_SINT:
34507ec681f3Smrg   case ISL_FORMAT_R16G16_FLOAT:
34517ec681f3Smrg      return 0x7;
34527ec681f3Smrg   case ISL_FORMAT_B8G8R8A8_UNORM:
34537ec681f3Smrg   case ISL_FORMAT_B8G8R8X8_UNORM:
34547ec681f3Smrg   case ISL_FORMAT_B8G8R8A8_UNORM_SRGB:
34557ec681f3Smrg   case ISL_FORMAT_B8G8R8X8_UNORM_SRGB:
34567ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_UNORM:
34577ec681f3Smrg   case ISL_FORMAT_R8G8B8X8_UNORM:
34587ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_UNORM_SRGB:
34597ec681f3Smrg   case ISL_FORMAT_R8G8B8X8_UNORM_SRGB:
34607ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_UINT:
34617ec681f3Smrg      return 0x8;
34627ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_SNORM:
34637ec681f3Smrg   case ISL_FORMAT_R8G8B8A8_SINT:
34647ec681f3Smrg      return 0x9;
34657ec681f3Smrg   case ISL_FORMAT_B5G6R5_UNORM:
34667ec681f3Smrg   case ISL_FORMAT_B5G6R5_UNORM_SRGB:
34677ec681f3Smrg   case ISL_FORMAT_B5G5R5A1_UNORM:
34687ec681f3Smrg   case ISL_FORMAT_B5G5R5A1_UNORM_SRGB:
34697ec681f3Smrg   case ISL_FORMAT_B4G4R4A4_UNORM:
34707ec681f3Smrg   case ISL_FORMAT_B4G4R4A4_UNORM_SRGB:
34717ec681f3Smrg   case ISL_FORMAT_B5G5R5X1_UNORM:
34727ec681f3Smrg   case ISL_FORMAT_B5G5R5X1_UNORM_SRGB:
34737ec681f3Smrg   case ISL_FORMAT_A1B5G5R5_UNORM:
34747ec681f3Smrg   case ISL_FORMAT_A4B4G4R4_UNORM:
34757ec681f3Smrg   case ISL_FORMAT_R8G8_UNORM:
34767ec681f3Smrg   case ISL_FORMAT_R8G8_UINT:
34777ec681f3Smrg      return 0xA;
34787ec681f3Smrg   case ISL_FORMAT_R8G8_SNORM:
34797ec681f3Smrg   case ISL_FORMAT_R8G8_SINT:
34807ec681f3Smrg      return 0xB;
34817ec681f3Smrg   case ISL_FORMAT_R10G10B10A2_UNORM:
34827ec681f3Smrg   case ISL_FORMAT_R10G10B10A2_UNORM_SRGB:
34837ec681f3Smrg   case ISL_FORMAT_R10G10B10_FLOAT_A2_UNORM:
34847ec681f3Smrg   case ISL_FORMAT_R10G10B10A2_UINT:
34857ec681f3Smrg   case ISL_FORMAT_B10G10R10A2_UNORM:
34867ec681f3Smrg   case ISL_FORMAT_B10G10R10X2_UNORM:
34877ec681f3Smrg   case ISL_FORMAT_B10G10R10A2_UNORM_SRGB:
34887ec681f3Smrg      return 0xC;
34897ec681f3Smrg   case ISL_FORMAT_R11G11B10_FLOAT:
34907ec681f3Smrg      return 0xD;
34917ec681f3Smrg   case ISL_FORMAT_R32_SINT:
34927ec681f3Smrg   case ISL_FORMAT_R32_FLOAT:
34937ec681f3Smrg      return 0x10;
34947ec681f3Smrg   case ISL_FORMAT_R32_UINT:
34957ec681f3Smrg   case ISL_FORMAT_R24_UNORM_X8_TYPELESS:
34967ec681f3Smrg      return 0x11;
34977ec681f3Smrg   case ISL_FORMAT_R16_UNORM:
34987ec681f3Smrg   case ISL_FORMAT_R16_UINT:
34997ec681f3Smrg      return 0x14;
35007ec681f3Smrg   case ISL_FORMAT_R16_SNORM:
35017ec681f3Smrg   case ISL_FORMAT_R16_SINT:
35027ec681f3Smrg   case ISL_FORMAT_R16_FLOAT:
35037ec681f3Smrg      return 0x15;
35047ec681f3Smrg   case ISL_FORMAT_R8_UNORM:
35057ec681f3Smrg   case ISL_FORMAT_R8_UINT:
35067ec681f3Smrg   case ISL_FORMAT_A8_UNORM:
35077ec681f3Smrg      return 0x18;
35087ec681f3Smrg   case ISL_FORMAT_R8_SNORM:
35097ec681f3Smrg   case ISL_FORMAT_R8_SINT:
35107ec681f3Smrg      return 0x19;
35117ec681f3Smrg   default:
35127ec681f3Smrg      unreachable("Unsupported render compression format!");
35137ec681f3Smrg      return 0;
35147ec681f3Smrg   }
35157ec681f3Smrg}
3516