/*============================================================================== 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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); // 2 tile wide VerifyResourceSize(ResourceInfo, PitchInBytes * AlignedHeight); // 4 tile big x 4 array size VerifyResourceQPitch(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(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(ResourceInfo, AllocationHeight * Pitch); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(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(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(ResourceInfo, PAGE_SIZE); // everything should fit in 1 tile VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 256 x 256 for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(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(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileWidth); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // 1 Tile Big VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileWidth * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2); // 2 tile big VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileWidth * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 4 tile big VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes / TileWidth * GMM_KBYTE(4)); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes / TileWidth * GMM_KBYTE(4)); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes / TileWidth * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes * AlignedHeight); // 4 tile big x 4 array size VerifyResourceQPitch(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(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(ResourceInfo, AllocationHeight * Pitch); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(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(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(ResourceInfo, PAGE_SIZE); // everything should fit in 1 tile VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(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(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 1); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(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(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(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GMM_ULT_MAX(GMM_BYTES(32), HAlign * GetBppValue(bpp)); // Min Pitch = 32 bytes VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // not applicable uint32_t ExpectedQPitch = VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(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(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(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(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // not applicable uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(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(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(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(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(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(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(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(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(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(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(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(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0][0]); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // All 6 faces should be accomated in a tile. VerifyResourceQPitch(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(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(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(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(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(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(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(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2; // 2 TileW tiles interleaved on same row VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile } VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, further doubled for interleaved rows 2*w = Pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile } VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, double again for interleaved rows 2*w = Pitch, VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(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(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, TwoDQPitch); //Gen8 doesn't support QPitch for RES_3D ExpectedQPitch = gmmParams.Depth * TwoDQPitch; //Depth slices arranged as 2D-arrayed slices. } VerifyResourceSize(ResourceInfo, ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch / 2, AllocTileSize[0][1])); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } //Mip-mapped array case: Stencil QPitch = h0 ie Stencil only has Lod0 //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(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(i); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile, Turn on verification after clarity } VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 2; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile. Turn on verification after clarity } VerifyResourceSize(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(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(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 2; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(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> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, TestArraySize index auto Size = BuildInputIterator(List, 3, 2, false); // 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(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(MSSResourceInfo, HAlign); VerifyResourceVAlign(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(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); //if (gmmParams.ArraySize > 1) - Arrayed MSS has QPitch { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } else // Interleaved MSS { uint32_t WidthMultiplier, HeightMultiplier; GetInterleaveMSSPattern((TEST_MSAA)k, WidthMultiplier, HeightMultiplier, IsRT, Bpp); 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(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) { VerifyResourcePitchInTiles(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(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, TileDimY); //Align Height = ExpectedQPitch*ArraySize, to Tile-Height VerifyResourceSize(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(MCSResourceInfo, MCSHAlign); // MCS alignment same as basic RT alignment VerifyResourceVAlign(MCSResourceInfo, MCSVAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, MCSHAlign) * ExpectedMCSBpp, MCSTileSize[0][0]); //AlignedWidth*bpp, then tile-alignment VerifyResourcePitch(MCSResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(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(MCSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, MCSTileSize[0][1]); VerifyResourceSize(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(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(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(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(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(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(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(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(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(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(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(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(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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)); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @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(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(bpp)); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint64_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * GetBppValue(static_cast(bpp)), TileSize[0]); uint64_t Size = Pitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]); Size = GMM_ULT_ALIGN(Size, PAGE_SIZE); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[0]); VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(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(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[0]); VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); }