• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Shader limit tests.
22 *//*--------------------------------------------------------------------*/
23 
24 #include "vktShaderRenderLimitTests.hpp"
25 #include "vktShaderRender.hpp"
26 #include "tcuImageCompare.hpp"
27 #include "tcuStringTemplate.hpp"
28 #include "tcuTextureUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include "vktDrawUtil.hpp"
31 #include "deMath.h"
32 
33 using namespace std;
34 using namespace tcu;
35 using namespace vk;
36 using namespace de;
37 
38 namespace vkt
39 {
40 using namespace drawutil;
41 
42 namespace sr
43 {
44 
45 namespace
46 {
47 
48 class FragmentInputComponentCaseInstance : public ShaderRenderCaseInstance
49 {
50 public:
51 	FragmentInputComponentCaseInstance (Context& context);
52 
53 	TestStatus		iterate(void);
54 	virtual void	setupDefaultInputs(void);
55 
56 private:
57 	const Vec4		m_constantColor;
58 };
59 
FragmentInputComponentCaseInstance(Context & context)60 FragmentInputComponentCaseInstance::FragmentInputComponentCaseInstance (Context& context)
61 	: ShaderRenderCaseInstance (context)
62 	, m_constantColor	(0.1f, 0.05f, 0.2f, 0.0f)
63 {
64 }
65 
iterate(void)66 TestStatus FragmentInputComponentCaseInstance::iterate (void)
67 {
68 	const UVec2		viewportSize	= getViewportSize();
69 	const int		width			= viewportSize.x();
70 	const int		height			= viewportSize.y();
71 	const tcu::RGBA	threshold		(2, 2, 2, 2);
72 	Surface			resImage		(width, height);
73 	Surface			refImage		(width, height);
74 	bool			compareOk		= false;
75 
76 	const deUint16	indices[12]		=
77 	{
78 		0, 4, 1,
79 		0, 5, 4,
80 		1, 2, 3,
81 		1, 3, 4
82 	};
83 
84 	setup();
85 	render(6, 4, indices);
86 	copy(resImage.getAccess(), getResultImage().getAccess());
87 
88 	// Reference image
89 	for (int y = 0; y < refImage.getHeight(); y++)
90 	{
91 		for (int x = 0; x < refImage.getWidth(); x++)
92 			refImage.setPixel(x, y, RGBA(0, 255, 0, 255));
93 	}
94 
95 	compareOk = pixelThresholdCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT);
96 
97 	if (compareOk)
98 		return TestStatus::pass("Result image matches reference");
99 	else
100 		return TestStatus::fail("Image mismatch");
101 }
102 
setupDefaultInputs(void)103 void FragmentInputComponentCaseInstance::setupDefaultInputs (void)
104 {
105 	const float vertices[] =
106 	{
107 		-1.0f, -1.0f, 0.0f, 1.0f,
108 		 0.0f, -1.0f, 0.0f, 1.0f,
109 		 1.0f, -1.0f, 0.0f, 1.0f,
110 		 1.0f,  1.0f, 0.0f, 1.0f,
111 		 0.0f,  1.0f, 0.0f, 1.0f,
112 		-1.0f,  1.0f, 0.0f, 1.0f
113 	};
114 
115 	addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint16(sizeof(float) * 4), 6, vertices);
116 }
117 
118 class FragmentInputComponentCase : public TestCase
119 {
120 public:
121 	FragmentInputComponentCase	(TestContext& testCtx, const string& name, const string& description, const deUint16 inputComponents);
122 	virtual						~FragmentInputComponentCase(void);
123 
124 	void						initPrograms(SourceCollections& dst) const;
125 	TestInstance*				createInstance(Context& context) const;
126 
127 private:
128 	FragmentInputComponentCase	(const FragmentInputComponentCase&);
129 	const deUint16				m_inputComponents;
130 };
131 
FragmentInputComponentCase(TestContext & testCtx,const string & name,const string & description,const deUint16 inputComponents)132 FragmentInputComponentCase::FragmentInputComponentCase (TestContext& testCtx, const string& name, const string& description, const deUint16 inputComponents)
133 	: TestCase			(testCtx, name, description)
134 	, m_inputComponents	(inputComponents)
135 {
136 }
137 
~FragmentInputComponentCase(void)138 FragmentInputComponentCase::~FragmentInputComponentCase (void)
139 {
140 }
141 
initPrograms(SourceCollections & dst) const142 void FragmentInputComponentCase::initPrograms (SourceCollections& dst) const
143 {
144 	const tcu::StringTemplate	vertexCodeTemplate(
145 		"#version 450\n"
146 		"layout(location = 0) in highp vec4 a_position;\n"
147 		"${VARYING_OUT}"
148 		"void main (void)\n"
149 		"{\n"
150 		"    gl_Position = a_position;\n"
151 		    "${VARYING_DECL}"
152 		"}\n");
153 
154 	const tcu::StringTemplate	fragmentCodeTemplate(
155 		"#version 450\n"
156 		"layout(location = 0) out highp vec4 o_color;\n"
157 		"${VARYING_IN}"
158 		"void main (void)\n"
159 		"{\n"
160 		"    int errorCount = 0;\n"
161 		    "${VERIFY}"
162 		"\n"
163 		"    if (errorCount == 0)\n"
164 		"        o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
165 		"    else\n"
166 		"        o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
167 		"}\n");
168 
169 	//
170 	// The number of vertex output/fragment input components is *inclusive* of any built-ins being used,
171 	// since gl_Position is always output by the shader, this actually means that there are n - 4 components
172 	// available as user specified output data.
173 	//
174 	// [14.1.4. Location Assignment, para 11]
175 	//
176 	// "The number of input and output locations available for a shader input or output
177 	//  interface are limited, and dependent on the shader stage as described in Shader
178 	//  Input and Output Locations. All variables in both the built-in interface block
179 	//  and the user-defined variable interface count against these limits."
180 	//
181 	// So, as an example, the '128' component variant of this test will specify 124 user
182 	// declared outputs in addition to gl_Position.
183 
184 	deUint16					maxLocations	= (deUint16)deCeilToInt32((float)(m_inputComponents - 4) / 4u);
185 	string						varyingType;
186 	map<string, string>			vertexParams;
187 	map<string, string>			fragmentParams;
188 
189 	for (deUint16 loc = 0; loc < maxLocations; loc++)
190 	{
191 		if (loc == (maxLocations - 1u))
192 		{
193 			switch (m_inputComponents - loc * 4u)
194 			{
195 			case 1:
196 				varyingType = "float";
197 				break;
198 			case 2:
199 				varyingType = "vec2";
200 				break;
201 			case 3:
202 				varyingType = "vec3";
203 				break;
204 			default:
205 				varyingType = "vec4";
206 			}
207 		}
208 		else
209 			varyingType = "vec4";
210 
211 		vertexParams["VARYING_OUT"]		+= "layout(location = "			+ de::toString(loc)	+ ") out highp "	+ varyingType	+ " o_color"	+ de::toString(loc)	+ ";\n";
212 		vertexParams["VARYING_DECL"]	+= "    o_color"				+ de::toString(loc)	+ " = "				+ varyingType	+ "("			+ de::toString(loc)	+ ".0);\n";
213 		fragmentParams["VARYING_IN"]	+= "layout(location = "			+ de::toString(loc)	+ ") in highp "		+ varyingType	+ " i_color"	+ de::toString(loc)	+ ";\n";
214 		fragmentParams["VERIFY"]		+= "    errorCount += (i_color"	+ de::toString(loc)	+ " == "			+ varyingType	+ "("			+ de::toString(loc)	+ ".0)) ? 0 : 1;\n";
215 	}
216 
217 	dst.glslSources.add("vert") << glu::VertexSource(vertexCodeTemplate.specialize(vertexParams));
218 	dst.glslSources.add("frag") << glu::FragmentSource(fragmentCodeTemplate.specialize(fragmentParams));
219 }
220 
createInstance(Context & context) const221 TestInstance* FragmentInputComponentCase::createInstance (Context& context) const
222 {
223 	const InstanceInterface&		vki							= context.getInstanceInterface();
224 	const VkPhysicalDevice			physDevice					= context.getPhysicalDevice();
225 	const VkPhysicalDeviceLimits	limits						= getPhysicalDeviceProperties(vki, physDevice).limits;
226 	const deUint16					maxFragmentInputComponents	= (deUint16)limits.maxFragmentInputComponents;
227 	const deUint16					maxVertexOutputComponents	= (deUint16)limits.maxVertexOutputComponents;
228 
229 	if (m_inputComponents > maxFragmentInputComponents)
230 	{
231 		const std::string notSupportedStr = "Unsupported number of fragment input components (" +
232 											de::toString(m_inputComponents) +
233 											") maxFragmentInputComponents=" + de::toString(maxFragmentInputComponents);
234 		TCU_THROW(NotSupportedError, notSupportedStr.c_str());
235 	}
236 
237 	// gl_Position counts as an output component as well, so outputComponents = inputComponents + 4
238 	if (m_inputComponents + 4 > maxVertexOutputComponents)
239 	{
240 		const std::string notSupportedStr = "Unsupported number of user specified vertex output components (" +
241 											de::toString(m_inputComponents + 4) +
242 											") maxVertexOutputComponents=" + de::toString(maxVertexOutputComponents);
243 		TCU_THROW(NotSupportedError, notSupportedStr.c_str());
244 	}
245 
246 	return new FragmentInputComponentCaseInstance(context);
247 }
248 } // anonymous
249 
createLimitTests(TestContext & testCtx)250 TestCaseGroup* createLimitTests (TestContext& testCtx)
251 {
252 	de::MovePtr<TestCaseGroup> limitGroup			(new TestCaseGroup(testCtx,	"limits",			"Shader device limit tests"));
253 	de::MovePtr<TestCaseGroup> nearGroup			(new TestCaseGroup(testCtx, "near_max",			"Shaders near maximum values"));
254 
255 	de::MovePtr<TestCaseGroup> inputComponentsGroup	(new TestCaseGroup(testCtx,	"fragment_input",	"Fragment input component variations"));
256 
257 	// Fragment input component case
258 	deUint16 fragmentComponentMaxLimits [] = { 64u, 128u, 256u };
259 
260 	for (deUint16 limitNdx = 0; limitNdx < DE_LENGTH_OF_ARRAY(fragmentComponentMaxLimits); limitNdx++)
261 	{
262 		for (deInt16 cases = 5; cases > 0; cases--)
263 			inputComponentsGroup->addChild(new FragmentInputComponentCase(testCtx, "components_" + de::toString(fragmentComponentMaxLimits[limitNdx] - cases), "Input component count", (deUint16)(fragmentComponentMaxLimits[limitNdx] - cases)));
264 	}
265 
266 	nearGroup->addChild(inputComponentsGroup.release());
267 	limitGroup->addChild(nearGroup.release());
268 	return limitGroup.release();
269 }
270 
271 } // sr
272 } // vkt
273