12f083884Ss.makeev_local // The MIT License (MIT) 22f083884Ss.makeev_local // 32f083884Ss.makeev_local // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 42f083884Ss.makeev_local // 52f083884Ss.makeev_local // Permission is hereby granted, free of charge, to any person obtaining a copy 62f083884Ss.makeev_local // of this software and associated documentation files (the "Software"), to deal 72f083884Ss.makeev_local // in the Software without restriction, including without limitation the rights 82f083884Ss.makeev_local // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 92f083884Ss.makeev_local // copies of the Software, and to permit persons to whom the Software is 102f083884Ss.makeev_local // furnished to do so, subject to the following conditions: 112f083884Ss.makeev_local // 122f083884Ss.makeev_local // The above copyright notice and this permission notice shall be included in 132f083884Ss.makeev_local // all copies or substantial portions of the Software. 142f083884Ss.makeev_local // 152f083884Ss.makeev_local // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 162f083884Ss.makeev_local // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 172f083884Ss.makeev_local // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 182f083884Ss.makeev_local // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 192f083884Ss.makeev_local // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 202f083884Ss.makeev_local // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 212f083884Ss.makeev_local // THE SOFTWARE. 222f083884Ss.makeev_local 232f083884Ss.makeev_local #include "Tests.h" 242f083884Ss.makeev_local #include <UnitTest++.h> 252f083884Ss.makeev_local #include <MTScheduler.h> 262f083884Ss.makeev_local 272f083884Ss.makeev_local #include <squish.h> 282f083884Ss.makeev_local #include <string.h> 29faa6c6e5Ss.makeev_local #include <math.h> 302f083884Ss.makeev_local 31*60ac17fbSs.makeev_local 322f083884Ss.makeev_local /* 332f083884Ss.makeev_local #ifdef _WIN32 342f083884Ss.makeev_local 352f083884Ss.makeev_local #include <conio.h> 362f083884Ss.makeev_local 372f083884Ss.makeev_local #else 382f083884Ss.makeev_local 392f083884Ss.makeev_local #include <stdio.h> 402f083884Ss.makeev_local #include <termios.h> 412f083884Ss.makeev_local #include <unistd.h> 422f083884Ss.makeev_local #include <fcntl.h> 432f083884Ss.makeev_local 442f083884Ss.makeev_local int _kbhit(void) 452f083884Ss.makeev_local { 462f083884Ss.makeev_local struct termios oldt, newt; 472f083884Ss.makeev_local int ch; 482f083884Ss.makeev_local int oldf; 492f083884Ss.makeev_local 502f083884Ss.makeev_local tcgetattr(STDIN_FILENO, &oldt); 512f083884Ss.makeev_local newt = oldt; 522f083884Ss.makeev_local newt.c_lflag &= ~(ICANON | ECHO); 532f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &newt); 542f083884Ss.makeev_local oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 552f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 562f083884Ss.makeev_local 572f083884Ss.makeev_local ch = getchar(); 582f083884Ss.makeev_local 592f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 602f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf); 612f083884Ss.makeev_local 622f083884Ss.makeev_local if(ch != EOF) 632f083884Ss.makeev_local { 642f083884Ss.makeev_local ungetc(ch, stdin); 652f083884Ss.makeev_local return 1; 662f083884Ss.makeev_local } 672f083884Ss.makeev_local 682f083884Ss.makeev_local return 0; 692f083884Ss.makeev_local } 702f083884Ss.makeev_local #endif 712f083884Ss.makeev_local */ 722f083884Ss.makeev_local 732f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 742f083884Ss.makeev_local 752f083884Ss.makeev_local class Microprofile : public MT::IProfilerEventListener 762f083884Ss.makeev_local { 772f083884Ss.makeev_local void OnThreadCreated(uint32 workerIndex) 782f083884Ss.makeev_local { 792f083884Ss.makeev_local MT_UNUSED(workerIndex); 802f083884Ss.makeev_local } 812f083884Ss.makeev_local 822f083884Ss.makeev_local void OnThreadStarted(uint32 workerIndex) 832f083884Ss.makeev_local { 842f083884Ss.makeev_local MT_UNUSED(workerIndex); 852f083884Ss.makeev_local } 862f083884Ss.makeev_local 872f083884Ss.makeev_local void OnThreadStoped(uint32 workerIndex) 882f083884Ss.makeev_local { 892f083884Ss.makeev_local MT_UNUSED(workerIndex); 902f083884Ss.makeev_local } 912f083884Ss.makeev_local 922f083884Ss.makeev_local void OnThreadIdleBegin(uint32 workerIndex) 932f083884Ss.makeev_local { 942f083884Ss.makeev_local MT_UNUSED(workerIndex); 952f083884Ss.makeev_local } 962f083884Ss.makeev_local 972f083884Ss.makeev_local void OnThreadIdleEnd(uint32 workerIndex) 982f083884Ss.makeev_local { 992f083884Ss.makeev_local MT_UNUSED(workerIndex); 1002f083884Ss.makeev_local } 1012f083884Ss.makeev_local 102*60ac17fbSs.makeev_local void OnTaskBeginExecute(MT::Color::Type debugColor, const mt_char* debugID) 1032f083884Ss.makeev_local { 1042f083884Ss.makeev_local MT_UNUSED(debugColor); 1052f083884Ss.makeev_local MT_UNUSED(debugID); 1062f083884Ss.makeev_local } 1072f083884Ss.makeev_local 108*60ac17fbSs.makeev_local void OnTaskEndExecute(MT::Color::Type debugColor, const mt_char* debugID) 1092f083884Ss.makeev_local { 1102f083884Ss.makeev_local MT_UNUSED(debugColor); 1112f083884Ss.makeev_local MT_UNUSED(debugID); 1122f083884Ss.makeev_local } 1132f083884Ss.makeev_local 1142f083884Ss.makeev_local }; 1152f083884Ss.makeev_local 1162f083884Ss.makeev_local 1172f083884Ss.makeev_local #endif 1182f083884Ss.makeev_local 1192f083884Ss.makeev_local 1202f083884Ss.makeev_local 1212f083884Ss.makeev_local 1222f083884Ss.makeev_local 1232f083884Ss.makeev_local namespace EmbeddedImage 1242f083884Ss.makeev_local { 1252f083884Ss.makeev_local #include "LenaDxt/LenaColor.h" 1262f083884Ss.makeev_local #include "LenaDxt/HeaderDDS.h" 1272f083884Ss.makeev_local } 1282f083884Ss.makeev_local 1292f083884Ss.makeev_local 1302f083884Ss.makeev_local bool CompareImagesPSNR(uint8 * img1, uint8 * img2, uint32 bytesCount, double psnrThreshold) 1312f083884Ss.makeev_local { 1322f083884Ss.makeev_local double mse = 0.0; 1332f083884Ss.makeev_local 1342f083884Ss.makeev_local for (uint32 i = 0; i < bytesCount; i++) 1352f083884Ss.makeev_local { 1362f083884Ss.makeev_local double error = (double)img1[0] - (double)img2[1]; 1372f083884Ss.makeev_local mse += (error * error); 1382f083884Ss.makeev_local } 1392f083884Ss.makeev_local 1402f083884Ss.makeev_local mse = mse / (double)bytesCount; 1412f083884Ss.makeev_local 1422f083884Ss.makeev_local if (mse > 0.0) 1432f083884Ss.makeev_local { 1442f083884Ss.makeev_local double psnr = 10.0 * log10(255.0*255.0/mse); 1452f083884Ss.makeev_local if (psnr < psnrThreshold) 1462f083884Ss.makeev_local { 1472f083884Ss.makeev_local return false; 1482f083884Ss.makeev_local } 1492f083884Ss.makeev_local } 1502f083884Ss.makeev_local 1512f083884Ss.makeev_local return true; 1522f083884Ss.makeev_local } 1532f083884Ss.makeev_local 1542f083884Ss.makeev_local 1552f083884Ss.makeev_local 1562f083884Ss.makeev_local SUITE(DxtTests) 1572f083884Ss.makeev_local { 1582f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1592f083884Ss.makeev_local struct CompressDxtBlock 1602f083884Ss.makeev_local { 1612f083884Ss.makeev_local MT_DECLARE_TASK(CompressDxtBlock, MT::StackRequirements::STANDARD, MT::Color::Blue); 1622f083884Ss.makeev_local 1632f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 1642f083884Ss.makeev_local MT::ArrayView<uint8> dstBlocks; 1652f083884Ss.makeev_local 1662f083884Ss.makeev_local int srcX; 1672f083884Ss.makeev_local int srcY; 1682f083884Ss.makeev_local 1692f083884Ss.makeev_local int stride; 1702f083884Ss.makeev_local int dstBlockOffset; 1712f083884Ss.makeev_local 1722f083884Ss.makeev_local CompressDxtBlock(int _srcX, int _srcY, int _stride, const MT::ArrayView<uint8> & _srcPixels, const MT::ArrayView<uint8> & _dstBlocks, int _dstBlockOffset) 1732f083884Ss.makeev_local : srcPixels(_srcPixels) 1742f083884Ss.makeev_local , dstBlocks(_dstBlocks) 1752f083884Ss.makeev_local { 1762f083884Ss.makeev_local srcX = _srcX; 1772f083884Ss.makeev_local srcY = _srcY; 1782f083884Ss.makeev_local stride = _stride; 1792f083884Ss.makeev_local dstBlockOffset = _dstBlockOffset; 1802f083884Ss.makeev_local } 1812f083884Ss.makeev_local 1822f083884Ss.makeev_local CompressDxtBlock(CompressDxtBlock&& other) 1832f083884Ss.makeev_local : srcPixels(other.srcPixels) 1842f083884Ss.makeev_local , dstBlocks(other.dstBlocks) 1852f083884Ss.makeev_local , srcX(other.srcX) 1862f083884Ss.makeev_local , srcY(other.srcY) 1872f083884Ss.makeev_local , stride(other.stride) 1882f083884Ss.makeev_local , dstBlockOffset(other.dstBlockOffset) 1892f083884Ss.makeev_local { 1902f083884Ss.makeev_local other.srcX = -1; 1912f083884Ss.makeev_local other.srcY = -1; 1922f083884Ss.makeev_local other.stride = -1; 1932f083884Ss.makeev_local other.dstBlockOffset = -1; 1942f083884Ss.makeev_local } 1952f083884Ss.makeev_local 1962f083884Ss.makeev_local ~CompressDxtBlock() 1972f083884Ss.makeev_local { 1982f083884Ss.makeev_local srcX = -1; 1992f083884Ss.makeev_local srcY = -1; 2002f083884Ss.makeev_local stride = -1; 2012f083884Ss.makeev_local dstBlockOffset = -1; 2022f083884Ss.makeev_local } 2032f083884Ss.makeev_local 2042f083884Ss.makeev_local void Do(MT::FiberContext&) 2052f083884Ss.makeev_local { 2062f083884Ss.makeev_local // 16 pixels of input 2072f083884Ss.makeev_local uint32 pixels[4*4]; 2082f083884Ss.makeev_local 2092f083884Ss.makeev_local // copy dxt1 block from image 2102f083884Ss.makeev_local for (int y = 0; y < 4; y++) 2112f083884Ss.makeev_local { 2122f083884Ss.makeev_local for (int x = 0; x < 4; x++) 2132f083884Ss.makeev_local { 2142f083884Ss.makeev_local int posX = srcX + x; 2152f083884Ss.makeev_local int posY = srcY + y; 2162f083884Ss.makeev_local 2172f083884Ss.makeev_local int index = posY * stride + (posX * 3); 2182f083884Ss.makeev_local 2192f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 2202f083884Ss.makeev_local 2212f083884Ss.makeev_local uint8 r = srcPixels[index + 0]; 2222f083884Ss.makeev_local uint8 g = srcPixels[index + 1]; 2232f083884Ss.makeev_local uint8 b = srcPixels[index + 2]; 2242f083884Ss.makeev_local 2252f083884Ss.makeev_local uint32 color = 0xFF000000 | ((b << 16) | (g << 8) | (r)); 2262f083884Ss.makeev_local 2272f083884Ss.makeev_local pixels[y * 4 + x] = color; 2282f083884Ss.makeev_local } 2292f083884Ss.makeev_local } 2302f083884Ss.makeev_local 2312f083884Ss.makeev_local // compress the 4x4 block using DXT1 compression 2322f083884Ss.makeev_local squish::Compress( (squish::u8 *)&pixels[0], &dstBlocks[dstBlockOffset], squish::kDxt1 ); 2332f083884Ss.makeev_local } 2342f083884Ss.makeev_local }; 2352f083884Ss.makeev_local 2362f083884Ss.makeev_local 2372f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2382f083884Ss.makeev_local struct CompressDxt 2392f083884Ss.makeev_local { 2402f083884Ss.makeev_local MT_DECLARE_TASK(CompressDxt, MT::StackRequirements::EXTENDED, MT::Color::Aqua); 2412f083884Ss.makeev_local 2422f083884Ss.makeev_local uint32 width; 2432f083884Ss.makeev_local uint32 height; 2442f083884Ss.makeev_local uint32 stride; 2452f083884Ss.makeev_local 2462f083884Ss.makeev_local uint32 blkWidth; 2472f083884Ss.makeev_local uint32 blkHeight; 2482f083884Ss.makeev_local 2492f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 2502f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 251d7cf17b1Ss.makeev_local MT::Atomic32<uint32>* pIsFinished; 2522f083884Ss.makeev_local 253d7cf17b1Ss.makeev_local 254d7cf17b1Ss.makeev_local CompressDxt(uint32 _width, uint32 _height, uint32 _stride, const MT::ArrayView<uint8> & _srcPixels, MT::Atomic32<uint32>* _pIsFinished = nullptr) 2552f083884Ss.makeev_local : srcPixels(_srcPixels) 256d7cf17b1Ss.makeev_local , pIsFinished(_pIsFinished) 2572f083884Ss.makeev_local { 2582f083884Ss.makeev_local width = _width; 2592f083884Ss.makeev_local height = _height; 2602f083884Ss.makeev_local stride = _stride; 2612f083884Ss.makeev_local 2622f083884Ss.makeev_local blkWidth = width >> 2; 2632f083884Ss.makeev_local blkHeight = height >> 2; 2642f083884Ss.makeev_local 2652f083884Ss.makeev_local int dxtBlocksTotalSizeInBytes = blkWidth * blkHeight * 8; // 8 bytes = 64 bits per block (dxt1) 266d7cf17b1Ss.makeev_local dxtBlocks = MT::ArrayView<uint8>( MT::Memory::Alloc( dxtBlocksTotalSizeInBytes ), dxtBlocksTotalSizeInBytes); 2672f083884Ss.makeev_local } 2682f083884Ss.makeev_local 2692f083884Ss.makeev_local ~CompressDxt() 2702f083884Ss.makeev_local { 2712f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 2722f083884Ss.makeev_local if (pDxtBlocks) 2732f083884Ss.makeev_local { 274d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks); 2752f083884Ss.makeev_local } 2762f083884Ss.makeev_local } 2772f083884Ss.makeev_local 2782f083884Ss.makeev_local 2792f083884Ss.makeev_local void Do(MT::FiberContext& context) 2802f083884Ss.makeev_local { 2812f083884Ss.makeev_local // use stack_array as subtask container. beware stack overflow! 2822f083884Ss.makeev_local MT::StackArray<CompressDxtBlock, 1024> subTasks; 2832f083884Ss.makeev_local 2842f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 2852f083884Ss.makeev_local { 2862f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 2872f083884Ss.makeev_local { 2882f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 2892f083884Ss.makeev_local subTasks.PushBack( CompressDxtBlock(blkX * 4, blkY * 4, stride, srcPixels, dxtBlocks, blockIndex * 8) ); 2902f083884Ss.makeev_local } 2912f083884Ss.makeev_local } 2922f083884Ss.makeev_local 2932f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 294d7cf17b1Ss.makeev_local 295d7cf17b1Ss.makeev_local if (pIsFinished != nullptr) 296d7cf17b1Ss.makeev_local { 297d7cf17b1Ss.makeev_local pIsFinished->Store(1); 298d7cf17b1Ss.makeev_local } 2992f083884Ss.makeev_local } 3002f083884Ss.makeev_local }; 3012f083884Ss.makeev_local 3022f083884Ss.makeev_local 3032f083884Ss.makeev_local 3042f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 3052f083884Ss.makeev_local struct DecompressDxtBlock 3062f083884Ss.makeev_local { 3072f083884Ss.makeev_local MT_DECLARE_TASK(DecompressDxtBlock, MT::StackRequirements::STANDARD, MT::Color::Red); 3082f083884Ss.makeev_local 3092f083884Ss.makeev_local MT::ArrayView<uint8> srcBlocks; 3102f083884Ss.makeev_local MT::ArrayView<uint8> dstPixels; 3112f083884Ss.makeev_local 3122f083884Ss.makeev_local int dstX; 3132f083884Ss.makeev_local int dstY; 3142f083884Ss.makeev_local 3152f083884Ss.makeev_local int stride; 3162f083884Ss.makeev_local int srcBlockOffset; 3172f083884Ss.makeev_local 3182f083884Ss.makeev_local DecompressDxtBlock(int _dstX, int _dstY, int _stride, const MT::ArrayView<uint8> & _dstPixels, const MT::ArrayView<uint8> & _srcBlocks, int _srcBlockOffset) 3192f083884Ss.makeev_local : srcBlocks(_srcBlocks) 3202f083884Ss.makeev_local , dstPixels(_dstPixels) 3212f083884Ss.makeev_local { 3222f083884Ss.makeev_local dstX = _dstX; 3232f083884Ss.makeev_local dstY = _dstY; 3242f083884Ss.makeev_local stride = _stride; 3252f083884Ss.makeev_local srcBlockOffset = _srcBlockOffset; 3262f083884Ss.makeev_local } 3272f083884Ss.makeev_local 3282f083884Ss.makeev_local DecompressDxtBlock(DecompressDxtBlock&& other) 3292f083884Ss.makeev_local : srcBlocks(other.srcBlocks) 3302f083884Ss.makeev_local , dstPixels(other.dstPixels) 3312f083884Ss.makeev_local , dstX(other.dstX) 3322f083884Ss.makeev_local , dstY(other.dstY) 3332f083884Ss.makeev_local , stride(other.stride) 3342f083884Ss.makeev_local , srcBlockOffset(other.srcBlockOffset) 3352f083884Ss.makeev_local { 3362f083884Ss.makeev_local other.dstX = -1; 3372f083884Ss.makeev_local other.dstY = -1; 3382f083884Ss.makeev_local other.stride = -1; 3392f083884Ss.makeev_local other.srcBlockOffset = -1; 3402f083884Ss.makeev_local } 3412f083884Ss.makeev_local 3422f083884Ss.makeev_local ~DecompressDxtBlock() 3432f083884Ss.makeev_local { 3442f083884Ss.makeev_local dstX = -1; 3452f083884Ss.makeev_local dstY = -1; 3462f083884Ss.makeev_local stride = -1; 3472f083884Ss.makeev_local srcBlockOffset = -1; 3482f083884Ss.makeev_local } 3492f083884Ss.makeev_local 3502f083884Ss.makeev_local 3512f083884Ss.makeev_local void Do(MT::FiberContext&) 3522f083884Ss.makeev_local { 3532f083884Ss.makeev_local // 16 pixels of output 3542f083884Ss.makeev_local uint32 pixels[4*4]; 3552f083884Ss.makeev_local 3562f083884Ss.makeev_local // copy dxt1 block from image 3572f083884Ss.makeev_local for (int y = 0; y < 4; y++) 3582f083884Ss.makeev_local { 3592f083884Ss.makeev_local for (int x = 0; x < 4; x++) 3602f083884Ss.makeev_local { 3612f083884Ss.makeev_local squish::Decompress((squish::u8 *)&pixels[0], &srcBlocks[srcBlockOffset], squish::kDxt1); 3622f083884Ss.makeev_local 3632f083884Ss.makeev_local int posX = dstX + x; 3642f083884Ss.makeev_local int posY = dstY + y; 3652f083884Ss.makeev_local 3662f083884Ss.makeev_local int index = posY * stride + (posX * 3); 3672f083884Ss.makeev_local 3682f083884Ss.makeev_local uint32 pixel = pixels[y * 4 + x]; 3692f083884Ss.makeev_local 3702f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 3712f083884Ss.makeev_local 3722f083884Ss.makeev_local dstPixels[index + 0] = (pixel & 0xFF); 3732f083884Ss.makeev_local dstPixels[index + 1] = (pixel >> 8 & 0xFF); 3742f083884Ss.makeev_local dstPixels[index + 2] = (pixel >> 16 & 0xFF); 3752f083884Ss.makeev_local } 3762f083884Ss.makeev_local } 3772f083884Ss.makeev_local 3782f083884Ss.makeev_local } 3792f083884Ss.makeev_local }; 3802f083884Ss.makeev_local 3812f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 3822f083884Ss.makeev_local struct DecompressDxt 3832f083884Ss.makeev_local { 3842f083884Ss.makeev_local MT_DECLARE_TASK(DecompressDxt, MT::StackRequirements::EXTENDED, MT::Color::Yellow); 3852f083884Ss.makeev_local 3862f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 3872f083884Ss.makeev_local MT::ArrayView<uint8> decompressedImage; 3882f083884Ss.makeev_local 3892f083884Ss.makeev_local uint32 blkWidth; 3902f083884Ss.makeev_local uint32 blkHeight; 3912f083884Ss.makeev_local 3922f083884Ss.makeev_local 3932f083884Ss.makeev_local DecompressDxt(const MT::ArrayView<uint8> & _dxtBlocks, uint32 dxtBlocksCountWidth, uint32 dxtBlocksCountHeight) 3942f083884Ss.makeev_local : dxtBlocks(_dxtBlocks) 3952f083884Ss.makeev_local { 3962f083884Ss.makeev_local blkWidth = dxtBlocksCountWidth; 3972f083884Ss.makeev_local blkHeight = dxtBlocksCountHeight; 3982f083884Ss.makeev_local 3992f083884Ss.makeev_local // dxt1 block = 16 rgb pixels = 48 bytes 4002f083884Ss.makeev_local uint32 bytesCount = blkWidth * blkHeight * 48; 401d7cf17b1Ss.makeev_local decompressedImage = MT::ArrayView<uint8>( MT::Memory::Alloc(bytesCount), bytesCount); 4022f083884Ss.makeev_local } 4032f083884Ss.makeev_local 4042f083884Ss.makeev_local ~DecompressDxt() 4052f083884Ss.makeev_local { 4062f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 4072f083884Ss.makeev_local if (pDxtBlocks) 4082f083884Ss.makeev_local { 409d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks); 4102f083884Ss.makeev_local } 4112f083884Ss.makeev_local 4122f083884Ss.makeev_local void* pDecompressedImage = decompressedImage.GetRawData(); 4132f083884Ss.makeev_local if (pDecompressedImage) 4142f083884Ss.makeev_local { 415d7cf17b1Ss.makeev_local MT::Memory::Free(pDecompressedImage); 4162f083884Ss.makeev_local } 4172f083884Ss.makeev_local 4182f083884Ss.makeev_local } 4192f083884Ss.makeev_local 4202f083884Ss.makeev_local void Do(MT::FiberContext& context) 4212f083884Ss.makeev_local { 4222f083884Ss.makeev_local // use stack_array as subtask container. beware stack overflow! 4232f083884Ss.makeev_local MT::StackArray<DecompressDxtBlock, 1024> subTasks; 4242f083884Ss.makeev_local 4252f083884Ss.makeev_local int stride = blkWidth * 4 * 3; 4262f083884Ss.makeev_local 4272f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 4282f083884Ss.makeev_local { 4292f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 4302f083884Ss.makeev_local { 4312f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 4322f083884Ss.makeev_local subTasks.PushBack( DecompressDxtBlock(blkX * 4, blkY * 4, stride, decompressedImage, dxtBlocks, blockIndex * 8) ); 4332f083884Ss.makeev_local } 4342f083884Ss.makeev_local } 4352f083884Ss.makeev_local 4362f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 4372f083884Ss.makeev_local } 4382f083884Ss.makeev_local 4392f083884Ss.makeev_local }; 4402f083884Ss.makeev_local 4412f083884Ss.makeev_local 4422f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4432f083884Ss.makeev_local void Wait(MT::TaskScheduler & scheduler) 4442f083884Ss.makeev_local { 4452f083884Ss.makeev_local //emulate game loop 4462f083884Ss.makeev_local for(;;) 4472f083884Ss.makeev_local { 4482f083884Ss.makeev_local bool waitDone = scheduler.WaitAll(33); 4492f083884Ss.makeev_local if (waitDone) 4502f083884Ss.makeev_local { 4512f083884Ss.makeev_local break; 4522f083884Ss.makeev_local } 4532f083884Ss.makeev_local } 4542f083884Ss.makeev_local } 4552f083884Ss.makeev_local 4562f083884Ss.makeev_local 457*60ac17fbSs.makeev_local 458d7cf17b1Ss.makeev_local // dxt compressor Hiload test (for profiling purposes) 459d7cf17b1Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 460d7cf17b1Ss.makeev_local TEST(HiloadDxtTest) 461d7cf17b1Ss.makeev_local { 462d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished1; 463d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished2; 464d7cf17b1Ss.makeev_local 465d7cf17b1Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 466d7cf17b1Ss.makeev_local 467d7cf17b1Ss.makeev_local int stride = 384; 468d7cf17b1Ss.makeev_local 469d7cf17b1Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 470d7cf17b1Ss.makeev_local 471d7cf17b1Ss.makeev_local CompressDxt compressTask1(128, 128, stride, srcImage, &isFinished1); 472d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask1.width & 3) == 0 && (compressTask1.height & 3) == 0, "Image size must be a multiple of 4"); 473d7cf17b1Ss.makeev_local 474d7cf17b1Ss.makeev_local CompressDxt compressTask2(128, 128, stride, srcImage, &isFinished2); 475d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask2.width & 3) == 0 && (compressTask2.height & 3) == 0, "Image size must be a multiple of 4"); 476d7cf17b1Ss.makeev_local 477d7cf17b1Ss.makeev_local MT::TaskScheduler scheduler; 478d7cf17b1Ss.makeev_local 479d7cf17b1Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 480d7cf17b1Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 481d7cf17b1Ss.makeev_local 482d7cf17b1Ss.makeev_local isFinished1.Store(0); 483d7cf17b1Ss.makeev_local isFinished2.Store(0); 484d7cf17b1Ss.makeev_local 485d7cf17b1Ss.makeev_local printf("HiloadDxtTest\n"); 486d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1); 487d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1); 488d7cf17b1Ss.makeev_local 489d7cf17b1Ss.makeev_local for(;;) 490d7cf17b1Ss.makeev_local { 491d7cf17b1Ss.makeev_local if (isFinished1.Load() != 0) 492d7cf17b1Ss.makeev_local { 493d7cf17b1Ss.makeev_local isFinished1.Store(0); 494d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1); 495d7cf17b1Ss.makeev_local } 496d7cf17b1Ss.makeev_local 497d7cf17b1Ss.makeev_local if (isFinished2.Load() != 0) 498d7cf17b1Ss.makeev_local { 499d7cf17b1Ss.makeev_local isFinished2.Store(0); 500d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1); 501d7cf17b1Ss.makeev_local } 502d7cf17b1Ss.makeev_local 503d7cf17b1Ss.makeev_local MT::Thread::Sleep(1); 504d7cf17b1Ss.makeev_local } 505d7cf17b1Ss.makeev_local } 506*60ac17fbSs.makeev_local 507d7cf17b1Ss.makeev_local 5082f083884Ss.makeev_local // dxt compressor complex test 5092f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 5102f083884Ss.makeev_local TEST(RunComplexDxtTest) 5112f083884Ss.makeev_local { 5122f083884Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 5132f083884Ss.makeev_local 5142f083884Ss.makeev_local int stride = 384; 5152f083884Ss.makeev_local 5162f083884Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 5172f083884Ss.makeev_local 5182f083884Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage); 5192f083884Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4"); 5202f083884Ss.makeev_local 5212f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 5222f083884Ss.makeev_local Microprofile profiler; 523d7cf17b1Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, &profiler); 5242f083884Ss.makeev_local #else 5252f083884Ss.makeev_local MT::TaskScheduler scheduler; 5262f083884Ss.makeev_local #endif 5272f083884Ss.makeev_local 5282f083884Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 5292f083884Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 5302f083884Ss.makeev_local 5312f083884Ss.makeev_local printf("Compress image\n"); 5322f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1); 5332f083884Ss.makeev_local 5342f083884Ss.makeev_local Wait(scheduler); 5352f083884Ss.makeev_local 5362f083884Ss.makeev_local DecompressDxt decompressTask(compressTask.dxtBlocks, compressTask.blkWidth, compressTask.blkHeight); 5372f083884Ss.makeev_local compressTask.dxtBlocks = MT::ArrayView<uint8>(); //transfer memory ownership to Decompress task 5382f083884Ss.makeev_local 5392f083884Ss.makeev_local printf("Decompress image\n"); 5402f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &decompressTask, 1); 5412f083884Ss.makeev_local 5422f083884Ss.makeev_local Wait(scheduler); 5432f083884Ss.makeev_local 5442f083884Ss.makeev_local /* 5452f083884Ss.makeev_local //save compressed image 5462f083884Ss.makeev_local { 5472f083884Ss.makeev_local FILE * file = fopen("lena_dxt1.dds", "w+b"); 5482f083884Ss.makeev_local fwrite(&EmbeddedImage::ddsHeader[0], MT_ARRAY_SIZE(EmbeddedImage::ddsHeader), 1, file); 5492f083884Ss.makeev_local fwrite(decompressTask.dxtBlocks, decompressTask.blkWidth * decompressTask.blkHeight * 8, 1, file); 5502f083884Ss.makeev_local fclose(file); 5512f083884Ss.makeev_local } 5522f083884Ss.makeev_local 5532f083884Ss.makeev_local //save uncompressed image 5542f083884Ss.makeev_local { 5552f083884Ss.makeev_local FILE * file = fopen("lena_rgb.raw", "w+b"); 5562f083884Ss.makeev_local fwrite(decompressTask.decompressedImage, decompressTask.blkWidth * decompressTask.blkHeight * 48, 1, file); 5572f083884Ss.makeev_local fclose(file); 5582f083884Ss.makeev_local } 5592f083884Ss.makeev_local */ 5602f083884Ss.makeev_local 5612f083884Ss.makeev_local printf("Compare images\n"); 5622f083884Ss.makeev_local bool imagesEqual = CompareImagesPSNR(&srcImage[0], &decompressTask.decompressedImage[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor), 8.0); 5632f083884Ss.makeev_local CHECK_EQUAL(true, imagesEqual); 5642f083884Ss.makeev_local 5652f083884Ss.makeev_local /* 5662f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 5672f083884Ss.makeev_local // waiting for profiler attach 5682f083884Ss.makeev_local printf("Press any key to continue\n"); 5692f083884Ss.makeev_local while(true) 5702f083884Ss.makeev_local { 5712f083884Ss.makeev_local if (_kbhit() != 0) 5722f083884Ss.makeev_local { 5732f083884Ss.makeev_local break; 5742f083884Ss.makeev_local } 5752f083884Ss.makeev_local } 5762f083884Ss.makeev_local #endif 5772f083884Ss.makeev_local */ 5782f083884Ss.makeev_local } 5792f083884Ss.makeev_local 5802f083884Ss.makeev_local 5812f083884Ss.makeev_local } 582