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