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