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 23*3d930776Ss.makeev_local 24*3d930776Ss.makeev_local #include <MTConfig.h> 25*3d930776Ss.makeev_local 26*3d930776Ss.makeev_local 272f083884Ss.makeev_local #include "Tests.h" 282f083884Ss.makeev_local #include <UnitTest++.h> 292f083884Ss.makeev_local #include <MTScheduler.h> 30b23bdf5aSs.makeev_local #include <MTStaticVector.h> 312f083884Ss.makeev_local 322f083884Ss.makeev_local #include <squish.h> 332f083884Ss.makeev_local #include <string.h> 34faa6c6e5Ss.makeev_local #include <math.h> 352f083884Ss.makeev_local 3660ac17fbSs.makeev_local 372f083884Ss.makeev_local /* 382f083884Ss.makeev_local #ifdef _WIN32 392f083884Ss.makeev_local 402f083884Ss.makeev_local #include <conio.h> 412f083884Ss.makeev_local 422f083884Ss.makeev_local #else 432f083884Ss.makeev_local 442f083884Ss.makeev_local #include <stdio.h> 452f083884Ss.makeev_local #include <termios.h> 462f083884Ss.makeev_local #include <unistd.h> 472f083884Ss.makeev_local #include <fcntl.h> 482f083884Ss.makeev_local 492f083884Ss.makeev_local int _kbhit(void) 502f083884Ss.makeev_local { 512f083884Ss.makeev_local struct termios oldt, newt; 522f083884Ss.makeev_local int ch; 532f083884Ss.makeev_local int oldf; 542f083884Ss.makeev_local 552f083884Ss.makeev_local tcgetattr(STDIN_FILENO, &oldt); 562f083884Ss.makeev_local newt = oldt; 572f083884Ss.makeev_local newt.c_lflag &= ~(ICANON | ECHO); 582f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &newt); 592f083884Ss.makeev_local oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 602f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 612f083884Ss.makeev_local 622f083884Ss.makeev_local ch = getchar(); 632f083884Ss.makeev_local 642f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 652f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf); 662f083884Ss.makeev_local 672f083884Ss.makeev_local if(ch != EOF) 682f083884Ss.makeev_local { 692f083884Ss.makeev_local ungetc(ch, stdin); 702f083884Ss.makeev_local return 1; 712f083884Ss.makeev_local } 722f083884Ss.makeev_local 732f083884Ss.makeev_local return 0; 742f083884Ss.makeev_local } 752f083884Ss.makeev_local #endif 762f083884Ss.makeev_local */ 772f083884Ss.makeev_local 782f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 792f083884Ss.makeev_local 806e90b535Ss.makeev_local 81*3d930776Ss.makeev_local void PushPerfMarker(const char* name, MT::Color::Type color) 82*3d930776Ss.makeev_local { 83*3d930776Ss.makeev_local MT_UNUSED(name); 84*3d930776Ss.makeev_local MT_UNUSED(color); 85*3d930776Ss.makeev_local } 86*3d930776Ss.makeev_local 87*3d930776Ss.makeev_local void PopPerfMarker(const char* name) 88*3d930776Ss.makeev_local { 89*3d930776Ss.makeev_local MT_UNUSED(name); 90*3d930776Ss.makeev_local } 91*3d930776Ss.makeev_local 926e90b535Ss.makeev_local 932f083884Ss.makeev_local class Microprofile : public MT::IProfilerEventListener 942f083884Ss.makeev_local { 95*3d930776Ss.makeev_local public: 96*3d930776Ss.makeev_local 97*3d930776Ss.makeev_local Microprofile() 98*3d930776Ss.makeev_local { 99*3d930776Ss.makeev_local } 100*3d930776Ss.makeev_local 101*3d930776Ss.makeev_local ~Microprofile() 102*3d930776Ss.makeev_local { 103*3d930776Ss.makeev_local } 104*3d930776Ss.makeev_local 1056e90b535Ss.makeev_local virtual void OnThreadCreated(uint32 workerIndex) override 1062f083884Ss.makeev_local { 1072f083884Ss.makeev_local MT_UNUSED(workerIndex); 1082f083884Ss.makeev_local } 1092f083884Ss.makeev_local 1106e90b535Ss.makeev_local virtual void OnThreadStarted(uint32 workerIndex) override 1112f083884Ss.makeev_local { 1122f083884Ss.makeev_local MT_UNUSED(workerIndex); 1132f083884Ss.makeev_local } 1142f083884Ss.makeev_local 1156e90b535Ss.makeev_local virtual void OnThreadStoped(uint32 workerIndex) override 1162f083884Ss.makeev_local { 1172f083884Ss.makeev_local MT_UNUSED(workerIndex); 1182f083884Ss.makeev_local } 1192f083884Ss.makeev_local 120*3d930776Ss.makeev_local virtual void OnThreadIdleStarted(uint32 workerIndex) override 1212f083884Ss.makeev_local { 1222f083884Ss.makeev_local MT_UNUSED(workerIndex); 123*3d930776Ss.makeev_local PushPerfMarker("ThreadIdle", MT::Color::Red); 1242f083884Ss.makeev_local } 1252f083884Ss.makeev_local 126*3d930776Ss.makeev_local virtual void OnThreadIdleFinished(uint32 workerIndex) override 1272f083884Ss.makeev_local { 1282f083884Ss.makeev_local MT_UNUSED(workerIndex); 129*3d930776Ss.makeev_local PopPerfMarker("ThreadIdle"); 130*3d930776Ss.makeev_local } 131*3d930776Ss.makeev_local 132*3d930776Ss.makeev_local virtual void OnThreadWaitStarted() override 133*3d930776Ss.makeev_local { 134*3d930776Ss.makeev_local PushPerfMarker("ThreadWait", MT::Color::Red); 135*3d930776Ss.makeev_local } 136*3d930776Ss.makeev_local 137*3d930776Ss.makeev_local virtual void OnThreadWaitFinished() override 138*3d930776Ss.makeev_local { 139*3d930776Ss.makeev_local PopPerfMarker("ThreadWait"); 1402f083884Ss.makeev_local } 1412f083884Ss.makeev_local 1426e90b535Ss.makeev_local virtual void NotifyTaskExecuteStateChanged(MT::Color::Type debugColor, const mt_char* debugID, MT::TaskExecuteState::Type type) override 1432f083884Ss.makeev_local { 144*3d930776Ss.makeev_local switch(type) 145*3d930776Ss.makeev_local { 146*3d930776Ss.makeev_local case MT::TaskExecuteState::START: 147*3d930776Ss.makeev_local case MT::TaskExecuteState::RESUME: 148*3d930776Ss.makeev_local PushPerfMarker(debugID, debugColor); 149*3d930776Ss.makeev_local break; 150*3d930776Ss.makeev_local case MT::TaskExecuteState::STOP: 151*3d930776Ss.makeev_local case MT::TaskExecuteState::SUSPEND: 152*3d930776Ss.makeev_local PopPerfMarker(debugID); 153*3d930776Ss.makeev_local break; 1542f083884Ss.makeev_local } 155*3d930776Ss.makeev_local } 1562f083884Ss.makeev_local }; 1572f083884Ss.makeev_local 1582f083884Ss.makeev_local 1592f083884Ss.makeev_local #endif 1602f083884Ss.makeev_local 1612f083884Ss.makeev_local 1622f083884Ss.makeev_local 1632f083884Ss.makeev_local 1642f083884Ss.makeev_local 1652f083884Ss.makeev_local namespace EmbeddedImage 1662f083884Ss.makeev_local { 1672f083884Ss.makeev_local #include "LenaDxt/LenaColor.h" 1682f083884Ss.makeev_local #include "LenaDxt/HeaderDDS.h" 1692f083884Ss.makeev_local } 1702f083884Ss.makeev_local 1712f083884Ss.makeev_local 1722f083884Ss.makeev_local bool CompareImagesPSNR(uint8 * img1, uint8 * img2, uint32 bytesCount, double psnrThreshold) 1732f083884Ss.makeev_local { 1742f083884Ss.makeev_local double mse = 0.0; 1752f083884Ss.makeev_local 1762f083884Ss.makeev_local for (uint32 i = 0; i < bytesCount; i++) 1772f083884Ss.makeev_local { 1782f083884Ss.makeev_local double error = (double)img1[0] - (double)img2[1]; 1792f083884Ss.makeev_local mse += (error * error); 1802f083884Ss.makeev_local } 1812f083884Ss.makeev_local 1822f083884Ss.makeev_local mse = mse / (double)bytesCount; 1832f083884Ss.makeev_local 1842f083884Ss.makeev_local if (mse > 0.0) 1852f083884Ss.makeev_local { 1862f083884Ss.makeev_local double psnr = 10.0 * log10(255.0*255.0/mse); 1872f083884Ss.makeev_local if (psnr < psnrThreshold) 1882f083884Ss.makeev_local { 1892f083884Ss.makeev_local return false; 1902f083884Ss.makeev_local } 1912f083884Ss.makeev_local } 1922f083884Ss.makeev_local 1932f083884Ss.makeev_local return true; 1942f083884Ss.makeev_local } 1952f083884Ss.makeev_local 1962f083884Ss.makeev_local 1972f083884Ss.makeev_local 1982f083884Ss.makeev_local SUITE(DxtTests) 1992f083884Ss.makeev_local { 2002f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2012f083884Ss.makeev_local struct CompressDxtBlock 2022f083884Ss.makeev_local { 203b23bdf5aSs.makeev_local MT_DECLARE_TASK(CompressDxtBlock, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue); 2042f083884Ss.makeev_local 2052f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 2062f083884Ss.makeev_local MT::ArrayView<uint8> dstBlocks; 2072f083884Ss.makeev_local 2082f083884Ss.makeev_local int srcX; 2092f083884Ss.makeev_local int srcY; 2102f083884Ss.makeev_local 2112f083884Ss.makeev_local int stride; 2122f083884Ss.makeev_local int dstBlockOffset; 2132f083884Ss.makeev_local 2142f083884Ss.makeev_local CompressDxtBlock(int _srcX, int _srcY, int _stride, const MT::ArrayView<uint8> & _srcPixels, const MT::ArrayView<uint8> & _dstBlocks, int _dstBlockOffset) 2152f083884Ss.makeev_local : srcPixels(_srcPixels) 2162f083884Ss.makeev_local , dstBlocks(_dstBlocks) 2172f083884Ss.makeev_local { 2182f083884Ss.makeev_local srcX = _srcX; 2192f083884Ss.makeev_local srcY = _srcY; 2202f083884Ss.makeev_local stride = _stride; 2212f083884Ss.makeev_local dstBlockOffset = _dstBlockOffset; 2222f083884Ss.makeev_local } 2232f083884Ss.makeev_local 2242f083884Ss.makeev_local CompressDxtBlock(CompressDxtBlock&& other) 2252f083884Ss.makeev_local : srcPixels(other.srcPixels) 2262f083884Ss.makeev_local , dstBlocks(other.dstBlocks) 2272f083884Ss.makeev_local , srcX(other.srcX) 2282f083884Ss.makeev_local , srcY(other.srcY) 2292f083884Ss.makeev_local , stride(other.stride) 2302f083884Ss.makeev_local , dstBlockOffset(other.dstBlockOffset) 2312f083884Ss.makeev_local { 2322f083884Ss.makeev_local other.srcX = -1; 2332f083884Ss.makeev_local other.srcY = -1; 2342f083884Ss.makeev_local other.stride = -1; 2352f083884Ss.makeev_local other.dstBlockOffset = -1; 2362f083884Ss.makeev_local } 2372f083884Ss.makeev_local 2382f083884Ss.makeev_local ~CompressDxtBlock() 2392f083884Ss.makeev_local { 2402f083884Ss.makeev_local srcX = -1; 2412f083884Ss.makeev_local srcY = -1; 2422f083884Ss.makeev_local stride = -1; 2432f083884Ss.makeev_local dstBlockOffset = -1; 2442f083884Ss.makeev_local } 2452f083884Ss.makeev_local 2462f083884Ss.makeev_local void Do(MT::FiberContext&) 2472f083884Ss.makeev_local { 2482f083884Ss.makeev_local // 16 pixels of input 2492f083884Ss.makeev_local uint32 pixels[4*4]; 2502f083884Ss.makeev_local 2512f083884Ss.makeev_local // copy dxt1 block from image 2522f083884Ss.makeev_local for (int y = 0; y < 4; y++) 2532f083884Ss.makeev_local { 2542f083884Ss.makeev_local for (int x = 0; x < 4; x++) 2552f083884Ss.makeev_local { 2562f083884Ss.makeev_local int posX = srcX + x; 2572f083884Ss.makeev_local int posY = srcY + y; 2582f083884Ss.makeev_local 2592f083884Ss.makeev_local int index = posY * stride + (posX * 3); 2602f083884Ss.makeev_local 2612f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 2622f083884Ss.makeev_local 2632f083884Ss.makeev_local uint8 r = srcPixels[index + 0]; 2642f083884Ss.makeev_local uint8 g = srcPixels[index + 1]; 2652f083884Ss.makeev_local uint8 b = srcPixels[index + 2]; 2662f083884Ss.makeev_local 2672f083884Ss.makeev_local uint32 color = 0xFF000000 | ((b << 16) | (g << 8) | (r)); 2682f083884Ss.makeev_local 2692f083884Ss.makeev_local pixels[y * 4 + x] = color; 2702f083884Ss.makeev_local } 2712f083884Ss.makeev_local } 2722f083884Ss.makeev_local 2732f083884Ss.makeev_local // compress the 4x4 block using DXT1 compression 2742f083884Ss.makeev_local squish::Compress( (squish::u8 *)&pixels[0], &dstBlocks[dstBlockOffset], squish::kDxt1 ); 2752f083884Ss.makeev_local } 2762f083884Ss.makeev_local }; 2772f083884Ss.makeev_local 2782f083884Ss.makeev_local 2792f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2802f083884Ss.makeev_local struct CompressDxt 2812f083884Ss.makeev_local { 282b23bdf5aSs.makeev_local MT_DECLARE_TASK(CompressDxt, MT::StackRequirements::EXTENDED, MT::TaskPriority::NORMAL, MT::Color::Aqua); 2832f083884Ss.makeev_local 2842f083884Ss.makeev_local uint32 width; 2852f083884Ss.makeev_local uint32 height; 2862f083884Ss.makeev_local uint32 stride; 2872f083884Ss.makeev_local 2882f083884Ss.makeev_local uint32 blkWidth; 2892f083884Ss.makeev_local uint32 blkHeight; 2902f083884Ss.makeev_local 291*3d930776Ss.makeev_local uint32 passCount; 292*3d930776Ss.makeev_local 2932f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 2942f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 295d7cf17b1Ss.makeev_local MT::Atomic32<uint32>* pIsFinished; 2962f083884Ss.makeev_local 297d7cf17b1Ss.makeev_local 298*3d930776Ss.makeev_local CompressDxt(uint32 _width, uint32 _height, uint32 _stride, const MT::ArrayView<uint8> & _srcPixels, MT::Atomic32<uint32>* _pIsFinished = nullptr, uint32 _passCount = 1) 2992f083884Ss.makeev_local : srcPixels(_srcPixels) 300d7cf17b1Ss.makeev_local , pIsFinished(_pIsFinished) 3012f083884Ss.makeev_local { 302*3d930776Ss.makeev_local passCount = _passCount; 303*3d930776Ss.makeev_local 3042f083884Ss.makeev_local width = _width; 3052f083884Ss.makeev_local height = _height; 3062f083884Ss.makeev_local stride = _stride; 3072f083884Ss.makeev_local 3082f083884Ss.makeev_local blkWidth = width >> 2; 3092f083884Ss.makeev_local blkHeight = height >> 2; 3102f083884Ss.makeev_local 3112f083884Ss.makeev_local int dxtBlocksTotalSizeInBytes = blkWidth * blkHeight * 8; // 8 bytes = 64 bits per block (dxt1) 312d7cf17b1Ss.makeev_local dxtBlocks = MT::ArrayView<uint8>( MT::Memory::Alloc( dxtBlocksTotalSizeInBytes ), dxtBlocksTotalSizeInBytes); 3132f083884Ss.makeev_local } 3142f083884Ss.makeev_local 3152f083884Ss.makeev_local ~CompressDxt() 3162f083884Ss.makeev_local { 3172f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 3182f083884Ss.makeev_local if (pDxtBlocks) 3192f083884Ss.makeev_local { 320d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks); 3212f083884Ss.makeev_local } 3222f083884Ss.makeev_local } 3232f083884Ss.makeev_local 3242f083884Ss.makeev_local 3252f083884Ss.makeev_local void Do(MT::FiberContext& context) 3262f083884Ss.makeev_local { 327*3d930776Ss.makeev_local for(uint32 i = 0; i < passCount; i++) 328*3d930776Ss.makeev_local { 329b23bdf5aSs.makeev_local // use StaticVector as subtask container. beware stack overflow! 330b23bdf5aSs.makeev_local MT::StaticVector<CompressDxtBlock, 1024> subTasks; 3312f083884Ss.makeev_local 3322f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 3332f083884Ss.makeev_local { 3342f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 3352f083884Ss.makeev_local { 3362f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 3372f083884Ss.makeev_local subTasks.PushBack( CompressDxtBlock(blkX * 4, blkY * 4, stride, srcPixels, dxtBlocks, blockIndex * 8) ); 3382f083884Ss.makeev_local } 3392f083884Ss.makeev_local } 3402f083884Ss.makeev_local 3412f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 342*3d930776Ss.makeev_local } 343*3d930776Ss.makeev_local 344d7cf17b1Ss.makeev_local 345d7cf17b1Ss.makeev_local if (pIsFinished != nullptr) 346d7cf17b1Ss.makeev_local { 347d7cf17b1Ss.makeev_local pIsFinished->Store(1); 348d7cf17b1Ss.makeev_local } 3492f083884Ss.makeev_local } 3502f083884Ss.makeev_local }; 3512f083884Ss.makeev_local 3522f083884Ss.makeev_local 3532f083884Ss.makeev_local 3542f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 3552f083884Ss.makeev_local struct DecompressDxtBlock 3562f083884Ss.makeev_local { 357b23bdf5aSs.makeev_local MT_DECLARE_TASK(DecompressDxtBlock, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Red); 3582f083884Ss.makeev_local 3592f083884Ss.makeev_local MT::ArrayView<uint8> srcBlocks; 3602f083884Ss.makeev_local MT::ArrayView<uint8> dstPixels; 3612f083884Ss.makeev_local 3622f083884Ss.makeev_local int dstX; 3632f083884Ss.makeev_local int dstY; 3642f083884Ss.makeev_local 3652f083884Ss.makeev_local int stride; 3662f083884Ss.makeev_local int srcBlockOffset; 3672f083884Ss.makeev_local 3682f083884Ss.makeev_local DecompressDxtBlock(int _dstX, int _dstY, int _stride, const MT::ArrayView<uint8> & _dstPixels, const MT::ArrayView<uint8> & _srcBlocks, int _srcBlockOffset) 3692f083884Ss.makeev_local : srcBlocks(_srcBlocks) 3702f083884Ss.makeev_local , dstPixels(_dstPixels) 3712f083884Ss.makeev_local { 3722f083884Ss.makeev_local dstX = _dstX; 3732f083884Ss.makeev_local dstY = _dstY; 3742f083884Ss.makeev_local stride = _stride; 3752f083884Ss.makeev_local srcBlockOffset = _srcBlockOffset; 3762f083884Ss.makeev_local } 3772f083884Ss.makeev_local 3782f083884Ss.makeev_local DecompressDxtBlock(DecompressDxtBlock&& other) 3792f083884Ss.makeev_local : srcBlocks(other.srcBlocks) 3802f083884Ss.makeev_local , dstPixels(other.dstPixels) 3812f083884Ss.makeev_local , dstX(other.dstX) 3822f083884Ss.makeev_local , dstY(other.dstY) 3832f083884Ss.makeev_local , stride(other.stride) 3842f083884Ss.makeev_local , srcBlockOffset(other.srcBlockOffset) 3852f083884Ss.makeev_local { 3862f083884Ss.makeev_local other.dstX = -1; 3872f083884Ss.makeev_local other.dstY = -1; 3882f083884Ss.makeev_local other.stride = -1; 3892f083884Ss.makeev_local other.srcBlockOffset = -1; 3902f083884Ss.makeev_local } 3912f083884Ss.makeev_local 3922f083884Ss.makeev_local ~DecompressDxtBlock() 3932f083884Ss.makeev_local { 3942f083884Ss.makeev_local dstX = -1; 3952f083884Ss.makeev_local dstY = -1; 3962f083884Ss.makeev_local stride = -1; 3972f083884Ss.makeev_local srcBlockOffset = -1; 3982f083884Ss.makeev_local } 3992f083884Ss.makeev_local 4002f083884Ss.makeev_local 4012f083884Ss.makeev_local void Do(MT::FiberContext&) 4022f083884Ss.makeev_local { 4032f083884Ss.makeev_local // 16 pixels of output 4042f083884Ss.makeev_local uint32 pixels[4*4]; 4052f083884Ss.makeev_local 4062f083884Ss.makeev_local // copy dxt1 block from image 4072f083884Ss.makeev_local for (int y = 0; y < 4; y++) 4082f083884Ss.makeev_local { 4092f083884Ss.makeev_local for (int x = 0; x < 4; x++) 4102f083884Ss.makeev_local { 4112f083884Ss.makeev_local squish::Decompress((squish::u8 *)&pixels[0], &srcBlocks[srcBlockOffset], squish::kDxt1); 4122f083884Ss.makeev_local 4132f083884Ss.makeev_local int posX = dstX + x; 4142f083884Ss.makeev_local int posY = dstY + y; 4152f083884Ss.makeev_local 4162f083884Ss.makeev_local int index = posY * stride + (posX * 3); 4172f083884Ss.makeev_local 4182f083884Ss.makeev_local uint32 pixel = pixels[y * 4 + x]; 4192f083884Ss.makeev_local 4202f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 4212f083884Ss.makeev_local 4222f083884Ss.makeev_local dstPixels[index + 0] = (pixel & 0xFF); 4232f083884Ss.makeev_local dstPixels[index + 1] = (pixel >> 8 & 0xFF); 4242f083884Ss.makeev_local dstPixels[index + 2] = (pixel >> 16 & 0xFF); 4252f083884Ss.makeev_local } 4262f083884Ss.makeev_local } 4272f083884Ss.makeev_local 4282f083884Ss.makeev_local } 4292f083884Ss.makeev_local }; 4302f083884Ss.makeev_local 4312f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4322f083884Ss.makeev_local struct DecompressDxt 4332f083884Ss.makeev_local { 434b23bdf5aSs.makeev_local MT_DECLARE_TASK(DecompressDxt, MT::StackRequirements::EXTENDED, MT::TaskPriority::NORMAL, MT::Color::Yellow); 4352f083884Ss.makeev_local 4362f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 4372f083884Ss.makeev_local MT::ArrayView<uint8> decompressedImage; 4382f083884Ss.makeev_local 4392f083884Ss.makeev_local uint32 blkWidth; 4402f083884Ss.makeev_local uint32 blkHeight; 4412f083884Ss.makeev_local 4422f083884Ss.makeev_local 4432f083884Ss.makeev_local DecompressDxt(const MT::ArrayView<uint8> & _dxtBlocks, uint32 dxtBlocksCountWidth, uint32 dxtBlocksCountHeight) 4442f083884Ss.makeev_local : dxtBlocks(_dxtBlocks) 4452f083884Ss.makeev_local { 4462f083884Ss.makeev_local blkWidth = dxtBlocksCountWidth; 4472f083884Ss.makeev_local blkHeight = dxtBlocksCountHeight; 4482f083884Ss.makeev_local 4492f083884Ss.makeev_local // dxt1 block = 16 rgb pixels = 48 bytes 4502f083884Ss.makeev_local uint32 bytesCount = blkWidth * blkHeight * 48; 451d7cf17b1Ss.makeev_local decompressedImage = MT::ArrayView<uint8>( MT::Memory::Alloc(bytesCount), bytesCount); 4522f083884Ss.makeev_local } 4532f083884Ss.makeev_local 4542f083884Ss.makeev_local ~DecompressDxt() 4552f083884Ss.makeev_local { 4562f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 4572f083884Ss.makeev_local if (pDxtBlocks) 4582f083884Ss.makeev_local { 459d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks); 4602f083884Ss.makeev_local } 4612f083884Ss.makeev_local 4622f083884Ss.makeev_local void* pDecompressedImage = decompressedImage.GetRawData(); 4632f083884Ss.makeev_local if (pDecompressedImage) 4642f083884Ss.makeev_local { 465d7cf17b1Ss.makeev_local MT::Memory::Free(pDecompressedImage); 4662f083884Ss.makeev_local } 4672f083884Ss.makeev_local 4682f083884Ss.makeev_local } 4692f083884Ss.makeev_local 4702f083884Ss.makeev_local void Do(MT::FiberContext& context) 4712f083884Ss.makeev_local { 472b23bdf5aSs.makeev_local // use StaticVector as subtask container. beware stack overflow! 473b23bdf5aSs.makeev_local MT::StaticVector<DecompressDxtBlock, 1024> subTasks; 4742f083884Ss.makeev_local 4752f083884Ss.makeev_local int stride = blkWidth * 4 * 3; 4762f083884Ss.makeev_local 4772f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 4782f083884Ss.makeev_local { 4792f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 4802f083884Ss.makeev_local { 4812f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 4822f083884Ss.makeev_local subTasks.PushBack( DecompressDxtBlock(blkX * 4, blkY * 4, stride, decompressedImage, dxtBlocks, blockIndex * 8) ); 4832f083884Ss.makeev_local } 4842f083884Ss.makeev_local } 4852f083884Ss.makeev_local 4862f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 4872f083884Ss.makeev_local } 4882f083884Ss.makeev_local 4892f083884Ss.makeev_local }; 4902f083884Ss.makeev_local 4912f083884Ss.makeev_local 4922f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4932f083884Ss.makeev_local void Wait(MT::TaskScheduler & scheduler) 4942f083884Ss.makeev_local { 4952f083884Ss.makeev_local //emulate game loop 4962f083884Ss.makeev_local for(;;) 4972f083884Ss.makeev_local { 4982f083884Ss.makeev_local bool waitDone = scheduler.WaitAll(33); 4992f083884Ss.makeev_local if (waitDone) 5002f083884Ss.makeev_local { 5012f083884Ss.makeev_local break; 5022f083884Ss.makeev_local } 5032f083884Ss.makeev_local } 5042f083884Ss.makeev_local } 5052f083884Ss.makeev_local 5064965e494Ss.makeev_local 5076e90b535Ss.makeev_local /* 508d7cf17b1Ss.makeev_local // dxt compressor Hiload test (for profiling purposes) 509d7cf17b1Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 510d7cf17b1Ss.makeev_local TEST(HiloadDxtTest) 511d7cf17b1Ss.makeev_local { 512d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished1; 513d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished2; 514d7cf17b1Ss.makeev_local 515d7cf17b1Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 516d7cf17b1Ss.makeev_local 517d7cf17b1Ss.makeev_local int stride = 384; 518d7cf17b1Ss.makeev_local 519d7cf17b1Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 520d7cf17b1Ss.makeev_local 521d7cf17b1Ss.makeev_local CompressDxt compressTask1(128, 128, stride, srcImage, &isFinished1); 522d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask1.width & 3) == 0 && (compressTask1.height & 3) == 0, "Image size must be a multiple of 4"); 523d7cf17b1Ss.makeev_local 524d7cf17b1Ss.makeev_local CompressDxt compressTask2(128, 128, stride, srcImage, &isFinished2); 525d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask2.width & 3) == 0 && (compressTask2.height & 3) == 0, "Image size must be a multiple of 4"); 526d7cf17b1Ss.makeev_local 5276e90b535Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 5286e90b535Ss.makeev_local Microprofile profiler; 5296e90b535Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, &profiler); 5306e90b535Ss.makeev_local #else 531d7cf17b1Ss.makeev_local MT::TaskScheduler scheduler; 5326e90b535Ss.makeev_local #endif 533d7cf17b1Ss.makeev_local 534d7cf17b1Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 535d7cf17b1Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 536d7cf17b1Ss.makeev_local 537d7cf17b1Ss.makeev_local isFinished1.Store(0); 538d7cf17b1Ss.makeev_local isFinished2.Store(0); 539d7cf17b1Ss.makeev_local 540d7cf17b1Ss.makeev_local printf("HiloadDxtTest\n"); 541d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1); 542d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1); 543d7cf17b1Ss.makeev_local 544d7cf17b1Ss.makeev_local for(;;) 545d7cf17b1Ss.makeev_local { 546d7cf17b1Ss.makeev_local if (isFinished1.Load() != 0) 547d7cf17b1Ss.makeev_local { 548d7cf17b1Ss.makeev_local isFinished1.Store(0); 549d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1); 550d7cf17b1Ss.makeev_local } 551d7cf17b1Ss.makeev_local 552d7cf17b1Ss.makeev_local if (isFinished2.Load() != 0) 553d7cf17b1Ss.makeev_local { 554d7cf17b1Ss.makeev_local isFinished2.Store(0); 555d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1); 556d7cf17b1Ss.makeev_local } 557d7cf17b1Ss.makeev_local 558d7cf17b1Ss.makeev_local MT::Thread::Sleep(1); 559d7cf17b1Ss.makeev_local } 560d7cf17b1Ss.makeev_local } 561c121d748Ss.makeev_local */ 56260ac17fbSs.makeev_local 563*3d930776Ss.makeev_local /* 564*3d930776Ss.makeev_local // dxt compressor stress test (for profiling purposes) 565*3d930776Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 566*3d930776Ss.makeev_local TEST(DxtStressTest) 567*3d930776Ss.makeev_local { 568*3d930776Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 569*3d930776Ss.makeev_local 570*3d930776Ss.makeev_local int stride = 384; 571*3d930776Ss.makeev_local 572*3d930776Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 573*3d930776Ss.makeev_local 574*3d930776Ss.makeev_local uint32 passCount = 10; 575*3d930776Ss.makeev_local 576*3d930776Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage, nullptr, passCount); 577*3d930776Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4"); 578*3d930776Ss.makeev_local 579*3d930776Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 580*3d930776Ss.makeev_local Microprofile profiler; 581*3d930776Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, &profiler); 582*3d930776Ss.makeev_local #else 583*3d930776Ss.makeev_local MT::TaskScheduler scheduler; 584*3d930776Ss.makeev_local #endif 585*3d930776Ss.makeev_local 586*3d930776Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 587*3d930776Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 588*3d930776Ss.makeev_local 589*3d930776Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 590*3d930776Ss.makeev_local PushPerfMarker("DxtStressTest", MT::Color::Red); 591*3d930776Ss.makeev_local #endif 592*3d930776Ss.makeev_local 593*3d930776Ss.makeev_local printf("DxtStressTest\n"); 594*3d930776Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1); 595*3d930776Ss.makeev_local 596*3d930776Ss.makeev_local CHECK(scheduler.WaitAll(10000000)); 597*3d930776Ss.makeev_local 598*3d930776Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 599*3d930776Ss.makeev_local PopPerfMarker("DxtStressTest"); 600*3d930776Ss.makeev_local #endif 601*3d930776Ss.makeev_local } 602*3d930776Ss.makeev_local */ 603*3d930776Ss.makeev_local 6042f083884Ss.makeev_local // dxt compressor complex test 6052f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 6062f083884Ss.makeev_local TEST(RunComplexDxtTest) 6072f083884Ss.makeev_local { 6082f083884Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 6092f083884Ss.makeev_local 6102f083884Ss.makeev_local int stride = 384; 6112f083884Ss.makeev_local 6122f083884Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 6132f083884Ss.makeev_local 6142f083884Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage); 6152f083884Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4"); 6162f083884Ss.makeev_local 6172f083884Ss.makeev_local MT::TaskScheduler scheduler; 6182f083884Ss.makeev_local 6192f083884Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 6202f083884Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 6212f083884Ss.makeev_local 6222f083884Ss.makeev_local printf("Compress image\n"); 6232f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1); 6242f083884Ss.makeev_local 6252f083884Ss.makeev_local Wait(scheduler); 6262f083884Ss.makeev_local 6272f083884Ss.makeev_local DecompressDxt decompressTask(compressTask.dxtBlocks, compressTask.blkWidth, compressTask.blkHeight); 6282f083884Ss.makeev_local compressTask.dxtBlocks = MT::ArrayView<uint8>(); //transfer memory ownership to Decompress task 6292f083884Ss.makeev_local 6302f083884Ss.makeev_local printf("Decompress image\n"); 6312f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &decompressTask, 1); 6322f083884Ss.makeev_local 6332f083884Ss.makeev_local Wait(scheduler); 6342f083884Ss.makeev_local 6352f083884Ss.makeev_local /* 6362f083884Ss.makeev_local //save compressed image 6372f083884Ss.makeev_local { 6382f083884Ss.makeev_local FILE * file = fopen("lena_dxt1.dds", "w+b"); 6392f083884Ss.makeev_local fwrite(&EmbeddedImage::ddsHeader[0], MT_ARRAY_SIZE(EmbeddedImage::ddsHeader), 1, file); 6402f083884Ss.makeev_local fwrite(decompressTask.dxtBlocks, decompressTask.blkWidth * decompressTask.blkHeight * 8, 1, file); 6412f083884Ss.makeev_local fclose(file); 6422f083884Ss.makeev_local } 6432f083884Ss.makeev_local 6442f083884Ss.makeev_local //save uncompressed image 6452f083884Ss.makeev_local { 6462f083884Ss.makeev_local FILE * file = fopen("lena_rgb.raw", "w+b"); 6472f083884Ss.makeev_local fwrite(decompressTask.decompressedImage, decompressTask.blkWidth * decompressTask.blkHeight * 48, 1, file); 6482f083884Ss.makeev_local fclose(file); 6492f083884Ss.makeev_local } 6502f083884Ss.makeev_local */ 6512f083884Ss.makeev_local 6522f083884Ss.makeev_local printf("Compare images\n"); 6532f083884Ss.makeev_local bool imagesEqual = CompareImagesPSNR(&srcImage[0], &decompressTask.decompressedImage[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor), 8.0); 6542f083884Ss.makeev_local CHECK_EQUAL(true, imagesEqual); 6552f083884Ss.makeev_local 6562f083884Ss.makeev_local /* 6572f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 6582f083884Ss.makeev_local // waiting for profiler attach 6592f083884Ss.makeev_local printf("Press any key to continue\n"); 6602f083884Ss.makeev_local while(true) 6612f083884Ss.makeev_local { 6622f083884Ss.makeev_local if (_kbhit() != 0) 6632f083884Ss.makeev_local { 6642f083884Ss.makeev_local break; 6652f083884Ss.makeev_local } 6662f083884Ss.makeev_local } 6672f083884Ss.makeev_local #endif 6682f083884Ss.makeev_local */ 6692f083884Ss.makeev_local } 6702f083884Ss.makeev_local 6712f083884Ss.makeev_local 6722f083884Ss.makeev_local } 673