1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2018 Google Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Shader limit tests.
22 *//*--------------------------------------------------------------------*/
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"
40 using namespace drawutil;
48 class FragmentInputComponentCaseInstance : public ShaderRenderCaseInstance
51 FragmentInputComponentCaseInstance (Context& context);
53 TestStatus iterate(void);
54 virtual void setupDefaultInputs(void);
57 const Vec4 m_constantColor;
60 FragmentInputComponentCaseInstance::FragmentInputComponentCaseInstance (Context& context)
61 : ShaderRenderCaseInstance (context)
62 , m_constantColor (0.1f, 0.05f, 0.2f, 0.0f)
66 TestStatus FragmentInputComponentCaseInstance::iterate (void)
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;
76 const deUint16 indices[12] =
85 render(6, 4, indices);
86 copy(resImage.getAccess(), getResultImage().getAccess());
89 for (int y = 0; y < refImage.getHeight(); y++)
91 for (int x = 0; x < refImage.getWidth(); x++)
92 refImage.setPixel(x, y, RGBA(0, 255, 0, 255));
95 compareOk = pixelThresholdCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT);
98 return TestStatus::pass("Result image matches reference");
100 return TestStatus::fail("Image mismatch");
103 void FragmentInputComponentCaseInstance::setupDefaultInputs (void)
105 const float vertices[] =
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
115 addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint16(sizeof(float) * 4), 6, vertices);
118 class FragmentInputComponentCase : public TestCase
121 FragmentInputComponentCase (TestContext& testCtx, const string& name, const string& description, const deUint16 inputComponents);
122 virtual ~FragmentInputComponentCase(void);
124 void initPrograms(SourceCollections& dst) const;
125 TestInstance* createInstance(Context& context) const;
128 FragmentInputComponentCase (const FragmentInputComponentCase&);
129 const deUint16 m_inputComponents;
132 FragmentInputComponentCase::FragmentInputComponentCase (TestContext& testCtx, const string& name, const string& description, const deUint16 inputComponents)
133 : TestCase (testCtx, name, description)
134 , m_inputComponents (inputComponents)
138 FragmentInputComponentCase::~FragmentInputComponentCase (void)
142 void FragmentInputComponentCase::initPrograms (SourceCollections& dst) const
144 const tcu::StringTemplate vertexCodeTemplate(
146 "layout(location = 0) in highp vec4 a_position;\n"
150 " gl_Position = a_position;\n"
154 const tcu::StringTemplate fragmentCodeTemplate(
156 "layout(location = 0) out highp vec4 o_color;\n"
160 " int errorCount = 0;\n"
163 " if (errorCount == 0)\n"
164 " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
166 " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
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.
174 // [14.1.4. Location Assignment, para 11]
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."
181 // So, as an example, the '128' component variant of this test will specify 124 user
182 // declared outputs in addition to gl_Position.
184 deUint16 maxLocations = (deUint16)deCeilToInt32((float)(m_inputComponents - 4) / 4u);
186 map<string, string> vertexParams;
187 map<string, string> fragmentParams;
189 for (deUint16 loc = 0; loc < maxLocations; loc++)
191 if (loc == (maxLocations - 1u))
193 switch (m_inputComponents - loc * 4u)
196 varyingType = "float";
199 varyingType = "vec2";
202 varyingType = "vec3";
205 varyingType = "vec4";
209 varyingType = "vec4";
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";
217 dst.glslSources.add("vert") << glu::VertexSource(vertexCodeTemplate.specialize(vertexParams));
218 dst.glslSources.add("frag") << glu::FragmentSource(fragmentCodeTemplate.specialize(fragmentParams));
221 TestInstance* FragmentInputComponentCase::createInstance (Context& context) const
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;
229 if (m_inputComponents > maxFragmentInputComponents)
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());
237 // gl_Position counts as an output component as well, so outputComponents = inputComponents + 4
238 if (m_inputComponents + 4 > maxVertexOutputComponents)
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());
246 return new FragmentInputComponentCaseInstance(context);
250 TestCaseGroup* createLimitTests (TestContext& testCtx)
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"));
255 de::MovePtr<TestCaseGroup> inputComponentsGroup (new TestCaseGroup(testCtx, "fragment_input", "Fragment input component variations"));
257 // Fragment input component case
258 deUint16 fragmentComponentMaxLimits [] = { 64u, 128u, 256u };
260 for (deUint16 limitNdx = 0; limitNdx < DE_LENGTH_OF_ARRAY(fragmentComponentMaxLimits); limitNdx++)
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)));
266 nearGroup->addChild(inputComponentsGroup.release());
267 limitGroup->addChild(nearGroup.release());
268 return limitGroup.release();