u64 TextureCacheBase::TCacheEntryBase::CalculateHash() const
{
	u8* ptr = Memory::GetPointer(addr);
	if (memory_stride == BytesPerRow())
	{
		return GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples);
	}
	else
	{
		u32 blocks = NumBlocksY();
		u64 temp_hash = size_in_bytes;

		u32 samples_per_row = 0;
		if (g_ActiveConfig.iSafeTextureCache_ColorSamples != 0)
		{
			// Hash at least 4 samples per row to avoid hashing in a bad pattern, like just on the left side of the efb copy
			samples_per_row = std::max(g_ActiveConfig.iSafeTextureCache_ColorSamples / blocks, 4u);
		}

		for (u32 i = 0; i < blocks; i++)
		{
			// Multiply by a prime number to mix the hash up a bit. This prevents identical blocks from canceling each other out
			temp_hash = (temp_hash * 397) ^ GetHash64(ptr, BytesPerRow(), samples_per_row);
			ptr += memory_stride;
		}
		return temp_hash;
	}
}
void TextureCacheBase::TCacheEntryBase::SetEfbCopy(u32 stride)
{
	is_efb_copy = true;
	memory_stride = stride;

	_assert_msg_(VIDEO, memory_stride >= BytesPerRow(), "Memory stride is too small");

	size_in_bytes = memory_stride * NumBlocksY();
}
/// Downsampler::Downsample
void Downsampler::Downsample(UBYTE **&data,class ImageLayout *src)
{
  UWORD i;
  // Delete the old image components. Does not release the
  // memory we hold.
  delete[] m_pComponent;
  m_pComponent  = NULL;
  ReleaseComponents(data);
  //
  if (m_bChromaOnly) {
    m_ulWidth     = src->WidthOf();
    m_ulHeight    = src->HeightOf();
  } else { 
    m_ulWidth     = (src->WidthOf()  + m_ucScaleX - 1) / m_ucScaleX;
    m_ulHeight    = (src->HeightOf() + m_ucScaleY - 1) / m_ucScaleY;
  }
  //
  m_usDepth     = src->DepthOf();
  m_pComponent  = new struct ComponentLayout[m_usDepth];
  //
  // Initialize component dimensions.
  for(i = 0; i < m_usDepth; i++) {
    if (m_bChromaOnly == false || i > 0) { 
      m_pComponent[i].m_ulWidth  = (src->WidthOf(i)  + m_ucScaleX - 1) / m_ucScaleX;
      m_pComponent[i].m_ulHeight = (src->HeightOf(i) + m_ucScaleY - 1) / m_ucScaleY;
    } else {
      m_pComponent[i].m_ulWidth  = src->WidthOf(i);
      m_pComponent[i].m_ulHeight = src->HeightOf(i);
    }
    m_pComponent[i].m_ucBits   = src->BitsOf(i);
    m_pComponent[i].m_bSigned  = src->isSigned(i);
    m_pComponent[i].m_bFloat   = src->isFloat(i);
    if (m_bChromaOnly && i > 0) { 
      m_pComponent[i].m_ucSubX   = src->SubXOf(i) * m_ucScaleX;
      m_pComponent[i].m_ucSubY   = src->SubYOf(i) * m_ucScaleY;
    } else {
      m_pComponent[i].m_ucSubX   = src->SubXOf(i);
      m_pComponent[i].m_ucSubY   = src->SubYOf(i);
    }
  }
  //
  data = new UBYTE *[m_usDepth];
  memset(data,0,sizeof(UBYTE *) * m_usDepth);
  //
  for(i = 0;i < m_usDepth;i++) {
    UBYTE bps = (m_pComponent[i].m_ucBits + 7) >> 3;
    if (m_pComponent[i].m_bFloat && m_pComponent[i].m_ucBits == 16)
      bps = sizeof(FLOAT); // stored as float
    //
    data[i]                           = new UBYTE[m_pComponent[i].m_ulWidth * m_pComponent[i].m_ulHeight * bps];
    m_pComponent[i].m_ulBytesPerPixel = bps;
    m_pComponent[i].m_ulBytesPerRow   = bps * m_pComponent[i].m_ulWidth;
    m_pComponent[i].m_pPtr            = data[i];
  }
  //
  for(i = 0;i < m_usDepth;i++) {
    UBYTE sx,sy;
    //
    if (m_bChromaOnly == false || i > 0) { 
      sx = m_ucScaleX;
      sy = m_ucScaleY;
    } else {
      sx = 1;
      sy = 1;
    }
    //
    if (isSigned(i)) {
      if (BitsOf(i) <= 8) {
	BoxFilter<BYTE>((BYTE *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			(BYTE *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			src->WidthOf(i),src->HeightOf(i),
			BYTE(-1UL << (BitsOf(i) - 1)),BYTE((1UL << (BitsOf(i) - 1)) - 1),
			sx,sy);
      } else if (!isFloat(i) && BitsOf(i) <= 16) {
	BoxFilter<WORD>((WORD *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			(WORD *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			src->WidthOf(i),src->HeightOf(i),
			WORD(-1UL << (BitsOf(i) - 1)),WORD((1UL << (BitsOf(i) - 1)) - 1),
			sx,sy);
      } else if (!isFloat(i) && BitsOf(i) <= 32) {
	BoxFilter<LONG>((LONG *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			(LONG *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			src->WidthOf(i),src->HeightOf(i),
			LONG(-1UL << (BitsOf(i) - 1)),LONG((1UL << (BitsOf(i) - 1)) - 1),
			sx,sy);
      } else if (isFloat(i) && BitsOf(i) <= 32) {
	BoxFilter<FLOAT>((FLOAT *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			(FLOAT *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			 src->WidthOf(i),src->HeightOf(i),
			 -HUGE_VAL,HUGE_VAL,
			 sx,sy);
      } else if (isFloat(i) && BitsOf(i) == 64) {
	BoxFilter<DOUBLE>((DOUBLE *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			  (DOUBLE *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			  src->WidthOf(i),src->HeightOf(i),
			  -HUGE_VAL,HUGE_VAL,
			  sx,sy);
      } else {
	throw "unsupported data type";
      }
    } else {
      if (BitsOf(i) <= 8) {
	BoxFilter<UBYTE>((UBYTE *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			(UBYTE *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			 src->WidthOf(i),src->HeightOf(i),
			 0,UBYTE((1UL << BitsOf(i)) - 1),
			 sx,sy);
      } else if (!isFloat(i) && BitsOf(i) <= 16) {
	BoxFilter<UWORD>((UWORD *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			 (UWORD *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			 src->WidthOf(i),src->HeightOf(i),
			 0,UWORD((1UL << BitsOf(i)) - 1),
			 sx,sy);
      } else if (!isFloat(i) && BitsOf(i) <= 32) {
	BoxFilter<ULONG>((ULONG *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			 (ULONG *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			 src->WidthOf(i),src->HeightOf(i),
			 0,LONG((1UL << BitsOf(i)) - 1),
			 sx,sy);
      } else if (isFloat(i) && BitsOf(i) <= 32) {
	BoxFilter<FLOAT>((FLOAT *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			(FLOAT *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			 src->WidthOf(i),src->HeightOf(i),
			 0.0,HUGE_VAL,
			 sx,sy);
      } else if (isFloat(i) && BitsOf(i) == 64) {
	BoxFilter<DOUBLE>((DOUBLE *)src->DataOf(i),src->BytesPerPixel(i),src->BytesPerRow(i),
			  (DOUBLE *)DataOf(i),BytesPerPixel(i),BytesPerRow(i),
			  src->WidthOf(i),src->HeightOf(i),
			  0.0,HUGE_VAL,
			  sx,sy);
      } else {
	throw "unsupported data type";
      }
    }
  }
  //
  Swap(*src);
}