1*2f083884Ss.makeev_local // The MIT License (MIT) 2*2f083884Ss.makeev_local // 3*2f083884Ss.makeev_local // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4*2f083884Ss.makeev_local // 5*2f083884Ss.makeev_local // Permission is hereby granted, free of charge, to any person obtaining a copy 6*2f083884Ss.makeev_local // of this software and associated documentation files (the "Software"), to deal 7*2f083884Ss.makeev_local // in the Software without restriction, including without limitation the rights 8*2f083884Ss.makeev_local // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9*2f083884Ss.makeev_local // copies of the Software, and to permit persons to whom the Software is 10*2f083884Ss.makeev_local // furnished to do so, subject to the following conditions: 11*2f083884Ss.makeev_local // 12*2f083884Ss.makeev_local // The above copyright notice and this permission notice shall be included in 13*2f083884Ss.makeev_local // all copies or substantial portions of the Software. 14*2f083884Ss.makeev_local // 15*2f083884Ss.makeev_local // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*2f083884Ss.makeev_local // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*2f083884Ss.makeev_local // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18*2f083884Ss.makeev_local // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*2f083884Ss.makeev_local // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20*2f083884Ss.makeev_local // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21*2f083884Ss.makeev_local // THE SOFTWARE. 22*2f083884Ss.makeev_local 23*2f083884Ss.makeev_local #include "Tests.h" 24*2f083884Ss.makeev_local #include <UnitTest++.h> 25*2f083884Ss.makeev_local #include <MTScheduler.h> 26*2f083884Ss.makeev_local 27*2f083884Ss.makeev_local #include <squish.h> 28*2f083884Ss.makeev_local #include <string.h> 29*2f083884Ss.makeev_local 30*2f083884Ss.makeev_local /* 31*2f083884Ss.makeev_local #ifdef _WIN32 32*2f083884Ss.makeev_local 33*2f083884Ss.makeev_local #include <conio.h> 34*2f083884Ss.makeev_local 35*2f083884Ss.makeev_local #else 36*2f083884Ss.makeev_local 37*2f083884Ss.makeev_local #include <math.h> 38*2f083884Ss.makeev_local #include <stdio.h> 39*2f083884Ss.makeev_local #include <termios.h> 40*2f083884Ss.makeev_local #include <unistd.h> 41*2f083884Ss.makeev_local #include <fcntl.h> 42*2f083884Ss.makeev_local 43*2f083884Ss.makeev_local int _kbhit(void) 44*2f083884Ss.makeev_local { 45*2f083884Ss.makeev_local struct termios oldt, newt; 46*2f083884Ss.makeev_local int ch; 47*2f083884Ss.makeev_local int oldf; 48*2f083884Ss.makeev_local 49*2f083884Ss.makeev_local tcgetattr(STDIN_FILENO, &oldt); 50*2f083884Ss.makeev_local newt = oldt; 51*2f083884Ss.makeev_local newt.c_lflag &= ~(ICANON | ECHO); 52*2f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &newt); 53*2f083884Ss.makeev_local oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 54*2f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 55*2f083884Ss.makeev_local 56*2f083884Ss.makeev_local ch = getchar(); 57*2f083884Ss.makeev_local 58*2f083884Ss.makeev_local tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 59*2f083884Ss.makeev_local fcntl(STDIN_FILENO, F_SETFL, oldf); 60*2f083884Ss.makeev_local 61*2f083884Ss.makeev_local if(ch != EOF) 62*2f083884Ss.makeev_local { 63*2f083884Ss.makeev_local ungetc(ch, stdin); 64*2f083884Ss.makeev_local return 1; 65*2f083884Ss.makeev_local } 66*2f083884Ss.makeev_local 67*2f083884Ss.makeev_local return 0; 68*2f083884Ss.makeev_local } 69*2f083884Ss.makeev_local #endif 70*2f083884Ss.makeev_local */ 71*2f083884Ss.makeev_local 72*2f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 73*2f083884Ss.makeev_local 74*2f083884Ss.makeev_local class Microprofile : public MT::IProfilerEventListener 75*2f083884Ss.makeev_local { 76*2f083884Ss.makeev_local void OnThreadCreated(uint32 workerIndex) 77*2f083884Ss.makeev_local { 78*2f083884Ss.makeev_local MT_UNUSED(workerIndex); 79*2f083884Ss.makeev_local } 80*2f083884Ss.makeev_local 81*2f083884Ss.makeev_local void OnThreadStarted(uint32 workerIndex) 82*2f083884Ss.makeev_local { 83*2f083884Ss.makeev_local MT_UNUSED(workerIndex); 84*2f083884Ss.makeev_local } 85*2f083884Ss.makeev_local 86*2f083884Ss.makeev_local void OnThreadStoped(uint32 workerIndex) 87*2f083884Ss.makeev_local { 88*2f083884Ss.makeev_local MT_UNUSED(workerIndex); 89*2f083884Ss.makeev_local } 90*2f083884Ss.makeev_local 91*2f083884Ss.makeev_local void OnThreadIdleBegin(uint32 workerIndex) 92*2f083884Ss.makeev_local { 93*2f083884Ss.makeev_local MT_UNUSED(workerIndex); 94*2f083884Ss.makeev_local } 95*2f083884Ss.makeev_local 96*2f083884Ss.makeev_local void OnThreadIdleEnd(uint32 workerIndex) 97*2f083884Ss.makeev_local { 98*2f083884Ss.makeev_local MT_UNUSED(workerIndex); 99*2f083884Ss.makeev_local } 100*2f083884Ss.makeev_local 101*2f083884Ss.makeev_local void OnTaskFinished(MT::Color::Type debugColor, const mt_char* debugID) 102*2f083884Ss.makeev_local { 103*2f083884Ss.makeev_local MT_UNUSED(debugColor); 104*2f083884Ss.makeev_local MT_UNUSED(debugID); 105*2f083884Ss.makeev_local } 106*2f083884Ss.makeev_local 107*2f083884Ss.makeev_local void OnTaskResumed(MT::Color::Type debugColor, const mt_char* debugID) 108*2f083884Ss.makeev_local { 109*2f083884Ss.makeev_local MT_UNUSED(debugColor); 110*2f083884Ss.makeev_local MT_UNUSED(debugID); 111*2f083884Ss.makeev_local } 112*2f083884Ss.makeev_local 113*2f083884Ss.makeev_local void OnTaskYielded(MT::Color::Type debugColor, const mt_char* debugID) 114*2f083884Ss.makeev_local { 115*2f083884Ss.makeev_local MT_UNUSED(debugColor); 116*2f083884Ss.makeev_local MT_UNUSED(debugID); 117*2f083884Ss.makeev_local } 118*2f083884Ss.makeev_local 119*2f083884Ss.makeev_local }; 120*2f083884Ss.makeev_local 121*2f083884Ss.makeev_local 122*2f083884Ss.makeev_local #endif 123*2f083884Ss.makeev_local 124*2f083884Ss.makeev_local 125*2f083884Ss.makeev_local 126*2f083884Ss.makeev_local 127*2f083884Ss.makeev_local 128*2f083884Ss.makeev_local namespace EmbeddedImage 129*2f083884Ss.makeev_local { 130*2f083884Ss.makeev_local #include "LenaDxt/LenaColor.h" 131*2f083884Ss.makeev_local #include "LenaDxt/HeaderDDS.h" 132*2f083884Ss.makeev_local } 133*2f083884Ss.makeev_local 134*2f083884Ss.makeev_local 135*2f083884Ss.makeev_local bool CompareImagesPSNR(uint8 * img1, uint8 * img2, uint32 bytesCount, double psnrThreshold) 136*2f083884Ss.makeev_local { 137*2f083884Ss.makeev_local double mse = 0.0; 138*2f083884Ss.makeev_local 139*2f083884Ss.makeev_local for (uint32 i = 0; i < bytesCount; i++) 140*2f083884Ss.makeev_local { 141*2f083884Ss.makeev_local double error = (double)img1[0] - (double)img2[1]; 142*2f083884Ss.makeev_local mse += (error * error); 143*2f083884Ss.makeev_local } 144*2f083884Ss.makeev_local 145*2f083884Ss.makeev_local mse = mse / (double)bytesCount; 146*2f083884Ss.makeev_local 147*2f083884Ss.makeev_local if (mse > 0.0) 148*2f083884Ss.makeev_local { 149*2f083884Ss.makeev_local double psnr = 10.0 * log10(255.0*255.0/mse); 150*2f083884Ss.makeev_local if (psnr < psnrThreshold) 151*2f083884Ss.makeev_local { 152*2f083884Ss.makeev_local return false; 153*2f083884Ss.makeev_local } 154*2f083884Ss.makeev_local } 155*2f083884Ss.makeev_local 156*2f083884Ss.makeev_local return true; 157*2f083884Ss.makeev_local } 158*2f083884Ss.makeev_local 159*2f083884Ss.makeev_local 160*2f083884Ss.makeev_local 161*2f083884Ss.makeev_local SUITE(DxtTests) 162*2f083884Ss.makeev_local { 163*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 164*2f083884Ss.makeev_local struct CompressDxtBlock 165*2f083884Ss.makeev_local { 166*2f083884Ss.makeev_local MT_DECLARE_TASK(CompressDxtBlock, MT::StackRequirements::STANDARD, MT::Color::Blue); 167*2f083884Ss.makeev_local 168*2f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 169*2f083884Ss.makeev_local MT::ArrayView<uint8> dstBlocks; 170*2f083884Ss.makeev_local 171*2f083884Ss.makeev_local int srcX; 172*2f083884Ss.makeev_local int srcY; 173*2f083884Ss.makeev_local 174*2f083884Ss.makeev_local int stride; 175*2f083884Ss.makeev_local int dstBlockOffset; 176*2f083884Ss.makeev_local 177*2f083884Ss.makeev_local CompressDxtBlock(int _srcX, int _srcY, int _stride, const MT::ArrayView<uint8> & _srcPixels, const MT::ArrayView<uint8> & _dstBlocks, int _dstBlockOffset) 178*2f083884Ss.makeev_local : srcPixels(_srcPixels) 179*2f083884Ss.makeev_local , dstBlocks(_dstBlocks) 180*2f083884Ss.makeev_local { 181*2f083884Ss.makeev_local srcX = _srcX; 182*2f083884Ss.makeev_local srcY = _srcY; 183*2f083884Ss.makeev_local stride = _stride; 184*2f083884Ss.makeev_local dstBlockOffset = _dstBlockOffset; 185*2f083884Ss.makeev_local } 186*2f083884Ss.makeev_local 187*2f083884Ss.makeev_local CompressDxtBlock(CompressDxtBlock&& other) 188*2f083884Ss.makeev_local : srcPixels(other.srcPixels) 189*2f083884Ss.makeev_local , dstBlocks(other.dstBlocks) 190*2f083884Ss.makeev_local , srcX(other.srcX) 191*2f083884Ss.makeev_local , srcY(other.srcY) 192*2f083884Ss.makeev_local , stride(other.stride) 193*2f083884Ss.makeev_local , dstBlockOffset(other.dstBlockOffset) 194*2f083884Ss.makeev_local { 195*2f083884Ss.makeev_local other.srcX = -1; 196*2f083884Ss.makeev_local other.srcY = -1; 197*2f083884Ss.makeev_local other.stride = -1; 198*2f083884Ss.makeev_local other.dstBlockOffset = -1; 199*2f083884Ss.makeev_local } 200*2f083884Ss.makeev_local 201*2f083884Ss.makeev_local ~CompressDxtBlock() 202*2f083884Ss.makeev_local { 203*2f083884Ss.makeev_local srcX = -1; 204*2f083884Ss.makeev_local srcY = -1; 205*2f083884Ss.makeev_local stride = -1; 206*2f083884Ss.makeev_local dstBlockOffset = -1; 207*2f083884Ss.makeev_local } 208*2f083884Ss.makeev_local 209*2f083884Ss.makeev_local void Do(MT::FiberContext&) 210*2f083884Ss.makeev_local { 211*2f083884Ss.makeev_local // 16 pixels of input 212*2f083884Ss.makeev_local uint32 pixels[4*4]; 213*2f083884Ss.makeev_local 214*2f083884Ss.makeev_local // copy dxt1 block from image 215*2f083884Ss.makeev_local for (int y = 0; y < 4; y++) 216*2f083884Ss.makeev_local { 217*2f083884Ss.makeev_local for (int x = 0; x < 4; x++) 218*2f083884Ss.makeev_local { 219*2f083884Ss.makeev_local int posX = srcX + x; 220*2f083884Ss.makeev_local int posY = srcY + y; 221*2f083884Ss.makeev_local 222*2f083884Ss.makeev_local int index = posY * stride + (posX * 3); 223*2f083884Ss.makeev_local 224*2f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 225*2f083884Ss.makeev_local 226*2f083884Ss.makeev_local uint8 r = srcPixels[index + 0]; 227*2f083884Ss.makeev_local uint8 g = srcPixels[index + 1]; 228*2f083884Ss.makeev_local uint8 b = srcPixels[index + 2]; 229*2f083884Ss.makeev_local 230*2f083884Ss.makeev_local uint32 color = 0xFF000000 | ((b << 16) | (g << 8) | (r)); 231*2f083884Ss.makeev_local 232*2f083884Ss.makeev_local pixels[y * 4 + x] = color; 233*2f083884Ss.makeev_local } 234*2f083884Ss.makeev_local } 235*2f083884Ss.makeev_local 236*2f083884Ss.makeev_local // compress the 4x4 block using DXT1 compression 237*2f083884Ss.makeev_local squish::Compress( (squish::u8 *)&pixels[0], &dstBlocks[dstBlockOffset], squish::kDxt1 ); 238*2f083884Ss.makeev_local } 239*2f083884Ss.makeev_local }; 240*2f083884Ss.makeev_local 241*2f083884Ss.makeev_local 242*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 243*2f083884Ss.makeev_local struct CompressDxt 244*2f083884Ss.makeev_local { 245*2f083884Ss.makeev_local MT_DECLARE_TASK(CompressDxt, MT::StackRequirements::EXTENDED, MT::Color::Aqua); 246*2f083884Ss.makeev_local 247*2f083884Ss.makeev_local uint32 width; 248*2f083884Ss.makeev_local uint32 height; 249*2f083884Ss.makeev_local uint32 stride; 250*2f083884Ss.makeev_local 251*2f083884Ss.makeev_local uint32 blkWidth; 252*2f083884Ss.makeev_local uint32 blkHeight; 253*2f083884Ss.makeev_local 254*2f083884Ss.makeev_local MT::ArrayView<uint8> srcPixels; 255*2f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 256*2f083884Ss.makeev_local 257*2f083884Ss.makeev_local CompressDxt(uint32 _width, uint32 _height, uint32 _stride, const MT::ArrayView<uint8> & _srcPixels ) 258*2f083884Ss.makeev_local : srcPixels(_srcPixels) 259*2f083884Ss.makeev_local { 260*2f083884Ss.makeev_local width = _width; 261*2f083884Ss.makeev_local height = _height; 262*2f083884Ss.makeev_local stride = _stride; 263*2f083884Ss.makeev_local 264*2f083884Ss.makeev_local blkWidth = width >> 2; 265*2f083884Ss.makeev_local blkHeight = height >> 2; 266*2f083884Ss.makeev_local 267*2f083884Ss.makeev_local int dxtBlocksTotalSizeInBytes = blkWidth * blkHeight * 8; // 8 bytes = 64 bits per block (dxt1) 268*2f083884Ss.makeev_local dxtBlocks = MT::ArrayView<uint8>( malloc( dxtBlocksTotalSizeInBytes ), dxtBlocksTotalSizeInBytes); 269*2f083884Ss.makeev_local } 270*2f083884Ss.makeev_local 271*2f083884Ss.makeev_local ~CompressDxt() 272*2f083884Ss.makeev_local { 273*2f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 274*2f083884Ss.makeev_local if (pDxtBlocks) 275*2f083884Ss.makeev_local { 276*2f083884Ss.makeev_local free(pDxtBlocks); 277*2f083884Ss.makeev_local } 278*2f083884Ss.makeev_local } 279*2f083884Ss.makeev_local 280*2f083884Ss.makeev_local 281*2f083884Ss.makeev_local void Do(MT::FiberContext& context) 282*2f083884Ss.makeev_local { 283*2f083884Ss.makeev_local // use stack_array as subtask container. beware stack overflow! 284*2f083884Ss.makeev_local MT::StackArray<CompressDxtBlock, 1024> subTasks; 285*2f083884Ss.makeev_local 286*2f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 287*2f083884Ss.makeev_local { 288*2f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 289*2f083884Ss.makeev_local { 290*2f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 291*2f083884Ss.makeev_local subTasks.PushBack( CompressDxtBlock(blkX * 4, blkY * 4, stride, srcPixels, dxtBlocks, blockIndex * 8) ); 292*2f083884Ss.makeev_local } 293*2f083884Ss.makeev_local } 294*2f083884Ss.makeev_local 295*2f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 296*2f083884Ss.makeev_local } 297*2f083884Ss.makeev_local }; 298*2f083884Ss.makeev_local 299*2f083884Ss.makeev_local 300*2f083884Ss.makeev_local 301*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 302*2f083884Ss.makeev_local struct DecompressDxtBlock 303*2f083884Ss.makeev_local { 304*2f083884Ss.makeev_local MT_DECLARE_TASK(DecompressDxtBlock, MT::StackRequirements::STANDARD, MT::Color::Red); 305*2f083884Ss.makeev_local 306*2f083884Ss.makeev_local MT::ArrayView<uint8> srcBlocks; 307*2f083884Ss.makeev_local MT::ArrayView<uint8> dstPixels; 308*2f083884Ss.makeev_local 309*2f083884Ss.makeev_local int dstX; 310*2f083884Ss.makeev_local int dstY; 311*2f083884Ss.makeev_local 312*2f083884Ss.makeev_local int stride; 313*2f083884Ss.makeev_local int srcBlockOffset; 314*2f083884Ss.makeev_local 315*2f083884Ss.makeev_local DecompressDxtBlock(int _dstX, int _dstY, int _stride, const MT::ArrayView<uint8> & _dstPixels, const MT::ArrayView<uint8> & _srcBlocks, int _srcBlockOffset) 316*2f083884Ss.makeev_local : srcBlocks(_srcBlocks) 317*2f083884Ss.makeev_local , dstPixels(_dstPixels) 318*2f083884Ss.makeev_local { 319*2f083884Ss.makeev_local dstX = _dstX; 320*2f083884Ss.makeev_local dstY = _dstY; 321*2f083884Ss.makeev_local stride = _stride; 322*2f083884Ss.makeev_local srcBlockOffset = _srcBlockOffset; 323*2f083884Ss.makeev_local } 324*2f083884Ss.makeev_local 325*2f083884Ss.makeev_local DecompressDxtBlock(DecompressDxtBlock&& other) 326*2f083884Ss.makeev_local : srcBlocks(other.srcBlocks) 327*2f083884Ss.makeev_local , dstPixels(other.dstPixels) 328*2f083884Ss.makeev_local , dstX(other.dstX) 329*2f083884Ss.makeev_local , dstY(other.dstY) 330*2f083884Ss.makeev_local , stride(other.stride) 331*2f083884Ss.makeev_local , srcBlockOffset(other.srcBlockOffset) 332*2f083884Ss.makeev_local { 333*2f083884Ss.makeev_local other.dstX = -1; 334*2f083884Ss.makeev_local other.dstY = -1; 335*2f083884Ss.makeev_local other.stride = -1; 336*2f083884Ss.makeev_local other.srcBlockOffset = -1; 337*2f083884Ss.makeev_local } 338*2f083884Ss.makeev_local 339*2f083884Ss.makeev_local ~DecompressDxtBlock() 340*2f083884Ss.makeev_local { 341*2f083884Ss.makeev_local dstX = -1; 342*2f083884Ss.makeev_local dstY = -1; 343*2f083884Ss.makeev_local stride = -1; 344*2f083884Ss.makeev_local srcBlockOffset = -1; 345*2f083884Ss.makeev_local } 346*2f083884Ss.makeev_local 347*2f083884Ss.makeev_local 348*2f083884Ss.makeev_local void Do(MT::FiberContext&) 349*2f083884Ss.makeev_local { 350*2f083884Ss.makeev_local // 16 pixels of output 351*2f083884Ss.makeev_local uint32 pixels[4*4]; 352*2f083884Ss.makeev_local 353*2f083884Ss.makeev_local // copy dxt1 block from image 354*2f083884Ss.makeev_local for (int y = 0; y < 4; y++) 355*2f083884Ss.makeev_local { 356*2f083884Ss.makeev_local for (int x = 0; x < 4; x++) 357*2f083884Ss.makeev_local { 358*2f083884Ss.makeev_local squish::Decompress((squish::u8 *)&pixels[0], &srcBlocks[srcBlockOffset], squish::kDxt1); 359*2f083884Ss.makeev_local 360*2f083884Ss.makeev_local int posX = dstX + x; 361*2f083884Ss.makeev_local int posY = dstY + y; 362*2f083884Ss.makeev_local 363*2f083884Ss.makeev_local int index = posY * stride + (posX * 3); 364*2f083884Ss.makeev_local 365*2f083884Ss.makeev_local uint32 pixel = pixels[y * 4 + x]; 366*2f083884Ss.makeev_local 367*2f083884Ss.makeev_local MT_ASSERT(index >= 0 && ((size_t)(index + 2) < MT_ARRAY_SIZE(EmbeddedImage::lenaColor)), "Invalid index"); 368*2f083884Ss.makeev_local 369*2f083884Ss.makeev_local dstPixels[index + 0] = (pixel & 0xFF); 370*2f083884Ss.makeev_local dstPixels[index + 1] = (pixel >> 8 & 0xFF); 371*2f083884Ss.makeev_local dstPixels[index + 2] = (pixel >> 16 & 0xFF); 372*2f083884Ss.makeev_local } 373*2f083884Ss.makeev_local } 374*2f083884Ss.makeev_local 375*2f083884Ss.makeev_local } 376*2f083884Ss.makeev_local }; 377*2f083884Ss.makeev_local 378*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 379*2f083884Ss.makeev_local struct DecompressDxt 380*2f083884Ss.makeev_local { 381*2f083884Ss.makeev_local MT_DECLARE_TASK(DecompressDxt, MT::StackRequirements::EXTENDED, MT::Color::Yellow); 382*2f083884Ss.makeev_local 383*2f083884Ss.makeev_local MT::ArrayView<uint8> dxtBlocks; 384*2f083884Ss.makeev_local MT::ArrayView<uint8> decompressedImage; 385*2f083884Ss.makeev_local 386*2f083884Ss.makeev_local uint32 blkWidth; 387*2f083884Ss.makeev_local uint32 blkHeight; 388*2f083884Ss.makeev_local 389*2f083884Ss.makeev_local 390*2f083884Ss.makeev_local DecompressDxt(const MT::ArrayView<uint8> & _dxtBlocks, uint32 dxtBlocksCountWidth, uint32 dxtBlocksCountHeight) 391*2f083884Ss.makeev_local : dxtBlocks(_dxtBlocks) 392*2f083884Ss.makeev_local { 393*2f083884Ss.makeev_local blkWidth = dxtBlocksCountWidth; 394*2f083884Ss.makeev_local blkHeight = dxtBlocksCountHeight; 395*2f083884Ss.makeev_local 396*2f083884Ss.makeev_local // dxt1 block = 16 rgb pixels = 48 bytes 397*2f083884Ss.makeev_local uint32 bytesCount = blkWidth * blkHeight * 48; 398*2f083884Ss.makeev_local decompressedImage = MT::ArrayView<uint8>( malloc(bytesCount), bytesCount); 399*2f083884Ss.makeev_local } 400*2f083884Ss.makeev_local 401*2f083884Ss.makeev_local ~DecompressDxt() 402*2f083884Ss.makeev_local { 403*2f083884Ss.makeev_local void* pDxtBlocks = dxtBlocks.GetRawData(); 404*2f083884Ss.makeev_local if (pDxtBlocks) 405*2f083884Ss.makeev_local { 406*2f083884Ss.makeev_local free(pDxtBlocks); 407*2f083884Ss.makeev_local } 408*2f083884Ss.makeev_local 409*2f083884Ss.makeev_local void* pDecompressedImage = decompressedImage.GetRawData(); 410*2f083884Ss.makeev_local if (pDecompressedImage) 411*2f083884Ss.makeev_local { 412*2f083884Ss.makeev_local free(pDecompressedImage); 413*2f083884Ss.makeev_local } 414*2f083884Ss.makeev_local 415*2f083884Ss.makeev_local } 416*2f083884Ss.makeev_local 417*2f083884Ss.makeev_local void Do(MT::FiberContext& context) 418*2f083884Ss.makeev_local { 419*2f083884Ss.makeev_local // use stack_array as subtask container. beware stack overflow! 420*2f083884Ss.makeev_local MT::StackArray<DecompressDxtBlock, 1024> subTasks; 421*2f083884Ss.makeev_local 422*2f083884Ss.makeev_local int stride = blkWidth * 4 * 3; 423*2f083884Ss.makeev_local 424*2f083884Ss.makeev_local for (uint32 blkY = 0; blkY < blkHeight; blkY++) 425*2f083884Ss.makeev_local { 426*2f083884Ss.makeev_local for (uint32 blkX = 0; blkX < blkWidth; blkX++) 427*2f083884Ss.makeev_local { 428*2f083884Ss.makeev_local uint32 blockIndex = blkY * blkWidth + blkX; 429*2f083884Ss.makeev_local subTasks.PushBack( DecompressDxtBlock(blkX * 4, blkY * 4, stride, decompressedImage, dxtBlocks, blockIndex * 8) ); 430*2f083884Ss.makeev_local } 431*2f083884Ss.makeev_local } 432*2f083884Ss.makeev_local 433*2f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &subTasks[0], subTasks.Size()); 434*2f083884Ss.makeev_local } 435*2f083884Ss.makeev_local 436*2f083884Ss.makeev_local }; 437*2f083884Ss.makeev_local 438*2f083884Ss.makeev_local 439*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 440*2f083884Ss.makeev_local void Wait(MT::TaskScheduler & scheduler) 441*2f083884Ss.makeev_local { 442*2f083884Ss.makeev_local //emulate game loop 443*2f083884Ss.makeev_local for(;;) 444*2f083884Ss.makeev_local { 445*2f083884Ss.makeev_local bool waitDone = scheduler.WaitAll(33); 446*2f083884Ss.makeev_local if (waitDone) 447*2f083884Ss.makeev_local { 448*2f083884Ss.makeev_local break; 449*2f083884Ss.makeev_local } 450*2f083884Ss.makeev_local } 451*2f083884Ss.makeev_local } 452*2f083884Ss.makeev_local 453*2f083884Ss.makeev_local 454*2f083884Ss.makeev_local // dxt compressor complex test 455*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 456*2f083884Ss.makeev_local TEST(RunComplexDxtTest) 457*2f083884Ss.makeev_local { 458*2f083884Ss.makeev_local static_assert(MT_ARRAY_SIZE(EmbeddedImage::lenaColor) == 49152, "Image size is invalid"); 459*2f083884Ss.makeev_local 460*2f083884Ss.makeev_local int stride = 384; 461*2f083884Ss.makeev_local 462*2f083884Ss.makeev_local MT::ArrayView<uint8> srcImage((void*)&EmbeddedImage::lenaColor[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor)); 463*2f083884Ss.makeev_local 464*2f083884Ss.makeev_local CompressDxt compressTask(128, 128, stride, srcImage); 465*2f083884Ss.makeev_local MT_ASSERT ((compressTask.width & 3) == 0 && (compressTask.height & 3) == 0, "Image size must be a multiple of 4"); 466*2f083884Ss.makeev_local 467*2f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 468*2f083884Ss.makeev_local Microprofile profiler; 469*2f083884Ss.makeev_local MT::TaskScheduler scheduler(0, &profiler); 470*2f083884Ss.makeev_local #else 471*2f083884Ss.makeev_local MT::TaskScheduler scheduler; 472*2f083884Ss.makeev_local #endif 473*2f083884Ss.makeev_local 474*2f083884Ss.makeev_local int workersCount = (int)scheduler.GetWorkersCount(); 475*2f083884Ss.makeev_local printf("Scheduler started, %d workers\n", workersCount); 476*2f083884Ss.makeev_local 477*2f083884Ss.makeev_local printf("Compress image\n"); 478*2f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &compressTask, 1); 479*2f083884Ss.makeev_local 480*2f083884Ss.makeev_local Wait(scheduler); 481*2f083884Ss.makeev_local 482*2f083884Ss.makeev_local DecompressDxt decompressTask(compressTask.dxtBlocks, compressTask.blkWidth, compressTask.blkHeight); 483*2f083884Ss.makeev_local compressTask.dxtBlocks = MT::ArrayView<uint8>(); //transfer memory ownership to Decompress task 484*2f083884Ss.makeev_local 485*2f083884Ss.makeev_local printf("Decompress image\n"); 486*2f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &decompressTask, 1); 487*2f083884Ss.makeev_local 488*2f083884Ss.makeev_local Wait(scheduler); 489*2f083884Ss.makeev_local 490*2f083884Ss.makeev_local /* 491*2f083884Ss.makeev_local //save compressed image 492*2f083884Ss.makeev_local { 493*2f083884Ss.makeev_local FILE * file = fopen("lena_dxt1.dds", "w+b"); 494*2f083884Ss.makeev_local fwrite(&EmbeddedImage::ddsHeader[0], MT_ARRAY_SIZE(EmbeddedImage::ddsHeader), 1, file); 495*2f083884Ss.makeev_local fwrite(decompressTask.dxtBlocks, decompressTask.blkWidth * decompressTask.blkHeight * 8, 1, file); 496*2f083884Ss.makeev_local fclose(file); 497*2f083884Ss.makeev_local } 498*2f083884Ss.makeev_local 499*2f083884Ss.makeev_local //save uncompressed image 500*2f083884Ss.makeev_local { 501*2f083884Ss.makeev_local FILE * file = fopen("lena_rgb.raw", "w+b"); 502*2f083884Ss.makeev_local fwrite(decompressTask.decompressedImage, decompressTask.blkWidth * decompressTask.blkHeight * 48, 1, file); 503*2f083884Ss.makeev_local fclose(file); 504*2f083884Ss.makeev_local } 505*2f083884Ss.makeev_local */ 506*2f083884Ss.makeev_local 507*2f083884Ss.makeev_local printf("Compare images\n"); 508*2f083884Ss.makeev_local bool imagesEqual = CompareImagesPSNR(&srcImage[0], &decompressTask.decompressedImage[0], MT_ARRAY_SIZE(EmbeddedImage::lenaColor), 8.0); 509*2f083884Ss.makeev_local CHECK_EQUAL(true, imagesEqual); 510*2f083884Ss.makeev_local 511*2f083884Ss.makeev_local /* 512*2f083884Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD 513*2f083884Ss.makeev_local // waiting for profiler attach 514*2f083884Ss.makeev_local printf("Press any key to continue\n"); 515*2f083884Ss.makeev_local while(true) 516*2f083884Ss.makeev_local { 517*2f083884Ss.makeev_local if (_kbhit() != 0) 518*2f083884Ss.makeev_local { 519*2f083884Ss.makeev_local break; 520*2f083884Ss.makeev_local } 521*2f083884Ss.makeev_local } 522*2f083884Ss.makeev_local #endif 523*2f083884Ss.makeev_local */ 524*2f083884Ss.makeev_local } 525*2f083884Ss.makeev_local 526*2f083884Ss.makeev_local 527*2f083884Ss.makeev_local } 528