/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL (ES) 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 Framebuffer completeness tests.
 *//*--------------------------------------------------------------------*/

#include "es2fFboCompletenessTests.hpp"

#include "glsFboCompletenessTests.hpp"
#include "gluObjectWrapper.hpp"

using namespace glw;
using deqp::gls::Range;
using namespace deqp::gls::FboUtil;
using namespace deqp::gls::FboUtil::config;
namespace fboc = deqp::gls::fboc;
typedef tcu::TestCase::IterateResult IterateResult;

namespace deqp
{
namespace gles2
{
namespace Functional
{

static const FormatKey s_es2ColorRenderables[] =
{
	GL_RGBA4, GL_RGB5_A1, GL_RGB565,
};

// GLES2 does not strictly allow these, but this seems to be a bug in the
// specification. For now, let's assume the unsized formats corresponding to
// the color-renderable sized formats are allowed.
// See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=7333

static const FormatKey s_es2UnsizedColorRenderables[] =
{
	GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4),
	GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1),
	GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_SHORT_5_6_5)
};

static const FormatKey s_es2DepthRenderables[] =
{
	GL_DEPTH_COMPONENT16,
};

static const FormatKey s_es2StencilRenderables[] =
{
	GL_STENCIL_INDEX8,
};

static const FormatEntry s_es2Formats[] =
{
	{ COLOR_RENDERABLE | TEXTURE_VALID,
	  GLS_ARRAY_RANGE(s_es2UnsizedColorRenderables) },
	{ REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID,
	  GLS_ARRAY_RANGE(s_es2ColorRenderables) },
	{ REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID,
	  GLS_ARRAY_RANGE(s_es2DepthRenderables) },
	{ REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID,
	  GLS_ARRAY_RANGE(s_es2StencilRenderables) },
};

// We have here only the extensions that are redundant in vanilla GLES3. Those
// that are applicable both to GLES2 and GLES3 are in glsFboCompletenessTests.cpp.

// GL_OES_texture_float
static const FormatKey s_oesTextureFloatFormats[] =
{
	GLS_UNSIZED_FORMATKEY(GL_RGBA,	GL_FLOAT),
	GLS_UNSIZED_FORMATKEY(GL_RGB,	GL_FLOAT),
};

// GL_OES_texture_half_float
static const FormatKey s_oesTextureHalfFloatFormats[] =
{
	GLS_UNSIZED_FORMATKEY(GL_RGBA,	GL_HALF_FLOAT_OES),
	GLS_UNSIZED_FORMATKEY(GL_RGB,	GL_HALF_FLOAT_OES),
};

// GL_EXT_sRGB_write_control
static const FormatKey s_extSrgbWriteControlFormats[] =
{
	GL_SRGB8_ALPHA8
};

// DEQP_gles3_core_no_extension_features
static const FormatKey s_es3NoExtRboFormats[] =
{
	GL_RGB10_A2,
	GL_SRGB8_ALPHA8,
};
static const FormatKey s_es3NoExtTextureFormats[] =
{
	GL_R16F,
	GL_RG16F,
	GL_RGB16F,
	GL_RGBA16F,
	GL_R11F_G11F_B10F,
};
static const FormatKey s_es3NoExtTextureColorRenderableFormats[] =
{
	GL_R8,
	GL_RG8,
	GL_RGB8,
	GL_RGBA4,
	GL_RGB5_A1,
	GL_RGBA8,
	GL_RGB10_A2,
	GL_RGB565,
	GL_SRGB8_ALPHA8,
};

// with ES3 core and GL_EXT_color_buffer_float
static const FormatKey s_es3NoExtExtColorBufferFloatFormats[] =
{
	// \note Only the GLES2+exts subset of formats
	GL_R11F_G11F_B10F, GL_RGBA16F, GL_RG16F, GL_R16F,
};

// with ES3 core with OES_texture_stencil8
static const FormatKey s_es3NoExtOesTextureStencil8Formats[] =
{
	GL_STENCIL_INDEX8,
};

// DEQP_gles3_core_changed_features
static const FormatKey s_es3NoExtDepthRenderable[] =
{
	GL_DEPTH_COMPONENT16,
	GL_DEPTH_COMPONENT24,
	GL_DEPTH24_STENCIL8,
};

static const FormatKey s_es3NoExtStencilRenderable[] =
{
	GL_DEPTH24_STENCIL8,
};

static const FormatExtEntry s_es2ExtFormats[] =
{
	// The extension does not specify these to be color-renderable.
	{
		"GL_OES_texture_float",
		(deUint32)TEXTURE_VALID,
		GLS_ARRAY_RANGE(s_oesTextureFloatFormats)
	},
	{
		"GL_OES_texture_half_float",
		(deUint32)TEXTURE_VALID,
		GLS_ARRAY_RANGE(s_oesTextureHalfFloatFormats)
	},

	// GL_EXT_sRGB_write_control makes SRGB8_ALPHA8 color-renderable
	{
		"GL_EXT_sRGB_write_control",
		(deUint32)(REQUIRED_RENDERABLE | TEXTURE_VALID | COLOR_RENDERABLE | RENDERBUFFER_VALID),
		GLS_ARRAY_RANGE(s_extSrgbWriteControlFormats)
	},

	// Since GLES3 is "backwards compatible" to GLES2, we might actually be running on a GLES3
	// context. Since GLES3 added some features to core with no corresponding GLES2 extension,
	// some tests might produce wrong results (since they are using rules of GLES2 & extensions)
	//
	// To avoid this, require new features of GLES3 that have no matching GLES2 extension if
	// context is GLES3. This can be done with a DEQP_* extensions.
	//
	// \note Not all feature changes are listed here but only those that alter GLES2 subset of
	//       the formats
	{
		"DEQP_gles3_core_compatible",
		(deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID),
		GLS_ARRAY_RANGE(s_es3NoExtRboFormats)
	},
	{
		"DEQP_gles3_core_compatible",
		(deUint32)TEXTURE_VALID,
		GLS_ARRAY_RANGE(s_es3NoExtTextureFormats)
	},
	{
		"DEQP_gles3_core_compatible",
		(deUint32)(REQUIRED_RENDERABLE | TEXTURE_VALID | COLOR_RENDERABLE | RENDERBUFFER_VALID),
		GLS_ARRAY_RANGE(s_es3NoExtTextureColorRenderableFormats)
	},
	{
		"DEQP_gles3_core_compatible GL_EXT_color_buffer_float",
		(deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID),
		GLS_ARRAY_RANGE(s_es3NoExtExtColorBufferFloatFormats)
	},
	{
		"DEQP_gles3_core_compatible GL_OES_texture_stencil8",
		(deUint32)(REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID),
		GLS_ARRAY_RANGE(s_es3NoExtOesTextureStencil8Formats)
	},
	{
		"DEQP_gles3_core_compatible GL_OES_texture_half_float GL_EXT_color_buffer_half_float",
		(deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE),
		GLS_ARRAY_RANGE(s_oesTextureHalfFloatFormats)
	},
	{
		"DEQP_gles3_core_compatible",
		(deUint32)(REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID),
		GLS_ARRAY_RANGE(s_es3NoExtDepthRenderable)
	},
	{
		"DEQP_gles3_core_compatible",
		(deUint32)(REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID),
		GLS_ARRAY_RANGE(s_es3NoExtStencilRenderable)
	},
};

class ES2Checker : public Checker
{
public:
			ES2Checker				(const glu::RenderContext& ctx);
	void	check					(GLenum attPoint, const Attachment& att,
									 const Image* image);
private:
	GLsizei	m_width;	//< The common width of images
	GLsizei	m_height;	//< The common height of images
};

ES2Checker::ES2Checker (const glu::RenderContext& ctx)\
	: Checker		(ctx)
	, m_width		(-1)
	, m_height		(-1)
{
}

void ES2Checker::check (GLenum attPoint, const Attachment& att, const Image* image)
{
	DE_UNREF(attPoint);
	DE_UNREF(att);
	// GLES2: "All attached images have the same width and height."
	if (m_width == -1)
	{
		m_width = image->width;
		m_height = image->height;
	}
	else if (image->width != m_width || image->height != m_height)
	{
		// Since GLES3 is "backwards compatible" to GLES2, we might actually be running
		// on a GLES3 context. On GLES3, FRAMEBUFFER_INCOMPLETE_DIMENSIONS is not generated
		// if attachments have different sizes.
		if (!gls::FboUtil::checkExtensionSupport(m_renderCtx, "DEQP_gles3_core_compatible"))
		{
			// running on GLES2
			addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS, "Sizes of attachments differ");
		}
	}
	// GLES2, 4.4.5: "some implementations may not support rendering to
	// particular combinations of internal formats. If the combination of
	// formats of the images attached to a framebuffer object are not
	// supported by the implementation, then the framebuffer is not complete
	// under the clause labeled FRAMEBUFFER_UNSUPPORTED."
	//
	// Hence it is _always_ allowed to report FRAMEBUFFER_UNSUPPORTED.
	addPotentialFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Particular format combinations need not to be supported");
}

struct FormatCombination
{
	GLenum			colorKind;
	ImageFormat		colorFmt;
	GLenum			depthKind;
	ImageFormat		depthFmt;
	GLenum			stencilKind;
	ImageFormat		stencilFmt;
};

class SupportedCombinationTest : public fboc::TestBase
{
public:
					SupportedCombinationTest	(fboc::Context& ctx,
												 const char* name, const char* desc)
						: TestBase		(ctx, name, desc) {}

	IterateResult	iterate						(void);
	bool			tryCombination				(const FormatCombination& comb);
	GLenum			formatKind					(ImageFormat fmt);
};

bool SupportedCombinationTest::tryCombination (const FormatCombination& comb)
{
	glu::Framebuffer fbo(m_ctx.getRenderContext());
	FboBuilder builder(*fbo, GL_FRAMEBUFFER, fboc::gl(*this));

	attachTargetToNew(GL_COLOR_ATTACHMENT0,		comb.colorKind,		comb.colorFmt,
					  64,						64,					builder);
	attachTargetToNew(GL_DEPTH_ATTACHMENT,		comb.depthKind,		comb.depthFmt,
					  64,						64,					builder);
	attachTargetToNew(GL_STENCIL_ATTACHMENT,	comb.stencilKind,	comb.stencilFmt,
					  64,						64,					builder);

	const GLenum glStatus = fboc::gl(*this).checkFramebufferStatus(GL_FRAMEBUFFER);

	return (glStatus == GL_FRAMEBUFFER_COMPLETE);
}

GLenum SupportedCombinationTest::formatKind (ImageFormat fmt)
{
	if (fmt.format == GL_NONE)
		return GL_NONE;

	const FormatFlags flags = m_ctx.getCoreFormats().getFormatInfo(fmt);
	const bool rbo = (flags & RENDERBUFFER_VALID) != 0;
	// exactly one of renderbuffer and texture is supported by vanilla GLES2 formats
	DE_ASSERT(rbo != ((flags & TEXTURE_VALID) != 0));

	return rbo ? GL_RENDERBUFFER : GL_TEXTURE;
}

IterateResult SupportedCombinationTest::iterate (void)
{
	const FormatDB& db		= m_ctx.getCoreFormats();
	const ImageFormat none	= ImageFormat::none();
	Formats colorFmts		= db.getFormats(COLOR_RENDERABLE);
	Formats depthFmts		= db.getFormats(DEPTH_RENDERABLE);
	Formats stencilFmts		= db.getFormats(STENCIL_RENDERABLE);
	FormatCombination comb;
	bool succ = false;

	colorFmts.insert(none);
	depthFmts.insert(none);
	stencilFmts.insert(none);

	for (Formats::const_iterator col = colorFmts.begin(); col != colorFmts.end(); col++)
	{
		comb.colorFmt = *col;
		comb.colorKind = formatKind(*col);
		for (Formats::const_iterator dep = depthFmts.begin(); dep != depthFmts.end(); dep++)
		{
			comb.depthFmt = *dep;
			comb.depthKind = formatKind(*dep);
			for (Formats::const_iterator stc = stencilFmts.begin();
				 stc != stencilFmts.end(); stc++)
			{
				comb.stencilFmt = *stc;
				comb.stencilKind = formatKind(*stc);
				succ = tryCombination(comb);
				if (succ)
					break;
			}
		}
	}

	if (succ)
		pass();
	else
		fail("No supported format combination found");

	return STOP;
}

class ES2CheckerFactory : public CheckerFactory
{
public:
	Checker*			createChecker	(const glu::RenderContext& ctx) { return new ES2Checker(ctx); }
};

class TestGroup : public TestCaseGroup
{
public:
						TestGroup		(Context& ctx);
	void				init			(void);
private:
	ES2CheckerFactory	m_checkerFactory;
	fboc::Context		m_fboc;
};

TestGroup::TestGroup (Context& ctx)
	: TestCaseGroup		(ctx, "completeness", "Completeness tests")
	, m_checkerFactory	()
	, m_fboc			(ctx.getTestContext(), ctx.getRenderContext(), m_checkerFactory)
{
	const FormatEntries stdRange = GLS_ARRAY_RANGE(s_es2Formats);
	const FormatExtEntries extRange = GLS_ARRAY_RANGE(s_es2ExtFormats);

	m_fboc.addFormats(stdRange);
	m_fboc.addExtFormats(extRange);
	m_fboc.setHaveMulticolorAtts(
		ctx.getContextInfo().isExtensionSupported("GL_NV_fbo_color_attachments"));
}

void TestGroup::init (void)
{
	tcu::TestCaseGroup* attCombTests = m_fboc.createAttachmentTests();
	addChild(m_fboc.createRenderableTests());
	attCombTests->addChild(new SupportedCombinationTest(
							   m_fboc,
							   "exists_supported",
							   "Test for existence of a supported combination of formats"));
	addChild(attCombTests);
	addChild(m_fboc.createSizeTests());
}

tcu::TestCaseGroup* createFboCompletenessTests (Context& context)
{
	return new TestGroup(context);
}

} // Functional
} // gles2
} // deqp
