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 Tests - General
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktDynamicStateGeneralTests.hpp"
26
27 #include "vktTestCaseUtil.hpp"
28 #include "vktDynamicStateTestCaseUtil.hpp"
29 #include "vktDynamicStateBaseClass.hpp"
30 #include "vktDrawCreateInfoUtil.hpp"
31 #include "vktDrawImageObjectUtil.hpp"
32 #include "vktDrawBufferObjectUtil.hpp"
33
34 #include "vkImageUtil.hpp"
35 #include "vkCmdUtil.hpp"
36
37 #include "tcuTestLog.hpp"
38 #include "tcuResource.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuRGBA.hpp"
42
43 #include "vkDefs.hpp"
44 #include "vkCmdUtil.hpp"
45
46 namespace vkt
47 {
48 namespace DynamicState
49 {
50
51 using namespace Draw;
52
53 namespace
54 {
55
56 class StateSwitchTestInstance : public DynamicStateBaseClass
57 {
58 public:
StateSwitchTestInstance(Context & context,ShaderMap shaders)59 StateSwitchTestInstance (Context &context, ShaderMap shaders)
60 : DynamicStateBaseClass (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
61 {
62 m_topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
63
64 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
65 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
66 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
67 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
68
69 DynamicStateBaseClass::initialize();
70 }
71
iterate(void)72 virtual tcu::TestStatus iterate (void)
73 {
74 tcu::TestLog& log = m_context.getTestContext().getLog();
75 const vk::VkQueue queue = m_context.getUniversalQueue();
76 const vk::VkDevice device = m_context.getDevice();
77
78 beginRenderPass();
79
80 // bind states here
81 vk::VkViewport viewport = { 0, 0, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f };
82 vk::VkRect2D scissor_1 = { { 0, 0 }, { WIDTH / 2, HEIGHT / 2 } };
83 vk::VkRect2D scissor_2 = { { WIDTH / 2, HEIGHT / 2 }, { WIDTH / 2, HEIGHT / 2 } };
84
85 setDynamicRasterizationState();
86 setDynamicBlendState();
87 setDynamicDepthStencilState();
88
89 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
90
91 const vk::VkDeviceSize vertexBufferOffset = 0;
92 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
93 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
94
95 // bind first state
96 setDynamicViewportState(1, &viewport, &scissor_1);
97 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
98
99 // bind second state
100 setDynamicViewportState(1, &viewport, &scissor_2);
101 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
102
103 endRenderPass(m_vk, *m_cmdBuffer);
104 endCommandBuffer(m_vk, *m_cmdBuffer);
105
106 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
107
108 //validation
109 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
110 referenceFrame.allocLevel(0);
111
112 const deInt32 frameWidth = referenceFrame.getWidth();
113 const deInt32 frameHeight = referenceFrame.getHeight();
114
115 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
116
117 for (int y = 0; y < frameHeight; y++)
118 {
119 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
120
121 for (int x = 0; x < frameWidth; x++)
122 {
123 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
124
125 if ((yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f) ||
126 (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f))
127 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
128 }
129 }
130
131 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
132 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
133 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT,
134 vk::VK_IMAGE_ASPECT_COLOR_BIT);
135
136 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
137 referenceFrame.getLevel(0), renderedFrame, 0.05f,
138 tcu::COMPARE_LOG_RESULT))
139 {
140
141 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
142 }
143
144 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
145 }
146 };
147
148 class BindOrderTestInstance : public DynamicStateBaseClass
149 {
150 public:
BindOrderTestInstance(Context & context,ShaderMap shaders)151 BindOrderTestInstance (Context& context, ShaderMap shaders)
152 : DynamicStateBaseClass (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
153 {
154 m_topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
155
156 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
157 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
158 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
159 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
160
161 DynamicStateBaseClass::initialize();
162 }
163
iterate(void)164 virtual tcu::TestStatus iterate (void)
165 {
166 tcu::TestLog &log = m_context.getTestContext().getLog();
167 const vk::VkQueue queue = m_context.getUniversalQueue();
168 const vk::VkDevice device = m_context.getDevice();
169
170 beginRenderPass();
171
172 // bind states here
173 vk::VkViewport viewport = { 0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f };
174 vk::VkRect2D scissor_1 = { { 0, 0 }, { WIDTH / 2, HEIGHT / 2 } };
175 vk::VkRect2D scissor_2 = { { WIDTH / 2, HEIGHT / 2 }, { WIDTH / 2, HEIGHT / 2 } };
176
177 setDynamicRasterizationState();
178 setDynamicBlendState();
179 setDynamicDepthStencilState();
180 setDynamicViewportState(1, &viewport, &scissor_1);
181
182 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
183
184 const vk::VkDeviceSize vertexBufferOffset = 0;
185 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
186 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
187
188 // rebind in different order
189 setDynamicBlendState();
190 setDynamicRasterizationState();
191 setDynamicDepthStencilState();
192
193 // bind first state
194 setDynamicViewportState(1, &viewport, &scissor_1);
195 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
196
197 setDynamicViewportState(1, &viewport, &scissor_2);
198 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0);
199
200 endRenderPass(m_vk, *m_cmdBuffer);
201 endCommandBuffer(m_vk, *m_cmdBuffer);
202
203 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
204
205 //validation
206 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
207 referenceFrame.allocLevel(0);
208
209 const deInt32 frameWidth = referenceFrame.getWidth();
210 const deInt32 frameHeight = referenceFrame.getHeight();
211
212 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
213
214 for (int y = 0; y < frameHeight; y++)
215 {
216 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
217
218 for (int x = 0; x < frameWidth; x++)
219 {
220 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
221
222 if ((yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f) ||
223 (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f))
224 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
225 }
226 }
227
228 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
229 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
230 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
231
232 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
233 referenceFrame.getLevel(0), renderedFrame, 0.05f,
234 tcu::COMPARE_LOG_RESULT))
235 {
236 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
237 }
238
239 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
240 }
241 };
242
243 class StatePersistenceTestInstance : public DynamicStateBaseClass
244 {
245 protected:
246 vk::Move<vk::VkPipeline> m_pipelineAdditional;
247
248 public:
StatePersistenceTestInstance(Context & context,ShaderMap shaders)249 StatePersistenceTestInstance (Context& context, ShaderMap shaders)
250 : DynamicStateBaseClass (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT])
251 {
252 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
253 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
254 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
255 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
256
257 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
258 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
259 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
260 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
261 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
262 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
263
264 DynamicStateBaseClass::initialize();
265 }
initPipeline(const vk::VkDevice device)266 virtual void initPipeline (const vk::VkDevice device)
267 {
268 // shaders
269 const vk::Unique<vk::VkShaderModule> vs (createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0));
270 const vk::Unique<vk::VkShaderModule> fs (createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0));
271
272 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
273
274 PipelineCreateInfo pipelineCreateInfo_1(*m_pipelineLayout, *m_renderPass, 0, 0);
275 pipelineCreateInfo_1.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
276 pipelineCreateInfo_1.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
277 pipelineCreateInfo_1.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
278 pipelineCreateInfo_1.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
279 pipelineCreateInfo_1.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
280 pipelineCreateInfo_1.addState(PipelineCreateInfo::ViewportState(1));
281 pipelineCreateInfo_1.addState(PipelineCreateInfo::DepthStencilState());
282 pipelineCreateInfo_1.addState(PipelineCreateInfo::RasterizerState());
283 pipelineCreateInfo_1.addState(PipelineCreateInfo::MultiSampleState());
284 pipelineCreateInfo_1.addState(PipelineCreateInfo::DynamicState());
285
286 PipelineCreateInfo pipelineCreateInfo_2(*m_pipelineLayout, *m_renderPass, 0, 0);
287 pipelineCreateInfo_2.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
288 pipelineCreateInfo_2.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
289 pipelineCreateInfo_2.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
290 pipelineCreateInfo_2.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
291 pipelineCreateInfo_2.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
292 pipelineCreateInfo_2.addState(PipelineCreateInfo::ViewportState(1));
293 pipelineCreateInfo_2.addState(PipelineCreateInfo::DepthStencilState());
294 pipelineCreateInfo_2.addState(PipelineCreateInfo::RasterizerState());
295 pipelineCreateInfo_2.addState(PipelineCreateInfo::MultiSampleState());
296 pipelineCreateInfo_2.addState(PipelineCreateInfo::DynamicState());
297
298 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo_1);
299 m_pipelineAdditional = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo_2);
300 }
301
iterate(void)302 virtual tcu::TestStatus iterate(void)
303 {
304 tcu::TestLog& log = m_context.getTestContext().getLog();
305 const vk::VkQueue queue = m_context.getUniversalQueue();
306 const vk::VkDevice device = m_context.getDevice();
307
308 beginRenderPass();
309
310 // bind states here
311 const vk::VkViewport viewport = { 0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f };
312 const vk::VkRect2D scissor_1 = { { 0, 0 }, { WIDTH / 2, HEIGHT / 2 } };
313 const vk::VkRect2D scissor_2 = { { WIDTH / 2, HEIGHT / 2 }, { WIDTH / 2, HEIGHT / 2 } };
314
315 setDynamicRasterizationState();
316 setDynamicBlendState();
317 setDynamicDepthStencilState();
318
319 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
320
321 const vk::VkDeviceSize vertexBufferOffset = 0;
322 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
323 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
324
325 // bind first state
326 setDynamicViewportState(1, &viewport, &scissor_1);
327 // draw quad using vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
328 m_vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
329
330 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineAdditional);
331
332 // bind second state
333 setDynamicViewportState(1, &viewport, &scissor_2);
334 // draw quad using vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
335 m_vk.cmdDraw(*m_cmdBuffer, 6, 1, 4, 0);
336
337 endRenderPass(m_vk, *m_cmdBuffer);
338 endCommandBuffer(m_vk, *m_cmdBuffer);
339
340 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
341
342 //validation
343 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
344 referenceFrame.allocLevel(0);
345
346 const deInt32 frameWidth = referenceFrame.getWidth();
347 const deInt32 frameHeight = referenceFrame.getHeight();
348
349 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
350
351 for (int y = 0; y < frameHeight; y++)
352 {
353 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
354
355 for (int x = 0; x < frameWidth; x++)
356 {
357 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
358
359 if (yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f)
360 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
361 else if (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f)
362 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
363 }
364 }
365
366 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
367 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
368 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
369
370 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
371 referenceFrame.getLevel(0), renderedFrame, 0.05f,
372 tcu::COMPARE_LOG_RESULT))
373 {
374 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
375 }
376
377 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
378 }
379 };
380
381 } //anonymous
382
DynamicStateGeneralTests(tcu::TestContext & testCtx)383 DynamicStateGeneralTests::DynamicStateGeneralTests (tcu::TestContext& testCtx)
384 : TestCaseGroup (testCtx, "general_state", "General tests for dynamic states")
385 {
386 /* Left blank on purpose */
387 }
388
~DynamicStateGeneralTests(void)389 DynamicStateGeneralTests::~DynamicStateGeneralTests (void) {}
390
init(void)391 void DynamicStateGeneralTests::init (void)
392 {
393 ShaderMap shaderPaths;
394 shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
395 shaderPaths[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
396
397 addChild(new InstanceFactory<StateSwitchTestInstance>(m_testCtx, "state_switch", "Perform multiple draws with different VP states (scissor test)", shaderPaths));
398 addChild(new InstanceFactory<BindOrderTestInstance>(m_testCtx, "bind_order", "Check if binding order is not important for pipeline configuration", shaderPaths));
399 addChild(new InstanceFactory<StatePersistenceTestInstance>(m_testCtx, "state_persistence", "Check if bound states are persistent across pipelines", shaderPaths));
400 }
401
402 } // DynamicState
403 } // vkt
404