210 lines
8.4 KiB
C++

//===============================================================================
// Copyright (c) 2007-2016 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2004-2006 ATI Technologies Inc.
//===============================================================================
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef _BC7_ENCODE_H_
#define _BC7_ENCODE_H_
#include <float.h>
#include "bc7_definitions.h"
#include "debug.h"
#include "cmp_core.h"
#include <mutex>
// Threshold quality below which we will always run fast quality and shaking
// Self note: User should be able to set this?
extern double g_qFAST_THRESHOLD;
extern double g_HIGHQULITY_THRESHOLD;
class BC7BlockEncoder {
public:
BC7BlockEncoder(CMP_DWORD validModeMask,
CMP_BOOL imageNeedsAlpha,
double quality,
CMP_BOOL colourRestrict,
CMP_BOOL alphaRestrict,
double performance = 1.0
) {
// Bug check : ModeMask must be > 0
if (validModeMask <= 0)
m_validModeMask = 0xCF;
else
m_validModeMask = validModeMask;
m_quality = cmp_minT(1.0, cmp_maxT(quality, 0.0));
m_performance = cmp_minT(1.0, cmp_maxT(performance, 0.0));
m_imageNeedsAlpha = imageNeedsAlpha;
m_smallestError = DBL_MAX;
m_largestError = 0.0;
m_colourRestrict = colourRestrict;
m_alphaRestrict = alphaRestrict;
m_quantizerRangeThreshold = 255 * m_performance;
if(m_quality < g_qFAST_THRESHOLD) { // Make sure this is below 0.5 since we are x2 below.
m_shakerRangeThreshold = 0.;
// Scale m_quality to be a linar range 0 to 1 in this section
// to maximize quality with fast performance...
m_errorThreshold = 256. * (1.0 - ((m_quality*2.0)/g_qFAST_THRESHOLD));
// Limit the size of the partition search space based on Quality
m_partitionSearchSize = cmp_maxT( (1.0/16.0), ((m_quality*2.0) / g_qFAST_THRESHOLD));
} else {
// m_qaulity = set the quality user want to see on encoding
// higher values will produce better encoding results.
// m_performance - sets a perfoamce level for a specified quality level
if(m_quality < g_HIGHQULITY_THRESHOLD) {
m_shakerRangeThreshold = 255 * (m_quality / 10); // gain performance within FAST_THRESHOLD and HIGHQULITY_THRESHOLD range
m_errorThreshold = 256. * (1.0 - (m_quality/g_qFAST_THRESHOLD));
// Limit the size of the partition search space based on Quality
m_partitionSearchSize = cmp_maxT( (1.0/16.0), (m_quality / g_qFAST_THRESHOLD));
} else {
m_shakerRangeThreshold = 255 * m_quality; // lowers performance with incresing values
m_errorThreshold = 0; // Dont exit early
m_partitionSearchSize = 1.0; // use all partitions for best quality
}
}
#ifdef USE_DBGTRACE
DbgTrace(("shakerRangeThreshold [%3.3f] errorThreshold [%3.3f] partitionSearchSize [%3.3f]",m_shakerRangeThreshold,m_errorThreshold,m_partitionSearchSize));
#endif
};
~BC7BlockEncoder() {
#ifdef USE_DBGTRACE
DbgTrace(("Smallest Error %f", (float)m_smallestError));
DbgTrace(("Largest Error %f", (float)m_largestError));
#endif
};
// This routine compresses a block and returns the RMS error
double CompressBlock(double in[MAX_SUBSET_SIZE][MAX_DIMENSION_BIG],
CMP_BYTE out[COMPRESSED_BLOCK_SIZE]);
private:
double quant_single_point_d(
double data[MAX_ENTRIES][MAX_DIMENSION_BIG],
int numEntries, int index[MAX_ENTRIES],
double out[MAX_ENTRIES][MAX_DIMENSION_BIG],
int epo_1[2][MAX_DIMENSION_BIG],
int Mi_, // last cluster
int bits[3], // including parity
int type,
int dimension
);
double ep_shaker_2_d(
double data[MAX_ENTRIES][MAX_DIMENSION_BIG],
int numEntries,
int index_[MAX_ENTRIES],
double out[MAX_ENTRIES][MAX_DIMENSION_BIG],
int epo_code[2][MAX_DIMENSION_BIG],
int size,
int Mi_, // last cluster
int bits, // total for all channels
// defined by total numbe of bits and dimensioin
int dimension,
double epo[2][MAX_DIMENSION_BIG]
);
double ep_shaker_d(
double data[MAX_ENTRIES][MAX_DIMENSION_BIG],
int numEntries,
int index_[MAX_ENTRIES],
double out[MAX_ENTRIES][MAX_DIMENSION_BIG],
int epo_code[2][MAX_DIMENSION_BIG],
int Mi_, // last cluster
int bits[3], // including parity
CMP_qt_cpu type,
int dimension
);
void BlockSetup(CMP_DWORD blockMode);
void EncodeSingleIndexBlock(CMP_DWORD blockMode,
CMP_DWORD partition,
CMP_DWORD colour[MAX_SUBSETS][2],
int indices[MAX_SUBSETS][MAX_SUBSET_SIZE],
CMP_BYTE block[COMPRESSED_BLOCK_SIZE]);
// This routine compresses a block to any of the single index modes
double CompressSingleIndexBlock(double in[MAX_SUBSET_SIZE][MAX_DIMENSION_BIG],
CMP_BYTE out[COMPRESSED_BLOCK_SIZE],
CMP_DWORD blockMode);
void EncodeDualIndexBlock(CMP_DWORD blockMode,
CMP_DWORD indexSelection,
CMP_DWORD componentRotation,
int endpoint[2][2][MAX_DIMENSION_BIG],
int indices[2][MAX_SUBSET_SIZE],
CMP_BYTE out[COMPRESSED_BLOCK_SIZE]);
// This routine compresses a block to any of the dual index modes
double CompressDualIndexBlock(double in[MAX_SUBSET_SIZE][MAX_DIMENSION_BIG],
CMP_BYTE out[COMPRESSED_BLOCK_SIZE],
CMP_DWORD blockMode);
// Bulky temporary data used during compression of a block
int m_storedIndices[MAX_PARTITIONS][MAX_SUBSETS][MAX_SUBSET_SIZE];
double m_storedError[MAX_PARTITIONS];
int m_sortedModes[MAX_PARTITIONS];
// This stores the min and max for the components of the block, and the ranges
double m_blockMin[MAX_DIMENSION_BIG];
double m_blockMax[MAX_DIMENSION_BIG];
double m_blockRange[MAX_DIMENSION_BIG];
double m_blockMaxRange;
// These are quality parameters used to select when to use the high precision quantizer
// and shaker paths
double m_quantizerRangeThreshold;
double m_shakerRangeThreshold;
double m_partitionSearchSize;
// Global data setup at initialisation time
double m_quality;
double m_performance;
double m_errorThreshold;
CMP_DWORD m_validModeMask;
CMP_BOOL m_imageNeedsAlpha;
CMP_BOOL m_colourRestrict;
CMP_BOOL m_alphaRestrict;
// Data for compressing a particular block mode
CMP_DWORD m_parityBits;
CMP_DWORD m_clusters[2];
CMP_DWORD m_componentBits[MAX_DIMENSION_BIG];
// Error stats
double m_smallestError;
double m_largestError;
};
#endif