/*-------------------------------------------------------------------------
 * drawElements Internal Test Module
 * ---------------------------------
 *
 * Copyright 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief ASTC tests.
 *//*--------------------------------------------------------------------*/

#include "ditAstcTests.hpp"

#include "tcuCompressedTexture.hpp"
#include "tcuAstcUtil.hpp"

#include "deUniquePtr.hpp"
#include "deStringUtil.hpp"

namespace dit
{

using std::string;
using std::vector;
using namespace tcu;

namespace
{

class AstcCase : public tcu::TestCase
{
public:
								AstcCase		(tcu::TestContext& testCtx, CompressedTexFormat format);

	IterateResult				iterate			(void);

private:
	const CompressedTexFormat	m_format;
};

static const string getASTCFormatShortName (CompressedTexFormat format)
{
	DE_ASSERT(isAstcFormat(format));
	const IVec3 blockSize = getBlockPixelSize(format);
	DE_ASSERT(blockSize.z() == 1);

	return de::toString(blockSize.x()) + "x" + de::toString(blockSize.y()) + (tcu::isAstcSRGBFormat(format) ? "_srgb" : "");
}

AstcCase::AstcCase (tcu::TestContext& testCtx, CompressedTexFormat format)
	: tcu::TestCase	(testCtx, getASTCFormatShortName(format).c_str(), "")
	, m_format		(format)
{
}

void testDecompress (CompressedTexFormat format, size_t numBlocks, const deUint8* data)
{
	const IVec3			blockPixelSize		= getBlockPixelSize(format);

	for (int astcModeNdx = 0; astcModeNdx < TexDecompressionParams::ASTCMODE_LAST; astcModeNdx++)
	{
		const TexDecompressionParams	decompressionParams		((TexDecompressionParams::AstcMode)astcModeNdx);
		const TextureFormat				uncompressedFormat		= getUncompressedFormat(format);
		TextureLevel					texture					(uncompressedFormat, blockPixelSize.x()*(int)numBlocks, blockPixelSize.y());

		decompress(texture.getAccess(), format, data, decompressionParams);
	}
}

void verifyBlocksValid (CompressedTexFormat format, TexDecompressionParams::AstcMode mode, size_t numBlocks, const deUint8* data)
{
	for (size_t blockNdx = 0; blockNdx < numBlocks; blockNdx++)
		TCU_CHECK(astc::isValidBlock(data + blockNdx*astc::BLOCK_SIZE_BYTES, format, mode));
}

inline size_t getNumBlocksFromBytes (size_t numBytes)
{
	TCU_CHECK(numBytes % astc::BLOCK_SIZE_BYTES == 0);
	return (numBytes / astc::BLOCK_SIZE_BYTES);
}

AstcCase::IterateResult AstcCase::iterate (void)
{
	vector<deUint8> generatedData;

	// Verify that can generate & decode data with all BlockTestType's
	for (int blockTestTypeNdx = 0; blockTestTypeNdx < astc::BLOCK_TEST_TYPE_LAST; blockTestTypeNdx++)
	{
		const astc::BlockTestType	blockTestType	= (const astc::BlockTestType)blockTestTypeNdx;

		if (astc::isBlockTestTypeHDROnly(blockTestType) && isAstcSRGBFormat(m_format))
			continue;

		generatedData.clear();
		astc::generateBlockCaseTestData(generatedData, m_format, blockTestType);

		testDecompress(m_format, getNumBlocksFromBytes(generatedData.size()), &generatedData[0]);

		// All but random case should generate only valid blocks
		if (blockTestType != astc::BLOCK_TEST_TYPE_RANDOM)
		{
			verifyBlocksValid(m_format, TexDecompressionParams::ASTCMODE_HDR, getNumBlocksFromBytes(generatedData.size()), &generatedData[0]);

			if (!astc::isBlockTestTypeHDROnly(blockTestType))
				verifyBlocksValid(m_format, TexDecompressionParams::ASTCMODE_LDR, getNumBlocksFromBytes(generatedData.size()), &generatedData[0]);
		}
	}

	// Verify generating void extent blocks (format-independent)
	{
		const size_t		numBlocks		= 1024;

		generatedData.resize(numBlocks*astc::BLOCK_SIZE_BYTES);
		astc::generateDummyVoidExtentBlocks(&generatedData[0], numBlocks);

		testDecompress(m_format, numBlocks, &generatedData[0]);

		verifyBlocksValid(m_format, TexDecompressionParams::ASTCMODE_LDR, numBlocks, &generatedData[0]);
		verifyBlocksValid(m_format, TexDecompressionParams::ASTCMODE_HDR, numBlocks, &generatedData[0]);
	}

	// Verify generating dummy normal blocks
	{
		const size_t		numBlocks			= 1024;
		const IVec3			blockPixelSize		= getBlockPixelSize(m_format);

		generatedData.resize(numBlocks*astc::BLOCK_SIZE_BYTES);
		astc::generateDummyNormalBlocks(&generatedData[0], numBlocks, blockPixelSize.x(), blockPixelSize.y());

		testDecompress(m_format, numBlocks, &generatedData[0]);

		verifyBlocksValid(m_format, TexDecompressionParams::ASTCMODE_LDR, numBlocks, &generatedData[0]);
		verifyBlocksValid(m_format, TexDecompressionParams::ASTCMODE_HDR, numBlocks, &generatedData[0]);
	}

	// Verify generating random valid blocks
	for (int astcModeNdx = 0; astcModeNdx < TexDecompressionParams::ASTCMODE_LAST; astcModeNdx++)
	{
		const TexDecompressionParams::AstcMode	mode		= (TexDecompressionParams::AstcMode)astcModeNdx;
		const size_t							numBlocks	= 1024;

		generatedData.resize(numBlocks*astc::BLOCK_SIZE_BYTES);
		astc::generateRandomValidBlocks(&generatedData[0], numBlocks, m_format, mode, deInt32Hash(m_format) ^ deInt32Hash(mode));

		testDecompress(m_format, numBlocks, &generatedData[0]);

		verifyBlocksValid(m_format, mode, numBlocks, &generatedData[0]);
	}

	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "All checks passed");
	return STOP;
}

} // anonymous

tcu::TestCaseGroup* createAstcTests (tcu::TestContext& testCtx)
{
	de::MovePtr<tcu::TestCaseGroup>	astcTests	(new tcu::TestCaseGroup(testCtx, "astc", "Tests for ASTC Utilities"));

	for (int formatNdx = 0; formatNdx < COMPRESSEDTEXFORMAT_LAST; formatNdx++)
	{
		const CompressedTexFormat	format	= (CompressedTexFormat)formatNdx;

		if (isAstcFormat(format))
			astcTests->addChild(new AstcCase(testCtx, format));
	}

	return astcTests.release();
}

} // dit
