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