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
233d930776Ss.makeev_local
243d930776Ss.makeev_local #include <MTConfig.h>
253d930776Ss.makeev_local
263d930776Ss.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
32*f7a9bfc3Ss.makeev_local #include "../Profiler/Profiler.h"
33*f7a9bfc3Ss.makeev_local
342f083884Ss.makeev_local #include <squish.h>
352f083884Ss.makeev_local #include <string.h>
36faa6c6e5Ss.makeev_local #include <math.h>
372f083884Ss.makeev_local
3860ac17fbSs.makeev_local
392f083884Ss.makeev_local
402f083884Ss.makeev_local namespace EmbeddedImage
412f083884Ss.makeev_local {
422f083884Ss.makeev_local #include "LenaDxt/LenaColor.h"
432f083884Ss.makeev_local #include "LenaDxt/HeaderDDS.h"
442f083884Ss.makeev_local }
452f083884Ss.makeev_local
462f083884Ss.makeev_local
CompareImagesPSNR(uint8 * img1,uint8 * img2,uint32 bytesCount,double psnrThreshold)472f083884Ss.makeev_local bool CompareImagesPSNR(uint8 * img1, uint8 * img2, uint32 bytesCount, double psnrThreshold)
482f083884Ss.makeev_local {
492f083884Ss.makeev_local double mse = 0.0;
502f083884Ss.makeev_local
512f083884Ss.makeev_local for (uint32 i = 0; i < bytesCount; i++)
522f083884Ss.makeev_local {
532f083884Ss.makeev_local double error = (double)img1[0] - (double)img2[1];
542f083884Ss.makeev_local mse += (error * error);
552f083884Ss.makeev_local }
562f083884Ss.makeev_local
572f083884Ss.makeev_local mse = mse / (double)bytesCount;
582f083884Ss.makeev_local
592f083884Ss.makeev_local if (mse > 0.0)
602f083884Ss.makeev_local {
612f083884Ss.makeev_local double psnr = 10.0 * log10(255.0*255.0/mse);
622f083884Ss.makeev_local if (psnr < psnrThreshold)
632f083884Ss.makeev_local {
642f083884Ss.makeev_local return false;
652f083884Ss.makeev_local }
662f083884Ss.makeev_local }
672f083884Ss.makeev_local
682f083884Ss.makeev_local return true;
692f083884Ss.makeev_local }
702f083884Ss.makeev_local
712f083884Ss.makeev_local
722f083884Ss.makeev_local
SUITE(DxtTests)732f083884Ss.makeev_local SUITE(DxtTests)
742f083884Ss.makeev_local {
752f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
762f083884Ss.makeev_local struct CompressDxtBlock
772f083884Ss.makeev_local {
78b23bdf5aSs.makeev_local MT_DECLARE_TASK(CompressDxtBlock, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
792f083884Ss.makeev_local
802f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels;
812f083884Ss.makeev_local MT::ArrayView<uint8> dstBlocks;
822f083884Ss.makeev_local
832f083884Ss.makeev_local int srcX;
842f083884Ss.makeev_local int srcY;
852f083884Ss.makeev_local
862f083884Ss.makeev_local int stride;
872f083884Ss.makeev_local int dstBlockOffset;
882f083884Ss.makeev_local
892f083884Ss.makeev_local CompressDxtBlock(int _srcX, int _srcY, int _stride, const MT::ArrayView<uint8> & _srcPixels, const MT::ArrayView<uint8> & _dstBlocks, int _dstBlockOffset)
902f083884Ss.makeev_local : srcPixels(_srcPixels)
912f083884Ss.makeev_local , dstBlocks(_dstBlocks)
922f083884Ss.makeev_local {
932f083884Ss.makeev_local srcX = _srcX;
942f083884Ss.makeev_local srcY = _srcY;
952f083884Ss.makeev_local stride = _stride;
962f083884Ss.makeev_local dstBlockOffset = _dstBlockOffset;
972f083884Ss.makeev_local }
982f083884Ss.makeev_local
992f083884Ss.makeev_local CompressDxtBlock(CompressDxtBlock&& other)
1002f083884Ss.makeev_local : srcPixels(other.srcPixels)
1012f083884Ss.makeev_local , dstBlocks(other.dstBlocks)
1022f083884Ss.makeev_local , srcX(other.srcX)
1032f083884Ss.makeev_local , srcY(other.srcY)
1042f083884Ss.makeev_local , stride(other.stride)
1052f083884Ss.makeev_local , dstBlockOffset(other.dstBlockOffset)
1062f083884Ss.makeev_local {
1072f083884Ss.makeev_local other.srcX = -1;
1082f083884Ss.makeev_local other.srcY = -1;
1092f083884Ss.makeev_local other.stride = -1;
1102f083884Ss.makeev_local other.dstBlockOffset = -1;
1112f083884Ss.makeev_local }
1122f083884Ss.makeev_local
1132f083884Ss.makeev_local ~CompressDxtBlock()
1142f083884Ss.makeev_local {
1152f083884Ss.makeev_local srcX = -1;
1162f083884Ss.makeev_local srcY = -1;
1172f083884Ss.makeev_local stride = -1;
1182f083884Ss.makeev_local dstBlockOffset = -1;
1192f083884Ss.makeev_local }
1202f083884Ss.makeev_local
1212f083884Ss.makeev_local void Do(MT::FiberContext&)
1222f083884Ss.makeev_local {
1232f083884Ss.makeev_local // 16 pixels of input
1242f083884Ss.makeev_local uint32 pixels[4*4];
1252f083884Ss.makeev_local
1262f083884Ss.makeev_local // copy dxt1 block from image
1272f083884Ss.makeev_local for (int y = 0; y < 4; y++)
1282f083884Ss.makeev_local {
1292f083884Ss.makeev_local for (int x = 0; x < 4; x++)
1302f083884Ss.makeev_local {
1312f083884Ss.makeev_local int posX = srcX + x;
1322f083884Ss.makeev_local int posY = srcY + y;
1332f083884Ss.makeev_local
1342f083884Ss.makeev_local int index = posY * stride + (posX * 3);
1352f083884Ss.makeev_local
1362f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index");
1372f083884Ss.makeev_local
1382f083884Ss.makeev_local uint8 r = srcPixels[index + 0];
1392f083884Ss.makeev_local uint8 g = srcPixels[index + 1];
1402f083884Ss.makeev_local uint8 b = srcPixels[index + 2];
1412f083884Ss.makeev_local
1422f083884Ss.makeev_local uint32 color = 0xFF000000 | ((b << 16) | (g << 8) | (r));
1432f083884Ss.makeev_local
1442f083884Ss.makeev_local pixels[y * 4 + x] = color;
1452f083884Ss.makeev_local }
1462f083884Ss.makeev_local }
1472f083884Ss.makeev_local
1482f083884Ss.makeev_local // compress the 4x4 block using DXT1 compression
1492f083884Ss.makeev_local squish::Compress( (squish::u8 *)&pixels[0], &dstBlocks[dstBlockOffset], squish::kDxt1 );
1502f083884Ss.makeev_local }
1512f083884Ss.makeev_local };
1522f083884Ss.makeev_local
1532f083884Ss.makeev_local
1542f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1552f083884Ss.makeev_local struct CompressDxt
1562f083884Ss.makeev_local {
157b23bdf5aSs.makeev_local MT_DECLARE_TASK(CompressDxt, MT::StackRequirements::EXTENDED, MT::TaskPriority::NORMAL, MT::Color::Aqua);
1582f083884Ss.makeev_local
1592f083884Ss.makeev_local uint32 width;
1602f083884Ss.makeev_local uint32 height;
1612f083884Ss.makeev_local uint32 stride;
1622f083884Ss.makeev_local
1632f083884Ss.makeev_local uint32 blkWidth;
1642f083884Ss.makeev_local uint32 blkHeight;
1652f083884Ss.makeev_local
1663d930776Ss.makeev_local uint32 passCount;
1673d930776Ss.makeev_local
1682f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels;
1692f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks;
170d7cf17b1Ss.makeev_local MT::Atomic32<uint32>* pIsFinished;
1712f083884Ss.makeev_local
172d7cf17b1Ss.makeev_local
1733d930776Ss.makeev_local CompressDxt(uint32 _width, uint32 _height, uint32 _stride, const MT::ArrayView<uint8> & _srcPixels, MT::Atomic32<uint32>* _pIsFinished = nullptr, uint32 _passCount = 1)
1742f083884Ss.makeev_local : srcPixels(_srcPixels)
175d7cf17b1Ss.makeev_local , pIsFinished(_pIsFinished)
1762f083884Ss.makeev_local {
1773d930776Ss.makeev_local passCount = _passCount;
1783d930776Ss.makeev_local
1792f083884Ss.makeev_local width = _width;
1802f083884Ss.makeev_local height = _height;
1812f083884Ss.makeev_local stride = _stride;
1822f083884Ss.makeev_local
1832f083884Ss.makeev_local blkWidth = width >> 2;
1842f083884Ss.makeev_local blkHeight = height >> 2;
1852f083884Ss.makeev_local
1862f083884Ss.makeev_local int dxtBlocksTotalSizeInBytes = blkWidth * blkHeight * 8; // 8 bytes = 64 bits per block (dxt1)
187d7cf17b1Ss.makeev_local dxtBlocks = MT::ArrayView<uint8>( MT::Memory::Alloc( dxtBlocksTotalSizeInBytes ), dxtBlocksTotalSizeInBytes);
1882f083884Ss.makeev_local }
1892f083884Ss.makeev_local
1902f083884Ss.makeev_local ~CompressDxt()
1912f083884Ss.makeev_local {
1922f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData();
1932f083884Ss.makeev_local if (pDxtBlocks)
1942f083884Ss.makeev_local {
195d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks);
1962f083884Ss.makeev_local }
1972f083884Ss.makeev_local }
1982f083884Ss.makeev_local
1992f083884Ss.makeev_local
2002f083884Ss.makeev_local void Do(MT::FiberContext& context)
2012f083884Ss.makeev_local {
2023d930776Ss.makeev_local for(uint32 i = 0; i < passCount; i++)
2033d930776Ss.makeev_local {
204b23bdf5aSs.makeev_local // use StaticVector as subtask container. beware stack overflow!
205b23bdf5aSs.makeev_local MT::StaticVector<CompressDxtBlock, 1024> subTasks;
2062f083884Ss.makeev_local
2072f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++)
2082f083884Ss.makeev_local {
2092f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++)
2102f083884Ss.makeev_local {
2112f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX;
2122f083884Ss.makeev_local subTasks.PushBack( CompressDxtBlock(blkX * 4, blkY * 4, stride, srcPixels, dxtBlocks, blockIndex * 8) );
2132f083884Ss.makeev_local }
2142f083884Ss.makeev_local }
2152f083884Ss.makeev_local
2162f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size());
2173d930776Ss.makeev_local }
2183d930776Ss.makeev_local
219d7cf17b1Ss.makeev_local
220d7cf17b1Ss.makeev_local if (pIsFinished != nullptr)
221d7cf17b1Ss.makeev_local {
222d7cf17b1Ss.makeev_local pIsFinished->Store(1);
223d7cf17b1Ss.makeev_local }
2242f083884Ss.makeev_local }
2252f083884Ss.makeev_local };
2262f083884Ss.makeev_local
2272f083884Ss.makeev_local
2282f083884Ss.makeev_local
2292f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2302f083884Ss.makeev_local struct DecompressDxtBlock
2312f083884Ss.makeev_local {
232b23bdf5aSs.makeev_local MT_DECLARE_TASK(DecompressDxtBlock, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Red);
2332f083884Ss.makeev_local
2342f083884Ss.makeev_local MT::ArrayView<uint8> srcBlocks;
2352f083884Ss.makeev_local MT::ArrayView<uint8> dstPixels;
2362f083884Ss.makeev_local
2372f083884Ss.makeev_local int dstX;
2382f083884Ss.makeev_local int dstY;
2392f083884Ss.makeev_local
2402f083884Ss.makeev_local int stride;
2412f083884Ss.makeev_local int srcBlockOffset;
2422f083884Ss.makeev_local
2432f083884Ss.makeev_local DecompressDxtBlock(int _dstX, int _dstY, int _stride, const MT::ArrayView<uint8> & _dstPixels, const MT::ArrayView<uint8> & _srcBlocks, int _srcBlockOffset)
2442f083884Ss.makeev_local : srcBlocks(_srcBlocks)
2452f083884Ss.makeev_local , dstPixels(_dstPixels)
2462f083884Ss.makeev_local {
2472f083884Ss.makeev_local dstX = _dstX;
2482f083884Ss.makeev_local dstY = _dstY;
2492f083884Ss.makeev_local stride = _stride;
2502f083884Ss.makeev_local srcBlockOffset = _srcBlockOffset;
2512f083884Ss.makeev_local }
2522f083884Ss.makeev_local
2532f083884Ss.makeev_local DecompressDxtBlock(DecompressDxtBlock&& other)
2542f083884Ss.makeev_local : srcBlocks(other.srcBlocks)
2552f083884Ss.makeev_local , dstPixels(other.dstPixels)
2562f083884Ss.makeev_local , dstX(other.dstX)
2572f083884Ss.makeev_local , dstY(other.dstY)
2582f083884Ss.makeev_local , stride(other.stride)
2592f083884Ss.makeev_local , srcBlockOffset(other.srcBlockOffset)
2602f083884Ss.makeev_local {
2612f083884Ss.makeev_local other.dstX = -1;
2622f083884Ss.makeev_local other.dstY = -1;
2632f083884Ss.makeev_local other.stride = -1;
2642f083884Ss.makeev_local other.srcBlockOffset = -1;
2652f083884Ss.makeev_local }
2662f083884Ss.makeev_local
2672f083884Ss.makeev_local ~DecompressDxtBlock()
2682f083884Ss.makeev_local {
2692f083884Ss.makeev_local dstX = -1;
2702f083884Ss.makeev_local dstY = -1;
2712f083884Ss.makeev_local stride = -1;
2722f083884Ss.makeev_local srcBlockOffset = -1;
2732f083884Ss.makeev_local }
2742f083884Ss.makeev_local
2752f083884Ss.makeev_local
2762f083884Ss.makeev_local void Do(MT::FiberContext&)
2772f083884Ss.makeev_local {
2782f083884Ss.makeev_local // 16 pixels of output
2792f083884Ss.makeev_local uint32 pixels[4*4];
2802f083884Ss.makeev_local
2812f083884Ss.makeev_local // copy dxt1 block from image
2822f083884Ss.makeev_local for (int y = 0; y < 4; y++)
2832f083884Ss.makeev_local {
2842f083884Ss.makeev_local for (int x = 0; x < 4; x++)
2852f083884Ss.makeev_local {
2862f083884Ss.makeev_local squish::Decompress((squish::u8 *)&pixels[0], &srcBlocks[srcBlockOffset], squish::kDxt1);
2872f083884Ss.makeev_local
2882f083884Ss.makeev_local int posX = dstX + x;
2892f083884Ss.makeev_local int posY = dstY + y;
2902f083884Ss.makeev_local
2912f083884Ss.makeev_local int index = posY * stride + (posX * 3);
2922f083884Ss.makeev_local
2932f083884Ss.makeev_local uint32 pixel = pixels[y * 4 + x];
2942f083884Ss.makeev_local
2952f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index");
2962f083884Ss.makeev_local
2972f083884Ss.makeev_local dstPixels[index + 0] = (pixel & 0xFF);
2982f083884Ss.makeev_local dstPixels[index + 1] = (pixel >> 8 & 0xFF);
2992f083884Ss.makeev_local dstPixels[index + 2] = (pixel >> 16 & 0xFF);
3002f083884Ss.makeev_local }
3012f083884Ss.makeev_local }
3022f083884Ss.makeev_local
3032f083884Ss.makeev_local }
3042f083884Ss.makeev_local };
3052f083884Ss.makeev_local
3062f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3072f083884Ss.makeev_local struct DecompressDxt
3082f083884Ss.makeev_local {
309b23bdf5aSs.makeev_local MT_DECLARE_TASK(DecompressDxt, MT::StackRequirements::EXTENDED, MT::TaskPriority::NORMAL, MT::Color::Yellow);
3102f083884Ss.makeev_local
3112f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks;
3122f083884Ss.makeev_local MT::ArrayView<uint8> decompressedImage;
3132f083884Ss.makeev_local
3142f083884Ss.makeev_local uint32 blkWidth;
3152f083884Ss.makeev_local uint32 blkHeight;
3162f083884Ss.makeev_local
3172f083884Ss.makeev_local
3182f083884Ss.makeev_local DecompressDxt(const MT::ArrayView<uint8> & _dxtBlocks, uint32 dxtBlocksCountWidth, uint32 dxtBlocksCountHeight)
3192f083884Ss.makeev_local : dxtBlocks(_dxtBlocks)
3202f083884Ss.makeev_local {
3212f083884Ss.makeev_local blkWidth = dxtBlocksCountWidth;
3222f083884Ss.makeev_local blkHeight = dxtBlocksCountHeight;
3232f083884Ss.makeev_local
3242f083884Ss.makeev_local // dxt1 block = 16 rgb pixels = 48 bytes
3252f083884Ss.makeev_local uint32 bytesCount = blkWidth * blkHeight * 48;
326d7cf17b1Ss.makeev_local decompressedImage = MT::ArrayView<uint8>( MT::Memory::Alloc(bytesCount), bytesCount);
3272f083884Ss.makeev_local }
3282f083884Ss.makeev_local
3292f083884Ss.makeev_local ~DecompressDxt()
3302f083884Ss.makeev_local {
3312f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData();
3322f083884Ss.makeev_local if (pDxtBlocks)
3332f083884Ss.makeev_local {
334d7cf17b1Ss.makeev_local MT::Memory::Free(pDxtBlocks);
3352f083884Ss.makeev_local }
3362f083884Ss.makeev_local
3372f083884Ss.makeev_local void* pDecompressedImage = decompressedImage.GetRawData();
3382f083884Ss.makeev_local if (pDecompressedImage)
3392f083884Ss.makeev_local {
340d7cf17b1Ss.makeev_local MT::Memory::Free(pDecompressedImage);
3412f083884Ss.makeev_local }
3422f083884Ss.makeev_local
3432f083884Ss.makeev_local }
3442f083884Ss.makeev_local
3452f083884Ss.makeev_local void Do(MT::FiberContext& context)
3462f083884Ss.makeev_local {
347b23bdf5aSs.makeev_local // use StaticVector as subtask container. beware stack overflow!
348b23bdf5aSs.makeev_local MT::StaticVector<DecompressDxtBlock, 1024> subTasks;
3492f083884Ss.makeev_local
3502f083884Ss.makeev_local int stride = blkWidth * 4 * 3;
3512f083884Ss.makeev_local
3522f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++)
3532f083884Ss.makeev_local {
3542f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++)
3552f083884Ss.makeev_local {
3562f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX;
3572f083884Ss.makeev_local subTasks.PushBack( DecompressDxtBlock(blkX * 4, blkY * 4, stride, decompressedImage, dxtBlocks, blockIndex * 8) );
3582f083884Ss.makeev_local }
3592f083884Ss.makeev_local }
3602f083884Ss.makeev_local
3612f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size());
3622f083884Ss.makeev_local }
3632f083884Ss.makeev_local
3642f083884Ss.makeev_local };
3652f083884Ss.makeev_local
3662f083884Ss.makeev_local
3672f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3682f083884Ss.makeev_local void Wait(MT::TaskScheduler & scheduler)
3692f083884Ss.makeev_local {
3702f083884Ss.makeev_local //emulate game loop
3712f083884Ss.makeev_local for(;;)
3722f083884Ss.makeev_local {
3732f083884Ss.makeev_local bool waitDone = scheduler.WaitAll(33);
3742f083884Ss.makeev_local if (waitDone)
3752f083884Ss.makeev_local {
3762f083884Ss.makeev_local break;
3772f083884Ss.makeev_local }
3782f083884Ss.makeev_local }
3792f083884Ss.makeev_local }
3802f083884Ss.makeev_local
3814965e494Ss.makeev_local
3826e90b535Ss.makeev_local /*
383d7cf17b1Ss.makeev_local // dxt compressor Hiload test (for profiling purposes)
384d7cf17b1Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
385d7cf17b1Ss.makeev_local TEST(HiloadDxtTest)
386d7cf17b1Ss.makeev_local {
387d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished1;
388d7cf17b1Ss.makeev_local MT::Atomic32<uint32> isFinished2;
389d7cf17b1Ss.makeev_local
390d7cf17b1Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid");
391d7cf17b1Ss.makeev_local
392d7cf17b1Ss.makeev_local int stride = 384;
393d7cf17b1Ss.makeev_local
394d7cf17b1Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor));
395d7cf17b1Ss.makeev_local
396d7cf17b1Ss.makeev_local CompressDxt compressTask1(128, 128, stride, srcImage, &isFinished1);
397d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask1.width & 3) == 0 && (compressTask1.height & 3) == 0, "Image size must be a multiple of 4");
398d7cf17b1Ss.makeev_local
399d7cf17b1Ss.makeev_local CompressDxt compressTask2(128, 128, stride, srcImage, &isFinished2);
400d7cf17b1Ss.makeev_local MT_ASSERT ((compressTask2.width & 3) == 0 && (compressTask2.height & 3) == 0, "Image size must be a multiple of 4");
401d7cf17b1Ss.makeev_local
4026e90b535Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
403*f7a9bfc3Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, GetProfiler());
4046e90b535Ss.makeev_local #else
405d7cf17b1Ss.makeev_local MT::TaskScheduler scheduler;
4066e90b535Ss.makeev_local #endif
407d7cf17b1Ss.makeev_local
408d7cf17b1Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount();
409d7cf17b1Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount);
410d7cf17b1Ss.makeev_local
411d7cf17b1Ss.makeev_local isFinished1.Store(0);
412d7cf17b1Ss.makeev_local isFinished2.Store(0);
413d7cf17b1Ss.makeev_local
414d7cf17b1Ss.makeev_local printf("HiloadDxtTest\n");
415d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1);
416d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1);
417d7cf17b1Ss.makeev_local
418d7cf17b1Ss.makeev_local for(;;)
419d7cf17b1Ss.makeev_local {
420d7cf17b1Ss.makeev_local if (isFinished1.Load() != 0)
421d7cf17b1Ss.makeev_local {
422d7cf17b1Ss.makeev_local isFinished1.Store(0);
423d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1);
424d7cf17b1Ss.makeev_local }
425d7cf17b1Ss.makeev_local
426d7cf17b1Ss.makeev_local if (isFinished2.Load() != 0)
427d7cf17b1Ss.makeev_local {
428d7cf17b1Ss.makeev_local isFinished2.Store(0);
429d7cf17b1Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1);
430d7cf17b1Ss.makeev_local }
431d7cf17b1Ss.makeev_local
432d7cf17b1Ss.makeev_local MT::Thread::Sleep(1);
433d7cf17b1Ss.makeev_local }
434d7cf17b1Ss.makeev_local }
435c121d748Ss.makeev_local */
43660ac17fbSs.makeev_local
437*f7a9bfc3Ss.makeev_local
4383d930776Ss.makeev_local /*
4393d930776Ss.makeev_local // dxt compressor stress test (for profiling purposes)
4403d930776Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4413d930776Ss.makeev_local TEST(DxtStressTest)
4423d930776Ss.makeev_local {
4433d930776Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid");
4443d930776Ss.makeev_local
4453d930776Ss.makeev_local int stride = 384;
4463d930776Ss.makeev_local
4473d930776Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor));
4483d930776Ss.makeev_local
4493d930776Ss.makeev_local uint32 passCount = 10;
4503d930776Ss.makeev_local
4513d930776Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage, nullptr, passCount);
4523d930776Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4");
4533d930776Ss.makeev_local
4543d930776Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
455*f7a9bfc3Ss.makeev_local MT::TaskScheduler scheduler(0, nullptr, GetProfiler());
4563d930776Ss.makeev_local #else
4573d930776Ss.makeev_local MT::TaskScheduler scheduler;
4583d930776Ss.makeev_local #endif
4593d930776Ss.makeev_local
4603d930776Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount();
4613d930776Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount);
4623d930776Ss.makeev_local
4633d930776Ss.makeev_local printf("DxtStressTest\n");
4643d930776Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1);
4653d930776Ss.makeev_local
4663d930776Ss.makeev_local CHECK(scheduler.WaitAll(10000000));
4673d930776Ss.makeev_local }
4683d930776Ss.makeev_local */
4693d930776Ss.makeev_local
4702f083884Ss.makeev_local // dxt compressor complex test
4712f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4722f083884Ss.makeev_local TEST(RunComplexDxtTest)
4732f083884Ss.makeev_local {
4742f083884Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid");
4752f083884Ss.makeev_local
4762f083884Ss.makeev_local int stride = 384;
4772f083884Ss.makeev_local
4782f083884Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor));
4792f083884Ss.makeev_local
4802f083884Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage);
4812f083884Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4");
4822f083884Ss.makeev_local
4832f083884Ss.makeev_local MT::TaskScheduler scheduler;
4842f083884Ss.makeev_local
4852f083884Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount();
4862f083884Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount);
4872f083884Ss.makeev_local
4882f083884Ss.makeev_local printf("Compress image\n");
4892f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1);
4902f083884Ss.makeev_local
4912f083884Ss.makeev_local Wait(scheduler);
4922f083884Ss.makeev_local
4932f083884Ss.makeev_local DecompressDxt decompressTask(compressTask.dxtBlocks, compressTask.blkWidth, compressTask.blkHeight);
4942f083884Ss.makeev_local compressTask.dxtBlocks = MT::ArrayView<uint8>(); //transfer memory ownership to Decompress task
4952f083884Ss.makeev_local
4962f083884Ss.makeev_local printf("Decompress image\n");
4972f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &decompressTask, 1);
4982f083884Ss.makeev_local
4992f083884Ss.makeev_local Wait(scheduler);
5002f083884Ss.makeev_local
5012f083884Ss.makeev_local /*
5022f083884Ss.makeev_local //save compressed image
5032f083884Ss.makeev_local {
5042f083884Ss.makeev_local FILE * file = fopen("lena_dxt1.dds", "w+b");
5052f083884Ss.makeev_local fwrite(&EmbeddedImage::ddsHeader[0], MT_ARRAY_SIZE(EmbeddedImage::ddsHeader), 1, file);
5062f083884Ss.makeev_local fwrite(decompressTask.dxtBlocks, decompressTask.blkWidth * decompressTask.blkHeight * 8, 1, file);
5072f083884Ss.makeev_local fclose(file);
5082f083884Ss.makeev_local }
5092f083884Ss.makeev_local
5102f083884Ss.makeev_local //save uncompressed image
5112f083884Ss.makeev_local {
5122f083884Ss.makeev_local FILE * file = fopen("lena_rgb.raw", "w+b");
5132f083884Ss.makeev_local fwrite(decompressTask.decompressedImage, decompressTask.blkWidth * decompressTask.blkHeight * 48, 1, file);
5142f083884Ss.makeev_local fclose(file);
5152f083884Ss.makeev_local }
5162f083884Ss.makeev_local */
5172f083884Ss.makeev_local
5182f083884Ss.makeev_local printf("Compare images\n");
5192f083884Ss.makeev_local bool imagesEqual = CompareImagesPSNR(&srcImage[0], &decompressTask.decompressedImage[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor), 8.0);
5202f083884Ss.makeev_local CHECK_EQUAL(true, imagesEqual);
5212f083884Ss.makeev_local
5222f083884Ss.makeev_local /*
5232f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
5242f083884Ss.makeev_local // waiting for profiler attach
5252f083884Ss.makeev_local printf("Press any key to continue\n");
5262f083884Ss.makeev_local while(true)
5272f083884Ss.makeev_local {
5282f083884Ss.makeev_local if (_kbhit() != 0)
5292f083884Ss.makeev_local {
5302f083884Ss.makeev_local break;
5312f083884Ss.makeev_local }
5322f083884Ss.makeev_local }
5332f083884Ss.makeev_local #endif
5342f083884Ss.makeev_local */
5352f083884Ss.makeev_local }
5362f083884Ss.makeev_local
5372f083884Ss.makeev_local
5382f083884Ss.makeev_local }
539