1 /* 2 * Copyright 2015 The Etc2Comp Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 EtcImage.cpp 19 20 Image is an array of 4x4 blocks that represent the encoding of the source image 21 22 */ 23 24 #include "EtcConfig.h" 25 26 #include <stdlib.h> 27 28 #include "EtcImage.h" 29 30 #include "Etc.h" 31 #include "EtcBlock4x4.h" 32 #include "EtcBlock4x4EncodingBits.h" 33 #include "EtcSortedBlockList.h" 34 35 #if ETC_WINDOWS 36 #include <windows.h> 37 #endif 38 #include <ctime> 39 #include <chrono> 40 #include <future> 41 #include <stdio.h> 42 #include <string.h> 43 #include <assert.h> 44 45 // fix conflict with Block4x4::AlphaMix 46 #ifdef OPAQUE 47 #undef OPAQUE 48 #endif 49 #ifdef TRANSPARENT 50 #undef TRANSPARENT 51 #endif 52 53 namespace Etc 54 { 55 56 // ---------------------------------------------------------------------------------------------------- 57 // Image(void)58 Image::Image(void) 59 { 60 m_encodingStatus = EncodingStatus::SUCCESS; 61 m_warningsToCapture = EncodingStatus::SUCCESS; 62 m_pafrgbaSource = nullptr; 63 64 m_pablock = nullptr; 65 66 m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; 67 m_uiEncodingBitsBytes = 0; 68 m_paucEncodingBits = nullptr; 69 70 m_format = Format::UNKNOWN; 71 m_iNumOpaquePixels = 0; 72 m_iNumTranslucentPixels = 0; 73 m_iNumTransparentPixels = 0; 74 } 75 76 // ---------------------------------------------------------------------------------------------------- 77 // constructor using source image 78 // used to set state before Encode() is called 79 // Image(float * a_pafSourceRGBA,unsigned int a_uiSourceWidth,unsigned int a_uiSourceHeight,ErrorMetric a_errormetric)80 Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth, 81 unsigned int a_uiSourceHeight, 82 ErrorMetric a_errormetric) 83 { 84 m_encodingStatus = EncodingStatus::SUCCESS; 85 m_warningsToCapture = EncodingStatus::SUCCESS; 86 m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA; 87 m_uiSourceWidth = a_uiSourceWidth; 88 m_uiSourceHeight = a_uiSourceHeight; 89 90 m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth); 91 m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight); 92 93 m_uiBlockColumns = m_uiExtendedWidth >> 2; 94 m_uiBlockRows = m_uiExtendedHeight >> 2; 95 96 m_pablock = new Block4x4[GetNumberOfBlocks()]; 97 assert(m_pablock); 98 99 m_format = Format::UNKNOWN; 100 101 m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; 102 m_uiEncodingBitsBytes = 0; 103 m_paucEncodingBits = nullptr; 104 105 m_errormetric = a_errormetric; 106 m_fEffort = 0.0f; 107 108 m_iEncodeTime_ms = -1; 109 110 m_iNumOpaquePixels = 0; 111 m_iNumTranslucentPixels = 0; 112 m_iNumTransparentPixels = 0; 113 m_bVerboseOutput = false; 114 115 } 116 117 // ---------------------------------------------------------------------------------------------------- 118 // constructor using encoding bits 119 // recreates encoding state using a previously encoded image 120 // Image(Format a_format,unsigned int a_uiSourceWidth,unsigned int a_uiSourceHeight,unsigned char * a_paucEncidingBits,unsigned int a_uiEncodingBitsBytes,Image * a_pimageSource,ErrorMetric a_errormetric)121 Image::Image(Format a_format, 122 unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight, 123 unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes, 124 Image *a_pimageSource, ErrorMetric a_errormetric) 125 { 126 m_encodingStatus = EncodingStatus::SUCCESS; 127 m_pafrgbaSource = nullptr; 128 m_uiSourceWidth = a_uiSourceWidth; 129 m_uiSourceHeight = a_uiSourceHeight; 130 131 m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth); 132 m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight); 133 134 m_uiBlockColumns = m_uiExtendedWidth >> 2; 135 m_uiBlockRows = m_uiExtendedHeight >> 2; 136 137 unsigned int uiBlocks = GetNumberOfBlocks(); 138 139 m_pablock = new Block4x4[uiBlocks]; 140 assert(m_pablock); 141 142 m_format = a_format; 143 144 m_iNumOpaquePixels = 0; 145 m_iNumTranslucentPixels = 0; 146 m_iNumTransparentPixels = 0; 147 148 m_encodingbitsformat = DetermineEncodingBitsFormat(m_format); 149 if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN) 150 { 151 AddToEncodingStatus(ERROR_UNKNOWN_FORMAT); 152 return; 153 } 154 m_uiEncodingBitsBytes = a_uiEncodingBitsBytes; 155 m_paucEncodingBits = a_paucEncidingBits; 156 157 m_errormetric = a_errormetric; 158 m_fEffort = 0.0f; 159 m_bVerboseOutput = false; 160 m_iEncodeTime_ms = -1; 161 162 unsigned char *paucEncodingBits = m_paucEncodingBits; 163 unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); 164 165 unsigned int uiH = 0; 166 unsigned int uiV = 0; 167 for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++) 168 { 169 m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits, 170 a_pimageSource, a_errormetric); 171 paucEncodingBits += uiEncodingBitsBytesPerBlock; 172 uiH += 4; 173 if (uiH >= m_uiSourceWidth) 174 { 175 uiH = 0; 176 uiV += 4; 177 } 178 } 179 180 } 181 182 // ---------------------------------------------------------------------------------------------------- 183 // ~Image(void)184 Image::~Image(void) 185 { 186 if (m_pablock != nullptr) 187 { 188 delete[] m_pablock; 189 m_pablock = nullptr; 190 } 191 192 /*if (m_paucEncodingBits != nullptr) 193 { 194 delete[] m_paucEncodingBits; 195 m_paucEncodingBits = nullptr; 196 }*/ 197 } 198 199 // ---------------------------------------------------------------------------------------------------- 200 // encode an image 201 // create a set of encoding bits that conforms to a_format 202 // find best fit using a_errormetric 203 // explore a range of possible encodings based on a_fEffort (range = [0:100]) 204 // speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs) 205 // Encode(Format a_format,ErrorMetric a_errormetric,float a_fEffort,unsigned int a_uiJobs,unsigned int a_uiMaxJobs)206 Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs) 207 { 208 209 auto start = std::chrono::steady_clock::now(); 210 211 m_encodingStatus = EncodingStatus::SUCCESS; 212 213 m_format = a_format; 214 m_errormetric = a_errormetric; 215 m_fEffort = a_fEffort; 216 217 if (m_errormetric < 0 || m_errormetric > ERROR_METRICS) 218 { 219 AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC); 220 return m_encodingStatus; 221 } 222 223 if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL) 224 { 225 AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE); 226 m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL; 227 } 228 else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL) 229 { 230 AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE); 231 m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL; 232 } 233 if (a_uiJobs < 1) 234 { 235 a_uiJobs = 1; 236 AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE); 237 } 238 else if (a_uiJobs > a_uiMaxJobs) 239 { 240 a_uiJobs = a_uiMaxJobs; 241 AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE); 242 } 243 244 m_encodingbitsformat = DetermineEncodingBitsFormat(m_format); 245 246 if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN) 247 { 248 AddToEncodingStatus(ERROR_UNKNOWN_FORMAT); 249 return m_encodingStatus; 250 } 251 252 assert(m_paucEncodingBits == nullptr); 253 m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); 254 m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes]; 255 256 InitBlocksAndBlockSorter(); 257 258 259 std::future<void> *handle = new std::future<void>[a_uiMaxJobs]; 260 261 unsigned int uiNumThreadsNeeded = 0; 262 unsigned int uiUnfinishedBlocks = GetNumberOfBlocks(); 263 264 uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs; 265 266 for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) 267 { 268 handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded); 269 } 270 271 RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded); 272 273 for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) 274 { 275 handle[i].get(); 276 } 277 278 // perform effort-based encoding 279 if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL) 280 { 281 unsigned int uiFinishedBlocks = 0; 282 unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks())); 283 284 if (m_bVerboseOutput) 285 { 286 printf("effortblocks = %d\n", uiTotalEffortBlocks); 287 } 288 unsigned int uiPass = 0; 289 while (1) 290 { 291 if (m_bVerboseOutput) 292 { 293 uiPass++; 294 printf("pass %u\n", uiPass); 295 } 296 m_psortedblocklist->Sort(); 297 uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks(); 298 uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks; 299 if (m_bVerboseOutput) 300 { 301 printf(" %u unfinished blocks\n", uiUnfinishedBlocks); 302 // m_psortedblocklist->Print(); 303 } 304 305 306 307 //stop enocding when we did enough to satify the effort percentage 308 if (uiFinishedBlocks >= uiTotalEffortBlocks) 309 { 310 if (m_bVerboseOutput) 311 { 312 printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks); 313 } 314 break; 315 } 316 317 unsigned int uiIteratedBlocks = 0; 318 unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks); 319 uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs; 320 321 if (uiNumThreadsNeeded <= 1) 322 { 323 //since we already how many blocks each thread will process 324 //cap the thread limit to do the proper amount of work, and not more 325 uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1); 326 } 327 else 328 { 329 //we have a lot of work to do, so lets multi thread it 330 std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1]; 331 332 for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) 333 { 334 handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded); 335 } 336 uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded); 337 338 for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++) 339 { 340 uiIteratedBlocks += handleToBlockEncoders[i].get(); 341 } 342 343 delete[] handleToBlockEncoders; 344 } 345 346 if (m_bVerboseOutput) 347 { 348 printf(" %u iterated blocks\n", uiIteratedBlocks); 349 } 350 } 351 } 352 353 // generate Etc2-compatible bit-format 4x4 blocks 354 for (int i = 0; i < (int)a_uiJobs - 1; i++) 355 { 356 handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs); 357 } 358 SetEncodingBits(a_uiJobs - 1, a_uiJobs); 359 360 for (int i = 0; i < (int)a_uiJobs - 1; i++) 361 { 362 handle[i].get(); 363 } 364 365 auto end = std::chrono::steady_clock::now(); 366 std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); 367 m_iEncodeTime_ms = (int)elapsed.count(); 368 369 delete[] handle; 370 delete m_psortedblocklist; 371 return m_encodingStatus; 372 } 373 374 // ---------------------------------------------------------------------------------------------------- 375 // iterate the encoding thru the blocks with the worst error 376 // stop when a_uiMaxBlocks blocks have been iterated 377 // split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride 378 // IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,unsigned int a_uiMultithreadingOffset,unsigned int a_uiMultithreadingStride)379 unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks, 380 unsigned int a_uiMultithreadingOffset, 381 unsigned int a_uiMultithreadingStride) 382 { 383 assert(a_uiMultithreadingStride > 0); 384 unsigned int uiIteratedBlocks = a_uiMultithreadingOffset; 385 386 SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock(); 387 for (plink = plink->Advance(a_uiMultithreadingOffset); 388 plink != nullptr; 389 plink = plink->Advance(a_uiMultithreadingStride) ) 390 { 391 if (uiIteratedBlocks >= a_uiMaxBlocks) 392 { 393 break; 394 } 395 396 plink->GetBlock()->PerformEncodingIteration(m_fEffort); 397 398 uiIteratedBlocks += a_uiMultithreadingStride; 399 } 400 401 return uiIteratedBlocks; 402 } 403 404 // ---------------------------------------------------------------------------------------------------- 405 // determine which warnings to check for during Encode() based on encoding format 406 // FindEncodingWarningTypesForCurFormat()407 void Image::FindEncodingWarningTypesForCurFormat() 408 { 409 TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS); 410 TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1); 411 switch (m_format) 412 { 413 case Image::Format::ETC1: 414 case Image::Format::RGB8: 415 case Image::Format::SRGB8: 416 TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); 417 TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); 418 break; 419 420 case Image::Format::RGB8A1: 421 case Image::Format::SRGB8A1: 422 TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); 423 TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS); 424 break; 425 case Image::Format::RGBA8: 426 case Image::Format::SRGBA8: 427 TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS); 428 break; 429 430 case Image::Format::R11: 431 case Image::Format::SIGNED_R11: 432 TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); 433 TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); 434 TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO); 435 TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); 436 break; 437 438 case Image::Format::RG11: 439 case Image::Format::SIGNED_RG11: 440 TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS); 441 TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS); 442 TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); 443 break; 444 case Image::Format::FORMATS: 445 case Image::Format::UNKNOWN: 446 default: 447 assert(0); 448 break; 449 } 450 } 451 452 // ---------------------------------------------------------------------------------------------------- 453 // examine source pixels to check for warnings 454 // FindAndSetEncodingWarnings()455 void Image::FindAndSetEncodingWarnings() 456 { 457 int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4); 458 if (m_iNumOpaquePixels == numPixels) 459 { 460 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS); 461 } 462 if (m_iNumOpaquePixels < numPixels) 463 { 464 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS); 465 } 466 if (m_iNumTranslucentPixels > 0) 467 { 468 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS); 469 } 470 if (m_iNumTransparentPixels == numPixels) 471 { 472 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS); 473 } 474 if (m_numColorValues.fB > 0.0f) 475 { 476 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO); 477 } 478 if (m_numColorValues.fG > 0.0f) 479 { 480 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO); 481 } 482 483 if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f) 484 { 485 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1); 486 } 487 if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f) 488 { 489 AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1); 490 } 491 } 492 493 // ---------------------------------------------------------------------------------------------------- 494 // return a string name for a given image format 495 // EncodingFormatToString(Image::Format a_format)496 const char * Image::EncodingFormatToString(Image::Format a_format) 497 { 498 switch (a_format) 499 { 500 case Image::Format::ETC1: 501 return "ETC1"; 502 case Image::Format::RGB8: 503 return "RGB8"; 504 case Image::Format::SRGB8: 505 return "SRGB8"; 506 507 case Image::Format::RGB8A1: 508 return "RGB8A1"; 509 case Image::Format::SRGB8A1: 510 return "SRGB8A1"; 511 case Image::Format::RGBA8: 512 return "RGBA8"; 513 case Image::Format::SRGBA8: 514 return "SRGBA8"; 515 516 case Image::Format::R11: 517 return "R11"; 518 case Image::Format::SIGNED_R11: 519 return "SIGNED_R11"; 520 521 case Image::Format::RG11: 522 return "RG11"; 523 case Image::Format::SIGNED_RG11: 524 return "SIGNED_RG11"; 525 case Image::Format::FORMATS: 526 case Image::Format::UNKNOWN: 527 default: 528 return "UNKNOWN"; 529 } 530 } 531 532 // ---------------------------------------------------------------------------------------------------- 533 // return a string name for the image's format 534 // EncodingFormatToString(void)535 const char * Image::EncodingFormatToString(void) 536 { 537 return EncodingFormatToString(m_format); 538 } 539 540 // ---------------------------------------------------------------------------------------------------- 541 // init image blocks prior to encoding 542 // init block sorter for subsequent sortings 543 // check for encoding warnings 544 // InitBlocksAndBlockSorter(void)545 void Image::InitBlocksAndBlockSorter(void) 546 { 547 548 FindEncodingWarningTypesForCurFormat(); 549 550 // init each block 551 Block4x4 *pblock = m_pablock; 552 unsigned char *paucEncodingBits = m_paucEncodingBits; 553 for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++) 554 { 555 unsigned int uiBlockV = uiBlockRow * 4; 556 557 for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++) 558 { 559 unsigned int uiBlockH = uiBlockColumn * 4; 560 561 pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric); 562 563 paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat); 564 565 pblock++; 566 } 567 } 568 569 FindAndSetEncodingWarnings(); 570 571 // init block sorter 572 { 573 m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100); 574 575 for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++) 576 { 577 pblock = &m_pablock[uiBlock]; 578 m_psortedblocklist->AddBlock(pblock); 579 } 580 } 581 582 } 583 584 // ---------------------------------------------------------------------------------------------------- 585 // run the first pass of the encoder 586 // the encoder generally finds a reasonable, fast encoding 587 // this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding 588 // RunFirstPass(unsigned int a_uiMultithreadingOffset,unsigned int a_uiMultithreadingStride)589 void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride) 590 { 591 assert(a_uiMultithreadingStride > 0); 592 593 for (unsigned int uiBlock = a_uiMultithreadingOffset; 594 uiBlock < GetNumberOfBlocks(); 595 uiBlock += a_uiMultithreadingStride) 596 { 597 Block4x4 *pblock = &m_pablock[uiBlock]; 598 pblock->PerformEncodingIteration(m_fEffort); 599 } 600 } 601 602 // ---------------------------------------------------------------------------------------------------- 603 // set the encoding bits (for the output file) based on the best encoding for each block 604 // SetEncodingBits(unsigned int a_uiMultithreadingOffset,unsigned int a_uiMultithreadingStride)605 void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset, 606 unsigned int a_uiMultithreadingStride) 607 { 608 assert(a_uiMultithreadingStride > 0); 609 610 for (unsigned int uiBlock = a_uiMultithreadingOffset; 611 uiBlock < GetNumberOfBlocks(); 612 uiBlock += a_uiMultithreadingStride) 613 { 614 Block4x4 *pblock = &m_pablock[uiBlock]; 615 pblock->SetEncodingBitsFromEncoding(); 616 } 617 618 } 619 620 // ---------------------------------------------------------------------------------------------------- 621 // return the image error 622 // image error is the sum of all block errors 623 // GetError(void)624 float Image::GetError(void) 625 { 626 float fError = 0.0f; 627 628 for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++) 629 { 630 Block4x4 *pblock = &m_pablock[uiBlock]; 631 fError += pblock->GetError(); 632 } 633 634 return fError; 635 } 636 637 // ---------------------------------------------------------------------------------------------------- 638 // determine the encoding bits format based on the encoding format 639 // the encoding bits format is a family of bit encodings that are shared across various encoding formats 640 // DetermineEncodingBitsFormat(Format a_format)641 Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format) 642 { 643 Block4x4EncodingBits::Format encodingbitsformat; 644 645 // determine encoding bits format from image format 646 switch (a_format) 647 { 648 case Format::ETC1: 649 case Format::RGB8: 650 case Format::SRGB8: 651 encodingbitsformat = Block4x4EncodingBits::Format::RGB8; 652 break; 653 654 case Format::RGBA8: 655 case Format::SRGBA8: 656 encodingbitsformat = Block4x4EncodingBits::Format::RGBA8; 657 break; 658 659 case Format::R11: 660 case Format::SIGNED_R11: 661 encodingbitsformat = Block4x4EncodingBits::Format::R11; 662 break; 663 664 case Format::RG11: 665 case Format::SIGNED_RG11: 666 encodingbitsformat = Block4x4EncodingBits::Format::RG11; 667 break; 668 669 case Format::RGB8A1: 670 case Format::SRGB8A1: 671 encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1; 672 break; 673 674 default: 675 encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN; 676 break; 677 } 678 679 return encodingbitsformat; 680 } 681 682 // ---------------------------------------------------------------------------------------------------- 683 // 684 685 } // namespace Etc 686