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>
29faa6c6e5Ss.makeev_local #include <math.h>
302f083884Ss.makeev_local 
31*60ac17fbSs.makeev_local 
322f083884Ss.makeev_local /*
332f083884Ss.makeev_local #ifdef _WIN32
342f083884Ss.makeev_local 
352f083884Ss.makeev_local #include <conio.h>
362f083884Ss.makeev_local 
372f083884Ss.makeev_local #else
382f083884Ss.makeev_local 
392f083884Ss.makeev_local #include <stdio.h>
402f083884Ss.makeev_local #include <termios.h>
412f083884Ss.makeev_local #include <unistd.h>
422f083884Ss.makeev_local #include <fcntl.h>
432f083884Ss.makeev_local 
442f083884Ss.makeev_local int _kbhit(void)
452f083884Ss.makeev_local {
462f083884Ss.makeev_local 	struct termios oldt, newt;
472f083884Ss.makeev_local 	int ch;
482f083884Ss.makeev_local 	int oldf;
492f083884Ss.makeev_local 
502f083884Ss.makeev_local 	tcgetattr(STDIN_FILENO, &oldt);
512f083884Ss.makeev_local 	newt = oldt;
522f083884Ss.makeev_local 	newt.c_lflag &= ~(ICANON | ECHO);
532f083884Ss.makeev_local 	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
542f083884Ss.makeev_local 	oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
552f083884Ss.makeev_local 	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
562f083884Ss.makeev_local 
572f083884Ss.makeev_local 	ch = getchar();
582f083884Ss.makeev_local 
592f083884Ss.makeev_local 	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
602f083884Ss.makeev_local 	fcntl(STDIN_FILENO, F_SETFL, oldf);
612f083884Ss.makeev_local 
622f083884Ss.makeev_local 	if(ch != EOF)
632f083884Ss.makeev_local 	{
642f083884Ss.makeev_local 		ungetc(ch, stdin);
652f083884Ss.makeev_local 		return 1;
662f083884Ss.makeev_local 	}
672f083884Ss.makeev_local 
682f083884Ss.makeev_local 	return 0;
692f083884Ss.makeev_local }
702f083884Ss.makeev_local #endif
712f083884Ss.makeev_local */
722f083884Ss.makeev_local 
732f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
742f083884Ss.makeev_local 
752f083884Ss.makeev_local class Microprofile : public MT::IProfilerEventListener
762f083884Ss.makeev_local {
772f083884Ss.makeev_local 	void OnThreadCreated(uint32 workerIndex)
782f083884Ss.makeev_local 	{
792f083884Ss.makeev_local 		MT_UNUSED(workerIndex);
802f083884Ss.makeev_local 	}
812f083884Ss.makeev_local 
822f083884Ss.makeev_local 	void OnThreadStarted(uint32 workerIndex)
832f083884Ss.makeev_local 	{
842f083884Ss.makeev_local 		MT_UNUSED(workerIndex);
852f083884Ss.makeev_local 	}
862f083884Ss.makeev_local 
872f083884Ss.makeev_local 	void OnThreadStoped(uint32 workerIndex)
882f083884Ss.makeev_local 	{
892f083884Ss.makeev_local 		MT_UNUSED(workerIndex);
902f083884Ss.makeev_local 	}
912f083884Ss.makeev_local 
922f083884Ss.makeev_local 	void OnThreadIdleBegin(uint32 workerIndex)
932f083884Ss.makeev_local 	{
942f083884Ss.makeev_local 		MT_UNUSED(workerIndex);
952f083884Ss.makeev_local 	}
962f083884Ss.makeev_local 
972f083884Ss.makeev_local 	void OnThreadIdleEnd(uint32 workerIndex)
982f083884Ss.makeev_local 	{
992f083884Ss.makeev_local 		MT_UNUSED(workerIndex);
1002f083884Ss.makeev_local 	}
1012f083884Ss.makeev_local 
102*60ac17fbSs.makeev_local 	void OnTaskBeginExecute(MT::Color::Type debugColor, const mt_char* debugID)
1032f083884Ss.makeev_local 	{
1042f083884Ss.makeev_local 		MT_UNUSED(debugColor);
1052f083884Ss.makeev_local 		MT_UNUSED(debugID);
1062f083884Ss.makeev_local 	}
1072f083884Ss.makeev_local 
108*60ac17fbSs.makeev_local 	void OnTaskEndExecute(MT::Color::Type debugColor, const mt_char* debugID)
1092f083884Ss.makeev_local 	{
1102f083884Ss.makeev_local 		MT_UNUSED(debugColor);
1112f083884Ss.makeev_local 		MT_UNUSED(debugID);
1122f083884Ss.makeev_local 	}
1132f083884Ss.makeev_local 
1142f083884Ss.makeev_local };
1152f083884Ss.makeev_local 
1162f083884Ss.makeev_local 
1172f083884Ss.makeev_local #endif
1182f083884Ss.makeev_local 
1192f083884Ss.makeev_local 
1202f083884Ss.makeev_local 
1212f083884Ss.makeev_local 
1222f083884Ss.makeev_local 
1232f083884Ss.makeev_local namespace EmbeddedImage
1242f083884Ss.makeev_local {
1252f083884Ss.makeev_local 	#include "LenaDxt/LenaColor.h"
1262f083884Ss.makeev_local 	#include "LenaDxt/HeaderDDS.h"
1272f083884Ss.makeev_local }
1282f083884Ss.makeev_local 
1292f083884Ss.makeev_local 
1302f083884Ss.makeev_local bool CompareImagesPSNR(uint8 * img1, uint8 * img2, uint32 bytesCount, double psnrThreshold)
1312f083884Ss.makeev_local {
1322f083884Ss.makeev_local 	double mse = 0.0;
1332f083884Ss.makeev_local 
1342f083884Ss.makeev_local 	for (uint32 i = 0; i < bytesCount; i++)
1352f083884Ss.makeev_local 	{
1362f083884Ss.makeev_local 		double error = (double)img1[0] - (double)img2[1];
1372f083884Ss.makeev_local 		mse += (error * error);
1382f083884Ss.makeev_local 	}
1392f083884Ss.makeev_local 
1402f083884Ss.makeev_local 	mse = mse / (double)bytesCount;
1412f083884Ss.makeev_local 
1422f083884Ss.makeev_local 	if (mse > 0.0)
1432f083884Ss.makeev_local 	{
1442f083884Ss.makeev_local 		double psnr = 10.0 * log10(255.0*255.0/mse);
1452f083884Ss.makeev_local 		if (psnr < psnrThreshold)
1462f083884Ss.makeev_local 		{
1472f083884Ss.makeev_local 			return false;
1482f083884Ss.makeev_local 		}
1492f083884Ss.makeev_local 	}
1502f083884Ss.makeev_local 
1512f083884Ss.makeev_local 	return true;
1522f083884Ss.makeev_local }
1532f083884Ss.makeev_local 
1542f083884Ss.makeev_local 
1552f083884Ss.makeev_local 
1562f083884Ss.makeev_local SUITE(DxtTests)
1572f083884Ss.makeev_local {
1582f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1592f083884Ss.makeev_local 	struct CompressDxtBlock
1602f083884Ss.makeev_local 	{
1612f083884Ss.makeev_local 		MT_DECLARE_TASK(CompressDxtBlock, MT::StackRequirements::STANDARD, MT::Color::Blue);
1622f083884Ss.makeev_local 
1632f083884Ss.makeev_local 		MT::ArrayView<uint8> srcPixels;
1642f083884Ss.makeev_local 		MT::ArrayView<uint8> dstBlocks;
1652f083884Ss.makeev_local 
1662f083884Ss.makeev_local 		int srcX;
1672f083884Ss.makeev_local 		int srcY;
1682f083884Ss.makeev_local 
1692f083884Ss.makeev_local 		int stride;
1702f083884Ss.makeev_local 		int dstBlockOffset;
1712f083884Ss.makeev_local 
1722f083884Ss.makeev_local 		CompressDxtBlock(int _srcX, int _srcY, int _stride, const MT::ArrayView<uint8> & _srcPixels, const MT::ArrayView<uint8> & _dstBlocks, int _dstBlockOffset)
1732f083884Ss.makeev_local 			: srcPixels(_srcPixels)
1742f083884Ss.makeev_local 			, dstBlocks(_dstBlocks)
1752f083884Ss.makeev_local 		{
1762f083884Ss.makeev_local 				srcX = _srcX;
1772f083884Ss.makeev_local 				srcY = _srcY;
1782f083884Ss.makeev_local 				stride = _stride;
1792f083884Ss.makeev_local 				dstBlockOffset = _dstBlockOffset;
1802f083884Ss.makeev_local 		}
1812f083884Ss.makeev_local 
1822f083884Ss.makeev_local 		CompressDxtBlock(CompressDxtBlock&& other)
1832f083884Ss.makeev_local 			: srcPixels(other.srcPixels)
1842f083884Ss.makeev_local 			, dstBlocks(other.dstBlocks)
1852f083884Ss.makeev_local 			, srcX(other.srcX)
1862f083884Ss.makeev_local 			, srcY(other.srcY)
1872f083884Ss.makeev_local 			, stride(other.stride)
1882f083884Ss.makeev_local 			, dstBlockOffset(other.dstBlockOffset)
1892f083884Ss.makeev_local 		{
1902f083884Ss.makeev_local 			other.srcX = -1;
1912f083884Ss.makeev_local 			other.srcY = -1;
1922f083884Ss.makeev_local 			other.stride = -1;
1932f083884Ss.makeev_local 			other.dstBlockOffset = -1;
1942f083884Ss.makeev_local 		}
1952f083884Ss.makeev_local 
1962f083884Ss.makeev_local 		~CompressDxtBlock()
1972f083884Ss.makeev_local 		{
1982f083884Ss.makeev_local 			srcX = -1;
1992f083884Ss.makeev_local 			srcY = -1;
2002f083884Ss.makeev_local 			stride = -1;
2012f083884Ss.makeev_local 			dstBlockOffset = -1;
2022f083884Ss.makeev_local 		}
2032f083884Ss.makeev_local 
2042f083884Ss.makeev_local 		void Do(MT::FiberContext&)
2052f083884Ss.makeev_local 		{
2062f083884Ss.makeev_local 			// 16 pixels of input
2072f083884Ss.makeev_local 			uint32 pixels[4*4];
2082f083884Ss.makeev_local 
2092f083884Ss.makeev_local 			// copy dxt1 block from image
2102f083884Ss.makeev_local 			for (int y = 0; y < 4; y++)
2112f083884Ss.makeev_local 			{
2122f083884Ss.makeev_local 				for (int x = 0; x < 4; x++)
2132f083884Ss.makeev_local 				{
2142f083884Ss.makeev_local 					int posX = srcX + x;
2152f083884Ss.makeev_local 					int posY = srcY + y;
2162f083884Ss.makeev_local 
2172f083884Ss.makeev_local 					int index = posY * stride + (posX * 3);
2182f083884Ss.makeev_local 
2192f083884Ss.makeev_local 					MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index");
2202f083884Ss.makeev_local 
2212f083884Ss.makeev_local 					uint8 r = srcPixels[index + 0];
2222f083884Ss.makeev_local 					uint8 g = srcPixels[index + 1];
2232f083884Ss.makeev_local 					uint8 b = srcPixels[index + 2];
2242f083884Ss.makeev_local 
2252f083884Ss.makeev_local 					uint32 color = 0xFF000000 | ((b << 16) | (g << 8) | (r));
2262f083884Ss.makeev_local 
2272f083884Ss.makeev_local 					pixels[y * 4 + x] = color;
2282f083884Ss.makeev_local 				}
2292f083884Ss.makeev_local 			}
2302f083884Ss.makeev_local 
2312f083884Ss.makeev_local 			// compress the 4x4 block using DXT1 compression
2322f083884Ss.makeev_local 			squish::Compress( (squish::u8 *)&pixels[0], &dstBlocks[dstBlockOffset], squish::kDxt1 );
2332f083884Ss.makeev_local 		}
2342f083884Ss.makeev_local 	};
2352f083884Ss.makeev_local 
2362f083884Ss.makeev_local 
2372f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2382f083884Ss.makeev_local 	struct CompressDxt
2392f083884Ss.makeev_local 	{
2402f083884Ss.makeev_local 		MT_DECLARE_TASK(CompressDxt, MT::StackRequirements::EXTENDED, MT::Color::Aqua);
2412f083884Ss.makeev_local 
2422f083884Ss.makeev_local 		uint32 width;
2432f083884Ss.makeev_local 		uint32 height;
2442f083884Ss.makeev_local 		uint32 stride;
2452f083884Ss.makeev_local 
2462f083884Ss.makeev_local 		uint32 blkWidth;
2472f083884Ss.makeev_local 		uint32 blkHeight;
2482f083884Ss.makeev_local 
2492f083884Ss.makeev_local 		MT::ArrayView<uint8> srcPixels;
2502f083884Ss.makeev_local 		MT::ArrayView<uint8> dxtBlocks;
251d7cf17b1Ss.makeev_local 		MT::Atomic32<uint32>* pIsFinished;
2522f083884Ss.makeev_local 
253d7cf17b1Ss.makeev_local 
254d7cf17b1Ss.makeev_local 		CompressDxt(uint32 _width, uint32 _height, uint32 _stride, const MT::ArrayView<uint8> & _srcPixels, MT::Atomic32<uint32>* _pIsFinished = nullptr)
2552f083884Ss.makeev_local 			: srcPixels(_srcPixels)
256d7cf17b1Ss.makeev_local 			, pIsFinished(_pIsFinished)
2572f083884Ss.makeev_local 		{
2582f083884Ss.makeev_local 			width = _width;
2592f083884Ss.makeev_local 			height = _height;
2602f083884Ss.makeev_local 			stride = _stride;
2612f083884Ss.makeev_local 
2622f083884Ss.makeev_local 			blkWidth = width >> 2;
2632f083884Ss.makeev_local 			blkHeight = height >> 2;
2642f083884Ss.makeev_local 
2652f083884Ss.makeev_local 			int dxtBlocksTotalSizeInBytes = blkWidth * blkHeight * 8; // 8 bytes = 64 bits per block (dxt1)
266d7cf17b1Ss.makeev_local 			dxtBlocks = MT::ArrayView<uint8>( MT::Memory::Alloc( dxtBlocksTotalSizeInBytes ), dxtBlocksTotalSizeInBytes);
2672f083884Ss.makeev_local 		}
2682f083884Ss.makeev_local 
2692f083884Ss.makeev_local 		~CompressDxt()
2702f083884Ss.makeev_local 		{
2712f083884Ss.makeev_local 			void* pDxtBlocks = dxtBlocks.GetRawData();
2722f083884Ss.makeev_local 			if (pDxtBlocks)
2732f083884Ss.makeev_local 			{
274d7cf17b1Ss.makeev_local 				MT::Memory::Free(pDxtBlocks);
2752f083884Ss.makeev_local 			}
2762f083884Ss.makeev_local 		}
2772f083884Ss.makeev_local 
2782f083884Ss.makeev_local 
2792f083884Ss.makeev_local 		void Do(MT::FiberContext& context)
2802f083884Ss.makeev_local 		{
2812f083884Ss.makeev_local 			// use stack_array as subtask container. beware stack overflow!
2822f083884Ss.makeev_local 			MT::StackArray<CompressDxtBlock, 1024> subTasks;
2832f083884Ss.makeev_local 
2842f083884Ss.makeev_local 			for (uint32 blkY = 0; blkY < blkHeight; blkY++)
2852f083884Ss.makeev_local 			{
2862f083884Ss.makeev_local 				for (uint32 blkX = 0; blkX < blkWidth; blkX++)
2872f083884Ss.makeev_local 				{
2882f083884Ss.makeev_local 					uint32 blockIndex = blkY * blkWidth + blkX;
2892f083884Ss.makeev_local 					subTasks.PushBack( CompressDxtBlock(blkX * 4, blkY * 4, stride, srcPixels, dxtBlocks, blockIndex * 8) );
2902f083884Ss.makeev_local 				}
2912f083884Ss.makeev_local 			}
2922f083884Ss.makeev_local 
2932f083884Ss.makeev_local 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size());
294d7cf17b1Ss.makeev_local 
295d7cf17b1Ss.makeev_local 			if (pIsFinished != nullptr)
296d7cf17b1Ss.makeev_local 			{
297d7cf17b1Ss.makeev_local 				pIsFinished->Store(1);
298d7cf17b1Ss.makeev_local 			}
2992f083884Ss.makeev_local 		}
3002f083884Ss.makeev_local 	};
3012f083884Ss.makeev_local 
3022f083884Ss.makeev_local 
3032f083884Ss.makeev_local 
3042f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3052f083884Ss.makeev_local 	struct DecompressDxtBlock
3062f083884Ss.makeev_local 	{
3072f083884Ss.makeev_local 		MT_DECLARE_TASK(DecompressDxtBlock, MT::StackRequirements::STANDARD, MT::Color::Red);
3082f083884Ss.makeev_local 
3092f083884Ss.makeev_local 		MT::ArrayView<uint8> srcBlocks;
3102f083884Ss.makeev_local 		MT::ArrayView<uint8> dstPixels;
3112f083884Ss.makeev_local 
3122f083884Ss.makeev_local 		int dstX;
3132f083884Ss.makeev_local 		int dstY;
3142f083884Ss.makeev_local 
3152f083884Ss.makeev_local 		int stride;
3162f083884Ss.makeev_local 		int srcBlockOffset;
3172f083884Ss.makeev_local 
3182f083884Ss.makeev_local 		DecompressDxtBlock(int _dstX, int _dstY, int _stride, const MT::ArrayView<uint8> & _dstPixels, const MT::ArrayView<uint8> & _srcBlocks, int _srcBlockOffset)
3192f083884Ss.makeev_local 			: srcBlocks(_srcBlocks)
3202f083884Ss.makeev_local 			, dstPixels(_dstPixels)
3212f083884Ss.makeev_local 		{
3222f083884Ss.makeev_local 			dstX = _dstX;
3232f083884Ss.makeev_local 			dstY = _dstY;
3242f083884Ss.makeev_local 			stride = _stride;
3252f083884Ss.makeev_local 			srcBlockOffset = _srcBlockOffset;
3262f083884Ss.makeev_local 		}
3272f083884Ss.makeev_local 
3282f083884Ss.makeev_local 		DecompressDxtBlock(DecompressDxtBlock&& other)
3292f083884Ss.makeev_local 			: srcBlocks(other.srcBlocks)
3302f083884Ss.makeev_local 			, dstPixels(other.dstPixels)
3312f083884Ss.makeev_local 			, dstX(other.dstX)
3322f083884Ss.makeev_local 			, dstY(other.dstY)
3332f083884Ss.makeev_local 			, stride(other.stride)
3342f083884Ss.makeev_local 			, srcBlockOffset(other.srcBlockOffset)
3352f083884Ss.makeev_local 		{
3362f083884Ss.makeev_local 			other.dstX = -1;
3372f083884Ss.makeev_local 			other.dstY = -1;
3382f083884Ss.makeev_local 			other.stride = -1;
3392f083884Ss.makeev_local 			other.srcBlockOffset = -1;
3402f083884Ss.makeev_local 		}
3412f083884Ss.makeev_local 
3422f083884Ss.makeev_local 		~DecompressDxtBlock()
3432f083884Ss.makeev_local 		{
3442f083884Ss.makeev_local 			dstX = -1;
3452f083884Ss.makeev_local 			dstY = -1;
3462f083884Ss.makeev_local 			stride = -1;
3472f083884Ss.makeev_local 			srcBlockOffset = -1;
3482f083884Ss.makeev_local 		}
3492f083884Ss.makeev_local 
3502f083884Ss.makeev_local 
3512f083884Ss.makeev_local 		void Do(MT::FiberContext&)
3522f083884Ss.makeev_local 		{
3532f083884Ss.makeev_local 			// 16 pixels of output
3542f083884Ss.makeev_local 			uint32 pixels[4*4];
3552f083884Ss.makeev_local 
3562f083884Ss.makeev_local 			// copy dxt1 block from image
3572f083884Ss.makeev_local 			for (int y = 0; y < 4; y++)
3582f083884Ss.makeev_local 			{
3592f083884Ss.makeev_local 				for (int x = 0; x < 4; x++)
3602f083884Ss.makeev_local 				{
3612f083884Ss.makeev_local 					squish::Decompress((squish::u8 *)&pixels[0], &srcBlocks[srcBlockOffset], squish::kDxt1);
3622f083884Ss.makeev_local 
3632f083884Ss.makeev_local 					int posX = dstX + x;
3642f083884Ss.makeev_local 					int posY = dstY + y;
3652f083884Ss.makeev_local 
3662f083884Ss.makeev_local 					int index = posY * stride + (posX * 3);
3672f083884Ss.makeev_local 
3682f083884Ss.makeev_local 					uint32 pixel = pixels[y * 4 + x];
3692f083884Ss.makeev_local 
3702f083884Ss.makeev_local 					MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index");
3712f083884Ss.makeev_local 
3722f083884Ss.makeev_local 					dstPixels[index + 0] = (pixel & 0xFF);
3732f083884Ss.makeev_local 					dstPixels[index + 1] = (pixel >> 8 & 0xFF);
3742f083884Ss.makeev_local 					dstPixels[index + 2] = (pixel >> 16 & 0xFF);
3752f083884Ss.makeev_local 				}
3762f083884Ss.makeev_local 			}
3772f083884Ss.makeev_local 
3782f083884Ss.makeev_local 		}
3792f083884Ss.makeev_local 	};
3802f083884Ss.makeev_local 
3812f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3822f083884Ss.makeev_local 	struct DecompressDxt
3832f083884Ss.makeev_local 	{
3842f083884Ss.makeev_local 		MT_DECLARE_TASK(DecompressDxt, MT::StackRequirements::EXTENDED, MT::Color::Yellow);
3852f083884Ss.makeev_local 
3862f083884Ss.makeev_local 		MT::ArrayView<uint8> dxtBlocks;
3872f083884Ss.makeev_local 		MT::ArrayView<uint8> decompressedImage;
3882f083884Ss.makeev_local 
3892f083884Ss.makeev_local 		uint32 blkWidth;
3902f083884Ss.makeev_local 		uint32 blkHeight;
3912f083884Ss.makeev_local 
3922f083884Ss.makeev_local 
3932f083884Ss.makeev_local 		DecompressDxt(const MT::ArrayView<uint8> & _dxtBlocks, uint32 dxtBlocksCountWidth, uint32 dxtBlocksCountHeight)
3942f083884Ss.makeev_local 			: dxtBlocks(_dxtBlocks)
3952f083884Ss.makeev_local 		{
3962f083884Ss.makeev_local 			blkWidth = dxtBlocksCountWidth;
3972f083884Ss.makeev_local 			blkHeight = dxtBlocksCountHeight;
3982f083884Ss.makeev_local 
3992f083884Ss.makeev_local 			// dxt1 block = 16 rgb pixels = 48 bytes
4002f083884Ss.makeev_local 			uint32 bytesCount = blkWidth * blkHeight * 48;
401d7cf17b1Ss.makeev_local 			decompressedImage = MT::ArrayView<uint8>( MT::Memory::Alloc(bytesCount), bytesCount);
4022f083884Ss.makeev_local 		}
4032f083884Ss.makeev_local 
4042f083884Ss.makeev_local 		~DecompressDxt()
4052f083884Ss.makeev_local 		{
4062f083884Ss.makeev_local 			void* pDxtBlocks = dxtBlocks.GetRawData();
4072f083884Ss.makeev_local 			if (pDxtBlocks)
4082f083884Ss.makeev_local 			{
409d7cf17b1Ss.makeev_local 				MT::Memory::Free(pDxtBlocks);
4102f083884Ss.makeev_local 			}
4112f083884Ss.makeev_local 
4122f083884Ss.makeev_local 			void* pDecompressedImage = decompressedImage.GetRawData();
4132f083884Ss.makeev_local 			if (pDecompressedImage)
4142f083884Ss.makeev_local 			{
415d7cf17b1Ss.makeev_local 				MT::Memory::Free(pDecompressedImage);
4162f083884Ss.makeev_local 			}
4172f083884Ss.makeev_local 
4182f083884Ss.makeev_local 		}
4192f083884Ss.makeev_local 
4202f083884Ss.makeev_local 		void Do(MT::FiberContext& context)
4212f083884Ss.makeev_local 		{
4222f083884Ss.makeev_local 			// use stack_array as subtask container. beware stack overflow!
4232f083884Ss.makeev_local 			MT::StackArray<DecompressDxtBlock, 1024> subTasks;
4242f083884Ss.makeev_local 
4252f083884Ss.makeev_local 			int stride = blkWidth * 4 * 3;
4262f083884Ss.makeev_local 
4272f083884Ss.makeev_local 			for (uint32 blkY = 0; blkY < blkHeight; blkY++)
4282f083884Ss.makeev_local 			{
4292f083884Ss.makeev_local 				for (uint32 blkX = 0; blkX < blkWidth; blkX++)
4302f083884Ss.makeev_local 				{
4312f083884Ss.makeev_local 					uint32 blockIndex = blkY * blkWidth + blkX;
4322f083884Ss.makeev_local 					subTasks.PushBack( DecompressDxtBlock(blkX * 4, blkY * 4, stride, decompressedImage, dxtBlocks, blockIndex * 8) );
4332f083884Ss.makeev_local 				}
4342f083884Ss.makeev_local 			}
4352f083884Ss.makeev_local 
4362f083884Ss.makeev_local 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size());
4372f083884Ss.makeev_local 		}
4382f083884Ss.makeev_local 
4392f083884Ss.makeev_local 	};
4402f083884Ss.makeev_local 
4412f083884Ss.makeev_local 
4422f083884Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4432f083884Ss.makeev_local 	void Wait(MT::TaskScheduler & scheduler)
4442f083884Ss.makeev_local 	{
4452f083884Ss.makeev_local 		//emulate game loop
4462f083884Ss.makeev_local 		for(;;)
4472f083884Ss.makeev_local 		{
4482f083884Ss.makeev_local 			bool waitDone = scheduler.WaitAll(33);
4492f083884Ss.makeev_local 			if (waitDone)
4502f083884Ss.makeev_local 			{
4512f083884Ss.makeev_local 				break;
4522f083884Ss.makeev_local 			}
4532f083884Ss.makeev_local 		}
4542f083884Ss.makeev_local 	}
4552f083884Ss.makeev_local 
4562f083884Ss.makeev_local 
457*60ac17fbSs.makeev_local 
458d7cf17b1Ss.makeev_local 	// dxt compressor Hiload test (for profiling purposes)
459d7cf17b1Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
460d7cf17b1Ss.makeev_local 	TEST(HiloadDxtTest)
461d7cf17b1Ss.makeev_local 	{
462d7cf17b1Ss.makeev_local 		MT::Atomic32<uint32> isFinished1;
463d7cf17b1Ss.makeev_local 		MT::Atomic32<uint32> isFinished2;
464d7cf17b1Ss.makeev_local 
465d7cf17b1Ss.makeev_local 		static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid");
466d7cf17b1Ss.makeev_local 
467d7cf17b1Ss.makeev_local 		int stride = 384;
468d7cf17b1Ss.makeev_local 
469d7cf17b1Ss.makeev_local 		MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor));
470d7cf17b1Ss.makeev_local 
471d7cf17b1Ss.makeev_local 		CompressDxt compressTask1(128, 128, stride, srcImage, &isFinished1);
472d7cf17b1Ss.makeev_local 		MT_ASSERT ((compressTask1.width & 3) == 0 && (compressTask1.height & 3) == 0, "Image size must be a multiple of 4");
473d7cf17b1Ss.makeev_local 
474d7cf17b1Ss.makeev_local 		CompressDxt compressTask2(128, 128, stride, srcImage, &isFinished2);
475d7cf17b1Ss.makeev_local 		MT_ASSERT ((compressTask2.width & 3) == 0 && (compressTask2.height & 3) == 0, "Image size must be a multiple of 4");
476d7cf17b1Ss.makeev_local 
477d7cf17b1Ss.makeev_local 		MT::TaskScheduler scheduler;
478d7cf17b1Ss.makeev_local 
479d7cf17b1Ss.makeev_local 		int workersCount = (int)scheduler.GetWorkersCount();
480d7cf17b1Ss.makeev_local 		printf("Scheduler started, %d workers\n", workersCount);
481d7cf17b1Ss.makeev_local 
482d7cf17b1Ss.makeev_local 		isFinished1.Store(0);
483d7cf17b1Ss.makeev_local 		isFinished2.Store(0);
484d7cf17b1Ss.makeev_local 
485d7cf17b1Ss.makeev_local 		printf("HiloadDxtTest\n");
486d7cf17b1Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1);
487d7cf17b1Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1);
488d7cf17b1Ss.makeev_local 
489d7cf17b1Ss.makeev_local 		for(;;)
490d7cf17b1Ss.makeev_local 		{
491d7cf17b1Ss.makeev_local 			if (isFinished1.Load() != 0)
492d7cf17b1Ss.makeev_local 			{
493d7cf17b1Ss.makeev_local 				isFinished1.Store(0);
494d7cf17b1Ss.makeev_local 				scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask1, 1);
495d7cf17b1Ss.makeev_local 			}
496d7cf17b1Ss.makeev_local 
497d7cf17b1Ss.makeev_local 			if (isFinished2.Load() != 0)
498d7cf17b1Ss.makeev_local 			{
499d7cf17b1Ss.makeev_local 				isFinished2.Store(0);
500d7cf17b1Ss.makeev_local 				scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask2, 1);
501d7cf17b1Ss.makeev_local 			}
502d7cf17b1Ss.makeev_local 
503d7cf17b1Ss.makeev_local 			MT::Thread::Sleep(1);
504d7cf17b1Ss.makeev_local 		}
505d7cf17b1Ss.makeev_local 	}
506*60ac17fbSs.makeev_local 
507d7cf17b1Ss.makeev_local 
5082f083884Ss.makeev_local 	// dxt compressor complex test
5092f083884Ss.makeev_local 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5102f083884Ss.makeev_local 	TEST(RunComplexDxtTest)
5112f083884Ss.makeev_local 	{
5122f083884Ss.makeev_local 		static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid");
5132f083884Ss.makeev_local 
5142f083884Ss.makeev_local 		int stride = 384;
5152f083884Ss.makeev_local 
5162f083884Ss.makeev_local 		MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor));
5172f083884Ss.makeev_local 
5182f083884Ss.makeev_local 		CompressDxt compressTask(128, 128, stride, srcImage);
5192f083884Ss.makeev_local 		MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4");
5202f083884Ss.makeev_local 
5212f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
5222f083884Ss.makeev_local 		Microprofile profiler;
523d7cf17b1Ss.makeev_local 		MT::TaskScheduler scheduler(0, nullptr, &profiler);
5242f083884Ss.makeev_local #else
5252f083884Ss.makeev_local 		MT::TaskScheduler scheduler;
5262f083884Ss.makeev_local #endif
5272f083884Ss.makeev_local 
5282f083884Ss.makeev_local 		int workersCount = (int)scheduler.GetWorkersCount();
5292f083884Ss.makeev_local 		printf("Scheduler started, %d workers\n", workersCount);
5302f083884Ss.makeev_local 
5312f083884Ss.makeev_local 		printf("Compress image\n");
5322f083884Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1);
5332f083884Ss.makeev_local 
5342f083884Ss.makeev_local 		Wait(scheduler);
5352f083884Ss.makeev_local 
5362f083884Ss.makeev_local 		DecompressDxt decompressTask(compressTask.dxtBlocks, compressTask.blkWidth, compressTask.blkHeight);
5372f083884Ss.makeev_local 		compressTask.dxtBlocks = MT::ArrayView<uint8>(); //transfer memory ownership to Decompress task
5382f083884Ss.makeev_local 
5392f083884Ss.makeev_local 		printf("Decompress image\n");
5402f083884Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &decompressTask, 1);
5412f083884Ss.makeev_local 
5422f083884Ss.makeev_local 		Wait(scheduler);
5432f083884Ss.makeev_local 
5442f083884Ss.makeev_local /*
5452f083884Ss.makeev_local 		//save compressed image
5462f083884Ss.makeev_local 		{
5472f083884Ss.makeev_local 			FILE * file = fopen("lena_dxt1.dds", "w+b");
5482f083884Ss.makeev_local 			fwrite(&EmbeddedImage::ddsHeader[0], MT_ARRAY_SIZE(EmbeddedImage::ddsHeader), 1, file);
5492f083884Ss.makeev_local 			fwrite(decompressTask.dxtBlocks, decompressTask.blkWidth * decompressTask.blkHeight * 8, 1, file);
5502f083884Ss.makeev_local 			fclose(file);
5512f083884Ss.makeev_local 		}
5522f083884Ss.makeev_local 
5532f083884Ss.makeev_local 		//save uncompressed image
5542f083884Ss.makeev_local 		{
5552f083884Ss.makeev_local 			FILE * file = fopen("lena_rgb.raw", "w+b");
5562f083884Ss.makeev_local 			fwrite(decompressTask.decompressedImage, decompressTask.blkWidth * decompressTask.blkHeight * 48, 1, file);
5572f083884Ss.makeev_local 			fclose(file);
5582f083884Ss.makeev_local 		}
5592f083884Ss.makeev_local */
5602f083884Ss.makeev_local 
5612f083884Ss.makeev_local 		printf("Compare images\n");
5622f083884Ss.makeev_local 		bool imagesEqual = CompareImagesPSNR(&srcImage[0], &decompressTask.decompressedImage[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor), 8.0);
5632f083884Ss.makeev_local 		CHECK_EQUAL(true, imagesEqual);
5642f083884Ss.makeev_local 
5652f083884Ss.makeev_local /*
5662f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
5672f083884Ss.makeev_local 		// waiting for profiler attach
5682f083884Ss.makeev_local 		printf("Press any key to continue\n");
5692f083884Ss.makeev_local 		while(true)
5702f083884Ss.makeev_local 		{
5712f083884Ss.makeev_local 			if (_kbhit() != 0)
5722f083884Ss.makeev_local 			{
5732f083884Ss.makeev_local 				break;
5742f083884Ss.makeev_local 			}
5752f083884Ss.makeev_local 		}
5762f083884Ss.makeev_local #endif
5772f083884Ss.makeev_local */
5782f083884Ss.makeev_local 	}
5792f083884Ss.makeev_local 
5802f083884Ss.makeev_local 
5812f083884Ss.makeev_local }
582