mirror of
				https://github.com/yuzu-emu/FasTC.git
				synced 2025-11-04 15:54:58 +00:00 
			
		
		
		
	Refactor shape and mode selection
We suffered another performance hit. This time it comes from the fact that we're copying around a lot of data based on what partition we're choosing. We can get rid of this a tad by only copying the data that we need once and then using getters/setters that selectively pull from an array based on our shape index.
This commit is contained in:
		
							parent
							
								
									26e816b3db
								
							
						
					
					
						commit
						cf937f2ad3
					
				| 
						 | 
					@ -86,14 +86,14 @@ namespace BPTCC {
 | 
				
			||||||
  // The enum is specialized to be power-of-two values so that an EBlockMode
 | 
					  // The enum is specialized to be power-of-two values so that an EBlockMode
 | 
				
			||||||
  // variable can be used as a bit mask.
 | 
					  // variable can be used as a bit mask.
 | 
				
			||||||
  enum EBlockMode {
 | 
					  enum EBlockMode {
 | 
				
			||||||
    eBlockMode_Zero = 0,
 | 
					    eBlockMode_Zero = 1,
 | 
				
			||||||
    eBlockMode_One = 1,
 | 
					    eBlockMode_One = 2,
 | 
				
			||||||
    eBlockMode_Two = 2,
 | 
					    eBlockMode_Two = 4,
 | 
				
			||||||
    eBlockMode_Three = 4,
 | 
					    eBlockMode_Three = 8,
 | 
				
			||||||
    eBlockMode_Four = 8,
 | 
					    eBlockMode_Four = 16,
 | 
				
			||||||
    eBlockMode_Five = 16,
 | 
					    eBlockMode_Five = 32,
 | 
				
			||||||
    eBlockMode_Six = 32,
 | 
					    eBlockMode_Six = 64,
 | 
				
			||||||
    eBlockMode_Seven = 64
 | 
					    eBlockMode_Seven = 128
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // A shape selection can influence the results of the compressor by choosing
 | 
					  // A shape selection can influence the results of the compressor by choosing
 | 
				
			||||||
| 
						 | 
					@ -110,13 +110,18 @@ namespace BPTCC {
 | 
				
			||||||
    // This is the additional mask to prevent modes once shape selection
 | 
					    // This is the additional mask to prevent modes once shape selection
 | 
				
			||||||
    // is done. This value is &-ed with m_BlockModes from CompressionSettings
 | 
					    // is done. This value is &-ed with m_BlockModes from CompressionSettings
 | 
				
			||||||
    // to determine what the final considered blocks are.
 | 
					    // to determine what the final considered blocks are.
 | 
				
			||||||
    EBlockMode m_AdditionalModes;
 | 
					    uint32 m_SelectedModes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Defaults
 | 
				
			||||||
 | 
					    ShapeSelection()
 | 
				
			||||||
 | 
					    : m_SelectedModes(static_cast<EBlockMode>(0xFF))
 | 
				
			||||||
 | 
					    { }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // A shape selection function is one that selects a BPTC shape from a given
 | 
					  // A shape selection function is one that selects a BPTC shape from a given
 | 
				
			||||||
  // block position and pixel array.
 | 
					  // block position and pixel array.
 | 
				
			||||||
  typedef ShapeSelection
 | 
					  typedef ShapeSelection
 | 
				
			||||||
    (*ShapeSelectionFn)(uint32 x, uint32 y, uint32 pixels[16]);
 | 
					    (*ShapeSelectionFn)(uint32 x, uint32 y, const uint32 pixels[16]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Compression parameters used to control the BPTC compressor. Each of the
 | 
					  // Compression parameters used to control the BPTC compressor. Each of the
 | 
				
			||||||
  // values has a default, so this is not strictly required to perform
 | 
					  // values has a default, so this is not strictly required to perform
 | 
				
			||||||
| 
						 | 
					@ -135,11 +140,11 @@ namespace BPTCC {
 | 
				
			||||||
    // This variable is a bit mask of EBlockMode values and by default contains
 | 
					    // This variable is a bit mask of EBlockMode values and by default contains
 | 
				
			||||||
    // every mode. This setting can be used to further restrict the search space
 | 
					    // every mode. This setting can be used to further restrict the search space
 | 
				
			||||||
    // and increase compression times.
 | 
					    // and increase compression times.
 | 
				
			||||||
    EBlockMode m_BlockModes;
 | 
					    uint32 m_BlockModes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CompressionSettings()
 | 
					    CompressionSettings()
 | 
				
			||||||
    : m_ShapeSelectionFn(NULL)
 | 
					    : m_ShapeSelectionFn(NULL)
 | 
				
			||||||
    , m_BlockModes(static_cast<EBlockMode>((1 << 7) - 1))
 | 
					    , m_BlockModes(static_cast<EBlockMode>(0xFF))
 | 
				
			||||||
    { }
 | 
					    { }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,8 +105,8 @@ class CompressionMode {
 | 
				
			||||||
  // This initializes the compression variables used in order to compress a list
 | 
					  // This initializes the compression variables used in order to compress a list
 | 
				
			||||||
  // of clusters. We can increase the speed a tad by specifying whether or not
 | 
					  // of clusters. We can increase the speed a tad by specifying whether or not
 | 
				
			||||||
  // the block is opaque or not.
 | 
					  // the block is opaque or not.
 | 
				
			||||||
  explicit CompressionMode(int mode, bool opaque = true)
 | 
					  explicit CompressionMode(int mode)
 | 
				
			||||||
    : m_IsOpaque(opaque)
 | 
					    : m_IsOpaque(mode < 4)
 | 
				
			||||||
    , m_Attributes(&(kModeAttributes[mode]))
 | 
					    , m_Attributes(&(kModeAttributes[mode]))
 | 
				
			||||||
    , m_RotateMode(0)
 | 
					    , m_RotateMode(0)
 | 
				
			||||||
    , m_IndexMode(0)
 | 
					    , m_IndexMode(0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,8 +103,7 @@ using FasTC::BitStreamReadOnly;
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <limits>
 | 
				
			||||||
// #define USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum EBlockStats {
 | 
					enum EBlockStats {
 | 
				
			||||||
  eBlockStat_Path,
 | 
					  eBlockStat_Path,
 | 
				
			||||||
| 
						 | 
					@ -1250,7 +1249,6 @@ void CompressionMode::Pack(Params ¶ms, BitStream &stream) const {
 | 
				
			||||||
  const int nPartitionBits = GetNumberOfPartitionBits();
 | 
					  const int nPartitionBits = GetNumberOfPartitionBits();
 | 
				
			||||||
  const int nSubsets = GetNumberOfSubsets();
 | 
					  const int nSubsets = GetNumberOfSubsets();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  // Mode #
 | 
					  // Mode #
 | 
				
			||||||
  stream.WriteBits(1 << kModeNumber, kModeNumber + 1);
 | 
					  stream.WriteBits(1 << kModeNumber, kModeNumber + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1791,114 +1789,15 @@ void CompressAtomic(FasTC::CompressionJobList &cjl) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static double CompressTwoClusters(
 | 
					 | 
				
			||||||
  int shapeIdx,
 | 
					 | 
				
			||||||
  const RGBACluster *clusters,
 | 
					 | 
				
			||||||
  uint8 *outBuf,
 | 
					 | 
				
			||||||
  bool opaque,
 | 
					 | 
				
			||||||
  double *errors = NULL,
 | 
					 | 
				
			||||||
  int *modeChosen = NULL
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint8 tempBuf1[16];
 | 
					 | 
				
			||||||
  BitStream tmpStream1(tempBuf1, 128, 0);
 | 
					 | 
				
			||||||
  double bestError =
 | 
					 | 
				
			||||||
    CompressionMode(1, opaque).Compress(tmpStream1, shapeIdx, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(errors) errors[1] = bestError;
 | 
					 | 
				
			||||||
  if(modeChosen) *modeChosen = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memcpy(outBuf, tempBuf1, 16);
 | 
					 | 
				
			||||||
  if(bestError == 0.0) {
 | 
					 | 
				
			||||||
    return 0.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint8 tempBuf3[16];
 | 
					 | 
				
			||||||
  BitStream tmpStream3(tempBuf3, 128, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  double error =
 | 
					 | 
				
			||||||
    CompressionMode(3, opaque).Compress(tmpStream3, shapeIdx, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(errors) errors[3] = error;
 | 
					 | 
				
			||||||
  if(error < bestError) {
 | 
					 | 
				
			||||||
    if(modeChosen) *modeChosen = 3;
 | 
					 | 
				
			||||||
    bestError = error;
 | 
					 | 
				
			||||||
    memcpy(outBuf, tempBuf3, 16);
 | 
					 | 
				
			||||||
    if(bestError == 0.0) {
 | 
					 | 
				
			||||||
      return 0.0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Mode 3 offers more precision for RGB data. Mode 7 is really only if we
 | 
					 | 
				
			||||||
  // have alpha.
 | 
					 | 
				
			||||||
  if(!opaque) {
 | 
					 | 
				
			||||||
    uint8 tempBuf7[16];
 | 
					 | 
				
			||||||
    BitStream tmpStream7(tempBuf7, 128, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    error =
 | 
					 | 
				
			||||||
      CompressionMode(7, opaque).Compress(tmpStream7, shapeIdx, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(errors) errors[7] = error;
 | 
					 | 
				
			||||||
    if(error < bestError) {
 | 
					 | 
				
			||||||
      if(modeChosen) *modeChosen = 7;
 | 
					 | 
				
			||||||
      memcpy(outBuf, tempBuf7, 16);
 | 
					 | 
				
			||||||
      return error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return bestError;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static double CompressThreeClusters(
 | 
					 | 
				
			||||||
  int shapeIdx,
 | 
					 | 
				
			||||||
  const RGBACluster *clusters,
 | 
					 | 
				
			||||||
  uint8 *outBuf,
 | 
					 | 
				
			||||||
  bool opaque,
 | 
					 | 
				
			||||||
  double *errors = NULL,
 | 
					 | 
				
			||||||
  int *modeChosen = NULL
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
  uint8 tempBuf0[16];
 | 
					 | 
				
			||||||
  BitStream tmpStream0(tempBuf0, 128, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint8 tempBuf2[16];
 | 
					 | 
				
			||||||
  BitStream tmpStream2(tempBuf2, 128, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  double error, bestError = DBL_MAX;;
 | 
					 | 
				
			||||||
  if(shapeIdx < 16) {
 | 
					 | 
				
			||||||
    bestError =
 | 
					 | 
				
			||||||
      CompressionMode(0, opaque).Compress(tmpStream0, shapeIdx, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(errors) errors[0] = bestError;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    if(errors) errors[0] = -1.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(modeChosen) *modeChosen = 0;
 | 
					 | 
				
			||||||
  memcpy(outBuf, tempBuf0, 16);
 | 
					 | 
				
			||||||
  if(bestError == 0.0) {
 | 
					 | 
				
			||||||
    return 0.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  error =
 | 
					 | 
				
			||||||
    CompressionMode(2, opaque).Compress(tmpStream2, shapeIdx, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(errors) errors[2] = error;
 | 
					 | 
				
			||||||
  if(error < bestError) {
 | 
					 | 
				
			||||||
    if(modeChosen) *modeChosen = 2;
 | 
					 | 
				
			||||||
    memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
    return error;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return bestError;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void PopulateTwoClustersForShape(
 | 
					static void PopulateTwoClustersForShape(
 | 
				
			||||||
  const RGBACluster &points, int shapeIdx, RGBACluster *clusters
 | 
					  const uint32 points[16], int shapeIdx, RGBACluster *clusters
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 | 
					  clusters[0].Reset();
 | 
				
			||||||
 | 
					  clusters[1].Reset();
 | 
				
			||||||
  const uint16 shape = kShapeMask2[shapeIdx];
 | 
					  const uint16 shape = kShapeMask2[shapeIdx];
 | 
				
			||||||
  for(uint32 pt = 0; pt < kMaxNumDataPoints; pt++) {
 | 
					  for(uint32 pt = 0; pt < kMaxNumDataPoints; pt++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const RGBAVector &p = points.GetPoint(pt);
 | 
					    const RGBAVector p = RGBAVector(pt, points[pt]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if((1 << pt) & shape)
 | 
					    if((1 << pt) & shape)
 | 
				
			||||||
      clusters[1].AddPoint(p);
 | 
					      clusters[1].AddPoint(p);
 | 
				
			||||||
| 
						 | 
					@ -1916,11 +1815,14 @@ static void PopulateTwoClustersForShape(
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void PopulateThreeClustersForShape(
 | 
					static void PopulateThreeClustersForShape(
 | 
				
			||||||
  const RGBACluster &points, int shapeIdx, RGBACluster *clusters
 | 
					  const uint32 points[16], int shapeIdx, RGBACluster *clusters
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 | 
					  clusters[0].Reset();
 | 
				
			||||||
 | 
					  clusters[1].Reset();
 | 
				
			||||||
 | 
					  clusters[2].Reset();
 | 
				
			||||||
  for(uint32 pt = 0; pt < kMaxNumDataPoints; pt++) {
 | 
					  for(uint32 pt = 0; pt < kMaxNumDataPoints; pt++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const RGBAVector &p = points.GetPoint(pt);
 | 
					    const RGBAVector p = RGBAVector(pt, points[pt]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if((1 << pt) & kShapeMask3[shapeIdx][0]) {
 | 
					    if((1 << pt) & kShapeMask3[shapeIdx][0]) {
 | 
				
			||||||
      if((1 << pt) & kShapeMask3[shapeIdx][1]) {
 | 
					      if((1 << pt) & kShapeMask3[shapeIdx][1]) {
 | 
				
			||||||
| 
						 | 
					@ -1955,18 +1857,8 @@ static double EstimateTwoClusterError(RGBACluster &c) {
 | 
				
			||||||
  const float *w = BPTCC::GetErrorMetric();
 | 
					  const float *w = BPTCC::GetErrorMetric();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  double error = 0.0001;
 | 
					  double error = 0.0001;
 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
  double eigOne = c.GetPrincipalEigenvalue();
 | 
					 | 
				
			||||||
  double eigTwo = c.GetSecondEigenvalue();
 | 
					 | 
				
			||||||
  if(eigOne != 0.0) {
 | 
					 | 
				
			||||||
    error += eigTwo / eigOne;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    error += 1.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  error += c.QuantizedError(Min, Max, 8,
 | 
					  error += c.QuantizedError(Min, Max, 8,
 | 
				
			||||||
                            0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
 | 
					                            0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  return error;
 | 
					  return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1981,22 +1873,159 @@ static double EstimateThreeClusterError(RGBACluster &c) {
 | 
				
			||||||
  const float *w = BPTCC::GetErrorMetric();
 | 
					  const float *w = BPTCC::GetErrorMetric();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  double error = 0.0001;
 | 
					  double error = 0.0001;
 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
  double eigOne = c.GetPrincipalEigenvalue();
 | 
					 | 
				
			||||||
  double eigTwo = c.GetSecondEigenvalue();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(eigOne != 0.0) {
 | 
					 | 
				
			||||||
    error += eigTwo / eigOne;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    error += 1.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  error += c.QuantizedError(Min, Max, 4,
 | 
					  error += c.QuantizedError(Min, Max, 4,
 | 
				
			||||||
                            0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
 | 
					                            0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  return error;
 | 
					  return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32 kTwoPartitionModes = 
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_One) |
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Three) |
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Seven);
 | 
				
			||||||
 | 
					static uint32 kThreePartitionModes =
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Zero) |
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Two);
 | 
				
			||||||
 | 
					static uint32 kAlphaModes =
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Four) |
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Five) |
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Six)  |
 | 
				
			||||||
 | 
					  static_cast<uint32>(eBlockMode_Seven);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ShapeSelection BoxSelection(uint32 x, uint32 y,
 | 
				
			||||||
 | 
					                                   const uint32 pixels[16]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ShapeSelection result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool opaque = true;
 | 
				
			||||||
 | 
					  for(uint32 i = 0; i < 16; i++) {
 | 
				
			||||||
 | 
					    uint32 a = (pixels[i] >> 24) & 0xFF;
 | 
				
			||||||
 | 
					    opaque = opaque && (a >= 250); // For all intents and purposes...
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // First we must figure out which shape to use. To do this, simply
 | 
				
			||||||
 | 
					  // see which shape has the smallest sum of minimum bounding spheres.
 | 
				
			||||||
 | 
					  double bestError[2] = { std::numeric_limits<double>::max(),
 | 
				
			||||||
 | 
					                          std::numeric_limits<double>::max() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for(unsigned int i = 0; i < kNumShapes2; i++) {
 | 
				
			||||||
 | 
					    RGBACluster clusters[2];
 | 
				
			||||||
 | 
					    PopulateTwoClustersForShape(pixels, i, clusters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    double err = 0.0;
 | 
				
			||||||
 | 
					    for(int ci = 0; ci < 2; ci++) {
 | 
				
			||||||
 | 
					      err += EstimateTwoClusterError(clusters[ci]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(err < bestError[0]) {
 | 
				
			||||||
 | 
					      bestError[0] = err;
 | 
				
			||||||
 | 
					      result.m_TwoShapeIndex = i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If it's small, we'll take it!
 | 
				
			||||||
 | 
					    if(err < 1e-9) {
 | 
				
			||||||
 | 
					      result.m_SelectedModes = kTwoPartitionModes;
 | 
				
			||||||
 | 
					      return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // There are not 3 subset blocks that support alpha, so only check these
 | 
				
			||||||
 | 
					  // if the entire block is opaque.
 | 
				
			||||||
 | 
					  if(opaque) {
 | 
				
			||||||
 | 
					    for(unsigned int i = 0; i < kNumShapes3; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      RGBACluster clusters[3];
 | 
				
			||||||
 | 
					      PopulateThreeClustersForShape(pixels, i, clusters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      double err = 0.0;
 | 
				
			||||||
 | 
					      for(int ci = 0; ci < 3; ci++) {
 | 
				
			||||||
 | 
					        err += EstimateThreeClusterError(clusters[ci]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if(err < bestError[1]) {
 | 
				
			||||||
 | 
					        bestError[1] = err;
 | 
				
			||||||
 | 
					        result.m_ThreeShapeIndex = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // If it's small, we'll take it!
 | 
				
			||||||
 | 
					      if(err < 1e-9) {
 | 
				
			||||||
 | 
					        result.m_SelectedModes = kThreePartitionModes;
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If it's opaque, we get more value out of mode 6 than modes
 | 
				
			||||||
 | 
					    // 4 and 5, so just ignore those.
 | 
				
			||||||
 | 
					    result.m_SelectedModes &=
 | 
				
			||||||
 | 
					      ~(static_cast<uint32>(eBlockMode_Four) |
 | 
				
			||||||
 | 
					        static_cast<uint32>(eBlockMode_Five));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // Only some modes support alpha
 | 
				
			||||||
 | 
					    result.m_SelectedModes &= kAlphaModes;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void CompressClusters(ShapeSelection selection, const uint32 pixels[16],
 | 
				
			||||||
 | 
					                             uint8 *outBuf, double *errors, int *modeChosen) {
 | 
				
			||||||
 | 
					  RGBACluster clusters[3];
 | 
				
			||||||
 | 
					  uint8 tmpBuf[16];
 | 
				
			||||||
 | 
					  double bestError = std::numeric_limits<double>::max();
 | 
				
			||||||
 | 
					  uint32 modes[8] = {0, 2, 1, 3, 7, 4, 5, 6};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool populatedThree = false;
 | 
				
			||||||
 | 
					  bool populatedTwo = false;
 | 
				
			||||||
 | 
					  bool populatedOne = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Block mode zero only has four bits for the partition index,
 | 
				
			||||||
 | 
					  // so if the chosen three-partition shape is not within this range,
 | 
				
			||||||
 | 
					  // then we shouldn't consider using this block mode...
 | 
				
			||||||
 | 
					  if(selection.m_ThreeShapeIndex >= 16) {
 | 
				
			||||||
 | 
					    selection.m_SelectedModes &= ~(static_cast<uint32>(eBlockMode_Zero));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for(uint32 modeIdx = 0; modeIdx < 8; modeIdx++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32 mode = modes[modeIdx];
 | 
				
			||||||
 | 
					    if((selection.m_SelectedModes & (1 << mode)) == 0) {
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32 shape = 0;
 | 
				
			||||||
 | 
					    if(modeIdx < 2) {
 | 
				
			||||||
 | 
					      shape = selection.m_ThreeShapeIndex;
 | 
				
			||||||
 | 
					      if(!populatedThree) {
 | 
				
			||||||
 | 
					        PopulateThreeClustersForShape(pixels, shape, clusters);
 | 
				
			||||||
 | 
					        populatedThree = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else if(modeIdx < 5) {
 | 
				
			||||||
 | 
					      shape = selection.m_TwoShapeIndex;
 | 
				
			||||||
 | 
					      if(!populatedTwo) {
 | 
				
			||||||
 | 
					        PopulateTwoClustersForShape(pixels, shape, clusters);
 | 
				
			||||||
 | 
					        populatedTwo = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else if(!populatedOne) {
 | 
				
			||||||
 | 
					      clusters[0].Reset();
 | 
				
			||||||
 | 
					      for(uint32 i = 0; i < 16; i++) {
 | 
				
			||||||
 | 
					        clusters[0].AddPoint(RGBAVector(i, pixels[i]));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      populatedOne = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BitStream tmpStream(tmpBuf, 128, 0);
 | 
				
			||||||
 | 
					    double error = CompressionMode(mode).Compress(tmpStream, shape, clusters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(errors) errors[mode] = error;
 | 
				
			||||||
 | 
					    if(error < bestError) {
 | 
				
			||||||
 | 
					      memcpy(outBuf, tmpBuf, sizeof(tmpBuf));
 | 
				
			||||||
 | 
					      bestError = error;
 | 
				
			||||||
 | 
					      if(modeChosen)
 | 
				
			||||||
 | 
					        *modeChosen = mode;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void CompressBC7Block(const uint32 block[16], uint8 *outBuf,
 | 
					static void CompressBC7Block(const uint32 block[16], uint8 *outBuf,
 | 
				
			||||||
                             const CompressionSettings settings) {
 | 
					                             const CompressionSettings settings) {
 | 
				
			||||||
  // All a single color?
 | 
					  // All a single color?
 | 
				
			||||||
| 
						 | 
					@ -2007,15 +2036,11 @@ static void CompressBC7Block(const uint32 block[16], uint8 *outBuf,
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  RGBACluster blockCluster;
 | 
					  RGBACluster blockCluster;
 | 
				
			||||||
  bool opaque = true;
 | 
					 | 
				
			||||||
  bool transparent = true;
 | 
					  bool transparent = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for(uint32 i = 0; i < kMaxNumDataPoints; i++) {
 | 
					  for(uint32 i = 0; i < kMaxNumDataPoints; i++) {
 | 
				
			||||||
    RGBAVector p = RGBAVector(i, block[i]);
 | 
					    RGBAVector p = RGBAVector(i, block[i]);
 | 
				
			||||||
    blockCluster.AddPoint(p);
 | 
					    blockCluster.AddPoint(p);
 | 
				
			||||||
    if(fabs(p.A() - 255.0f) > 1e-10)
 | 
					 | 
				
			||||||
      opaque = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(p.A() > 0.0f)
 | 
					    if(p.A() > 0.0f)
 | 
				
			||||||
      transparent = false;
 | 
					      transparent = false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -2027,122 +2052,16 @@ static void CompressBC7Block(const uint32 block[16], uint8 *outBuf,
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // First we must figure out which shape to use. To do this, simply
 | 
					  ShapeSelectionFn selectionFn = BoxSelection;
 | 
				
			||||||
  // see which shape has the smallest sum of minimum bounding spheres.
 | 
					  if(settings.m_ShapeSelectionFn != NULL) {
 | 
				
			||||||
  double bestError[2] = { DBL_MAX, DBL_MAX };
 | 
					    selectionFn = settings.m_ShapeSelectionFn;
 | 
				
			||||||
  int bestShapeIdx[2] = { -1, -1 };
 | 
					 | 
				
			||||||
  RGBACluster bestClusters[2][3];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for(unsigned int i = 0; i < kNumShapes2; i++) {
 | 
					 | 
				
			||||||
    RGBACluster clusters[2];
 | 
					 | 
				
			||||||
    PopulateTwoClustersForShape(blockCluster, i, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    double err = 0.0;
 | 
					 | 
				
			||||||
    for(int ci = 0; ci < 2; ci++) {
 | 
					 | 
				
			||||||
      err += EstimateTwoClusterError(clusters[ci]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // If it's small, we'll take it!
 | 
					 | 
				
			||||||
    if(err < 1e-9) {
 | 
					 | 
				
			||||||
      CompressTwoClusters(i, clusters, outBuf, opaque);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(err < bestError[0]) {
 | 
					 | 
				
			||||||
      bestError[0] = err;
 | 
					 | 
				
			||||||
      bestShapeIdx[0] = i;
 | 
					 | 
				
			||||||
      bestClusters[0][0] = clusters[0];
 | 
					 | 
				
			||||||
      bestClusters[0][1] = clusters[1];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  assert(selectionFn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // There are not 3 subset blocks that support alpha, so only check these
 | 
					  ShapeSelection selection = selectionFn(0, 0, block);
 | 
				
			||||||
  // if the entire block is opaque.
 | 
					  selection.m_SelectedModes &= settings.m_BlockModes;
 | 
				
			||||||
  if(opaque) {
 | 
					  assert(selection.m_SelectedModes);
 | 
				
			||||||
    for(unsigned int i = 0; i < kNumShapes3; i++) {
 | 
					  CompressClusters(selection, block, outBuf, NULL, NULL);
 | 
				
			||||||
 | 
					 | 
				
			||||||
      RGBACluster clusters[3];
 | 
					 | 
				
			||||||
      PopulateThreeClustersForShape(blockCluster, i, clusters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      double err = 0.0;
 | 
					 | 
				
			||||||
      for(int ci = 0; ci < 3; ci++) {
 | 
					 | 
				
			||||||
        err += EstimateThreeClusterError(clusters[ci]);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // If it's small, we'll take it!
 | 
					 | 
				
			||||||
      if(err < 1e-9) {
 | 
					 | 
				
			||||||
        CompressThreeClusters(i, clusters, outBuf, opaque);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if(err < bestError[1]) {
 | 
					 | 
				
			||||||
        bestError[1] = err;
 | 
					 | 
				
			||||||
        bestShapeIdx[1] = i;
 | 
					 | 
				
			||||||
        bestClusters[1][0] = clusters[0];
 | 
					 | 
				
			||||||
        bestClusters[1][1] = clusters[1];
 | 
					 | 
				
			||||||
        bestClusters[1][2] = clusters[2];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint8 tempBuf1[16], tempBuf2[16];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  BitStream tempStream1 (tempBuf1, 128, 0);
 | 
					 | 
				
			||||||
  CompressionMode compressor(6, opaque);
 | 
					 | 
				
			||||||
  double best = compressor.Compress(tempStream1, 0, &blockCluster);
 | 
					 | 
				
			||||||
  if(best == 0.0f) {
 | 
					 | 
				
			||||||
    memcpy(outBuf, tempBuf1, 16);
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Check modes 4 and 5 if the block isn't opaque...
 | 
					 | 
				
			||||||
  if(!opaque) {
 | 
					 | 
				
			||||||
    for(int mode = 4; mode <= 5; mode++) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      BitStream tempStream2(tempBuf2, 128, 0);
 | 
					 | 
				
			||||||
      CompressionMode compressorTry(mode, opaque);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      double error = compressorTry.Compress(tempStream2, 0, &blockCluster);
 | 
					 | 
				
			||||||
      if(error < best) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        best = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(best == 0.0f) {
 | 
					 | 
				
			||||||
          memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          memcpy(tempBuf1, tempBuf2, 16);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  double error =
 | 
					 | 
				
			||||||
    CompressTwoClusters(bestShapeIdx[0], bestClusters[0], tempBuf2, opaque);
 | 
					 | 
				
			||||||
  if(error < best) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    best = error;
 | 
					 | 
				
			||||||
    if(error == 0.0f) {
 | 
					 | 
				
			||||||
      memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      memcpy(tempBuf1, tempBuf2, 16);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(opaque) {
 | 
					 | 
				
			||||||
    const double newError =
 | 
					 | 
				
			||||||
      CompressThreeClusters(bestShapeIdx[1],
 | 
					 | 
				
			||||||
                            bestClusters[1],
 | 
					 | 
				
			||||||
                            tempBuf2,
 | 
					 | 
				
			||||||
                            opaque);
 | 
					 | 
				
			||||||
    if(newError < best) {
 | 
					 | 
				
			||||||
      memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memcpy(outBuf, tempBuf1, 16);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static double EstimateTwoClusterErrorStats(
 | 
					static double EstimateTwoClusterErrorStats(
 | 
				
			||||||
| 
						 | 
					@ -2179,17 +2098,7 @@ static double EstimateTwoClusterErrorStats(
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  double error = 0.0001;
 | 
					  double error = 0.0001;
 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
  double eigOne = c.GetPrincipalEigenvalue();
 | 
					 | 
				
			||||||
  double eigTwo = c.GetSecondEigenvalue();
 | 
					 | 
				
			||||||
  if(eigOne != 0.0) {
 | 
					 | 
				
			||||||
    error += eigTwo / eigOne;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    error += 1.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  error += std::min(err1, err3);
 | 
					  error += std::min(err1, err3);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  return error;
 | 
					  return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2226,18 +2135,7 @@ static double EstimateThreeClusterErrorStats(
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  double error = 0.0001;
 | 
					  double error = 0.0001;
 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
  double eigOne = c.GetPrincipalEigenvalue();
 | 
					 | 
				
			||||||
  double eigTwo = c.GetSecondEigenvalue();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(eigOne != 0.0) {
 | 
					 | 
				
			||||||
    error += eigTwo / eigOne;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    error += 1.0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  error += std::min(err0, err2);
 | 
					  error += std::min(err0, err2);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  return error;
 | 
					  return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2364,31 +2262,19 @@ static void CompressBC7Block(
 | 
				
			||||||
        Min, Max, 4, 0xFEFEFEFE, RGBAVector(w[0], w[1], w[2], w[3])
 | 
					        Min, Max, 4, 0xFEFEFEFE, RGBAVector(w[0], w[1], w[2], w[3])
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      UpdateErrorEstimate(modeEstimate, 6, err);
 | 
					      UpdateErrorEstimate(modeEstimate, 6, err);
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
      double eigOne = blockCluster.GetPrincipalEigenvalue();
 | 
					 | 
				
			||||||
      double eigTwo = blockCluster.GetSecondEigenvalue();
 | 
					 | 
				
			||||||
      double error;
 | 
					 | 
				
			||||||
      if(eigOne != 0.0) {
 | 
					 | 
				
			||||||
        error = eigTwo / eigOne;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        error = 1.0;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      PrintStream(logStream, kBlockStatString[eBlockStat_SingleShapeEstimate], error);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // First we must figure out which shape to use. To do this, simply
 | 
					  // First we must figure out which shape to use. To do this, simply
 | 
				
			||||||
  // see which shape has the smallest sum of minimum bounding spheres.
 | 
					  // see which shape has the smallest sum of minimum bounding spheres.
 | 
				
			||||||
  double bestError[2] = { DBL_MAX, DBL_MAX };
 | 
					  double bestError[2] = { DBL_MAX, DBL_MAX };
 | 
				
			||||||
  int bestShapeIdx[2] = { -1, -1 };
 | 
					
 | 
				
			||||||
  RGBACluster bestClusters[2][3];
 | 
					  ShapeSelection selection;
 | 
				
			||||||
 | 
					  uint32 path = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for(unsigned int i = 0; i < kNumShapes2; i++) {
 | 
					  for(unsigned int i = 0; i < kNumShapes2; i++) {
 | 
				
			||||||
    RGBACluster clusters[2];
 | 
					    RGBACluster clusters[2];
 | 
				
			||||||
    PopulateTwoClustersForShape(blockCluster, i, clusters);
 | 
					    PopulateTwoClustersForShape(block, i, clusters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    double err = 0.0;
 | 
					    double err = 0.0;
 | 
				
			||||||
    double errEstimate[2] = { -1.0, -1.0 };
 | 
					    double errEstimate[2] = { -1.0, -1.0 };
 | 
				
			||||||
| 
						 | 
					@ -2407,10 +2293,6 @@ static void CompressBC7Block(
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
    err /= 2.0;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(errEstimate[0] != -1.0) {
 | 
					    if(errEstimate[0] != -1.0) {
 | 
				
			||||||
      UpdateErrorEstimate(modeEstimate, 1, errEstimate[0]);
 | 
					      UpdateErrorEstimate(modeEstimate, 1, errEstimate[0]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -2427,21 +2309,15 @@ static void CompressBC7Block(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If it's small, we'll take it!
 | 
					    // If it's small, we'll take it!
 | 
				
			||||||
    if(err < 1e-9) {
 | 
					    if(err < 1e-9) {
 | 
				
			||||||
      int modeChosen;
 | 
					      path = 2;
 | 
				
			||||||
      CompressTwoClusters(
 | 
					      selection.m_TwoShapeIndex = i;
 | 
				
			||||||
        i, clusters, outBuf, opaque, modeError, &modeChosen
 | 
					      selection.m_SelectedModes = kTwoPartitionModes;
 | 
				
			||||||
      );
 | 
					      break;
 | 
				
			||||||
      bestMode = modeChosen;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      PrintStat(logStream, kBlockStatString[eBlockStat_Path], 2);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(err < bestError[0]) {
 | 
					    if(err < bestError[0]) {
 | 
				
			||||||
      bestError[0] = err;
 | 
					      bestError[0] = err;
 | 
				
			||||||
      bestShapeIdx[0] = i;
 | 
					      selection.m_TwoShapeIndex = i;
 | 
				
			||||||
      bestClusters[0][0] = clusters[0];
 | 
					 | 
				
			||||||
      bestClusters[0][1] = clusters[1];
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2451,7 +2327,7 @@ static void CompressBC7Block(
 | 
				
			||||||
    for(unsigned int i = 0; i < kNumShapes3; i++) {
 | 
					    for(unsigned int i = 0; i < kNumShapes3; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      RGBACluster clusters[3];
 | 
					      RGBACluster clusters[3];
 | 
				
			||||||
      PopulateThreeClustersForShape(blockCluster, i, clusters);
 | 
					      PopulateThreeClustersForShape(block, i, clusters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      double err = 0.0;
 | 
					      double err = 0.0;
 | 
				
			||||||
      double errEstimate[2] = { -1.0, -1.0 };
 | 
					      double errEstimate[2] = { -1.0, -1.0 };
 | 
				
			||||||
| 
						 | 
					@ -2470,10 +2346,6 @@ static void CompressBC7Block(
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
 | 
					 | 
				
			||||||
      err /= 3.0;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if(errEstimate[0] != -1.0) {
 | 
					      if(errEstimate[0] != -1.0) {
 | 
				
			||||||
        UpdateErrorEstimate(modeEstimate, 0, errEstimate[0]);
 | 
					        UpdateErrorEstimate(modeEstimate, 0, errEstimate[0]);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -2490,94 +2362,26 @@ static void CompressBC7Block(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // If it's small, we'll take it!
 | 
					      // If it's small, we'll take it!
 | 
				
			||||||
      if(err < 1e-9) {
 | 
					      if(err < 1e-9) {
 | 
				
			||||||
        int modeChosen;
 | 
					        path = 2;
 | 
				
			||||||
        CompressThreeClusters(
 | 
					        selection.m_TwoShapeIndex = i;
 | 
				
			||||||
          i, clusters, outBuf, opaque, modeError, &modeChosen
 | 
					        selection.m_SelectedModes = kThreePartitionModes;
 | 
				
			||||||
        );
 | 
					        break;
 | 
				
			||||||
        bestMode = modeChosen;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PrintStat(logStream, kBlockStatString[eBlockStat_Path], 2);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(err < bestError[1]) {
 | 
					      if(err < bestError[1]) {
 | 
				
			||||||
        bestError[1] = err;
 | 
					        bestError[1] = err;
 | 
				
			||||||
        bestShapeIdx[1] = i;
 | 
					        selection.m_ThreeShapeIndex = i;
 | 
				
			||||||
        bestClusters[1][0] = clusters[0];
 | 
					 | 
				
			||||||
        bestClusters[1][1] = clusters[1];
 | 
					 | 
				
			||||||
        bestClusters[1][2] = clusters[2];
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PrintStat(logStream, kBlockStatString[eBlockStat_Path], 3);
 | 
					  if(path == 0) path = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint8 tempBuf1[16], tempBuf2[16];
 | 
					  selection.m_SelectedModes &= settings.m_BlockModes;
 | 
				
			||||||
 | 
					  assert(selection.m_SelectedModes);
 | 
				
			||||||
 | 
					  CompressClusters(selection, block, outBuf, modeError, &bestMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BitStream tempStream1 (tempBuf1, 128, 0);
 | 
					  PrintStat(logStream, kBlockStatString[eBlockStat_Path], path);
 | 
				
			||||||
  CompressionMode compressor(6, opaque);
 | 
					 | 
				
			||||||
  double best = compressor.Compress(tempStream1, 0, &blockCluster);
 | 
					 | 
				
			||||||
  modeError[6] = best;
 | 
					 | 
				
			||||||
  bestMode = 6;
 | 
					 | 
				
			||||||
  if(best == 0.0f) {
 | 
					 | 
				
			||||||
    memcpy(outBuf, tempBuf1, 16);
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Check modes 4 and 5 if the block isn't opaque...
 | 
					 | 
				
			||||||
  if(!opaque) {
 | 
					 | 
				
			||||||
    for(int mode = 4; mode <= 5; mode++) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      BitStream tempStream2(tempBuf2, 128, 0);
 | 
					 | 
				
			||||||
      CompressionMode compressorTry(mode, opaque);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      double error = compressorTry.Compress(tempStream2, 0, &blockCluster);
 | 
					 | 
				
			||||||
      if(error < best) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bestMode = mode;
 | 
					 | 
				
			||||||
        best = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(best == 0.0f) {
 | 
					 | 
				
			||||||
          memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          memcpy(tempBuf1, tempBuf2, 16);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int modeChosen;
 | 
					 | 
				
			||||||
  double error = CompressTwoClusters(
 | 
					 | 
				
			||||||
    bestShapeIdx[0], bestClusters[0], tempBuf2, opaque, modeError, &modeChosen
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  if(error < best) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bestMode = modeChosen;
 | 
					 | 
				
			||||||
    best = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(error == 0.0f) {
 | 
					 | 
				
			||||||
      memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      memcpy(tempBuf1, tempBuf2, 16);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(opaque) {
 | 
					 | 
				
			||||||
    const double newError = CompressThreeClusters(
 | 
					 | 
				
			||||||
      bestShapeIdx[1], bestClusters[1],
 | 
					 | 
				
			||||||
      tempBuf2, opaque, modeError, &modeChosen
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    if(newError < best) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      bestMode = modeChosen;
 | 
					 | 
				
			||||||
      memcpy(outBuf, tempBuf2, 16);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memcpy(outBuf, tempBuf1, 16);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void DecompressBC7Block(const uint8 block[16], uint32 outBuf[16]) {
 | 
					static void DecompressBC7Block(const uint8 block[16], uint32 outBuf[16]) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,6 +177,8 @@ public:
 | 
				
			||||||
  bool AllSamePoint() const { return m_Max == m_Min; }
 | 
					  bool AllSamePoint() const { return m_Max == m_Min; }
 | 
				
			||||||
  int GetPointBitString() const { return m_PointBitString; }
 | 
					  int GetPointBitString() const { return m_PointBitString; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void Reset() { *this = RGBACluster(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  // The number of points in the cluster.
 | 
					  // The number of points in the cluster.
 | 
				
			||||||
  uint32 m_NumPoints;
 | 
					  uint32 m_NumPoints;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue