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> 26*b23bdf5aSs.makeev_local #include <MTStaticVector.h> 272f083884Ss.makeev_local 282f083884Ss.makeev_local #include <squish.h> 292f083884Ss.makeev_local #include <string.h> 30faa6c6e5Ss.makeev_local #include <math.h> 312f083884Ss.makeev_local 3260ac17fbSs.makeev_local 332f083884Ss.makeev_local /* 342f083884Ss.makeev_local #ifdef _WIN32 352f083884Ss.makeev_local 362f083884Ss.makeev_local #include <conio.h> 372f083884Ss.makeev_local 382f083884Ss.makeev_local #else 392f083884Ss.makeev_local 402f083884Ss.makeev_local #include <stdio.h> 412f083884Ss.makeev_local #include <termios.h> 422f083884Ss.makeev_local #include <unistd.h> 432f083884Ss.makeev_local #include <fcntl.h> 442f083884Ss.makeev_local 452f083884Ss.makeev_local int _kbhit(void) 462f083884Ss.makeev_local { 472f083884Ss.makeev_local struct termios oldt, newt; 482f083884Ss.makeev_local int ch; 492f083884Ss.makeev_local int oldf; 502f083884Ss.makeev_local 512f083884Ss.makeev_local tcgetattr(STDIN_FILENO, &oldt); 522f083884Ss.makeev_local newt = oldt; 532f083884Ss.makeev_local newt.c_lflag &= ~(ICANON | ECHO); 542f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &newt); 552f083884Ss.makeev_local oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 562f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 572f083884Ss.makeev_local 582f083884Ss.makeev_local ch = getchar(); 592f083884Ss.makeev_local 602f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 612f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf); 622f083884Ss.makeev_local 632f083884Ss.makeev_local if(ch != EOF) 642f083884Ss.makeev_local { 652f083884Ss.makeev_local ungetc(ch, stdin); 662f083884Ss.makeev_local return 1; 672f083884Ss.makeev_local } 682f083884Ss.makeev_local 692f083884Ss.makeev_local return 0; 702f083884Ss.makeev_local } 712f083884Ss.makeev_local #endif 722f083884Ss.makeev_local */ 732f083884Ss.makeev_local 742f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 752f083884Ss.makeev_local 766e90b535Ss.makeev_local 776e90b535Ss.makeev_local #ifdef MT_PLATFORM_ORBIS 786e90b535Ss.makeev_local #include <perf.h> 796e90b535Ss.makeev_local #endif 806e90b535Ss.makeev_local 812f083884Ss.makeev_local class Microprofile : public MT::IProfilerEventListener 822f083884Ss.makeev_local { 836e90b535Ss.makeev_local virtual void OnThreadCreated(uint32 workerIndex) override 842f083884Ss.makeev_local { 852f083884Ss.makeev_local MT_UNUSED(workerIndex); 862f083884Ss.makeev_local } 872f083884Ss.makeev_local 886e90b535Ss.makeev_local virtual void OnThreadStarted(uint32 workerIndex) override 892f083884Ss.makeev_local { 902f083884Ss.makeev_local MT_UNUSED(workerIndex); 912f083884Ss.makeev_local } 922f083884Ss.makeev_local 936e90b535Ss.makeev_local virtual void OnThreadStoped(uint32 workerIndex) override 942f083884Ss.makeev_local { 952f083884Ss.makeev_local MT_UNUSED(workerIndex); 962f083884Ss.makeev_local } 972f083884Ss.makeev_local 986e90b535Ss.makeev_local virtual void OnThreadIdleBegin(uint32 workerIndex) override 992f083884Ss.makeev_local { 1002f083884Ss.makeev_local MT_UNUSED(workerIndex); 1012f083884Ss.makeev_local } 1022f083884Ss.makeev_local 1036e90b535Ss.makeev_local virtual void OnThreadIdleEnd(uint32 workerIndex) override 1042f083884Ss.makeev_local { 1052f083884Ss.makeev_local MT_UNUSED(workerIndex); 1062f083884Ss.makeev_local } 1072f083884Ss.makeev_local 1086e90b535Ss.makeev_local virtual void NotifyTaskExecuteStateChanged(MT::Color::Type debugColor, const mt_char* debugID, MT::TaskExecuteState::Type type) override 1092f083884Ss.makeev_local { 1102f083884Ss.makeev_local MT_UNUSED(debugColor); 1112f083884Ss.makeev_local MT_UNUSED(debugID); 1126e90b535Ss.makeev_local MT_UNUSED(type); 1136e90b535Ss.makeev_local 1146e90b535Ss.makeev_local #ifdef MT_PLATFORM_ORBIS 1156e90b535Ss.makeev_local switch(type) 1166e90b535Ss.makeev_local { 1176e90b535Ss.makeev_local case MT::TaskExecuteState::START: 1186e90b535Ss.makeev_local sceRazorCpuPushMarkerStatic(debugID, MT::Color::ConvertToABGR(debugColor), SCE_RAZOR_MARKER_DISABLE_HUD); 1196e90b535Ss.makeev_local break; 1206e90b535Ss.makeev_local case MT::TaskExecuteState::STOP: 1216e90b535Ss.makeev_local sceRazorCpuPopMarker(); 1226e90b535Ss.makeev_local break; 1236e90b535Ss.makeev_local case MT::TaskExecuteState::RESUME: 1246e90b535Ss.makeev_local break; 1256e90b535Ss.makeev_local case MT::TaskExecuteState::SUSPEND: 1266e90b535Ss.makeev_local break; 1276e90b535Ss.makeev_local } 1286e90b535Ss.makeev_local #endif 1292f083884Ss.makeev_local } 1302f083884Ss.makeev_local 1312f083884Ss.makeev_local 1322f083884Ss.makeev_local }; 1332f083884Ss.makeev_local 1342f083884Ss.makeev_local 1352f083884Ss.makeev_local #endif 1362f083884Ss.makeev_local 1372f083884Ss.makeev_local 1382f083884Ss.makeev_local 1392f083884Ss.makeev_local 1402f083884Ss.makeev_local 1412f083884Ss.makeev_local namespace EmbeddedImage 1422f083884Ss.makeev_local { 1432f083884Ss.makeev_local #include "LenaDxt/LenaColor.h" 1442f083884Ss.makeev_local #include "LenaDxt/HeaderDDS.h" 1452f083884Ss.makeev_local } 1462f083884Ss.makeev_local 1472f083884Ss.makeev_local 1482f083884Ss.makeev_local bool CompareImagesPSNR(uint8 * img1, uint8 * img2, uint32 bytesCount, double psnrThreshold) 1492f083884Ss.makeev_local { 1502f083884Ss.makeev_local double mse = 0.0; 1512f083884Ss.makeev_local 1522f083884Ss.makeev_local for (uint32 i = 0; i < bytesCount; i++) 1532f083884Ss.makeev_local { 1542f083884Ss.makeev_local double error = (double)img1[0] - (double)img2[1]; 1552f083884Ss.makeev_local mse += (error * error); 1562f083884Ss.makeev_local } 1572f083884Ss.makeev_local 1582f083884Ss.makeev_local mse = mse / (double)bytesCount; 1592f083884Ss.makeev_local 1602f083884Ss.makeev_local if (mse > 0.0) 1612f083884Ss.makeev_local { 1622f083884Ss.makeev_local double psnr = 10.0 * log10(255.0*255.0/mse); 1632f083884Ss.makeev_local if (psnr < psnrThreshold) 1642f083884Ss.makeev_local { 1652f083884Ss.makeev_local return false; 1662f083884Ss.makeev_local } 1672f083884Ss.makeev_local } 1682f083884Ss.makeev_local 1692f083884Ss.makeev_local return true; 1702f083884Ss.makeev_local } 1712f083884Ss.makeev_local 1722f083884Ss.makeev_local 1732f083884Ss.makeev_local 1742f083884Ss.makeev_local SUITE(DxtTests) 1752f083884Ss.makeev_local { 1762f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1772f083884Ss.makeev_local struct CompressDxtBlock 1782f083884Ss.makeev_local { 179*b23bdf5aSs.makeev_local MT_DECLARE_TASK(CompressDxtBlock, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue); 1802f083884Ss.makeev_local 1812f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 1822f083884Ss.makeev_local MT::ArrayView<uint8> dstBlocks; 1832f083884Ss.makeev_local 1842f083884Ss.makeev_local int srcX; 1852f083884Ss.makeev_local int srcY; 1862f083884Ss.makeev_local 1872f083884Ss.makeev_local int stride; 1882f083884Ss.makeev_local int dstBlockOffset; 1892f083884Ss.makeev_local 1902f083884Ss.makeev_local CompressDxtBlock(int _srcX, int _srcY, int _stride, const MT::ArrayView<uint8> & _srcPixels, const MT::ArrayView<uint8> & _dstBlocks, int _dstBlockOffset) 1912f083884Ss.makeev_local : srcPixels(_srcPixels) 1922f083884Ss.makeev_local , dstBlocks(_dstBlocks) 1932f083884Ss.makeev_local { 1942f083884Ss.makeev_local srcX = _srcX; 1952f083884Ss.makeev_local srcY = _srcY; 1962f083884Ss.makeev_local stride = _stride; 1972f083884Ss.makeev_local dstBlockOffset = _dstBlockOffset; 1982f083884Ss.makeev_local } 1992f083884Ss.makeev_local 2002f083884Ss.makeev_local CompressDxtBlock(CompressDxtBlock&& other) 2012f083884Ss.makeev_local : srcPixels(other.srcPixels) 2022f083884Ss.makeev_local , dstBlocks(other.dstBlocks) 2032f083884Ss.makeev_local , srcX(other.srcX) 2042f083884Ss.makeev_local , srcY(other.srcY) 2052f083884Ss.makeev_local , stride(other.stride) 2062f083884Ss.makeev_local , dstBlockOffset(other.dstBlockOffset) 2072f083884Ss.makeev_local { 2082f083884Ss.makeev_local other.srcX = -1; 2092f083884Ss.makeev_local other.srcY = -1; 2102f083884Ss.makeev_local other.stride = -1; 2112f083884Ss.makeev_local other.dstBlockOffset = -1; 2122f083884Ss.makeev_local } 2132f083884Ss.makeev_local 2142f083884Ss.makeev_local ~CompressDxtBlock() 2152f083884Ss.makeev_local { 2162f083884Ss.makeev_local srcX = -1; 2172f083884Ss.makeev_local srcY = -1; 2182f083884Ss.makeev_local stride = -1; 2192f083884Ss.makeev_local dstBlockOffset = -1; 2202f083884Ss.makeev_local } 2212f083884Ss.makeev_local 2222f083884Ss.makeev_local void Do(MT::FiberContext&) 2232f083884Ss.makeev_local { 2242f083884Ss.makeev_local // 16 pixels of input 2252f083884Ss.makeev_local uint32 pixels[4*4]; 2262f083884Ss.makeev_local 2272f083884Ss.makeev_local // copy dxt1 block from image 2282f083884Ss.makeev_local for (int y = 0; y < 4; y++) 2292f083884Ss.makeev_local { 2302f083884Ss.makeev_local for (int x = 0; x < 4; x++) 2312f083884Ss.makeev_local { 2322f083884Ss.makeev_local int posX = srcX + x; 2332f083884Ss.makeev_local int posY = srcY + y; 2342f083884Ss.makeev_local 2352f083884Ss.makeev_local int index = posY * stride + (posX * 3); 2362f083884Ss.makeev_local 2372f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 2382f083884Ss.makeev_local 2392f083884Ss.makeev_local uint8 r = srcPixels[index + 0]; 2402f083884Ss.makeev_local uint8 g = srcPixels[index + 1]; 2412f083884Ss.makeev_local uint8 b = srcPixels[index + 2]; 2422f083884Ss.makeev_local 2432f083884Ss.makeev_local uint32 color = 0xFF000000 | ((b << 16) | (g << 8) | (r)); 2442f083884Ss.makeev_local 2452f083884Ss.makeev_local pixels[y * 4 + x] = color; 2462f083884Ss.makeev_local } 2472f083884Ss.makeev_local } 2482f083884Ss.makeev_local 2492f083884Ss.makeev_local // compress the 4x4 block using DXT1 compression 2502f083884Ss.makeev_local squish::Compress( (squish::u8 *)&pixels[0], &dstBlocks[dstBlockOffset], squish::kDxt1 ); 2512f083884Ss.makeev_local } 2522f083884Ss.makeev_local }; 2532f083884Ss.makeev_local 2542f083884Ss.makeev_local 2552f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2562f083884Ss.makeev_local struct CompressDxt 2572f083884Ss.makeev_local { 258*b23bdf5aSs.makeev_local MT_DECLARE_TASK(CompressDxt, MT::StackRequirements::EXTENDED, MT::TaskPriority::NORMAL, MT::Color::Aqua); 2592f083884Ss.makeev_local 2602f083884Ss.makeev_local uint32 width; 2612f083884Ss.makeev_local uint32 height; 2622f083884Ss.makeev_local uint32 stride; 2632f083884Ss.makeev_local 2642f083884Ss.makeev_local uint32 blkWidth; 2652f083884Ss.makeev_local uint32 blkHeight; 2662f083884Ss.makeev_local 2672f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 2682f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 269d7cf17b1Ss.makeev_local MT::Atomic32<uint32>* pIsFinished; 2702f083884Ss.makeev_local 271d7cf17b1Ss.makeev_local 272d7cf17b1Ss.makeev_local CompressDxt(uint32 _width, uint32 _height, uint32 _stride, const MT::ArrayView<uint8> & _srcPixels, MT::Atomic32<uint32>* _pIsFinished = nullptr) 2732f083884Ss.makeev_local : srcPixels(_srcPixels) 274d7cf17b1Ss.makeev_local , pIsFinished(_pIsFinished) 2752f083884Ss.makeev_local { 2762f083884Ss.makeev_local width = _width; 2772f083884Ss.makeev_local height = _height; 2782f083884Ss.makeev_local stride = _stride; 2792f083884Ss.makeev_local 2802f083884Ss.makeev_local blkWidth = width >> 2; 2812f083884Ss.makeev_local blkHeight = height >> 2; 2822f083884Ss.makeev_local 2832f083884Ss.makeev_local int dxtBlocksTotalSizeInBytes = blkWidth * blkHeight * 8; // 8 bytes = 64 bits per block (dxt1) 284d7cf17b1Ss.makeev_local dxtBlocks = MT::ArrayView<uint8>( MT::Memory::Alloc( dxtBlocksTotalSizeInBytes ), dxtBlocksTotalSizeInBytes); 2852f083884Ss.makeev_local } 2862f083884Ss.makeev_local 2872f083884Ss.makeev_local ~CompressDxt() 2882f083884Ss.makeev_local { 2892f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 2902f083884Ss.makeev_local if (pDxtBlocks) 2912f083884Ss.makeev_local { 292d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks); 2932f083884Ss.makeev_local } 2942f083884Ss.makeev_local } 2952f083884Ss.makeev_local 2962f083884Ss.makeev_local 2972f083884Ss.makeev_local void Do(MT::FiberContext& context) 2982f083884Ss.makeev_local { 2996e90b535Ss.makeev_local #if defined(MT_PLATFORM_ORBIS) && defined(MT_INSTRUMENTED_BUILD) 3006e90b535Ss.makeev_local sceRazorCpuPushMarkerStatic("compress_dxt_task", MT::Color::ConvertToABGR(MT::Color::SteelBlue), SCE_RAZOR_MARKER_DISABLE_HUD); 3016e90b535Ss.makeev_local #endif 3026e90b535Ss.makeev_local 303*b23bdf5aSs.makeev_local // use StaticVector as subtask container. beware stack overflow! 304*b23bdf5aSs.makeev_local MT::StaticVector<CompressDxtBlock, 1024> subTasks; 3052f083884Ss.makeev_local 3062f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 3072f083884Ss.makeev_local { 3082f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 3092f083884Ss.makeev_local { 3102f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 3112f083884Ss.makeev_local subTasks.PushBack( CompressDxtBlock(blkX * 4, blkY * 4, stride, srcPixels, dxtBlocks, blockIndex * 8) ); 3122f083884Ss.makeev_local } 3132f083884Ss.makeev_local } 3142f083884Ss.makeev_local 3152f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 316d7cf17b1Ss.makeev_local 317d7cf17b1Ss.makeev_local if (pIsFinished != nullptr) 318d7cf17b1Ss.makeev_local { 319d7cf17b1Ss.makeev_local pIsFinished->Store(1); 320d7cf17b1Ss.makeev_local } 3216e90b535Ss.makeev_local 3226e90b535Ss.makeev_local #if defined(MT_PLATFORM_ORBIS) && defined(MT_INSTRUMENTED_BUILD) 3236e90b535Ss.makeev_local sceRazorCpuPopMarker(); 3246e90b535Ss.makeev_local #endif 3252f083884Ss.makeev_local } 3262f083884Ss.makeev_local }; 3272f083884Ss.makeev_local 3282f083884Ss.makeev_local 3292f083884Ss.makeev_local 3302f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 3312f083884Ss.makeev_local struct DecompressDxtBlock 3322f083884Ss.makeev_local { 333*b23bdf5aSs.makeev_local MT_DECLARE_TASK(DecompressDxtBlock, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Red); 3342f083884Ss.makeev_local 3352f083884Ss.makeev_local MT::ArrayView<uint8> srcBlocks; 3362f083884Ss.makeev_local MT::ArrayView<uint8> dstPixels; 3372f083884Ss.makeev_local 3382f083884Ss.makeev_local int dstX; 3392f083884Ss.makeev_local int dstY; 3402f083884Ss.makeev_local 3412f083884Ss.makeev_local int stride; 3422f083884Ss.makeev_local int srcBlockOffset; 3432f083884Ss.makeev_local 3442f083884Ss.makeev_local DecompressDxtBlock(int _dstX, int _dstY, int _stride, const MT::ArrayView<uint8> & _dstPixels, const MT::ArrayView<uint8> & _srcBlocks, int _srcBlockOffset) 3452f083884Ss.makeev_local : srcBlocks(_srcBlocks) 3462f083884Ss.makeev_local , dstPixels(_dstPixels) 3472f083884Ss.makeev_local { 3482f083884Ss.makeev_local dstX = _dstX; 3492f083884Ss.makeev_local dstY = _dstY; 3502f083884Ss.makeev_local stride = _stride; 3512f083884Ss.makeev_local srcBlockOffset = _srcBlockOffset; 3522f083884Ss.makeev_local } 3532f083884Ss.makeev_local 3542f083884Ss.makeev_local DecompressDxtBlock(DecompressDxtBlock&& other) 3552f083884Ss.makeev_local : srcBlocks(other.srcBlocks) 3562f083884Ss.makeev_local , dstPixels(other.dstPixels) 3572f083884Ss.makeev_local , dstX(other.dstX) 3582f083884Ss.makeev_local , dstY(other.dstY) 3592f083884Ss.makeev_local , stride(other.stride) 3602f083884Ss.makeev_local , srcBlockOffset(other.srcBlockOffset) 3612f083884Ss.makeev_local { 3622f083884Ss.makeev_local other.dstX = -1; 3632f083884Ss.makeev_local other.dstY = -1; 3642f083884Ss.makeev_local other.stride = -1; 3652f083884Ss.makeev_local other.srcBlockOffset = -1; 3662f083884Ss.makeev_local } 3672f083884Ss.makeev_local 3682f083884Ss.makeev_local ~DecompressDxtBlock() 3692f083884Ss.makeev_local { 3702f083884Ss.makeev_local dstX = -1; 3712f083884Ss.makeev_local dstY = -1; 3722f083884Ss.makeev_local stride = -1; 3732f083884Ss.makeev_local srcBlockOffset = -1; 3742f083884Ss.makeev_local } 3752f083884Ss.makeev_local 3762f083884Ss.makeev_local 3772f083884Ss.makeev_local void Do(MT::FiberContext&) 3782f083884Ss.makeev_local { 3792f083884Ss.makeev_local // 16 pixels of output 3802f083884Ss.makeev_local uint32 pixels[4*4]; 3812f083884Ss.makeev_local 3822f083884Ss.makeev_local // copy dxt1 block from image 3832f083884Ss.makeev_local for (int y = 0; y < 4; y++) 3842f083884Ss.makeev_local { 3852f083884Ss.makeev_local for (int x = 0; x < 4; x++) 3862f083884Ss.makeev_local { 3872f083884Ss.makeev_local squish::Decompress((squish::u8 *)&pixels[0], &srcBlocks[srcBlockOffset], squish::kDxt1); 3882f083884Ss.makeev_local 3892f083884Ss.makeev_local int posX = dstX + x; 3902f083884Ss.makeev_local int posY = dstY + y; 3912f083884Ss.makeev_local 3922f083884Ss.makeev_local int index = posY * stride + (posX * 3); 3932f083884Ss.makeev_local 3942f083884Ss.makeev_local uint32 pixel = pixels[y * 4 + x]; 3952f083884Ss.makeev_local 3962f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 3972f083884Ss.makeev_local 3982f083884Ss.makeev_local dstPixels[index + 0] = (pixel & 0xFF); 3992f083884Ss.makeev_local dstPixels[index + 1] = (pixel >> 8 & 0xFF); 4002f083884Ss.makeev_local dstPixels[index + 2] = (pixel >> 16 & 0xFF); 4012f083884Ss.makeev_local } 4022f083884Ss.makeev_local } 4032f083884Ss.makeev_local 4042f083884Ss.makeev_local } 4052f083884Ss.makeev_local }; 4062f083884Ss.makeev_local 4072f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4082f083884Ss.makeev_local struct DecompressDxt 4092f083884Ss.makeev_local { 410*b23bdf5aSs.makeev_local MT_DECLARE_TASK(DecompressDxt, MT::StackRequirements::EXTENDED, MT::TaskPriority::NORMAL, MT::Color::Yellow); 4112f083884Ss.makeev_local 4122f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 4132f083884Ss.makeev_local MT::ArrayView<uint8> decompressedImage; 4142f083884Ss.makeev_local 4152f083884Ss.makeev_local uint32 blkWidth; 4162f083884Ss.makeev_local uint32 blkHeight; 4172f083884Ss.makeev_local 4182f083884Ss.makeev_local 4192f083884Ss.makeev_local DecompressDxt(const MT::ArrayView<uint8> & _dxtBlocks, uint32 dxtBlocksCountWidth, uint32 dxtBlocksCountHeight) 4202f083884Ss.makeev_local : dxtBlocks(_dxtBlocks) 4212f083884Ss.makeev_local { 4222f083884Ss.makeev_local blkWidth = dxtBlocksCountWidth; 4232f083884Ss.makeev_local blkHeight = dxtBlocksCountHeight; 4242f083884Ss.makeev_local 4252f083884Ss.makeev_local // dxt1 block = 16 rgb pixels = 48 bytes 4262f083884Ss.makeev_local uint32 bytesCount = blkWidth * blkHeight * 48; 427d7cf17b1Ss.makeev_local decompressedImage = MT::ArrayView<uint8>( MT::Memory::Alloc(bytesCount), bytesCount); 4282f083884Ss.makeev_local } 4292f083884Ss.makeev_local 4302f083884Ss.makeev_local ~DecompressDxt() 4312f083884Ss.makeev_local { 4322f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 4332f083884Ss.makeev_local if (pDxtBlocks) 4342f083884Ss.makeev_local { 435d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks); 4362f083884Ss.makeev_local } 4372f083884Ss.makeev_local 4382f083884Ss.makeev_local void* pDecompressedImage = decompressedImage.GetRawData(); 4392f083884Ss.makeev_local if (pDecompressedImage) 4402f083884Ss.makeev_local { 441d7cf17b1Ss.makeev_local MT::Memory::Free(pDecompressedImage); 4422f083884Ss.makeev_local } 4432f083884Ss.makeev_local 4442f083884Ss.makeev_local } 4452f083884Ss.makeev_local 4462f083884Ss.makeev_local void Do(MT::FiberContext& context) 4472f083884Ss.makeev_local { 448*b23bdf5aSs.makeev_local // use StaticVector as subtask container. beware stack overflow! 449*b23bdf5aSs.makeev_local MT::StaticVector<DecompressDxtBlock, 1024> subTasks; 4502f083884Ss.makeev_local 4512f083884Ss.makeev_local int stride = blkWidth * 4 * 3; 4522f083884Ss.makeev_local 4532f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 4542f083884Ss.makeev_local { 4552f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 4562f083884Ss.makeev_local { 4572f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 4582f083884Ss.makeev_local subTasks.PushBack( DecompressDxtBlock(blkX * 4, blkY * 4, stride, decompressedImage, dxtBlocks, blockIndex * 8) ); 4592f083884Ss.makeev_local } 4602f083884Ss.makeev_local } 4612f083884Ss.makeev_local 4622f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 4632f083884Ss.makeev_local } 4642f083884Ss.makeev_local 4652f083884Ss.makeev_local }; 4662f083884Ss.makeev_local 4672f083884Ss.makeev_local 4682f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4692f083884Ss.makeev_local void Wait(MT::TaskScheduler & scheduler) 4702f083884Ss.makeev_local { 4712f083884Ss.makeev_local //emulate game loop 4722f083884Ss.makeev_local for(;;) 4732f083884Ss.makeev_local { 4742f083884Ss.makeev_local bool waitDone = scheduler.WaitAll(33); 4752f083884Ss.makeev_local if (waitDone) 4762f083884Ss.makeev_local { 4772f083884Ss.makeev_local break; 4782f083884Ss.makeev_local } 4792f083884Ss.makeev_local } 4802f083884Ss.makeev_local } 4812f083884Ss.makeev_local 4824965e494Ss.makeev_local 4836e90b535Ss.makeev_local 4846e90b535Ss.makeev_local /* 485d7cf17b1Ss.makeev_local // dxt compressor Hiload test (for profiling purposes) 486d7cf17b1Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 487d7cf17b1Ss.makeev_local TEST(HiloadDxtTest) 488d7cf17b1Ss.makeev_local { 489d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished1; 490d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished2; 491d7cf17b1Ss.makeev_local 492d7cf17b1Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 493d7cf17b1Ss.makeev_local 494d7cf17b1Ss.makeev_local int stride = 384; 495d7cf17b1Ss.makeev_local 496d7cf17b1Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 497d7cf17b1Ss.makeev_local 498d7cf17b1Ss.makeev_local CompressDxt compressTask1(128, 128, stride, srcImage, &isFinished1); 499d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask1.width & 3) == 0 && (compressTask1.height & 3) == 0, "Image size must be a multiple of 4"); 500d7cf17b1Ss.makeev_local 501d7cf17b1Ss.makeev_local CompressDxt compressTask2(128, 128, stride, srcImage, &isFinished2); 502d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask2.width & 3) == 0 && (compressTask2.height & 3) == 0, "Image size must be a multiple of 4"); 503d7cf17b1Ss.makeev_local 5046e90b535Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 5056e90b535Ss.makeev_local Microprofile profiler; 5066e90b535Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, &profiler); 5076e90b535Ss.makeev_local #else 508d7cf17b1Ss.makeev_local MT::TaskScheduler scheduler; 5096e90b535Ss.makeev_local #endif 510d7cf17b1Ss.makeev_local 511d7cf17b1Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 512d7cf17b1Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 513d7cf17b1Ss.makeev_local 514d7cf17b1Ss.makeev_local isFinished1.Store(0); 515d7cf17b1Ss.makeev_local isFinished2.Store(0); 516d7cf17b1Ss.makeev_local 517d7cf17b1Ss.makeev_local printf("HiloadDxtTest\n"); 518d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1); 519d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1); 520d7cf17b1Ss.makeev_local 521d7cf17b1Ss.makeev_local for(;;) 522d7cf17b1Ss.makeev_local { 523d7cf17b1Ss.makeev_local if (isFinished1.Load() != 0) 524d7cf17b1Ss.makeev_local { 525d7cf17b1Ss.makeev_local isFinished1.Store(0); 526d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1); 527d7cf17b1Ss.makeev_local } 528d7cf17b1Ss.makeev_local 529d7cf17b1Ss.makeev_local if (isFinished2.Load() != 0) 530d7cf17b1Ss.makeev_local { 531d7cf17b1Ss.makeev_local isFinished2.Store(0); 532d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1); 533d7cf17b1Ss.makeev_local } 534d7cf17b1Ss.makeev_local 535d7cf17b1Ss.makeev_local MT::Thread::Sleep(1); 536d7cf17b1Ss.makeev_local } 537d7cf17b1Ss.makeev_local } 538c121d748Ss.makeev_local */ 53960ac17fbSs.makeev_local 5402f083884Ss.makeev_local // dxt compressor complex test 5412f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 5422f083884Ss.makeev_local TEST(RunComplexDxtTest) 5432f083884Ss.makeev_local { 5442f083884Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 5452f083884Ss.makeev_local 5462f083884Ss.makeev_local int stride = 384; 5472f083884Ss.makeev_local 5482f083884Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 5492f083884Ss.makeev_local 5502f083884Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage); 5512f083884Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4"); 5522f083884Ss.makeev_local 5532f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 5542f083884Ss.makeev_local Microprofile profiler; 555d7cf17b1Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, &profiler); 5562f083884Ss.makeev_local #else 5572f083884Ss.makeev_local MT::TaskScheduler scheduler; 5582f083884Ss.makeev_local #endif 5592f083884Ss.makeev_local 5602f083884Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 5612f083884Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 5622f083884Ss.makeev_local 5632f083884Ss.makeev_local printf("Compress image\n"); 5642f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1); 5652f083884Ss.makeev_local 5662f083884Ss.makeev_local Wait(scheduler); 5672f083884Ss.makeev_local 5682f083884Ss.makeev_local DecompressDxt decompressTask(compressTask.dxtBlocks, compressTask.blkWidth, compressTask.blkHeight); 5692f083884Ss.makeev_local compressTask.dxtBlocks = MT::ArrayView<uint8>(); //transfer memory ownership to Decompress task 5702f083884Ss.makeev_local 5712f083884Ss.makeev_local printf("Decompress image\n"); 5722f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &decompressTask, 1); 5732f083884Ss.makeev_local 5742f083884Ss.makeev_local Wait(scheduler); 5752f083884Ss.makeev_local 5762f083884Ss.makeev_local /* 5772f083884Ss.makeev_local //save compressed image 5782f083884Ss.makeev_local { 5792f083884Ss.makeev_local FILE * file = fopen("lena_dxt1.dds", "w+b"); 5802f083884Ss.makeev_local fwrite(&EmbeddedImage::ddsHeader[0], MT_ARRAY_SIZE(EmbeddedImage::ddsHeader), 1, file); 5812f083884Ss.makeev_local fwrite(decompressTask.dxtBlocks, decompressTask.blkWidth * decompressTask.blkHeight * 8, 1, file); 5822f083884Ss.makeev_local fclose(file); 5832f083884Ss.makeev_local } 5842f083884Ss.makeev_local 5852f083884Ss.makeev_local //save uncompressed image 5862f083884Ss.makeev_local { 5872f083884Ss.makeev_local FILE * file = fopen("lena_rgb.raw", "w+b"); 5882f083884Ss.makeev_local fwrite(decompressTask.decompressedImage, decompressTask.blkWidth * decompressTask.blkHeight * 48, 1, file); 5892f083884Ss.makeev_local fclose(file); 5902f083884Ss.makeev_local } 5912f083884Ss.makeev_local */ 5922f083884Ss.makeev_local 5932f083884Ss.makeev_local printf("Compare images\n"); 5942f083884Ss.makeev_local bool imagesEqual = CompareImagesPSNR(&srcImage[0], &decompressTask.decompressedImage[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor), 8.0); 5952f083884Ss.makeev_local CHECK_EQUAL(true, imagesEqual); 5962f083884Ss.makeev_local 5972f083884Ss.makeev_local /* 5982f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 5992f083884Ss.makeev_local // waiting for profiler attach 6002f083884Ss.makeev_local printf("Press any key to continue\n"); 6012f083884Ss.makeev_local while(true) 6022f083884Ss.makeev_local { 6032f083884Ss.makeev_local if (_kbhit() != 0) 6042f083884Ss.makeev_local { 6052f083884Ss.makeev_local break; 6062f083884Ss.makeev_local } 6072f083884Ss.makeev_local } 6082f083884Ss.makeev_local #endif 6092f083884Ss.makeev_local */ 6102f083884Ss.makeev_local } 6112f083884Ss.makeev_local 6122f083884Ss.makeev_local 6132f083884Ss.makeev_local } 614