1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Dynamic State Viewport Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktDynamicStateVPTests.hpp"
26
27 #include "vktDynamicStateBaseClass.hpp"
28 #include "vktDynamicStateTestCaseUtil.hpp"
29
30 #include "vkImageUtil.hpp"
31 #include "vkCmdUtil.hpp"
32
33 #include "tcuTextureUtil.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "tcuRGBA.hpp"
36
37 namespace vkt
38 {
39 namespace DynamicState
40 {
41
42 using namespace Draw;
43
44 namespace
45 {
46
47 class ViewportStateBaseCase : public DynamicStateBaseClass
48 {
49 public:
ViewportStateBaseCase(Context & context,const char * vertexShaderName,const char * fragmentShaderName)50 ViewportStateBaseCase (Context& context, const char* vertexShaderName, const char* fragmentShaderName)
51 : DynamicStateBaseClass (context, vertexShaderName, fragmentShaderName)
52 {}
53
initialize(void)54 void initialize(void)
55 {
56 m_topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
57
58 m_data.push_back(PositionColorVertex(tcu::Vec4(-0.5f, 0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
59 m_data.push_back(PositionColorVertex(tcu::Vec4(0.5f, 0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
60 m_data.push_back(PositionColorVertex(tcu::Vec4(-0.5f, -0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
61 m_data.push_back(PositionColorVertex(tcu::Vec4(0.5f, -0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
62
63 DynamicStateBaseClass::initialize();
64 }
65
buildReferenceFrame(void)66 virtual tcu::Texture2D buildReferenceFrame (void)
67 {
68 DE_ASSERT(false);
69 return tcu::Texture2D(tcu::TextureFormat(), 0, 0);
70 }
71
setDynamicStates(void)72 virtual void setDynamicStates (void)
73 {
74 DE_ASSERT(false);
75 }
76
iterate(void)77 virtual tcu::TestStatus iterate (void)
78 {
79 tcu::TestLog& log = m_context.getTestContext().getLog();
80 const vk::VkQueue queue = m_context.getUniversalQueue();
81 const vk::VkDevice device = m_context.getDevice();
82
83 beginRenderPass();
84
85 // set states here
86 setDynamicStates();
87
88 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
89
90 const vk::VkDeviceSize vertexBufferOffset = 0;
91 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
92 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
93
94 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
95
96 endRenderPass(m_vk, *m_cmdBuffer);
97 endCommandBuffer(m_vk, *m_cmdBuffer);
98
99 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
100
101 // validation
102 {
103 tcu::Texture2D referenceFrame = buildReferenceFrame();
104
105 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
106 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
107 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
108
109 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
110 referenceFrame.getLevel(0), renderedFrame, 0.05f,
111 tcu::COMPARE_LOG_RESULT))
112 {
113 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
114 }
115
116 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
117 }
118 }
119 };
120
121 class ViewportParamTestInstance : public ViewportStateBaseCase
122 {
123 public:
ViewportParamTestInstance(Context & context,ShaderMap shaders)124 ViewportParamTestInstance (Context& context, ShaderMap shaders)
125 : ViewportStateBaseCase (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
126 {
127 ViewportStateBaseCase::initialize();
128 }
129
setDynamicStates(void)130 virtual void setDynamicStates(void)
131 {
132 const vk::VkViewport viewport = { 0.0f, 0.0f, static_cast<float>(WIDTH) * 2.0f, static_cast<float>(HEIGHT) * 2.0f, 0.0f, 0.0f };
133 const vk::VkRect2D scissor = { { 0, 0 }, { WIDTH, HEIGHT } };
134
135 setDynamicViewportState(1, &viewport, &scissor);
136 setDynamicRasterizationState();
137 setDynamicBlendState();
138 setDynamicDepthStencilState();
139 }
140
buildReferenceFrame(void)141 virtual tcu::Texture2D buildReferenceFrame (void)
142 {
143 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
144 referenceFrame.allocLevel(0);
145
146 const deInt32 frameWidth = referenceFrame.getWidth();
147 const deInt32 frameHeight = referenceFrame.getHeight();
148
149 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
150
151 for (int y = 0; y < frameHeight; y++)
152 {
153 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
154
155 for (int x = 0; x < frameWidth; x++)
156 {
157 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
158
159 if (xCoord >= 0.0f && xCoord <= 1.0f && yCoord >= 0.0f && yCoord <= 1.0f)
160 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
161 }
162 }
163
164 return referenceFrame;
165 }
166 };
167
168 class ScissorParamTestInstance : public ViewportStateBaseCase
169 {
170 public:
ScissorParamTestInstance(Context & context,ShaderMap shaders)171 ScissorParamTestInstance (Context& context, ShaderMap shaders)
172 : ViewportStateBaseCase (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
173 {
174 ViewportStateBaseCase::initialize();
175 }
176
setDynamicStates(void)177 virtual void setDynamicStates (void)
178 {
179 const vk::VkViewport viewport = { 0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f };
180 const vk::VkRect2D scissor = { { 0, 0 }, { WIDTH / 2, HEIGHT / 2 } };
181
182 setDynamicViewportState(1, &viewport, &scissor);
183 setDynamicRasterizationState();
184 setDynamicBlendState();
185 setDynamicDepthStencilState();
186 }
187
buildReferenceFrame(void)188 virtual tcu::Texture2D buildReferenceFrame (void)
189 {
190 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
191 referenceFrame.allocLevel(0);
192
193 const deInt32 frameWidth = referenceFrame.getWidth();
194 const deInt32 frameHeight = referenceFrame.getHeight();
195
196 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
197
198 for (int y = 0; y < frameHeight; y++)
199 {
200 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
201
202 for (int x = 0; x < frameWidth; x++)
203 {
204 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
205
206 if (xCoord >= -0.5f && xCoord <= 0.0f && yCoord >= -0.5f && yCoord <= 0.0f)
207 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
208 }
209 }
210
211 return referenceFrame;
212 }
213 };
214
215 class ViewportArrayTestInstance : public DynamicStateBaseClass
216 {
217 protected:
218 std::string m_geometryShaderName;
219
220 public:
221
ViewportArrayTestInstance(Context & context,ShaderMap shaders)222 ViewportArrayTestInstance (Context& context, ShaderMap shaders)
223 : DynamicStateBaseClass (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
224 , m_geometryShaderName (shaders[glu::SHADERTYPE_GEOMETRY])
225 {
226 for (int i = 0; i < 4; i++)
227 {
228 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
229 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
230 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
231 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec()));
232 }
233
234 DynamicStateBaseClass::initialize();
235 }
236
initPipeline(const vk::VkDevice device)237 virtual void initPipeline (const vk::VkDevice device)
238 {
239 const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0));
240 const vk::Unique<vk::VkShaderModule> gs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_geometryShaderName), 0));
241 const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0));
242
243 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
244
245 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
246 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
247 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*gs, "main", vk::VK_SHADER_STAGE_GEOMETRY_BIT));
248 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
249 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
250 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_topology));
251 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
252 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(4));
253 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
254 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
255 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
256 pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState());
257
258 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
259 }
260
iterate(void)261 virtual tcu::TestStatus iterate (void)
262 {
263 tcu::TestLog& log = m_context.getTestContext().getLog();
264 const vk::VkQueue queue = m_context.getUniversalQueue();
265 const vk::VkDevice device = m_context.getDevice();
266
267 beginRenderPass();
268
269 // set states here
270 const float halfWidth = (float)WIDTH / 2;
271 const float halfHeight = (float)HEIGHT / 2;
272 const deInt32 quarterWidth = WIDTH / 4;
273 const deInt32 quarterHeight = HEIGHT / 4;
274
275 const vk::VkViewport viewports[4] =
276 {
277 { 0.0f, 0.0f, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f },
278 { halfWidth, 0.0f, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f },
279 { halfWidth, halfHeight, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f },
280 { 0.0f, halfHeight, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f }
281 };
282
283 const vk::VkRect2D scissors[4] =
284 {
285 { { quarterWidth, quarterHeight }, { quarterWidth, quarterHeight } },
286 { { (deInt32)halfWidth, quarterHeight }, { quarterWidth, quarterHeight } },
287 { { (deInt32)halfWidth, (deInt32)halfHeight }, { quarterWidth, quarterHeight } },
288 { { quarterWidth, (deInt32)halfHeight }, { quarterWidth, quarterHeight } },
289 };
290
291 setDynamicViewportState(4, viewports, scissors);
292 setDynamicRasterizationState();
293 setDynamicBlendState();
294 setDynamicDepthStencilState();
295
296 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
297
298 const vk::VkDeviceSize vertexBufferOffset = 0;
299 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
300 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
301
302 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
303
304 endRenderPass(m_vk, *m_cmdBuffer);
305 endCommandBuffer(m_vk, *m_cmdBuffer);
306
307 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
308
309 // validation
310 {
311 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
312 referenceFrame.allocLevel(0);
313
314 const deInt32 frameWidth = referenceFrame.getWidth();
315 const deInt32 frameHeight = referenceFrame.getHeight();
316
317 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
318
319 for (int y = 0; y < frameHeight; y++)
320 {
321 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
322
323 for (int x = 0; x < frameWidth; x++)
324 {
325 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
326
327 if (xCoord >= -0.5f && xCoord <= 0.5f && yCoord >= -0.5f && yCoord <= 0.5f)
328 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
329 }
330 }
331
332 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
333 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
334 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
335
336 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
337 referenceFrame.getLevel(0), renderedFrame, 0.05f,
338 tcu::COMPARE_LOG_RESULT))
339 {
340 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
341 }
342
343 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
344 }
345 }
346 };
347
checkGeometryAndMultiViewportSupport(Context & context)348 void checkGeometryAndMultiViewportSupport (Context& context)
349 {
350 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
351 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
352 }
353
354 } //anonymous
355
DynamicStateVPTests(tcu::TestContext & testCtx)356 DynamicStateVPTests::DynamicStateVPTests (tcu::TestContext& testCtx)
357 : TestCaseGroup (testCtx, "vp_state", "Tests for viewport state")
358 {
359 /* Left blank on purpose */
360 }
361
~DynamicStateVPTests()362 DynamicStateVPTests::~DynamicStateVPTests ()
363 {
364 }
365
init(void)366 void DynamicStateVPTests::init (void)
367 {
368 ShaderMap shaderPaths;
369 shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
370 shaderPaths[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
371
372 addChild(new InstanceFactory<ViewportParamTestInstance>(m_testCtx, "viewport", "Set viewport which is twice bigger than screen size", shaderPaths));
373 addChild(new InstanceFactory<ScissorParamTestInstance>(m_testCtx, "scissor", "Perform a scissor test on 1/4 bottom-left part of the surface", shaderPaths));
374
375 shaderPaths[glu::SHADERTYPE_GEOMETRY] = "vulkan/dynamic_state/ViewportArray.geom";
376 addChild(new InstanceFactory<ViewportArrayTestInstance, FunctionSupport0>(m_testCtx, "viewport_array", "Multiple viewports and scissors", shaderPaths, checkGeometryAndMultiViewportSupport));
377 }
378
379 } // DynamicState
380 } // vkt
381