text: /*==============================================================================
  Copyright(c) 2017 Intel Corporation
  
  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files(the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and / or sell copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
  ============================================================================*/
  
  #include "GmmResourceULT.h"
  
  /////////////////////////////////////////////////////////////////////////////////////
  /// CTestResource Constructor
  /////////////////////////////////////////////////////////////////////////////////////
  CTestResource::CTestResource()
  {
  }
  
  
  /////////////////////////////////////////////////////////////////////////////////////
  /// CTestResource Destructor
  ///
  /////////////////////////////////////////////////////////////////////////////////////
  CTestResource::~CTestResource()
  {
  }
  
  /////////////////////////////////////////////////////////////////////////////////////
  /// Sets up common environment for Resource fixture tests. this is called once per
  /// test case before executing all tests under resource fixture test case.
  ///  It also calls SetupTestCase from CommonULT to initialize global context and others.
  ///
  /// @see    CTestResource::SetUpTestCase()
  ///
  /////////////////////////////////////////////////////////////////////////////////////
  void CTestResource::SetUpTestCase()
  {
      printf("%s\n", __FUNCTION__);
  
      GfxPlatform.eProductFamily    = IGFX_BROADWELL;
      GfxPlatform.eRenderCoreFamily = IGFX_GEN8_CORE;
  
      CommonULT::SetUpTestCase();
  }
  
  /////////////////////////////////////////////////////////////////////////////////////
  /// Cleans up once all the tests finish execution.  It also calls TearDownTestCase
  /// from CommonULT to destroy global context and others.
  ///
  /// @see    CTestResource::TearDownTestCase()
  /////////////////////////////////////////////////////////////////////////////////////
  void CTestResource::TearDownTestCase()
  {
      printf("%s\n", __FUNCTION__);
  
      CommonULT::TearDownTestCase();
  }
  
  /// @brief ULT for 1D Linear Resource
  TEST_F(CTestResource, Test1DLinearResource)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign         = 16;
      const uint32_t VAlign         = 4;
      const uint32_t MinPitch       = 32;
      const uint32_t PitchAlignment = 64;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_1D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes           = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes           = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
          VerifyResourceQPitch<false>(ResourceInfo, 0); // Not valid for 1D
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
  
      // Allocate more than 1 page
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1001;
          gmmParams.BaseHeight  = 1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes           = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes           = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
          VerifyResourceQPitch<false>(ResourceInfo, 0);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 1D Linear Resource Arrays
  TEST_F(CTestResource, Test1DLinearResourceArrays)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign         = 16;
      const uint32_t VAlign         = 4;
      const uint32_t MinPitch       = 32;
      const uint32_t PitchAlignment = 64;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_1D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.ArraySize            = 4;
  
      // Allocate 1x1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x100;
          gmmParams.BaseHeight  = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes           = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes           = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
          VerifyResourceQPitch<true>(ResourceInfo, AlignedHeight);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 1D Mipped Linear Resource
  TEST_F(CTestResource, Test1DLinearResourceMips)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign         = 16;
      const uint32_t VAlign         = 4;
      const uint32_t MinPitch       = 32;
      const uint32_t PitchAlignment = 64;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_1D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.MaxLod               = 5;
  
      // Allocate 256x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x100;
          gmmParams.BaseHeight  = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          // Height of 1D surface will just be VAlign. So height of the whole block will be
          // Height of Mip0 + Mip2 + Mip3 + Mip4 + Mip5...
          AlignedHeight         = gmmParams.MaxLod * AlignedHeight;
          uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes          = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes          = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          uint32_t AlignedSize  = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for non-arrayed surface
  
          // Mip0 should be at offset 0. X/Y/Z Offset should be 0 for linear.
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1 should be after Mip0.  X/Y/Z Offset should be 0 for linear.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; //Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
          uint32_t SizeOfMip0 = PitchInBytes * GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2 should to the right of Mip1.  X/Y/Z Offset should be 0 for linear.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2; //Mip 2
          ResourceInfo->GetOffset(OffsetInfo);
          uint32_t StartOfMip = SizeOfMip0 + (GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign) * GetBppValue(bpp));
          EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Rest of the mips should be below mip2, each with height of HAlign. X/Y/Z Offset should be 0 for linear.
          for(int mip = 3; mip <= gmmParams.MaxLod; mip++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = mip;
              ResourceInfo->GetOffset(OffsetInfo);
              StartOfMip += PitchInBytes * VAlign;
              EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64);
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);
              EXPECT_EQ(0, OffsetInfo.Render.YOffset);
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  
  // ********************************************************************************//
  
  /// @brief ULT for 2D Linear Resource Arrays
  TEST_F(CTestResource, Test2DLinearResourceArrays)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign         = 16;
      const uint32_t VAlign         = 4;
      const uint32_t MinPitch       = 32;
      const uint32_t PitchAlignment = 64;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.ArraySize            = 4;
  
      // Allocate 256x256 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x100;
          gmmParams.BaseHeight  = 0x100;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes           = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes           = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
          VerifyResourceQPitch<true>(ResourceInfo, AlignedHeight);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 2D Mipped Linear Resource
  TEST_F(CTestResource, Test2DLinearResourceMips)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign         = 16;
      const uint32_t VAlign         = 4;
      const uint32_t MinPitch       = 32;
      const uint32_t PitchAlignment = 64;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.MaxLod               = 8;
  
      // Allocate 256x256 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x100;
          gmmParams.BaseHeight  = 0x100;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t AlignedHeight;
          uint32_t PitchInBytes    = AlignedWidth * GetBppValue(bpp);
          PitchInBytes             = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes             = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          uint32_t HeightOfPrevMip = AlignedHeight = gmmParams.BaseHeight;
  
          // Mip0 should be at offset 0. X/Y/Z Offset should be 0 for linear.
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1 should be after Mip0.  X/Y/Z Offset should be 0 for linear.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; //Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
          uint32_t SizeOfMip0 = PitchInBytes * GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2 should to the right of Mip1.  X/Y/Z Offset should be 0 for linear.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2; //Mip 2
          ResourceInfo->GetOffset(OffsetInfo);
          uint32_t StartOfMip = SizeOfMip0 + (GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign) * GetBppValue(bpp));
          EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Rest of the mips should be below mip2, each with height of HAlign. X/Y/Z Offset should be 0 for linear.
          for(int mip = 3; mip <= 8; mip++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = mip;
              ResourceInfo->GetOffset(OffsetInfo);
              HeightOfPrevMip = GMM_ULT_ALIGN((gmmParams.BaseHeight >> (mip - 1)), VAlign);
              AlignedHeight += HeightOfPrevMip;
              StartOfMip += PitchInBytes * HeightOfPrevMip;
              EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64);
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);
              EXPECT_EQ(0, OffsetInfo.Render.YOffset);
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          //Mip8 will go till Mip0Height + Mip1Height + VALIGN
          AlignedHeight += VAlign;
          uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for non-arrayed surface
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Arrayed 2D TileX Resource
  TEST_F(CTestResource, Test2DTileXResourceArrays)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileWidth  = 512;
      const uint32_t TileHeight = 8;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledX    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.ArraySize            = 4;
  
      // Allocate 2 tiles in X/Y dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = TileHeight + 1;                     // 1 row larger than 1 tile height
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileWidth);
  
          uint32_t AlignedHeight, BlockHeight;
          BlockHeight   = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          AlignedHeight = GMM_ULT_ALIGN_NP2(BlockHeight * gmmParams.ArraySize, TileHeight);
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);                    // As wide as 2 tile
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileWidth); // 2 tile wide
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes * AlignedHeight);     // 4 tile big x 4 array size
  
          VerifyResourceQPitch<true>(ResourceInfo, BlockHeight);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Mipped 2D TileX Resource
  TEST_F(CTestResource, Test2DTileXResourceMips)
  {
      const uint32_t TileSize[2] = {512, 8};
      enum Coords
      {
          X = 0,
          Y = 1
      };
  
      // Test normal mip case
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          const uint32_t ResourceWidth  = 0x400;
          const uint32_t ResourceHeight = 0x400;
          const uint32_t MaxLod         = 10;
  
  
          TEST_BPP             bpp       = static_cast<TEST_BPP>(i);
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.Flags.Info.TiledX    = 1;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = ResourceWidth;
          gmmParams.BaseHeight           = ResourceHeight;
          gmmParams.MaxLod               = MaxLod;
          gmmParams.Format               = SetResourceFormat(bpp);
  
          // Create resource
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          // Mip0 is the widest mip. So it will dictate the pitch of the whole surface
          const uint32_t Pitch            = ResourceWidth * GetBppValue(bpp);
          uint32_t       AllocationHeight = 0;
  
          // Mip0 should be at offset 0 and tile aligned
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1 should be after whole Mip0. Should still be tile aligned.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; // Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
          uint32_t SizeOfMip0      = Pitch * ResourceHeight;
          uint32_t HeightOfPrevMip = AllocationHeight = ResourceHeight;
          EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2 should be on the right of Mip1. Should still be tile aligned.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2; // Mip 2
          ResourceInfo->GetOffset(OffsetInfo);
          // MipOffset = Mip1Offset + Mip1Width in tiles
          uint32_t MipOffset = SizeOfMip0 + ((Pitch >> 1) / TileSize[X]) * PAGE_SIZE;
          EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mips 3-8 should be on tile boundary
          for(int i = 3; i < 9; i++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = i;
              ResourceInfo->GetOffset(OffsetInfo);
  
              HeightOfPrevMip = (ResourceHeight >> (i - 1));
              AllocationHeight += HeightOfPrevMip;
              MipOffset += Pitch * HeightOfPrevMip;
              EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64);
              // No X/Y/Z offset since mip is at tile boundary
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);
              EXPECT_EQ(0, OffsetInfo.Render.YOffset);
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          // Mips 9 will share 1 tile with Mip 8
          AllocationHeight += TileSize[Y];
          uint32_t HeightOfPrevMipsInTile = 0;
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = 9;
              ResourceInfo->GetOffset(OffsetInfo);
  
              EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); // Same as previous tile aligned mip offset
  
              // X is 0, but Y offset will change
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);
              HeightOfPrevMipsInTile += (ResourceHeight >> (9 - 1));
              EXPECT_EQ(HeightOfPrevMipsInTile, OffsetInfo.Render.YOffset);
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          // Mip 10 is back on tile boundary
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 10; // Mip 10
          ResourceInfo->GetOffset(OffsetInfo);
  
          MipOffset += Pitch * TileSize[Y];
          AllocationHeight += TileSize[Y];
          EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Verify ResourceSize and Pitch
          VerifyResourceSize<true>(ResourceInfo, AllocationHeight * Pitch);
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[X]);
          // These are verified elsewhere
          VerifyResourceHAlign<false>(ResourceInfo, 0);
          VerifyResourceVAlign<false>(ResourceInfo, 0);
          VerifyResourceQPitch<false>(ResourceInfo, 0);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
  
      // Test where Mip1 + Mip2 width > Mip0 width, and where everything fits in 1 tile
      for(uint32_t i = 0; i < TEST_BPP_64; i++)
      {
          const uint32_t ResourceWidth  = 0x4;
          const uint32_t ResourceHeight = 0x2;
          const uint32_t MaxLod         = 0x2;
  
          TEST_BPP             bpp       = static_cast<TEST_BPP>(i);
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.Flags.Info.TiledX    = 1;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = ResourceWidth;
          gmmParams.BaseHeight           = ResourceHeight;
          gmmParams.MaxLod               = MaxLod;
          gmmParams.Format               = SetResourceFormat(bpp);
  
          // Create resource
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          // Get Alignment that GmmLib is using
          const uint32_t HAlign = ResourceInfo->GetHAlign();
          const uint32_t VAlign = ResourceInfo->GetVAlign();
  
          // Mip1 + Mip2 is the widest width. So it will dictate the pitch of the whole surface
          uint32_t Pitch = GetBppValue(bpp) *
                           (GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) + GMM_ULT_ALIGN(ResourceWidth >> 2, HAlign));
          Pitch = GMM_ULT_ALIGN(Pitch, TileSize[X]);
  
          // Mip0 should be at offset 0 and tile aligned
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1 should be after whole Mip0. Not tile aligned
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; // Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same tile as Mip0
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2 should be on the right of Mip1. Not tile aligned
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2; // Mip 2
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same Tile as Mip0
          uint32_t Mip1Width = GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) * GetBppValue(bpp);
          EXPECT_EQ(Mip1Width, OffsetInfo.Render.XOffset);                             // On right of Mip1
          EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Verify ResourceSize and Pitch
          VerifyResourceSize<true>(ResourceInfo, PAGE_SIZE); // everything should fit in 1 tile
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[X]);
          // These are verified elsewhere
          VerifyResourceHAlign<false>(ResourceInfo, 0);
          VerifyResourceVAlign<false>(ResourceInfo, 0);
          VerifyResourceQPitch<false>(ResourceInfo, 0);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 2D Linear Resource
  TEST_F(CTestResource, Test2DLinearResource)
  {
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      //Allocate 1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 64;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t       PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                 = GMM_ULT_MAX(PitchInBytes, MinPitch);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          const uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 256 x 256
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 256;
          gmmParams.BaseHeight  = 256;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 64;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t       PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                 = GMM_ULT_MAX(PitchInBytes, MinPitch);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          const uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 2D TileX Resource
  TEST_F(CTestResource, Test2DTileXResource)
  {
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileWidth  = 512;
      const uint32_t TileHeight = 8;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledX    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      //Allocate 1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, TileWidth);   // As wide as 1 Tile
          VerifyResourcePitchInTiles<true>(ResourceInfo, 1);    // 1 Tile wide
          VerifyResourceSize<true>(ResourceInfo, GMM_KBYTE(4)); // 1 Tile Big
          VerifyResourceQPitch<false>(ResourceInfo, 0);         // Not Tested
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate surface that requires multi tiles in two dimension
      // Allocate 2 tiles in X dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, TileWidth * 2);   // As wide as 2 tile
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2);        // 2 tile wide
          VerifyResourceSize<true>(ResourceInfo, GMM_KBYTE(4) * 2); // 2 tile big
  
          VerifyResourceQPitch<false>(ResourceInfo, 0); // Not tested
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = TileHeight + 1;                     // 1 row larger than 1 tile height
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, TileWidth * 2);   // As wide as 2 tile
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2);        // 2 tile wide
          VerifyResourceSize<true>(ResourceInfo, GMM_KBYTE(4) * 4); // 4 tile big
  
          VerifyResourceQPitch<false>(ResourceInfo, 0); // Not tested
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 2D TileY Resource
  TEST_F(CTestResource, Test2DTileYResource)
  {
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileWidth  = 128;
      const uint32_t TileHeight = 32;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledY    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      //Allocate 1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GMM_ULT_MAX(PitchInBytes, MinPitch);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileWidth);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileWidth);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes / TileWidth * GMM_KBYTE(4));
          VerifyResourceQPitch<false>(ResourceInfo, 0); // Not Tested
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate surface that requires multi tiles in two dimension
      // Allocate 2 tiles in X dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GMM_ULT_MAX(PitchInBytes, MinPitch);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileWidth);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileWidth);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes / TileWidth * GMM_KBYTE(4));
  
          VerifyResourceQPitch<false>(ResourceInfo, 0); // Not tested
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = TileHeight + 1;                     // 1 row larger than 1 tile height
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GMM_ULT_MAX(PitchInBytes, MinPitch);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileWidth);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileWidth);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes / TileWidth * 2 * GMM_KBYTE(4));
  
          VerifyResourceQPitch<false>(ResourceInfo, 0); // Not tested
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Arrayed 2D TileY Resource
  TEST_F(CTestResource, Test2DTileYResourceArrays)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileWidth  = 128;
      const uint32_t TileHeight = 32;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledY    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.ArraySize            = 4;
  
      // Allocate 2 tiles in X/Y dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = TileHeight + 1;                     // 1 row larger than 1 tile height
          uint32_t AlignedHeight, BlockHeight;
  
          BlockHeight   = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          AlignedHeight = GMM_ULT_ALIGN_NP2(BlockHeight * gmmParams.ArraySize, TileHeight);
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileWidth);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileWidth);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes * AlignedHeight); // 4 tile big x 4 array size
          VerifyResourceQPitch<true>(ResourceInfo, BlockHeight);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Mipped 2D TileY Resource
  TEST_F(CTestResource, Test2DTileYResourceMips)
  {
      const uint32_t TileSize[2] = {128, 32};
      enum Coords
      {
          X = 0,
          Y = 1
      };
  
      // Test normal mip case
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          const uint32_t ResourceWidth  = 0x200;
          const uint32_t ResourceHeight = 0x200;
          const uint32_t MaxLod         = 0x9;
  
  
          TEST_BPP             bpp       = static_cast<TEST_BPP>(i);
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.Flags.Info.TiledY    = 1;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = ResourceWidth;
          gmmParams.BaseHeight           = ResourceHeight;
          gmmParams.MaxLod               = MaxLod;
          gmmParams.Format               = SetResourceFormat(bpp);
  
          // Create resource
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          // Mip0 is the widest mip. So it will dictate the pitch of the whole surface
          const uint32_t Pitch            = ResourceWidth * GetBppValue(bpp);
          uint32_t       AllocationHeight = 0;
  
          // Mip0 should be at offset 0 and tile aligned
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1 should be after whole Mip0. Should still be tile aligned.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; // Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
          uint32_t SizeOfMip0      = Pitch * ResourceHeight;
          uint32_t HeightOfPrevMip = AllocationHeight = ResourceHeight;
          EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2 should be on the right of Mip1. Should still be tile aligned.
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2; // Mip 2
          ResourceInfo->GetOffset(OffsetInfo);
          // MipOffset = Mip1Offset + Mip1Width in tiles
          uint32_t MipOffset = SizeOfMip0 + ((Pitch >> 1) / TileSize[X]) * PAGE_SIZE;
          EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mips 3-5 should be on tile boundary
          for(int i = 3; i < 6; i++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = i;
              ResourceInfo->GetOffset(OffsetInfo);
  
              HeightOfPrevMip = (ResourceHeight >> (i - 1));
              AllocationHeight += HeightOfPrevMip;
              MipOffset += Pitch * HeightOfPrevMip;
              EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64);
              // No X/Y/Z offset since mip is at tile boundary
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);
              EXPECT_EQ(0, OffsetInfo.Render.YOffset);
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          // Mips 6-8 will share 1 tile
          AllocationHeight += TileSize[Y];
          uint32_t HeightOfPrevMipsInTile = 0;
          for(int i = 6; i < 9; i++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = i;
              ResourceInfo->GetOffset(OffsetInfo);
  
              EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); // Same as previous tile aligned mip offset
  
              // X is 0, but Y offset will change
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);
              HeightOfPrevMipsInTile += (ResourceHeight >> (i - 1));
              EXPECT_EQ(HeightOfPrevMipsInTile, OffsetInfo.Render.YOffset);
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          // Mip 9 is back on tile boundary
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 9; // Mip 9
          ResourceInfo->GetOffset(OffsetInfo);
  
          MipOffset += Pitch * TileSize[Y];
          AllocationHeight += TileSize[Y];
          EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Verify ResourceSize and Pitch
          VerifyResourceSize<true>(ResourceInfo, AllocationHeight * Pitch);
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[X]);
          // These are verified elsewhere
          VerifyResourceHAlign<false>(ResourceInfo, 0);
          VerifyResourceVAlign<false>(ResourceInfo, 0);
          VerifyResourceQPitch<false>(ResourceInfo, 0);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
  
      // Test where Mip1 + Mip2 width > Mip0 width, and where everything fits in 1 tile
      for(uint32_t i = 0; i < TEST_BPP_64; i++)
      {
          const uint32_t ResourceWidth  = 0x4;
          const uint32_t ResourceHeight = 0x2;
          const uint32_t MaxLod         = 0x2;
  
          TEST_BPP             bpp       = static_cast<TEST_BPP>(i);
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.Flags.Info.TiledY    = 1;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = ResourceWidth;
          gmmParams.BaseHeight           = ResourceHeight;
          gmmParams.MaxLod               = MaxLod;
          gmmParams.Format               = SetResourceFormat(bpp);
  
          // Create resource
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          // Get Alignment that GmmLib is using
          const uint32_t HAlign = ResourceInfo->GetHAlign();
          const uint32_t VAlign = ResourceInfo->GetVAlign();
  
          // Mip1 + Mip2 is the widest width. So it will dictate the pitch of the whole surface
          uint32_t Pitch = GetBppValue(bpp) *
                           (GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) + GMM_ULT_ALIGN(ResourceWidth >> 2, HAlign));
          Pitch = GMM_ULT_ALIGN(Pitch, TileSize[X]);
  
          // Mip0 should be at offset 0 and tile aligned
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1 should be after whole Mip0. Not tile aligned
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; // Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same tile as Mip0
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2 should be on the right of Mip1. Not tile aligned
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2; // Mip 2
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same Tile as Mip0
          uint32_t Mip1Width = GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) * GetBppValue(bpp);
          EXPECT_EQ(Mip1Width, OffsetInfo.Render.XOffset);                             // On right of Mip1
          EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Verify ResourceSize and Pitch
          VerifyResourceSize<true>(ResourceInfo, PAGE_SIZE); // everything should fit in 1 tile
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[X]);
          // These are verified elsewhere
          VerifyResourceHAlign<false>(ResourceInfo, 0);
          VerifyResourceVAlign<false>(ResourceInfo, 0);
          VerifyResourceQPitch<false>(ResourceInfo, 0);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  // ********************************************************************************//
  
  /// @brief ULT for 3D Linear Resource
  TEST_F(CTestResource, Test3DLinearResource)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_3D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t       PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                 = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          const uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 256 x 256 x 256
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 256;
          gmmParams.BaseHeight  = 256;
          gmmParams.Depth       = 256;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          uint32_t       PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                 = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          const uint32_t AlignedSize   = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.Depth, PAGE_SIZE);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourceSize<true>(ResourceInfo, AlignedSize);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 3D TileX Resource
  TEST_F(CTestResource, Test3DTileXResource)
  {
      const uint32_t HAlign                    = 16;
      const uint32_t VAlign                    = 4;
      const uint32_t TileSize[TEST_BPP_MAX][3] = {{512, 8, 1},
                                                  {512, 8, 1},
                                                  {512, 8, 1},
                                                  {512, 8, 1},
                                                  {512, 8, 1}};
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_3D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledX    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, TileSize[i][0]);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 1);
          VerifyResourceSize<true>(ResourceInfo, GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, 2 * TileSize[i][0]);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2);
          VerifyResourceSize<true>(ResourceInfo, 2 * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1;
          gmmParams.BaseHeight  = TileSize[i][1] + 1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, 2 * TileSize[i][0]);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2);
          VerifyResourceSize<true>(ResourceInfo, 2 * 2 * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y/Z dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1;
          gmmParams.BaseHeight  = TileSize[i][1] + 1;
          gmmParams.Depth       = TileSize[i][2] + 1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                 = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]);
          const uint32_t AlignedHeight = 24; // See details in GetTotal3DHeight();
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileSize[i][0]);
          VerifyResourceSize<true>(ResourceInfo, AlignedHeight / TileSize[i][1] * PitchInBytes / TileSize[i][0] * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for 3D TileY Resource
  TEST_F(CTestResource, Test3DTileYResource)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign                    = 16;
      const uint32_t VAlign                    = 4;
      const uint32_t TileSize[TEST_BPP_MAX][3] = {{128, 32, 1},
                                                  {128, 32, 1},
                                                  {128, 32, 1},
                                                  {128, 32, 1},
                                                  {128, 32, 1}};
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_3D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledY    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1x1 surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileSize[i][0]);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes / TileSize[i][0] * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileSize[i][0]);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes / TileSize[i][0] * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1;
          gmmParams.BaseHeight  = TileSize[i][1] + 1;
          gmmParams.Depth       = 0x1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileSize[i][0]);
          VerifyResourceSize<true>(ResourceInfo, PitchInBytes / TileSize[i][0] * 2 * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y/Z dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1;
          gmmParams.BaseHeight  = TileSize[i][1] + 1;
          gmmParams.Depth       = TileSize[i][2] + 1;
  
          const uint32_t MinPitch       = 32;
          const uint32_t PitchAlignment = 32;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t AlignedWidth  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign);
          uint32_t       PitchInBytes  = AlignedWidth * GetBppValue(bpp);
          PitchInBytes                 = GFX_MAX(PitchInBytes, MinPitch);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment);
          PitchInBytes                 = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]);
          const uint32_t AlignedHeight = 96; // See details in GetTotal3DHeight();
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, PitchInBytes);
          VerifyResourcePitchInTiles<true>(ResourceInfo, PitchInBytes / TileSize[i][0]);
          VerifyResourceSize<true>(ResourceInfo, AlignedHeight / TileSize[i][1] * PitchInBytes / TileSize[i][0] * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Cube Linear Resource
  TEST_F(CTestResource, Test3DTileYMippedResource)
  {
      // Horizontal/Vertical pixel alignment
      const uint32_t HAlign                    = 16;
      const uint32_t VAlign                    = 4;
      const uint32_t TileSize[TEST_BPP_MAX][3] = {{128, 32, 1},
                                                  {128, 32, 1},
                                                  {128, 32, 1},
                                                  {128, 32, 1},
                                                  {128, 32, 1}};
  
      const uint32_t ResourceWidth  = 0x100;
      const uint32_t ResourceHeight = 0x100;
      const uint32_t ResourceDepth  = 0x100;
      const uint32_t MaxLod         = 0x9;
  
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP             bpp       = static_cast<TEST_BPP>(i);
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_3D;
          gmmParams.Flags.Info.TiledY    = 1;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = ResourceWidth;
          gmmParams.BaseHeight           = ResourceHeight;
          gmmParams.Depth                = ResourceDepth;
          gmmParams.MaxLod               = MaxLod;
          gmmParams.Format               = SetResourceFormat(bpp);
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          const uint32_t Pitch      = ResourceWidth * GetBppValue(bpp);
          const uint32_t Mip0Height = ResourceHeight;
          const uint32_t Mip0Depth  = ResourceDepth;
  
          // Mip0
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0;
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip1
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1;
          ResourceInfo->GetOffset(OffsetInfo);
  
          const uint32_t SizeOfMip0 = Pitch * Mip0Height * Mip0Depth;
          const uint32_t Mip1Offset = SizeOfMip0;
          const uint32_t Mip1Height = Mip0Height >> 1;
          const uint32_t Mip1Depth  = Mip0Depth >> 1;
  
          EXPECT_EQ(Mip1Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip2
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 2;
          ResourceInfo->GetOffset(OffsetInfo);
  
          const uint32_t SizeOfMip1 = (Pitch >> 1) * Mip1Height * Mip1Depth;
          const uint32_t Mip2Offset = Mip1Offset + SizeOfMip1;
          const uint32_t Mip2Height = Mip1Height >> 1;
          const uint32_t Mip2Depth  = Mip1Depth >> 1;
  
          EXPECT_EQ(Mip2Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip3
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 3;
          ResourceInfo->GetOffset(OffsetInfo);
  
          const uint32_t SizeOfMip2 = (Pitch >> 2) * Mip2Height * Mip2Depth;
          const uint32_t Mip3Offset = Mip2Offset + SizeOfMip2;
          const uint32_t Mip3Height = Mip2Height >> 1;
          const uint32_t Mip3Depth  = Mip2Depth >> 1;
  
          EXPECT_EQ(Mip3Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip4 (Packed Mip)
          // For those mip width/height smaller than H/VAlign, they are upscaled to align with H/VAlign
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 4;
          ResourceInfo->GetOffset(OffsetInfo);
  
          const uint32_t SizeOfMip3 = (Pitch >> 3) * Mip3Height * Mip3Depth;
          const uint32_t Mip4Offset = Mip3Offset + SizeOfMip3;
  
          EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip 5
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 5;
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(16, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip 6
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 6;
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(24, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip 7
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 7;
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(28, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip8 (Start of another packed Mip)
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 8;
          ResourceInfo->GetOffset(OffsetInfo);
  
          const uint32_t Mip8Offset = Mip4Offset + Pitch * TileSize[i][1];
  
          EXPECT_EQ(Mip8Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          // Mip9
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 9;
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(Mip8Offset, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(4, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  // ********************************************************************************//
  
  /// @brief ULT for Cube Linear Resource
  TEST_F(CTestResource, TestCubeLinearResource)
  {
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_CUBE;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
  
          uint32_t ExpectedPitch = GMM_ULT_MAX(GMM_BYTES(32), HAlign * GetBppValue(bpp)); // Min Pitch = 32 bytes
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);                         // As wide as 1 tile
          VerifyResourcePitchInTiles<false>(ResourceInfo, 1);                             // not applicable
  
          uint32_t ExpectedQPitch = VAlign;
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned PAGE_SIZE
                                   GMM_ULT_ALIGN(ExpectedPitch *
                                                 __GMM_MAX_CUBE_FACE * ExpectedQPitch,
                                                 PAGE_SIZE));
  
          for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
          {
              GMM_REQ_OFFSET_INFO OffsetInfo = {};
              OffsetInfo.ReqRender           = 1;
              OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
              ResourceInfo->GetOffset(OffsetInfo);
  
              EXPECT_EQ(CubeFaceIndex * ExpectedQPitch * ExpectedPitch,
                        OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
              EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0
              EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate arbitrary size (X/Y dimension not applicable as linear surface)
      // Width and Height must be equal
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x201;                 // 512 + 1, help ult HAlign/VAlign/Pitch alignment logic as well.
          gmmParams.BaseHeight  = gmmParams.BaseWidth64; // Heigth must be equal to width.
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
  
          uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * GetBppValue(bpp); // HAligned-width in bytes.
          ExpectedPitch          = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32));
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<false>(ResourceInfo, 2); // not applicable
  
          uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned PAGE_SIZE
                                   GMM_ULT_ALIGN(ExpectedPitch *
                                                 __GMM_MAX_CUBE_FACE * ExpectedQPitch,
                                                 PAGE_SIZE));
  
          for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
          {
              GMM_REQ_OFFSET_INFO OffsetInfo = {};
              OffsetInfo.ReqRender           = 1;
              OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
              ResourceInfo->GetOffset(OffsetInfo);
  
              EXPECT_EQ(CubeFaceIndex * ExpectedQPitch * ExpectedPitch,
                        OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
              EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0
              EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Cube Linear Mipped Resource
  TEST_F(CTestResource, TestCubeLinearMippedResourceArray)
  {
      const uint32_t HAlign       = 16;
      const uint32_t VAlign       = 4;
      const uint32_t MaxLod       = 9;
      const uint32_t ResWidth     = 0x201;
      const uint32_t MaxArraySize = 0x10;
  
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_CUBE;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.Linear    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.MaxLod               = MaxLod;
      gmmParams.ArraySize            = MaxArraySize;
  
      // Allocate arbitrary size (X/Y dimension not applicable as linear surface)
      // Width and Height must be equal
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          struct //Cache the value for verifying array elements/Cube face offset/Mip Offset
          {
              uint64_t Offset; // Note : absolute mip offset
          } RenderOffset[GMM_ULT_MAX_MIPMAP] = {};
  
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = ResWidth;              // 1024 + 1, help ult HAlign/VAlign/Pitch alignment logic as well.
          gmmParams.BaseHeight  = gmmParams.BaseWidth64; // Heigth must be equal to width.
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
  
          //------------------------------|
          //                              |
          //          LOD0                |
          //                              |
          //                              |
          //------------------------------|
          //    LOD1     |    LOD2  |
          //             |----------|
          //             | LOD3 |
          //-------------| LOD4 .. so on
  
          // Mip 0
          // Mip 0 decides the pitch of the entire surface
          const uint32_t AlignedWidthMip0  = GMM_ULT_ALIGN(ResWidth, HAlign); // HAlign width in pixel
          const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign);
          uint32_t       ExpectedPitch     = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * GetBppValue(bpp); // HAligned-width in bytes.
          ExpectedPitch                    = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32));
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<false>(ResourceInfo, 2); // Not applicable
  
          // Mip0 should be at offset 0 and tile aligned
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          //cache Mip 0 offset
          RenderOffset[0].Offset = 0;
  
          // Mip 1 should be under mip 0
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; //Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(AlignedHeightMip0 * ExpectedPitch, // Render offset is the absolute address at which the mip begins
                    OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Not applicable for linear surface
          EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Not applicable for linear surface
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // n/a
  
          //cache Mip 1 offset
          RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base
  
          const uint32_t AlignedWidthMip1  = GMM_ULT_ALIGN(ResWidth >> 1, HAlign); // Align width in pixel to HAlign
          const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign);
  
          uint32_t HeightOfMip;
          uint32_t HeightLinesLevel2 = 0;
  
          // Mips 2-9 should be stacked on the right of Mip1 as shown in figure above.
          for(int i = 2; i <= MaxLod; i++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = i;
              ResourceInfo->GetOffset(OffsetInfo);
  
              HeightOfMip = GMM_ULT_ALIGN(ResWidth >> i, VAlign);
  
              EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + // Render offset is tile's base address on which mip begins
                        (AlignedWidthMip1 * GetBppValue(bpp)),
                        OffsetInfo.Render.Offset64);
  
              EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Not applicable for linear surface
              EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Not applicable for linear surface
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
              //cache Mip i'th offset
              RenderOffset[i].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch +
                                       (AlignedWidthMip1 * GetBppValue(bpp));
  
              HeightLinesLevel2 += HeightOfMip;
          }
  
          uint32_t ExpectedQPitch = AlignedHeightMip0 + AlignedHeightMip1 + 12 * VAlign;
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary
                                   GMM_ULT_ALIGN(ExpectedPitch *
                                                 MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch,
                                                 PAGE_SIZE));
  
          // Verify each array element's  Mip offset, Cube face offset etc.
          for(uint32_t ArrayIndex = 0; ArrayIndex < __GMM_MAX_CUBE_FACE; ArrayIndex++)
          {
              for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
              {
                  GMM_REQ_OFFSET_INFO OffsetInfo = {};
                  OffsetInfo.ReqRender           = 1;
                  OffsetInfo.ArrayIndex          = ArrayIndex;
                  OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
                  ResourceInfo->GetOffset(OffsetInfo);
  
                  //Verify cube face offsets
                  EXPECT_EQ(((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch * ExpectedPitch,
                            OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
                  EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as linear surf
                  EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as linear surf
                  EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
  
                  uint32_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * ExpectedPitch);
  
                  //Verify mip offsets in each cube face
                  for(uint32_t Lod = 0; Lod <= MaxLod; Lod++)
                  {
                      OffsetInfo.MipLevel = Lod;
                      ResourceInfo->GetOffset(OffsetInfo);
  
                      uint32_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset;
  
                      uint32_t OffsetX = MipOffset % ExpectedPitch;
                      uint32_t OffsetY = MipOffset / ExpectedPitch;
  
                      uint32_t RenderAlignOffset = OffsetY * ExpectedPitch + OffsetX;
  
                      EXPECT_EQ(RenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset absolute address on which cube face begins.
                      EXPECT_EQ(0, OffsetInfo.Render.XOffset);                  // X Offset should be 0 as linear surf
                      EXPECT_EQ(0, OffsetInfo.Render.YOffset);                  // Y Offset should be 0 as linear surf
                      EXPECT_EQ(0, OffsetInfo.Render.ZOffset);                  // Z offset N/A should be 0
                  }
              }
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Cube TileX Resource
  TEST_F(CTestResource, TestCubeTileXResource)
  {
      // Cube is allocated as an array of 6 2D surface representing each cube face below
      //===============================
      //  q  coordinate  |    face    |
      //      0          |    + x     |
      //      1          |    - x     |
      //      2          |    + y     |
      //      3          |    - y     |
      //      4          |    + z     |
      //      5          |    - z     |
      //===============================
  
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileSize[1][2] = {512, 8};
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_CUBE;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledX    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1 surface so that it occupies 1 Tile in X dimension
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = TileSize[0][0];
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch); // As wide as 1 tile
          VerifyResourcePitchInTiles<true>(ResourceInfo, 1);      // 1 tile wide
  
          uint32_t ExpectedQPitch = VAlign;
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary
                                   ExpectedPitch *
                                   GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch,
                                                 TileSize[0][1]));
  
          for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
          {
              GMM_REQ_OFFSET_INFO OffsetInfo = {};
              OffsetInfo.ReqRender           = 1;
              OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
              ResourceInfo->GetOffset(OffsetInfo);
  
              EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch,
                        OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
              EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0
              EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1],
                        OffsetInfo.Render.YOffset);    // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X dimension.
      // Width and Height must be equal
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[0][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = gmmParams.BaseWidth64;                   // Heigth must be equal to width.
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
  
          uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tile wide
  
          uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary
                                   ExpectedPitch *
                                   GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch,
                                                 TileSize[0][1]));
  
          for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
          {
              GMM_REQ_OFFSET_INFO OffsetInfo = {};
              OffsetInfo.ReqRender           = 1;
              OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
              ResourceInfo->GetOffset(OffsetInfo);
              EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch,
                        OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
              EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0
              EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1],
                        OffsetInfo.Render.YOffset);    // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  
  /// @brief ULT for Cube TileY Resource
  TEST_F(CTestResource, TestCubeTileYResource)
  {
      // Cube is allocated as an array of 6 2D surface representing each cube face below
      //===============================
      //   q coordinate  |    face    |
      //      0          |    + x     |
      //      1          |    - x     |
      //      2          |    + y     |
      //      3          |    - y     |
      //      4          |    + z     |
      //      5          |    - z     |
      //===============================
  
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileSize[1][2] = {128, 32};
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_CUBE;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledY    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate 1x1 surface within a tile.
      for(uint32_t i = 0; i < TEST_BPP_128; i++) //TEST_BPP_128 cannot fit in a tile as HAlign = 16
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          VerifyResourcePitch<true>(ResourceInfo, TileSize[0][0]); // As wide as 1 tile
          VerifyResourcePitchInTiles<true>(ResourceInfo, 1);       // 1 tile wide
          VerifyResourceSize<true>(ResourceInfo, GMM_KBYTE(4));    // All 6 faces should be accomated in a tile.
          VerifyResourceQPitch<true>(ResourceInfo, VAlign);        // Each face should be VAlign rows apart within a tile
  
          for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
          {
              GMM_REQ_OFFSET_INFO OffsetInfo = {};
              OffsetInfo.ReqRender           = 1;
              OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
              ResourceInfo->GetOffset(OffsetInfo);
              EXPECT_EQ(0, OffsetInfo.Render.Offset64);                     // Render offset should be 0 as its on single tile.
              EXPECT_EQ(0, OffsetInfo.Render.XOffset);                      // X Offset should be 0
              EXPECT_EQ(CubeFaceIndex * VAlign, OffsetInfo.Render.YOffset); // Y Offset should be VALIGN * CubeFace Index
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X dimension.
      // Width and Height of Cube must be equal
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = (TileSize[0][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = gmmParams.BaseWidth64;                   // Heigth must be equal to width.
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
  
          uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tile wide
  
          uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary
                                   ExpectedPitch *
                                   GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch,
                                                 TileSize[0][1]));
  
  
          for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
          {
              GMM_REQ_OFFSET_INFO OffsetInfo = {};
              OffsetInfo.ReqRender           = 1;
              OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
              ResourceInfo->GetOffset(OffsetInfo);
              EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch,
                        OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
              EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0
              EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1],
                        OffsetInfo.Render.YOffset);    // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Cube TileY Mipped Resource Array
  TEST_F(CTestResource, TestCubeTileYMippedResourceArray)
  {
      const uint32_t HAlign = 16;
      const uint32_t VAlign = 4;
  
      const uint32_t TileSize[2] = {128, 32};
      enum Coords
      {
          X = 0,
          Y = 1
      };
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_CUBE;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledY    = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
  
      // Allocate CUBE surface
      for(uint32_t i = 0; i < TEST_BPP_MAX; i++)
      {
          const uint32_t ResWidth     = 0x201;
          const uint32_t MaxLod       = 0x9;
          const uint32_t MaxArraySize = 0x10;
  
          struct //Cache the value for verifying array elements/Cube face offset/Mip Offset
          {
              uint64_t Offset; // Note : absolute mip offset
          } RenderOffset[GMM_ULT_MAX_MIPMAP];
  
          TEST_BPP bpp          = static_cast<TEST_BPP>(i);
          gmmParams.Format      = SetResourceFormat(bpp);
          gmmParams.BaseWidth64 = ResWidth;              // 1 pixel larger than 1 tile width
          gmmParams.BaseHeight  = gmmParams.BaseWidth64; // Heigth must be equal to width.
          gmmParams.Depth       = 0x1;
          gmmParams.MaxLod      = MaxLod;
          gmmParams.ArraySize   = MaxArraySize;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
  
          //------------------------------|
          //                              |
          //          LOD0                |
          //                              |
          //                              |
          //------------------------------|
          //    LOD1     |    LOD2  |
          //             |----------|
          //             | LOD3 |
          //-------------| LOD4 .. so on
  
          //Mip 0
          //Mip 0 decides the pitch of the entire resource.
          const uint32_t AlignedWidthMip0  = GMM_ULT_ALIGN(ResWidth, HAlign); // HAlign width in pixel
          const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign);
          uint32_t       ExpectedPitch     = GMM_ULT_ALIGN(AlignedWidthMip0 * GetBppValue(bpp), TileSize[X]); // Align AlignedWidthMip0 to 128 bytes
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, ExpectedPitch / TileSize[X]); // Pitch/TileY-Width
  
          // Mip0 should be at offset 0 and tile aligned
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);
          EXPECT_EQ(0, OffsetInfo.Render.YOffset);
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          //cache Mip 0 offset
          RenderOffset[0].Offset = 0;
  
          // Mip 1 should be under mip 0
          OffsetInfo           = {};
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 1; //Mip 1
          ResourceInfo->GetOffset(OffsetInfo);
  
          EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(AlignedHeightMip0, TileSize[Y]) * ExpectedPitch, // Render offset is tile's base address on which mip begins
                    OffsetInfo.Render.Offset64);
          EXPECT_EQ(0, OffsetInfo.Render.XOffset);                                 // Aligns with Mip0 at X = 0
          EXPECT_EQ((AlignedHeightMip0) % TileSize[Y], OffsetInfo.Render.YOffset); // AlignedHeightMip0 % TileY-Height
          EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
          //cache Mip 1 offset
          RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base
  
          const uint32_t AlignedWidthMip1  = GMM_ULT_ALIGN(ResWidth >> 1, HAlign); // Align width in pixel to HAlign
          const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign);
  
          uint32_t HeightOfMip;
          uint32_t HeightLinesLevel2 = 0;
  
          // Mips 2-9 should be stacked on the right of Mip1 as shown in figure above.
          for(int i = 2; i <= MaxLod; i++)
          {
              OffsetInfo           = {};
              OffsetInfo.ReqRender = 1;
              OffsetInfo.MipLevel  = i;
              ResourceInfo->GetOffset(OffsetInfo);
  
              HeightOfMip = GMM_ULT_ALIGN(ResWidth >> i, VAlign);
  
              EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(AlignedHeightMip0 + HeightLinesLevel2, TileSize[Y]) * ExpectedPitch + // Render offset is tile's base address on which mip begins
                        (AlignedWidthMip1 * GetBppValue(bpp) / TileSize[X]) * PAGE_SIZE,
                        OffsetInfo.Render.Offset64);
  
              EXPECT_EQ((AlignedWidthMip1 * GetBppValue(bpp)) % TileSize[X], OffsetInfo.Render.XOffset);   // Aligns with Mip0 at X = 0
              EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) % TileSize[Y], OffsetInfo.Render.YOffset); // AlignedHeightMip0 % TileY-Height
              EXPECT_EQ(0, OffsetInfo.Render.ZOffset);
  
              //cache Mip i'th offset
              RenderOffset[i].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch +
                                       (AlignedWidthMip1 * GetBppValue(bpp));
  
              HeightLinesLevel2 += HeightOfMip;
          }
  
          uint32_t ExpectedQPitch = AlignedHeightMip0 + AlignedHeightMip1 + 12 * VAlign;
          VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary
                                   ExpectedPitch *
                                   GMM_ULT_ALIGN(MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[Y]));
  
          // Verify each array element's  Mip offset, Cube face offset etc.
          for(uint32_t ArrayIndex = 0; ArrayIndex < __GMM_MAX_CUBE_FACE; ArrayIndex++)
          {
              for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++)
              {
                  GMM_REQ_OFFSET_INFO OffsetInfo = {};
                  OffsetInfo.ReqRender           = 1;
                  OffsetInfo.ArrayIndex          = ArrayIndex;
                  OffsetInfo.CubeFace            = static_cast<GMM_CUBE_FACE_ENUM>(CubeFaceIndex);
                  ResourceInfo->GetOffset(OffsetInfo);
  
                  //Verify cube face offsets
                  EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch, TileSize[Y]) * ExpectedPitch,
                            OffsetInfo.Render.Offset64);   // Render offset is tile's base address on which cube face begins.
                  EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0
                  EXPECT_EQ((((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch) % TileSize[Y],
                            OffsetInfo.Render.YOffset);    // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight
                  EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0
  
                  uint32_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * ExpectedPitch);
  
                  //Verify mip offsets in each cube face
                  for(uint32_t Lod = 0; Lod <= MaxLod; Lod++)
                  {
                      OffsetInfo.MipLevel = Lod;
                      ResourceInfo->GetOffset(OffsetInfo);
  
                      uint32_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset;
  
                      uint32_t OffsetX            = MipOffset % ExpectedPitch;
                      uint32_t TileAlignedOffsetX = GMM_ULT_ALIGN_FLOOR(OffsetX, TileSize[X]);
                      OffsetX -= TileAlignedOffsetX;
  
                      uint32_t OffsetY            = MipOffset / ExpectedPitch;
                      uint32_t TileAlignedOffsetY = GMM_ULT_ALIGN_FLOOR(OffsetY, TileSize[Y]);
                      OffsetY -= TileAlignedOffsetY;
  
                      uint32_t RenderAlignOffset =
                      TileAlignedOffsetY * ExpectedPitch +
                      (TileAlignedOffsetX / TileSize[X]) * PAGE_SIZE;
  
  
                      EXPECT_EQ(RenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins.
                      EXPECT_EQ(OffsetX, OffsetInfo.Render.XOffset);
                      EXPECT_EQ(OffsetY, OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight
                      EXPECT_EQ(0, OffsetInfo.Render.ZOffset);       // Z offset N/A should be 0
                  }
              }
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  // ********************************************************************************//
  
  /// @brief ULT for Buffer Resource
  TEST_F(CTestResource, TestBufferLinearResource)
  {
  }
  
  // ********************************************************************************//
  
  /// @brief ULT for Separate Stencil Resource
  TEST_F(CTestResource, TestSeparateStencil)
  {
      const uint32_t HAlign = 8; //Separate Stencil alignment (8x8)
      const uint32_t VAlign = 8;
  
      const uint32_t StencilTileSize[1][2] = {64, 64};  //Stencil is TileW, swizzled (2*w x h/2) onto TileY
      const uint32_t AllocTileSize[1][2]   = {128, 32}; //Allocation-aligned to TileY since some HW units support TileW by WA'ing TileY
  
      GMM_RESCREATE_PARAMS gmmParams      = {};
      gmmParams.NoGfxMemory               = 1;
      gmmParams.Flags.Info.TiledX         = 1; //Any input Tiling - changed to TileW? YES, but expected one is TileW
      gmmParams.Flags.Gpu.SeparateStencil = 1;
      gmmParams.Format                    = SetResourceFormat(TEST_BPP_8); //Only R8_UNIT supported, driver assumes so, but creates resource even for other bpps requests (as bpp=8)
  
      // Allocate 1x1 surface so that it occupies 1 Tile in X dimension
      for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++) //SeparateStencil with 2D, cube, 1D, 3D with mip-maps
      {
          gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i);
          gmmParams.BaseWidth64 = 0x1;
          gmmParams.BaseHeight  = 0x1;
          gmmParams.Depth       = 0x1; //Depth !=1 supported for stencil? Supported on all Gens. Gen8 gives only Lod0 for mip-mapped Stencil too
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = StencilTileSize[0][0] * 2; // 2 TileW tiles interleaved on same row
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 1); // 1 tileY wide
  
          if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE)
          {
              uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Interleaved rows for TielW-arrangement. No Qpitch for 3d, only for 2d-array and cube on Gen8
              //it needs to be in VALign multiple, for Stencil buffer needs it as multiple of 8
              VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile
          }
  
          VerifyResourceSize<true>(ResourceInfo, GMM_KBYTE(4)); //1 Tile should be enough
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X dimension.
      for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++)
      {
          gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i); //Could we loop over Res_types for speacil allocation types
          gmmParams.BaseWidth64 = StencilTileSize[0][0] + 0x1;
          gmmParams.BaseHeight  = (gmmParams.Type == RESOURCE_1D) ? 0x1 :
                                                                   (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 :
                                                                                                       StencilTileSize[0][1];
          gmmParams.Depth = 0x1; //HW doesn't support Depth/STC for 3D res_type, but driver has no such restriction
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, further doubled for interleaved rows 2*w = Pitch
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tiles wide
  
          uint32_t ExpectedQPitch = 0;
          if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE)
          {
              ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Interleaved rows for TileW-arrangement - but Qpitch calculated w/o interleaving in mind. No Qpitch for 3d, only for 2d-array and cube on Gen8
              //GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign)/2, VAlign); //Doesn't HW expect distance in rows between 2 cube-faces (array slices) : It does so, but in logical view not physical view, so not interleaved rows.
              //it needs to be in VALign multiple, for Stencil buffer needs it as multiple of 8
              VerifyResourceQPitch<true>(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile
          }
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary
                                   ((gmmParams.Type == RESOURCE_CUBE) ?
                                    ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * __GMM_MAX_CUBE_FACE / 2, AllocTileSize[0][1]) : //cube
                                    2 * GMM_KBYTE(4)));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y dimension.
      for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++)
      {
          gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i);
          gmmParams.BaseWidth64 = StencilTileSize[0][0] + 0x1;
          gmmParams.BaseHeight  = StencilTileSize[0][1] + 0x1;
          gmmParams.Depth       = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, double again for interleaved rows 2*w = Pitch,
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tile wide
  
          VerifyResourceSize<true>(ResourceInfo, 2 * 2 * GMM_KBYTE(4));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate multi-tiles in X/Y/Z dimension.
      for(uint32_t i = RESOURCE_3D; i <= RESOURCE_3D; i++)
      {
          gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i);
          gmmParams.BaseWidth64 = StencilTileSize[0][0] + 0x1;
          gmmParams.BaseHeight  = StencilTileSize[0][1] + 0x1;
          gmmParams.Depth       = StencilTileSize[0][1] + 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, doubled again for interleaved rows 2*w = Pitch, width < 1.5 Tiles
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tile wide
  
          uint32_t TwoDQPitch, ExpectedQPitch = 0;
          {
              TwoDQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Interleaved rows for TileW-arrangement - but Qpitch calculated w/o interleaving in mind. No Qpitch for 3d, only for 2d-array and cube on Gen8
              //GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign)/2, VAlign); //Doesn't HW expect distance in rows between 2 cube-faces (array slices) : It does so, but in logical view not physical view, so not interleaved rows.
              //it needs to be in VALign multiple, for Stencil buffer needs it as multiple of 8
  
              //VerifyResourceQPitch<false>(ResourceInfo, TwoDQPitch);       //Gen8 doesn't support QPitch for RES_3D
  
              ExpectedQPitch = gmmParams.Depth * TwoDQPitch; //Depth slices arranged as 2D-arrayed slices.
          }
          VerifyResourceSize<true>(ResourceInfo,
                                   ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch / 2, AllocTileSize[0][1]));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      //Mip-mapped array case: <SNB>Stencil QPitch = h0 ie Stencil only has Lod0
      //<BDW>Above limit not there, should have mip-map block height for Qpitch
  }
  
  /// @brief ULT for Hiz Depth buffer Resource
  TEST_F(CTestResource, TestHiZ)
  {
      const uint32_t HAlign = 16; //HiZ alignment (16x8) [Depth 16bit: 8x4; ow 4x4]
      const uint32_t VAlign = 4;  // 8; Need to debug why driver uses VAlign/2
  
      //const uint32_t DepthTileSize[1][2] = { 64, 64 };  //Depth/Stencil buffer should be TileY/Ys/Yf only (16,24,32 bpp only) no 3D or MSAA
      const uint32_t AllocTileSize[1][2] = {128, 32}; //HiZ is TileY
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Info.TiledX    = 1; //Not supported for Depth buffer, but HiZ output is TileY
      gmmParams.Flags.Gpu.Depth      = 1; //GPU Flags= Depth/SeparateStencil + HiZ
      gmmParams.Flags.Gpu.HiZ        = 1;
  
      // Allocate 1x1 surface so that it occupies 1 Tile in X dimension
      for(uint32_t j = TEST_BPP_8; j <= TEST_BPP_128; j++) //Depth bpp doesn't matter, Depth px dimensions decide HiZ size in HW
      {
          gmmParams.Format = SetResourceFormat(static_cast<TEST_BPP>(j)); //Only 16,24,32 supported; But driver creates the resource even for other bpps without failing
          for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++)          //3D doesn't support HiZ - test driver returns proper?
          {
              gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i);
              gmmParams.BaseWidth64 = 0x1;
              gmmParams.BaseHeight  = 0x1;
              gmmParams.Depth       = 0x1;
  
              GMM_RESOURCE_INFO *ResourceInfo;
              ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
              VerifyResourceHAlign<true>(ResourceInfo, HAlign);
              VerifyResourceVAlign<true>(ResourceInfo, VAlign);
              uint32_t ExpectedPitch = AllocTileSize[0][0];
              VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
              VerifyResourcePitchInTiles<true>(ResourceInfo, 1); // 1 tileY wide
  
              if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE)
              {
                  uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
                  ExpectedQPitch          = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign);
  
                  VerifyResourceQPitch<false>(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile, Turn on verification after clarity
              }
  
              VerifyResourceSize<true>(ResourceInfo,
                                       GMM_KBYTE(4)); //1 Tile should be enough
  
              pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
          }
      }
      // Allocate 2 tiles in X dimension. (muti-tiles Tiles in Y dimension for cube/array)
      for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++)
      {
          gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i);
          gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1;
          gmmParams.BaseHeight  = (gmmParams.Type == RESOURCE_1D) ? 0x1 :
                                                                   (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 :
                                                                                                       VAlign / 2;
          gmmParams.ArraySize = (gmmParams.Type != RESOURCE_3D) ? VAlign : 1; // Gen8 doesn't support 3D-arrays (so HiZ not supported) [test 3d arrays once -- HiZ would fail but ResCreate doesn't?]
          gmmParams.Depth     = 0x1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = AllocTileSize[0][0] * 2;
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tileY wide
  
          uint32_t ExpectedQPitch = 0;
          if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE)
          {
              ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
              ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign);
  
              VerifyResourceQPitch<false>(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile. Turn on verification after clarity
          }
  
          VerifyResourceSize<true>(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary
                                   ((gmmParams.Type == RESOURCE_CUBE) ?
                                    ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize * __GMM_MAX_CUBE_FACE, AllocTileSize[0][1]) : //cube
                                    ((gmmParams.ArraySize > 1) ?
                                     ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, AllocTileSize[0][1]) : //array
                                     2 * GMM_KBYTE(4))));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      // Allocate 2 tiles in X/Y dimension (non-arrayed) Multi-tiles for 3D
      for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++)
      {
          gmmParams.Type        = static_cast<GMM_RESOURCE_TYPE>(i);
          gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1;
          gmmParams.BaseHeight  = 2 * AllocTileSize[0][1] + 0x1; //Half-Depth Height or QPitch (lod!=0), aligned to 8 required by HW
          gmmParams.Depth       = (gmmParams.Type == RESOURCE_2D) ? 0x1 :
                                                              VAlign + 1;
          gmmParams.ArraySize = 1;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          VerifyResourceHAlign<true>(ResourceInfo, HAlign);
          VerifyResourceVAlign<true>(ResourceInfo, VAlign);
          uint32_t ExpectedPitch = AllocTileSize[0][0] * 2;
          VerifyResourcePitch<true>(ResourceInfo, ExpectedPitch);
          VerifyResourcePitchInTiles<true>(ResourceInfo, 2); // 2 tile wide
  
          uint32_t TwoDQPitch = 0, ExpectedQPitch = 0;
          if(gmmParams.Type == RESOURCE_3D)
          {
              TwoDQPitch     = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
              ExpectedQPitch = gmmParams.Depth * GMM_ULT_ALIGN(TwoDQPitch / 2, VAlign); //Depth slices arranged as 2D-arrayed slices.
          }
          else
          {
              //HiZ for 3D not supported. Driver still allocates like IVB/HSW. (should Qpitch or only overall buffer height be Valigned ?)
              VerifyResourceSize<true>(ResourceInfo,
                                       ((gmmParams.Type == RESOURCE_3D) ?
                                        ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch, AllocTileSize[0][1]) :
                                        2 * 2 * GMM_KBYTE(4)));
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  
      //Mip-mapped case:
  }
  
  /// @brief ULT for MSAA Resource
  TEST_F(CTestResource, TestMSAA)
  {
      enum MSAA_Samples
      {
          MSAA_None,
          MSAA_2x,
          MSAA_4x,
          MSAA_8x,
          MSAA_16x
      };
  
      const uint32_t MCSTileSize[1][2] = {128, 32}; //MCS is TileY
  
      //Gen8:No mip-map for MSAA (MSS and MCS), No 16x
      //No MSAA for YUV/compressed formats
      //Interleaved MSS (IMS) for Depth/Stencil. Arrayed MSS (CMS) for Color RT
      //QPitch exists for arrayed MSS - gives distance between slices
      //MSS (Arrayed): px_wL, px_hL = pixel width/height of single sample at Lod L
      //                 MSS width = px_wL, MSS height = NumSamples*px_hL
      //MSS (Interleaved): px_wL, px_hL = pixel width/height of single sample at Lod L
      // Samples         MSS width                MSS Height
      //   2x            4*ceil(px_wL/2)             px_hL
      //   4x            4*ceil(px_wL/2)           4*ceil(px_hL/2)
      //   8x            8*ceil(px_wL/2)           4*ceil(px_hL/2)
      //  16x            8*ceil(px_wL/2)           8*ceil(px_hL/2)
      //MCS (bpp): 2x/4x - bpp_8, 8x - bpp_32, 16x - bpp_64
  
      const uint32_t TestDimensions[3][2] = {
      {0, 0}, //1x1x1
      {1, 0}, //2 Tilesx1
      {1, 1}, //2 Tilesx 2
      };
  
      uint32_t TestArraySize[2] = {1, 7};
  
      uint32_t HAlign, VAlign, TileDimX, TileDimY, MCSHAlign, MCSVAlign, TileSize;
      uint32_t ExpectedMCSBpp;
  
      std::vector<std::tuple<int, int, int, bool, int, int>> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, TestArraySize index
      auto Size = BuildInputIterator(List, 3, 2);                  // Size of arrays TestDimensions, TestArraySize
  
      for(auto element : List)
      {
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Flags.Info           = {0};
  
          TEST_TILE_TYPE     Tiling     = (TEST_TILE_TYPE)std::get<0>(element);
          TEST_BPP           Bpp        = (TEST_BPP)std::get<1>(element);
          TEST_RESOURCE_TYPE ResType    = (TEST_RESOURCE_TYPE)std::get<2>(element);
          bool               IsRT       = std::get<3>(element); // True for RT, False for Depth
          int                TestDimIdx = std::get<4>(element); //index into TestDimensions array
          int                ArrayIdx   = std::get<5>(element); //index into TestArraySize
          TileSize                      = GMM_KBYTE(4);
  
          //Discard un-supported Tiling/Res_type/bpp for this test
          if(ResType != TEST_RESOURCE_2D || Tiling > TEST_TILEY           //No 1D/3D/Cube. Supported 2D mip-maps/array
             || (!IsRT && (Tiling == TEST_TILEX ||
                           !(Bpp == TEST_BPP_16 || Bpp == TEST_BPP_32)))) //depth supported on 16bit, 32bit formats only
              continue;
  
          SetTileFlag(gmmParams, Tiling);
          SetResType(gmmParams, ResType);
          SetResGpuFlags(gmmParams, IsRT);
          SetResArraySize(gmmParams, TestArraySize[ArrayIdx]);
  
          gmmParams.NoGfxMemory = 1;
          gmmParams.Format      = SetResourceFormat(Bpp);
          for(uint32_t k = MSAA_2x; k < MSAA_16x; k++) //No 16x MSAA on Gen8
          {
              GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k,
                                                   TileDimX, TileDimY, HAlign, VAlign,
                                                   ExpectedMCSBpp, MCSHAlign, MCSVAlign);
  
              gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1;
              gmmParams.BaseHeight  = TestDimensions[TestDimIdx][1] * TileDimY + 0x1;
  
              gmmParams.Depth           = 0x1; //2D Res_type with Depth > 1 doesn't fail, although Tex_cacl doesn't use it
              gmmParams.MSAA.NumSamples = static_cast<uint32_t>(pow((double)2, k));
              gmmParams.Flags.Gpu.MCS   = 0;
              gmmParams.ArraySize       = 1;
  
              //MSS surface
              GMM_RESOURCE_INFO *MSSResourceInfo;
              MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
              if(MSSResourceInfo)
              {
                  VerifyResourceHAlign<true>(MSSResourceInfo, HAlign);
                  VerifyResourceVAlign<true>(MSSResourceInfo, VAlign);
                  if(IsRT) //Arrayed MSS
                  {
                      uint32_t ExpectedPitch = 0, ExpectedQPitch = 0;
                      ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth
                      VerifyResourcePitch<true>(MSSResourceInfo, ExpectedPitch);
                      if(Tiling != TEST_LINEAR)
                          VerifyResourcePitchInTiles<true>(MSSResourceInfo, ExpectedPitch / TileDimX);
  
                      //if (gmmParams.ArraySize > 1) - Arrayed MSS has QPitch
                      {
                          ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign);
                          VerifyResourceQPitch<true>(MSSResourceInfo, ExpectedQPitch);
                      }
  
                      uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height
                      VerifyResourceSize<true>(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize));
                  }
                  else // Interleaved MSS
                  {
                      uint32_t WidthMultiplier, HeightMultiplier;
                      GetInterleaveMSSPattern((TEST_MSAA)k, WidthMultiplier, HeightMultiplier);
                      gmmParams.BaseWidth64 = WidthMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseWidth64, 2) : gmmParams.BaseWidth64;
                      gmmParams.BaseHeight  = HeightMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) : gmmParams.BaseHeight;
  
                      uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64 * WidthMultiplier, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); //AlignedWidth*bpp, then align to Tile
                      VerifyResourcePitch<true>(MSSResourceInfo, ExpectedPitch);
                      if(Tiling != TEST_LINEAR)
                      {
                          VerifyResourcePitchInTiles<true>(MSSResourceInfo, ExpectedPitch / TileDimX); // 1 tileY wide
                      }
  
                      uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight * HeightMultiplier, VAlign);
                      if(gmmParams.ArraySize > 1)
                      {
                          // it needs to be in VALign multiple
                          VerifyResourceQPitch<true>(MSSResourceInfo, ExpectedQPitch);
                      }
                      uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, TileDimY);            //Align Height = ExpectedQPitch*ArraySize, to Tile-Height
                      VerifyResourceSize<true>(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); //ExpectedPitch *ExpectedHeight
                  }
              }
  
              //No MCS surface if MSS creation failed
              if(MSSResourceInfo)
              {
                  gmmParams.Flags.Gpu.MCS = 1;
                  GMM_RESOURCE_INFO *MCSResourceInfo;
                  MCSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
                  VerifyResourceHAlign<true>(MCSResourceInfo, MCSHAlign); // MCS alignment same as basic RT alignment
                  VerifyResourceVAlign<true>(MCSResourceInfo, MCSVAlign);
  
                  uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, MCSHAlign) * ExpectedMCSBpp, MCSTileSize[0][0]); //AlignedWidth*bpp, then tile-alignment
                  VerifyResourcePitch<true>(MCSResourceInfo, ExpectedPitch);
                  VerifyResourcePitchInTiles<true>(MCSResourceInfo, ExpectedPitch / MCSTileSize[0][0]);
  
                  uint32_t ExpectedQPitch = gmmParams.BaseHeight;
                  if(gmmParams.ArraySize > 1)
                  {
                      ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, MCSVAlign); //QPitch only for array
                      VerifyResourceQPitch<true>(MCSResourceInfo, ExpectedQPitch);
                  }
  
                  uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, MCSTileSize[0][1]);
                  VerifyResourceSize<true>(MCSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize));
  
                  pGmmULTClientContext->DestroyResInfoObject(MCSResourceInfo);
              } //MCS
  
              pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo);
          } //NumSamples = k
      }     //Iterate through all input tuples
  }
  
  /// @brief ULT for Plannar 2D Resource - RGBP
  TEST_F(CTestResource, TestPlanar2D_RGBP)
  {
      /* Test planar surfaces where all planes are full-sized */
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // UUUUUUUU
      // UUUUUUUU
      // UUUUUUUU
      // UUUUUUUU
      // VVVVVVVV
      // VVVVVVVV
      // VVVVVVVV
      // VVVVVVVV
      const TEST_TILE_TYPE TileTypes[]       = {TEST_LINEAR, TEST_TILEX, TEST_TILEY};
      const uint32_t       PlaneRowAlignment = 16;
  
      const uint32_t TileSize[3][2] = {{1, 1},     //Linear
                                       {512, 8},   // TileX
                                       {128, 32}}; // TileY
      for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++)
      {
          TEST_TILE_TYPE Tile = TileTypes[TileIndex];
  
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = 0x101;
          gmmParams.BaseHeight           = 0x101;
          gmmParams.Depth                = 0x1;
          SetTileFlag(gmmParams, static_cast<TEST_TILE_TYPE>(Tile));
          gmmParams.Format = GMM_FORMAT_RGBP;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t Pitch, Height;
          if(Tile != TEST_LINEAR)
          {
              Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
              //Since Tile alignment factor is greater than GMM_IMCx_PLANE_ROW_ALIGNMENT=16
              Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              Height = GMM_ULT_ALIGN(Height, TileSize[TileIndex][1]) * 3 /*Y, U, V*/;
          }
          else
          {
              Pitch  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64));
              Height = gmmParams.BaseHeight * 3 /*Y, U, V*/;
          }
          uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          if(Tile != TEST_LINEAR)
          {
              VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[TileIndex][0]);
          }
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
          // Y plane should be at 0,0
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
          EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
          // U plane should be at end of Y plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
          EXPECT_EQ(Height / 3, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
  
          // V plane should be at end of U plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
          EXPECT_EQ(2 * (Height / 3), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Plannar 2D Resource Unaligned - RGBP
  TEST_F(CTestResource, TestPlanar2D_RGBP_Unaligned)
  {
      /* Test planar surfaces where all planes are full-sized */
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // UUUUUUUU
      // UUUUUUUU
      // UUUUUUUU
      // UUUUUUUU
      // VVVVVVVV
      // VVVVVVVV
      // VVVVVVVV
      // VVVVVVVV
      const TEST_TILE_TYPE TileTypes[]       = {TEST_LINEAR, TEST_TILEX, TEST_TILEY};
      const uint32_t       PlaneRowAlignment = 16;
  
      const uint32_t TileSize[3][2] = {{1, 1},     //Linear
                                       {512, 8},   // TileX
                                       {128, 32}}; // TileY
      for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++)
      {
          TEST_TILE_TYPE Tile = TileTypes[TileIndex];
  
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = 480;
          gmmParams.BaseHeight           = 300;
          gmmParams.Depth                = 0x1;
          SetTileFlag(gmmParams, static_cast<TEST_TILE_TYPE>(Tile));
          gmmParams.Format = GMM_FORMAT_RGBP;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t Pitch, Height;
          if(Tile != TEST_LINEAR)
          {
              Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
              //Since Tile alignment factor is greater than GMM_IMCx_PLANE_ROW_ALIGNMENT=16
              Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              Height = GMM_ULT_ALIGN(Height, TileSize[TileIndex][1]) * 3 /*Y, U, V*/;
          }
          else
          {
              Pitch  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64));
              Height = gmmParams.BaseHeight * 3 /*Y, U, V*/;
          }
          uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          if(Tile != TEST_LINEAR)
          {
              VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[TileIndex][0]);
          }
  
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
          // Y plane should be at 0,0
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
          EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
          // U plane should be at end of Y plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
          EXPECT_EQ(Height / 3, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
  
          // V plane should be at end of U plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
          EXPECT_EQ(2 * (Height / 3), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
  
          //Resource Offset
          //Y PLANE
          GMM_REQ_OFFSET_INFO OffsetInfo = {};
          OffsetInfo.ReqRender           = 1;
          OffsetInfo.MipLevel            = 0; //Mip 0
          OffsetInfo.Plane               = GMM_PLANE_Y;
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(0, OffsetInfo.Render.Offset64);
  
          //U PLANE
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 0; //Mip 0
          OffsetInfo.Plane     = GMM_PLANE_U;
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(Pitch * (Height / 3), OffsetInfo.Render.Offset64);
  
          // V PLANE
          OffsetInfo.ReqRender = 1;
          OffsetInfo.MipLevel  = 0; //Mip 0
          OffsetInfo.Plane     = GMM_PLANE_V;
          ResourceInfo->GetOffset(OffsetInfo);
          EXPECT_EQ(2 * Pitch * (Height / 3), OffsetInfo.Render.Offset64);
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Plannar 2D Resource - MFX_JPEG_YUV422V
  TEST_F(CTestResource, TestPlanar2D_MFX_JPEG_YUV422V)
  {
      /* Test planar surfaces where both U and V are half the size of Y */
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // UUUUUUUU
      // UUUUUUUU
      // VVVVVVVV
      // VVVVVVVV
      const TEST_TILE_TYPE TileTypes[]       = {TEST_LINEAR, TEST_TILEX, TEST_TILEY};
      const uint32_t       PlaneRowAlignment = 16;
  
      const uint32_t TileSize[3][2] = {{1, 1},     //Linear
                                       {512, 8},   // TileX
                                       {128, 32}}; // TileY
      for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++)
      {
          TEST_TILE_TYPE Tile = TileTypes[TileIndex];
  
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = 0x101;
          gmmParams.BaseHeight           = 0x101;
          gmmParams.Depth                = 0x1;
          SetTileFlag(gmmParams, static_cast<TEST_TILE_TYPE>(Tile));
          gmmParams.Flags.Info.Linear = 1; // GmmLib needs linear to be set as fallback for all planar surfaces
          gmmParams.Format            = GMM_FORMAT_MFX_JPEG_YUV422V;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t Pitch, Height;
          uint32_t YHeight, VHeight;
          if(Tile != TEST_LINEAR)
          {
              Pitch   = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
              YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]);
  
              VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) / 2, PlaneRowAlignment);
              VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]);
          }
          else
          {
              Pitch   = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64));
              YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) / 2, PlaneRowAlignment);
          }
          Height        = YHeight + 2 * VHeight;
          uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          if(Tile != TEST_LINEAR)
          {
              VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[TileIndex][0]);
          }
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
          // Y plane should be at 0,0
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
          EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
          // U plane should be at end of Y plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
          EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
  
          // V plane should be at end of U plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
          EXPECT_EQ(YHeight + VHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Plannar 2D Resource - MFX_JPEG_YUV411R
  TEST_F(CTestResource, TestPlanar2D_MFX_JPEG_YUV411R)
  {
      /* Test planar surfaces where both U and V are quarter the size of Y */
      //YYYYYYYY
      //YYYYYYYY
      //YYYYYYYY
      //YYYYYYYY
      //UUUUUUUU
      //VVVVVVVV
      const TEST_TILE_TYPE TileTypes[]       = {TEST_LINEAR, TEST_TILEX, TEST_TILEY};
      const uint32_t       PlaneRowAlignment = 16;
  
      const uint32_t TileSize[3][2] = {{1, 1},     //Linear
                                       {512, 8},   // TileX
                                       {128, 32}}; // TileY
      for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++)
      {
          TEST_TILE_TYPE Tile = TileTypes[TileIndex];
  
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = 0x101;
          gmmParams.BaseHeight           = 0x101;
          gmmParams.Depth                = 0x1;
          SetTileFlag(gmmParams, static_cast<TEST_TILE_TYPE>(Tile));
          gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV411R_TYPE;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t Pitch, Height;
          uint32_t YHeight, VHeight;
          if(Tile != TEST_LINEAR)
          {
              Pitch   = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
              YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]);
  
              VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 4) / 4, PlaneRowAlignment);
              VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]);
          }
          else
          {
              Pitch   = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64));
              YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 4) / 4, PlaneRowAlignment);
          }
  
          Height        = YHeight + 2 * VHeight;
          uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          if(Tile != TEST_LINEAR)
          {
              VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[TileIndex][0]);
          }
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
          // Y plane should be at 0,0
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
          EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
          // U plane should be at end of Y plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
          EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
  
          // V plane should be at end of U plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
          EXPECT_EQ(YHeight + VHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Plannar 2D Resource - NV12
  TEST_F(CTestResource, TestPlanar2D_NV12)
  {
      /* Test planar surface with hybrid UV planes where UV plane is half the size
         of Y and U/V data is packed together */
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // [UV-Packing]
      const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY};
  
      const uint32_t TileSize[3][2] = {{1, 1},     //Linear
                                       {512, 8},   // TileX
                                       {128, 32}}; // TileY
      for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++)
      {
          TEST_TILE_TYPE Tile = TileTypes[TileIndex];
  
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = 0x100;
          gmmParams.BaseHeight           = 0x100;
          gmmParams.Depth                = 0x1;
          SetTileFlag(gmmParams, static_cast<TEST_TILE_TYPE>(Tile));
          gmmParams.Format = GMM_FORMAT_NV12;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t Pitch, Height;
  
          if(Tile != TEST_LINEAR)
          {
              Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
  
              Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]) +
                       GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[TileIndex][1]);
          }
          else
          {
              Pitch  = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
              Height = GMM_ULT_ALIGN(gmmParams.BaseHeight /*Y*/ + gmmParams.BaseHeight / 2 /*UV*/, TileSize[TileIndex][1]);
          }
          uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          if(Tile != TEST_LINEAR)
          {
              VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[TileIndex][0]);
          }
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
          // Y plane should be at 0,0
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
          EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
          // U/V plane should be at end of Y plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
  
          if(Tile != TEST_LINEAR)
          {
              EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
              EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
          }
          else
          {
              EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
              EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
          }
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Planar 2D Resource - IMC4
  TEST_F(CTestResource, TestPlanar2D_IMC4)
  {
      /* Test planar surface V surface is on the right of U */
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // UUUUVVVV
      // UUUUVVVV
      const TEST_TILE_TYPE TileTypes[]       = {TEST_LINEAR, TEST_TILEX, TEST_TILEY};
      const uint32_t       PlaneRowAlignment = 16;
  
      const uint32_t TileSize[3][2] = {{1, 1},     //Linear
                                       {512, 8},   // TileX
                                       {128, 32}}; // TileY
      for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++)
      {
          TEST_TILE_TYPE Tile = TileTypes[TileIndex];
  
          GMM_RESCREATE_PARAMS gmmParams = {};
          gmmParams.Type                 = RESOURCE_2D;
          gmmParams.NoGfxMemory          = 1;
          gmmParams.Flags.Gpu.Texture    = 1;
          gmmParams.BaseWidth64          = 0x101;
          gmmParams.BaseHeight           = 0x101;
          gmmParams.Depth                = 0x1;
          SetTileFlag(gmmParams, static_cast<TEST_TILE_TYPE>(Tile));
          gmmParams.Format = GMM_FORMAT_IMC4;
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint32_t Pitch, Height;
          uint32_t YHeight, VHeight;
          if(Tile != TEST_LINEAR)
          {
              Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]);
              if(Pitch / TileSize[TileIndex][0] % 2)
              {
                  Pitch += TileSize[TileIndex][0];
              }
  
              YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              VHeight = YHeight / 2;
  
              YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]);
              VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); // No need of PlaneRowAlignment since last plane
          }
          else
          {
              Pitch   = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64));
              YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment);
              VHeight = YHeight / 2;
          }
  
          Height = YHeight + VHeight;
  
          uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          if(Tile != TEST_LINEAR)
          {
              VerifyResourcePitchInTiles<true>(ResourceInfo, Pitch / TileSize[TileIndex][0]);
          }
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
          // Y plane should be at 0,0
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
          EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
          // U plane should be at end of Y plane
          EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
          EXPECT_EQ(Pitch / 2, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
  
          if(Tile != TEST_LINEAR)
          {
              EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
              EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
          }
          else
          {
              EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
              EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
          }
      }
  }
  
  /// @brief ULT for Planar 2D Resource - YV12
  TEST_F(CTestResource, TestPlanar2D_YV12)
  {
      /* Test planar surface V surface follows U surface linearly */
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // YYYYYYYY
      // VVVVVV..  <-- V and U planes follow the Y plane, as linear
      // ..UUUUUU      arrays--without respect to pitch.
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.BaseWidth64          = 0x100;
      gmmParams.BaseHeight           = 0x100;
      gmmParams.Depth                = 0x1;
      gmmParams.Flags.Info.Linear    = 1; // Linear only since UV plane doesn't have a pitch
      gmmParams.Format               = GMM_FORMAT_YV12;
  
      GMM_RESOURCE_INFO *ResourceInfo;
      ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
      uint32_t Pitch   = gmmParams.BaseWidth64;
      uint32_t SizeOfY = Pitch * gmmParams.BaseHeight;
      uint32_t Height  = (SizeOfY /*Y*/ + SizeOfY / 4 /*V*/ + SizeOfY / 4 /*U*/) / Pitch;
      uint32_t Size    = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4));
  
      VerifyResourcePitch<true>(ResourceInfo, Pitch);
      VerifyResourcePitchInTiles<false>(ResourceInfo, 0); // N/A for linear
      VerifyResourceSize<true>(ResourceInfo, Size);
      VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
      VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
      VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for planar
  
      // Y plane should be at 0,0
      EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y));
      EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y));
  
      // V plane follows Y
      EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V));
      EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V));
  
      // U plane should be at end of V plane
      uint32_t UByteOffset = SizeOfY /* Y */ +
                             SizeOfY / 4; /* Size of V = 1/4 of Y */
      EXPECT_EQ(UByteOffset % Pitch, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U));
      EXPECT_EQ(UByteOffset / Pitch, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U));
  
      pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
  }
  
  /// @brief ULT for Unified aux surface
  TEST_F(CTestResource, TestUnifiedAuxSurface)
  {
      uint32_t TileSize[] = {128, 32};
  
      GMM_RESCREATE_PARAMS gmmParams        = {};
      gmmParams.Type                        = RESOURCE_2D;
      gmmParams.NoGfxMemory                 = 1;
      gmmParams.Flags.Gpu.Texture           = 1;
      gmmParams.Flags.Gpu.CCS               = 1;
      gmmParams.Flags.Gpu.UnifiedAuxSurface = 1;
      gmmParams.BaseWidth64                 = 0x100;
      gmmParams.BaseHeight                  = 0x100;
      gmmParams.Depth                       = 0x1;
      SetTileFlag(gmmParams, TEST_TILEY);
  
      for(uint32_t bpp = TEST_BPP_32; bpp <= TEST_BPP_128; bpp++) // 32/64/128 only
      {
          gmmParams.Format = SetResourceFormat(static_cast<TEST_BPP>(bpp));
  
          GMM_RESOURCE_INFO *ResourceInfo;
          ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
          uint64_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * GetBppValue(static_cast<TEST_BPP>(bpp)), TileSize[0]);
          uint64_t Size  = Pitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]);
  
          Size = GMM_ULT_ALIGN(Size, PAGE_SIZE);
  
          VerifyResourcePitch<true>(ResourceInfo, Pitch);
          VerifyResourcePitchInTiles<false>(ResourceInfo, Pitch / TileSize[0]);
          VerifyResourceSize<true>(ResourceInfo, Size);
          VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
          VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for non-arrayed
  
          uint32_t AuxPitch = Pitch;
          switch(bpp)
          {
              case TEST_BPP_32:
                  AuxPitch /= 8;
                  break;
              case TEST_BPP_64:
                  AuxPitch /= 4;
                  break;
              case TEST_BPP_128:
                  AuxPitch /= 2;
                  break;
          }
          uint64_t AuxSize = AuxPitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]);
          AuxSize          = GMM_ULT_ALIGN(AuxSize, PAGE_SIZE);
  
          // Verify unified aux info
          EXPECT_EQ(AuxSize, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS));
  
          if(ResourceInfo->Is64KBPageSuitable())
          {
              EXPECT_EQ(GMM_ULT_ALIGN(Size, 64 * PAGE_SIZE) + AuxSize, ResourceInfo->GetSizeSurface());
          }
          else
          {
              EXPECT_EQ(Size + AuxSize, ResourceInfo->GetSizeSurface());
          }
  
          EXPECT_EQ(256, ResourceInfo->GetAuxHAlign());
          EXPECT_EQ(128, ResourceInfo->GetAuxVAlign());
          EXPECT_EQ(0, ResourceInfo->GetAuxQPitch());
          EXPECT_EQ(AuxPitch, ResourceInfo->GetUnifiedAuxPitch());
          EXPECT_EQ(AuxPitch / TileSize[0], ResourceInfo->GetRenderAuxPitchTiles());
          EXPECT_EQ(Size, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS));
  
          pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
      }
  }
  
  /// @brief ULT for Compressed Resource
  TEST_F(CTestResource, TestCompressedSurface)
  {
      uint32_t TileSize[]  = {128, 32};
      uint32_t CompBlock[] = {4, 4};
  
      GMM_RESCREATE_PARAMS gmmParams = {};
      gmmParams.Type                 = RESOURCE_2D;
      gmmParams.NoGfxMemory          = 1;
      gmmParams.Flags.Gpu.Texture    = 1;
      gmmParams.BaseWidth64          = 0x100;
      gmmParams.BaseHeight           = 0x100;
      gmmParams.Depth                = 0x1;
      SetTileFlag(gmmParams, TEST_TILEY);
      //TODO: Programatically test all compression formats.
      gmmParams.Format = GMM_FORMAT_BC1_UNORM; // BC1 is 4x4 compression block, 64bpe
  
      GMM_RESOURCE_INFO *ResourceInfo;
      ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams);
  
      uint64_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / CompBlock[0] * GetBppValue(TEST_BPP_64), TileSize[0]);
      uint64_t Size  = Pitch * GMM_ULT_ALIGN(gmmParams.BaseHeight / CompBlock[1], TileSize[1]);
      Size           = GMM_ULT_ALIGN(Size, PAGE_SIZE);
  
      VerifyResourcePitch<true>(ResourceInfo, Pitch);
      VerifyResourcePitchInTiles<false>(ResourceInfo, Pitch / TileSize[0]);
      VerifyResourceSize<true>(ResourceInfo, Size);
      VerifyResourceHAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
      VerifyResourceVAlign<false>(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere
      VerifyResourceQPitch<false>(ResourceInfo, 0); // N/A for non-arrayed
  
      pGmmULTClientContext->DestroyResInfoObject(ResourceInfo);
  }
  