/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 3.0 Module
 * -------------------------------------------------
 *
 * Copyright 2014 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 Internal Format Query tests.
 *//*--------------------------------------------------------------------*/

#include "es3fInternalFormatQueryTests.hpp"
#include "glsStateQueryUtil.hpp"
#include "es3fApiCase.hpp"
#include "gluRenderContext.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "deMath.h"

using namespace glw; // GLint and other GL types
using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard;

namespace deqp
{
namespace gles3
{
namespace Functional
{
namespace
{

class SamplesCase : public ApiCase
{
public:
	SamplesCase(Context& context, const char* name, const char* description, GLenum internalFormat, bool isIntegerInternalFormat)
		: ApiCase					(context, name, description)
		, m_internalFormat			(internalFormat)
		, m_isIntegerInternalFormat	(isIntegerInternalFormat)
	{
	}

	void test (void)
	{
		using tcu::TestLog;

		StateQueryMemoryWriteGuard<GLint> sampleCounts;
		glGetInternalformativ(GL_RENDERBUFFER, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCounts);
		expectError(GL_NO_ERROR);

		if (!sampleCounts.verifyValidity(m_testCtx))
			return;

		m_testCtx.getLog() << TestLog::Message << "// sample counts is " << sampleCounts << TestLog::EndMessage;

		if (sampleCounts == 0)
			return;

		std::vector<GLint> samples;
		samples.resize(sampleCounts, -1);
		glGetInternalformativ(GL_RENDERBUFFER, m_internalFormat, GL_SAMPLES, sampleCounts, &samples[0]);
		expectError(GL_NO_ERROR);

		GLint prevSampleCount = 0;
		GLint sampleCount = 0;
		for (size_t ndx = 0; ndx < samples.size(); ++ndx, prevSampleCount = sampleCount)
		{
			sampleCount = samples[ndx];

			// sample count must be > 0
			if (sampleCount <= 0)
			{
				m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected sample count to be at least one; got " << sampleCount << TestLog::EndMessage;
				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
			}

			// samples must be ordered descending
			if (ndx != 0 && !(sampleCount < prevSampleCount))
			{
				m_testCtx.getLog() << TestLog::Message
					<< "// ERROR: Expected sample count to be ordered in descending order;"
					<< "got " << prevSampleCount << " at index " << (ndx - 1) << ", and " << sampleCount << " at index " << ndx << TestLog::EndMessage;
				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid order");
			}
		}

		if (!m_isIntegerInternalFormat)
		{
			// the maximum value in SAMPLES is guaranteed to be at least the value of MAX_SAMPLES
			StateQueryMemoryWriteGuard<GLint> maxSamples;
			glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
			expectError(GL_NO_ERROR);

			if (maxSamples.verifyValidity(m_testCtx))
			{
				const GLint maximumFormatSampleCount = samples[0];
				if (!(maximumFormatSampleCount >= maxSamples))
				{
					m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected maximum value in SAMPLES (" << maximumFormatSampleCount << ") to be at least the value of MAX_SAMPLES (" << maxSamples << ")" << TestLog::EndMessage;
					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid maximum sample count");
				}
		  }
		}
	}

private:
	const GLenum	m_internalFormat;
	const bool		m_isIntegerInternalFormat;
};

class SamplesBufferSizeCase : public ApiCase
{
public:
	SamplesBufferSizeCase(Context& context, const char* name, const char* description, GLenum internalFormat)
		: ApiCase			(context, name, description)
		, m_internalFormat	(internalFormat)
	{
	}

	void test (void)
	{
		using tcu::TestLog;

		StateQueryMemoryWriteGuard<GLint> sampleCounts;
		glGetInternalformativ(GL_RENDERBUFFER, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCounts);
		expectError(GL_NO_ERROR);

		if (!sampleCounts.verifyValidity(m_testCtx))
			return;

		// test with bufSize = 0
		GLint queryTargetValue = -1;
		glGetInternalformativ(GL_RENDERBUFFER, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 0, &queryTargetValue);
		expectError(GL_NO_ERROR);

		if (queryTargetValue != -1)
		{
			m_testCtx.getLog() << TestLog::Message << "// ERROR: Expected output variable not to be written to." << TestLog::EndMessage;
			if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid write");
		}
	}

private:
	GLenum m_internalFormat;
};

} // anonymous


InternalFormatQueryTests::InternalFormatQueryTests (Context& context)
	: TestCaseGroup(context, "internal_format", "Internal Format Query tests.")
{
}

void InternalFormatQueryTests::init (void)
{
	const struct InternalFormat
	{
		const char*	name;
		GLenum		format;
		bool		isIntegerFormat;
	} internalFormats[] =
	{
		// color renderable and unsized
		// \note These unsized formats seem to allowed by the spec, but they are not useful in any way. (You can't create a renderbuffer with such internalFormat)
		{ "rgba",					GL_RGBA,				false	},
		{ "rgb",					GL_RGB,					false	},

		// color renderable
		{ "r8",						GL_R8,					false	},
		{ "rg8",					GL_RG8,					false	},
		{ "rgb8",					GL_RGB8,				false	},
		{ "rgb565",					GL_RGB565,				false	},
		{ "rgba4",					GL_RGBA4,				false	},
		{ "rgb5_a1",				GL_RGB5_A1,				false	},
		{ "rgba8",					GL_RGBA8,				false	},
		{ "rgb10_a2",				GL_RGB10_A2,			false	},
		{ "rgb10_a2ui",				GL_RGB10_A2UI,			true	},
		{ "srgb8_alpha8",			GL_SRGB8_ALPHA8,		false	},
		{ "r8i",					GL_R8I,					true	},
		{ "r8ui",					GL_R8UI,				true	},
		{ "r16i",					GL_R16I,				true	},
		{ "r16ui",					GL_R16UI,				true	},
		{ "r32i",					GL_R32I,				true	},
		{ "r32ui",					GL_R32UI,				true	},
		{ "rg8i",					GL_RG8I,				true	},
		{ "rg8ui",					GL_RG8UI,				true	},
		{ "rg16i",					GL_RG16I,				true	},
		{ "rg16ui",					GL_RG16UI,				true	},
		{ "rg32i",					GL_RG32I,				true	},
		{ "rg32ui",					GL_RG32UI,				true	},
		{ "rgba8i",					GL_RGBA8I,				true	},
		{ "rgba8ui",				GL_RGBA8UI,				true	},
		{ "rgba16i",				GL_RGBA16I,				true	},
		{ "rgba16ui",				GL_RGBA16UI,			true	},
		{ "rgba32i",				GL_RGBA32I,				true	},
		{ "rgba32ui",				GL_RGBA32UI,			true	},

		// depth renderable
		{ "depth_component16",		GL_DEPTH_COMPONENT16,	false	},
		{ "depth_component24",		GL_DEPTH_COMPONENT24,	false	},
		{ "depth_component32f",		GL_DEPTH_COMPONENT32F,	false	},
		{ "depth24_stencil8",		GL_DEPTH24_STENCIL8,	false	},
		{ "depth32f_stencil8",		GL_DEPTH32F_STENCIL8,	false	},

		// stencil renderable
		{ "stencil_index8",			GL_STENCIL_INDEX8,		false	}
		// DEPTH24_STENCIL8,  duplicate
		// DEPTH32F_STENCIL8  duplicate
	};

	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(internalFormats); ++ndx)
	{
		const InternalFormat internalFormat = internalFormats[ndx];

		addChild(new SamplesCase(m_context, (std::string(internalFormat.name) + "_samples").c_str(), "SAMPLES and NUM_SAMPLE_COUNTS", internalFormat.format, internalFormat.isIntegerFormat));
	}

	addChild(new SamplesBufferSizeCase(m_context, "rgba8_samples_buffer", "SAMPLES bufSize parameter", GL_RGBA8));
}

} // Functional
} // gles3
} // deqp
