1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Dynamic State Tests - General
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktDynamicStateGeneralTests.hpp"
28
29 #include "vktTestCaseUtil.hpp"
30 #include "vktDynamicStateTestCaseUtil.hpp"
31 #include "vktDynamicStateBaseClass.hpp"
32 #include "vktDrawCreateInfoUtil.hpp"
33 #include "vktDrawImageObjectUtil.hpp"
34 #include "vktDrawBufferObjectUtil.hpp"
35
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38
39 #include "tcuTestLog.hpp"
40 #include "tcuResource.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuTextureUtil.hpp"
43 #include "tcuRGBA.hpp"
44
45 #include "vkDefs.hpp"
46 #include "vkCmdUtil.hpp"
47 #include "vkObjUtil.hpp"
48 #include "vkBarrierUtil.hpp"
49
50 namespace vkt
51 {
52 namespace DynamicState
53 {
54
55 using namespace Draw;
56
57 namespace
58 {
59
60 class StateSwitchTestInstance : public DynamicStateBaseClass
61 {
62 public:
StateSwitchTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)63 StateSwitchTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
64 const ShaderMap &shaders)
65 : DynamicStateBaseClass(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX),
66 shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
67 {
68 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
69 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
70 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
71 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
72
73 DynamicStateBaseClass::initialize();
74 }
75
iterate(void)76 virtual tcu::TestStatus iterate(void)
77 {
78 tcu::TestLog &log = m_context.getTestContext().getLog();
79 const vk::VkQueue queue = m_context.getUniversalQueue();
80 const vk::VkDevice device = m_context.getDevice();
81
82 beginRenderPass();
83
84 // bind states here
85 vk::VkViewport viewport = {0, 0, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f};
86 vk::VkRect2D scissor_1 = {{0, 0}, {WIDTH / 2, HEIGHT / 2}};
87 vk::VkRect2D scissor_2 = {{WIDTH / 2, HEIGHT / 2}, {WIDTH / 2, HEIGHT / 2}};
88
89 setDynamicRasterizationState();
90 setDynamicBlendState();
91 setDynamicDepthStencilState();
92
93 m_pipeline.bind(*m_cmdBuffer);
94
95 #ifndef CTS_USES_VULKANSC
96 if (m_isMesh)
97 {
98 const auto numVert = static_cast<uint32_t>(m_data.size());
99 DE_ASSERT(numVert >= 2u);
100
101 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u,
102 1u, &m_descriptorSet.get(), 0u, nullptr);
103 pushVertexOffset(0u, *m_pipelineLayout);
104
105 // bind first state
106 setDynamicViewportState(1, &viewport, &scissor_1);
107 m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
108
109 // bind second state
110 setDynamicViewportState(1, &viewport, &scissor_2);
111 m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
112 }
113 else
114 #endif // CTS_USES_VULKANSC
115 {
116 const vk::VkDeviceSize vertexBufferOffset = 0;
117 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
118 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
119
120 // bind first state
121 setDynamicViewportState(1, &viewport, &scissor_1);
122 m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
123
124 // bind second state
125 setDynamicViewportState(1, &viewport, &scissor_2);
126 m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
127 }
128
129 m_renderPass.end(m_vk, *m_cmdBuffer);
130 endCommandBuffer(m_vk, *m_cmdBuffer);
131
132 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
133
134 //validation
135 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
136 (int)(0.5f + static_cast<float>(HEIGHT)));
137 referenceFrame.allocLevel(0);
138
139 const int32_t frameWidth = referenceFrame.getWidth();
140 const int32_t frameHeight = referenceFrame.getHeight();
141
142 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
143
144 for (int y = 0; y < frameHeight; y++)
145 {
146 const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
147
148 for (int x = 0; x < frameWidth; x++)
149 {
150 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
151
152 if ((yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f) ||
153 (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f))
154 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
155 }
156 }
157
158 const vk::VkOffset3D zeroOffset = {0, 0, 0};
159 const tcu::ConstPixelBufferAccess renderedFrame =
160 m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
161 zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
162
163 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame,
164 0.05f, tcu::COMPARE_LOG_RESULT))
165 {
166
167 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
168 }
169
170 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
171 }
172 };
173
174 class BindOrderTestInstance : public DynamicStateBaseClass
175 {
176 public:
BindOrderTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)177 BindOrderTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
178 const ShaderMap &shaders)
179 : DynamicStateBaseClass(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX),
180 shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
181 {
182 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
183 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
184 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
185 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
186
187 DynamicStateBaseClass::initialize();
188 }
189
iterate(void)190 virtual tcu::TestStatus iterate(void)
191 {
192 tcu::TestLog &log = m_context.getTestContext().getLog();
193 const vk::VkQueue queue = m_context.getUniversalQueue();
194 const vk::VkDevice device = m_context.getDevice();
195
196 beginRenderPass();
197
198 // bind states here
199 vk::VkViewport viewport = {0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f};
200 vk::VkRect2D scissor_1 = {{0, 0}, {WIDTH / 2, HEIGHT / 2}};
201 vk::VkRect2D scissor_2 = {{WIDTH / 2, HEIGHT / 2}, {WIDTH / 2, HEIGHT / 2}};
202
203 setDynamicRasterizationState();
204 setDynamicBlendState();
205 setDynamicDepthStencilState();
206 setDynamicViewportState(1, &viewport, &scissor_1);
207
208 m_pipeline.bind(*m_cmdBuffer);
209
210 #ifndef CTS_USES_VULKANSC
211 if (m_isMesh)
212 {
213 const auto numVert = static_cast<uint32_t>(m_data.size());
214 DE_ASSERT(numVert >= 2u);
215
216 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u,
217 1u, &m_descriptorSet.get(), 0u, nullptr);
218 pushVertexOffset(0u, *m_pipelineLayout);
219
220 // rebind in different order
221 setDynamicBlendState();
222 setDynamicRasterizationState();
223 setDynamicDepthStencilState();
224
225 // bind first state
226 setDynamicViewportState(1, &viewport, &scissor_1);
227 m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
228
229 setDynamicViewportState(1, &viewport, &scissor_2);
230 m_vk.cmdDrawMeshTasksEXT(*m_cmdBuffer, numVert - 2u, 1u, 1u);
231 }
232 else
233 #endif // CTS_USES_VULKANSC
234 {
235 const vk::VkDeviceSize vertexBufferOffset = 0;
236 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
237 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
238
239 // rebind in different order
240 setDynamicBlendState();
241 setDynamicRasterizationState();
242 setDynamicDepthStencilState();
243
244 // bind first state
245 setDynamicViewportState(1, &viewport, &scissor_1);
246 m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
247
248 setDynamicViewportState(1, &viewport, &scissor_2);
249 m_vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_data.size()), 1, 0, 0);
250 }
251
252 m_renderPass.end(m_vk, *m_cmdBuffer);
253 endCommandBuffer(m_vk, *m_cmdBuffer);
254
255 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
256
257 //validation
258 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
259 (int)(0.5f + static_cast<float>(HEIGHT)));
260 referenceFrame.allocLevel(0);
261
262 const int32_t frameWidth = referenceFrame.getWidth();
263 const int32_t frameHeight = referenceFrame.getHeight();
264
265 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
266
267 for (int y = 0; y < frameHeight; y++)
268 {
269 const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
270
271 for (int x = 0; x < frameWidth; x++)
272 {
273 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
274
275 if ((yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f) ||
276 (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f))
277 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
278 }
279 }
280
281 const vk::VkOffset3D zeroOffset = {0, 0, 0};
282 const tcu::ConstPixelBufferAccess renderedFrame =
283 m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
284 zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
285
286 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame,
287 0.05f, tcu::COMPARE_LOG_RESULT))
288 {
289 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
290 }
291
292 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
293 }
294 };
295
296 class StatePersistenceTestInstance : public DynamicStateBaseClass
297 {
298 protected:
299 vk::GraphicsPipelineWrapper m_pipelineAdditional;
300
301 public:
StatePersistenceTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const ShaderMap & shaders)302 StatePersistenceTestInstance(Context &context, vk::PipelineConstructionType pipelineConstructionType,
303 const ShaderMap &shaders)
304 : DynamicStateBaseClass(context, pipelineConstructionType, shaders.at(glu::SHADERTYPE_VERTEX),
305 shaders.at(glu::SHADERTYPE_FRAGMENT), shaders.at(glu::SHADERTYPE_MESH))
306 , m_pipelineAdditional(context.getInstanceInterface(), context.getDeviceInterface(),
307 context.getPhysicalDevice(), context.getDevice(), context.getDeviceExtensions(),
308 pipelineConstructionType)
309 {
310 // This test does not make sense for mesh shader variants.
311 DE_ASSERT(!m_isMesh);
312
313 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
314 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
315 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
316 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
317
318 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
319 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
320 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
321 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
322 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
323 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
324
325 DynamicStateBaseClass::initialize();
326 }
initPipeline(const vk::VkDevice device)327 virtual void initPipeline(const vk::VkDevice device)
328 {
329 const vk::ShaderWrapper vs(
330 vk::ShaderWrapper(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0));
331 const vk::ShaderWrapper fs(
332 vk::ShaderWrapper(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0));
333 std::vector<vk::VkViewport> viewports{{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}};
334 std::vector<vk::VkRect2D> scissors{{{0u, 0u}, {0u, 0u}}};
335
336 const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
337 const PipelineCreateInfo::ColorBlendState colorBlendState(
338 1, static_cast<const vk::VkPipelineColorBlendAttachmentState *>(&attachmentState));
339 const PipelineCreateInfo::RasterizerState rasterizerState;
340 const PipelineCreateInfo::DepthStencilState depthStencilState;
341 const PipelineCreateInfo::DynamicState dynamicState;
342
343 m_pipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
344 .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo *>(&dynamicState))
345 .setDefaultMultisampleState()
346 .setupVertexInputState(&m_vertexInputState)
347 .setupPreRasterizationShaderState(
348 viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vs,
349 static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState))
350 .setupFragmentShaderState(
351 m_pipelineLayout, *m_renderPass, 0u, fs,
352 static_cast<const vk::VkPipelineDepthStencilStateCreateInfo *>(&depthStencilState))
353 .setupFragmentOutputState(*m_renderPass, 0u,
354 static_cast<const vk::VkPipelineColorBlendStateCreateInfo *>(&colorBlendState))
355 .setMonolithicPipelineLayout(m_pipelineLayout)
356 .buildPipeline();
357
358 m_pipelineAdditional.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
359 .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo *>(&dynamicState))
360 .setDefaultMultisampleState()
361 .setupVertexInputState(&m_vertexInputState)
362 .setupPreRasterizationShaderState(
363 viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vs,
364 static_cast<const vk::VkPipelineRasterizationStateCreateInfo *>(&rasterizerState))
365 .setupFragmentShaderState(
366 m_pipelineLayout, *m_renderPass, 0u, fs,
367 static_cast<const vk::VkPipelineDepthStencilStateCreateInfo *>(&depthStencilState))
368 .setupFragmentOutputState(*m_renderPass, 0u,
369 static_cast<const vk::VkPipelineColorBlendStateCreateInfo *>(&colorBlendState))
370 .setMonolithicPipelineLayout(m_pipelineLayout)
371 .buildPipeline();
372 }
373
iterate(void)374 virtual tcu::TestStatus iterate(void)
375 {
376 tcu::TestLog &log = m_context.getTestContext().getLog();
377 const vk::VkQueue queue = m_context.getUniversalQueue();
378 const vk::VkDevice device = m_context.getDevice();
379
380 beginRenderPass();
381
382 // bind states here
383 const vk::VkViewport viewport = {0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f};
384 const vk::VkRect2D scissor_1 = {{0, 0}, {WIDTH / 2, HEIGHT / 2}};
385 const vk::VkRect2D scissor_2 = {{WIDTH / 2, HEIGHT / 2}, {WIDTH / 2, HEIGHT / 2}};
386
387 setDynamicRasterizationState();
388 setDynamicBlendState();
389 setDynamicDepthStencilState();
390
391 m_pipeline.bind(*m_cmdBuffer);
392
393 const vk::VkDeviceSize vertexBufferOffset = 0;
394 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
395 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
396
397 // bind first state
398 setDynamicViewportState(1, &viewport, &scissor_1);
399 // draw quad using vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
400 m_vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
401
402 m_pipelineAdditional.bind(*m_cmdBuffer);
403
404 // bind second state
405 setDynamicViewportState(1, &viewport, &scissor_2);
406 // draw quad using vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
407 m_vk.cmdDraw(*m_cmdBuffer, 6, 1, 4, 0);
408
409 m_renderPass.end(m_vk, *m_cmdBuffer);
410 endCommandBuffer(m_vk, *m_cmdBuffer);
411
412 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
413
414 //validation
415 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
416 (int)(0.5f + static_cast<float>(HEIGHT)));
417 referenceFrame.allocLevel(0);
418
419 const int32_t frameWidth = referenceFrame.getWidth();
420 const int32_t frameHeight = referenceFrame.getHeight();
421
422 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
423
424 for (int y = 0; y < frameHeight; y++)
425 {
426 const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
427
428 for (int x = 0; x < frameWidth; x++)
429 {
430 const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
431
432 if (yCoord >= -1.0f && yCoord <= 0.0f && xCoord >= -1.0f && xCoord <= 0.0f)
433 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y);
434 else if (yCoord > 0.0f && yCoord <= 1.0f && xCoord > 0.0f && xCoord < 1.0f)
435 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
436 }
437 }
438
439 const vk::VkOffset3D zeroOffset = {0, 0, 0};
440 const tcu::ConstPixelBufferAccess renderedFrame =
441 m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
442 zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
443
444 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame,
445 0.05f, tcu::COMPARE_LOG_RESULT))
446 {
447 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
448 }
449
450 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
451 }
452 };
453
454 #ifndef CTS_USES_VULKANSC
checkMeshShaderSupport(Context & context)455 void checkMeshShaderSupport(Context &context)
456 {
457 context.requireDeviceFunctionality("VK_EXT_mesh_shader");
458 }
459 #endif // CTS_USES_VULKANSC
460
checkNothing(Context &)461 void checkNothing(Context &)
462 {
463 }
464
initStaticStencilMaskZeroPrograms(vk::SourceCollections & dst,vk::PipelineConstructionType)465 void initStaticStencilMaskZeroPrograms(vk::SourceCollections &dst, vk::PipelineConstructionType)
466 {
467 std::ostringstream vert;
468 vert << "#version 460\n"
469 << "layout (location=0) in vec4 inPos;\n"
470 << "layout (location=1) in vec4 inColor;\n"
471 << "layout (location=0) out vec4 outColor;\n"
472 << "void main (void) {\n"
473 << " gl_Position = inPos;\n"
474 << " outColor = inColor;\n"
475 << "}\n";
476 dst.glslSources.add("vert") << glu::VertexSource(vert.str());
477
478 // Fragment shader such that it will actually discard all fragments.
479 std::ostringstream frag;
480 frag << "#version 460\n"
481 << "layout (location=0) in vec4 inColor;\n"
482 << "layout (location=0) out vec4 outColor;\n"
483 << "void main (void) {\n"
484 << " if (inColor == vec4(0.0, 0.0, 1.0, 1.0)) {\n"
485 << " discard;\n"
486 << " }\n"
487 << " outColor = inColor;\n"
488 << "}\n";
489 dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
490 }
491
checkStaticStencilMaskZeroSupport(vkt::Context & context,vk::PipelineConstructionType pipelineConstructionType)492 void checkStaticStencilMaskZeroSupport(vkt::Context &context, vk::PipelineConstructionType pipelineConstructionType)
493 {
494 const auto &vki = context.getInstanceInterface();
495 const auto physicalDevice = context.getPhysicalDevice();
496
497 checkPipelineConstructionRequirements(vki, physicalDevice, pipelineConstructionType);
498 }
499
500 // Find a suitable format for the depth/stencil buffer.
chooseDepthStencilFormat(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physDev)501 vk::VkFormat chooseDepthStencilFormat(const vk::InstanceInterface &vki, vk::VkPhysicalDevice physDev)
502 {
503 // The spec mandates support for one of these two formats.
504 const vk::VkFormat candidates[] = {vk::VK_FORMAT_D32_SFLOAT_S8_UINT, vk::VK_FORMAT_D24_UNORM_S8_UINT};
505
506 for (const auto &format : candidates)
507 {
508 const auto properties = getPhysicalDeviceFormatProperties(vki, physDev, format);
509 if ((properties.optimalTilingFeatures & vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u)
510 return format;
511 }
512
513 TCU_FAIL("No suitable depth/stencil format found");
514 return vk::VK_FORMAT_UNDEFINED; // Unreachable.
515 }
516
517 // On some implementations, when the static state is 0, the pipeline is created
518 // such that it is unable to avoid writing to stencil when a pixel is discarded.
staticStencilMaskZeroProgramsTest(Context & context,vk::PipelineConstructionType pipelineConstructionType)519 tcu::TestStatus staticStencilMaskZeroProgramsTest(Context &context,
520 vk::PipelineConstructionType pipelineConstructionType)
521 {
522 const auto &ctx = context.getContextCommonData();
523 const tcu::IVec3 fbExtent(1, 1, 1);
524 const auto pixelCount = fbExtent.x() * fbExtent.y() * fbExtent.z();
525 const auto vkExtent = vk::makeExtent3D(fbExtent);
526 const auto fbFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
527 const auto tcuFormat = mapVkFormat(fbFormat);
528 const auto fbUsage = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
529 const auto dsFormat = chooseDepthStencilFormat(ctx.vki, ctx.physicalDevice);
530 const auto depthFormat = vk::getDepthCopyFormat(dsFormat);
531 const auto stencilFmt = vk::getStencilCopyFormat(dsFormat);
532 const auto dsUsage = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
533 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
534 const float clearDepth = 1.0f;
535 const uint32_t clearStenc = 0u;
536 const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader discard color.
537 const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
538 const auto colorSRR = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
539 const auto dsSRR = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT),
540 0u, 1u, 0u, 1u);
541 const auto colorSRL = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
542 const auto depthSRL = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u);
543 const auto stencilSRL = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 0u, 1u);
544
545 // Color buffer with verification buffer.
546 vk::ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage,
547 vk::VK_IMAGE_TYPE_2D);
548
549 // Depth/stencil buffer.
550 const vk::VkImageCreateInfo dsCreateInfo = {
551 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
552 nullptr, // const void* pNext;
553 0u, // VkImageCreateFlags flags;
554 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
555 dsFormat, // VkFormat format;
556 vkExtent, // VkExtent3D extent;
557 1u, // uint32_t mipLevels;
558 1u, // uint32_t arrayLayers;
559 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
560 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
561 dsUsage, // VkImageUsageFlags usage;
562 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
563 0u, // uint32_t queueFamilyIndexCount;
564 nullptr, // const uint32_t* pQueueFamilyIndices;
565 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
566 };
567 vk::ImageWithMemory dsBuffer(ctx.vkd, ctx.device, ctx.allocator, dsCreateInfo, vk::MemoryRequirement::Any);
568 const auto dsImageView =
569 vk::makeImageView(ctx.vkd, ctx.device, dsBuffer.get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsSRR);
570
571 // Verification buffers for depth and stencil.
572 const auto depthVerifBufferSize = static_cast<vk::VkDeviceSize>(tcu::getPixelSize(depthFormat) * pixelCount);
573 const auto depthVerifBufferInfo =
574 vk::makeBufferCreateInfo(depthVerifBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
575 vk::BufferWithMemory depthVerifBuffer(ctx.vkd, ctx.device, ctx.allocator, depthVerifBufferInfo,
576 vk::MemoryRequirement::HostVisible);
577
578 const auto stencilVerifBufferSize = static_cast<vk::VkDeviceSize>(tcu::getPixelSize(stencilFmt) * pixelCount);
579 const auto stencilVerifBufferInfo =
580 vk::makeBufferCreateInfo(stencilVerifBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
581 vk::BufferWithMemory stencilVerifBuffer(ctx.vkd, ctx.device, ctx.allocator, stencilVerifBufferInfo,
582 vk::MemoryRequirement::HostVisible);
583
584 // Vertices.
585 const std::vector<PositionColorVertex> vertices{
586 PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), geomColor),
587 PositionColorVertex(tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f), geomColor),
588 PositionColorVertex(tcu::Vec4(3.0f, -1.0f, 0.0f, 1.0f), geomColor),
589 };
590
591 // Vertex buffer
592 const auto vbSize = static_cast<vk::VkDeviceSize>(de::dataSize(vertices));
593 const auto vbInfo = vk::makeBufferCreateInfo(vbSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
594 vk::BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, vk::MemoryRequirement::HostVisible);
595 const auto vbAlloc = vertexBuffer.getAllocation();
596 void *vbData = vbAlloc.getHostPtr();
597 const auto vbOffset = static_cast<vk::VkDeviceSize>(0);
598
599 deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
600 flushAlloc(ctx.vkd, ctx.device, vbAlloc); // strictly speaking, not needed.
601
602 const std::vector<vk::VkImage> framebufferImages{
603 colorBuffer.getImage(),
604 dsBuffer.get(),
605 };
606
607 const std::vector<vk::VkImageView> framebufferViews{
608 colorBuffer.getImageView(),
609 dsImageView.get(),
610 };
611
612 const auto pipelineLayout = vk::PipelineLayoutWrapper(pipelineConstructionType, ctx.vkd, ctx.device);
613 auto renderPass = vk::RenderPassWrapper(pipelineConstructionType, ctx.vkd, ctx.device, fbFormat, dsFormat);
614
615 DE_ASSERT(framebufferImages.size() == framebufferViews.size());
616 renderPass.createFramebuffer(ctx.vkd, ctx.device, de::sizeU32(framebufferViews), de::dataOrNull(framebufferImages),
617 de::dataOrNull(framebufferViews), vkExtent.width, vkExtent.height);
618
619 // Modules.
620 const auto &binaries = context.getBinaryCollection();
621 const auto vertModule = vk::ShaderWrapper(ctx.vkd, ctx.device, binaries.get("vert"));
622 const auto fragModule = vk::ShaderWrapper(ctx.vkd, ctx.device, binaries.get("frag"));
623
624 const std::vector<vk::VkViewport> viewports(1u, makeViewport(vkExtent));
625 const std::vector<vk::VkRect2D> scissors(1u, makeRect2D(vkExtent));
626
627 const auto stencilStaticWriteMask =
628 0u; // This is key for this test and what was causing issues in some implementations.
629 const auto stencilDynamicWriteMask = 0xFFu;
630
631 const std::vector<vk::VkDynamicState> dynamicStates{vk::VK_DYNAMIC_STATE_STENCIL_WRITE_MASK};
632
633 // The stencil op state is such that it will overwrite the stencil value for all non-discarded fragments.
634 // However, the fragment shader should discard all fragments.
635 const auto stencilOpState =
636 vk::makeStencilOpState(vk::VK_STENCIL_OP_REPLACE, vk::VK_STENCIL_OP_REPLACE, vk::VK_STENCIL_OP_REPLACE,
637 vk::VK_COMPARE_OP_ALWAYS, 0xFFu, stencilStaticWriteMask, 0xFFu);
638
639 const auto vtxBindingDesc = vk::makeVertexInputBindingDescription(
640 0u, static_cast<uint32_t>(sizeof(PositionColorVertex)), vk::VK_VERTEX_INPUT_RATE_VERTEX);
641
642 const std::vector<vk::VkVertexInputAttributeDescription> vtxAttributes{
643 vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
644 static_cast<uint32_t>(offsetof(PositionColorVertex, position))),
645 vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
646 static_cast<uint32_t>(offsetof(PositionColorVertex, color))),
647 };
648
649 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
650 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
651 nullptr, // const void* pNext;
652 0u, // VkPipelineVertexInputStateCreateFlags flags;
653 1u, // uint32_t vertexBindingDescriptionCount;
654 &vtxBindingDesc, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
655 de::sizeU32(vtxAttributes), // uint32_t vertexAttributeDescriptionCount;
656 de::dataOrNull(vtxAttributes), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
657 };
658
659 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilState = {
660 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
661 nullptr, // const void* pNext;
662 0u, // VkPipelineDepthStencilStateCreateFlags flags;
663 VK_FALSE, // VkBool32 depthTestEnable;
664 VK_TRUE, // VkBool32 depthWriteEnable;
665 vk::VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
666 VK_FALSE, // VkBool32 depthBoundsTestEnable;
667 VK_TRUE, // VkBool32 stencilTestEnable;
668 stencilOpState, // VkStencilOpState front;
669 stencilOpState, // VkStencilOpState back;
670 0.0f, // float minDepthBounds;
671 1.0f, // float maxDepthBounds;
672 };
673
674 const vk::VkPipelineDynamicStateCreateInfo dynamicStateInfo = {
675 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
676 nullptr, // const void* pNext;
677 0u, // VkPipelineDynamicStateCreateFlags flags;
678 de::sizeU32(dynamicStates), // uint32_t dynamicStateCount;
679 de::dataOrNull(dynamicStates), // const VkDynamicState* pDynamicStates;
680 };
681
682 vk::GraphicsPipelineWrapper pipeline(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
683 context.getDeviceExtensions(), pipelineConstructionType);
684 pipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
685 .setDefaultMultisampleState()
686 .setDefaultRasterizationState()
687 .setDefaultColorBlendState()
688 .setDynamicState(&dynamicStateInfo)
689 .setupVertexInputState(&vertexInputStateCreateInfo)
690 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u, vertModule)
691 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragModule, &depthStencilState)
692 .setupFragmentOutputState(*renderPass)
693 .setMonolithicPipelineLayout(pipelineLayout)
694 .buildPipeline();
695
696 vk::CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
697 const auto cmdBuffer = *cmd.cmdBuffer;
698
699 const std::vector<vk::VkClearValue> clearValues{
700 vk::makeClearValueColor(clearColor),
701 vk::makeClearValueDepthStencil(clearDepth, clearStenc),
702 };
703
704 beginCommandBuffer(ctx.vkd, cmdBuffer);
705 renderPass.begin(ctx.vkd, cmdBuffer, scissors.at(0u), de::sizeU32(clearValues), de::dataOrNull(clearValues));
706 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
707 pipeline.bind(cmdBuffer);
708 ctx.vkd.cmdSetStencilWriteMask(cmdBuffer, vk::VK_STENCIL_FACE_FRONT_AND_BACK,
709 stencilDynamicWriteMask); // Write every value.
710 ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
711 renderPass.end(ctx.vkd, cmdBuffer);
712 {
713 // Insert barriers and copy images to the different verification buffers.
714 const std::vector<vk::VkImageMemoryBarrier> imageBarriers{
715 // Color barrier.
716 vk::makeImageMemoryBarrier(vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
717 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
718 vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getImage(), colorSRR),
719 // Depth/stencil barrier.
720 vk::makeImageMemoryBarrier(vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
721 vk::VK_ACCESS_TRANSFER_READ_BIT,
722 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
723 vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dsBuffer.get(), dsSRR),
724 };
725 const auto srcPipelineStages =
726 (vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
727 vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
728
729 ctx.vkd.cmdPipelineBarrier(cmdBuffer, srcPipelineStages, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr,
730 0u, nullptr, de::sizeU32(imageBarriers), de::dataOrNull(imageBarriers));
731
732 const auto colorRegion = vk::makeBufferImageCopy(vkExtent, colorSRL);
733 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.getImage(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
734 colorBuffer.getBuffer(), 1u, &colorRegion);
735
736 const auto depthRegion = vk::makeBufferImageCopy(vkExtent, depthSRL);
737 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
738 depthVerifBuffer.get(), 1u, &depthRegion);
739
740 const auto stencilRegion = vk::makeBufferImageCopy(vkExtent, stencilSRL);
741 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
742 stencilVerifBuffer.get(), 1u, &stencilRegion);
743 }
744 {
745 // Transfer to host sync barrier.
746 const auto transfer2Host = vk::makeMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT);
747 ctx.vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u,
748 1u, &transfer2Host, 0u, nullptr, 0u, nullptr);
749 }
750 endCommandBuffer(ctx.vkd, cmdBuffer);
751 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
752
753 auto &log = context.getTestContext().getLog();
754
755 // Verify color output.
756 vk::invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
757 tcu::PixelBufferAccess resColorAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
758
759 tcu::TextureLevel refColorLevel(tcuFormat, fbExtent.x(), fbExtent.y());
760 auto refColorAccess = refColorLevel.getAccess();
761 tcu::clear(refColorAccess, clearColor); // All fragments should have been discarded.
762
763 if (!tcu::floatThresholdCompare(log, "ColorResult", "", refColorAccess, resColorAccess, threshold,
764 tcu::COMPARE_LOG_ON_ERROR))
765 return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
766
767 // Verify depth.
768 vk::invalidateAlloc(ctx.vkd, ctx.device, depthVerifBuffer.getAllocation());
769 tcu::PixelBufferAccess resDepthAccess(depthFormat, fbExtent, depthVerifBuffer.getAllocation().getHostPtr());
770
771 tcu::TextureLevel refDepthLevel(depthFormat, fbExtent.x(), fbExtent.y());
772 auto refDepthAccess = refDepthLevel.getAccess();
773 tcu::clearDepth(refDepthAccess, clearDepth); // All fragments should have been discarded.
774
775 if (!tcu::dsThresholdCompare(log, "DepthResult", "", refDepthAccess, resDepthAccess, 0.0f,
776 tcu::COMPARE_LOG_ON_ERROR))
777 return tcu::TestStatus::fail("Unexpected depth in result buffer; check log for details");
778
779 // Verify stencil.
780 vk::invalidateAlloc(ctx.vkd, ctx.device, stencilVerifBuffer.getAllocation());
781 tcu::PixelBufferAccess resStencilAccess(stencilFmt, fbExtent, stencilVerifBuffer.getAllocation().getHostPtr());
782
783 tcu::TextureLevel refStencilLevel(stencilFmt, fbExtent.x(), fbExtent.y());
784 auto refStencilAccess = refStencilLevel.getAccess();
785 tcu::clearStencil(refStencilAccess, static_cast<int>(clearStenc)); // All fragments should have been discarded.
786
787 if (!tcu::dsThresholdCompare(log, "StencilResult", "", refStencilAccess, resStencilAccess, 0.0f,
788 tcu::COMPARE_LOG_ON_ERROR))
789 return tcu::TestStatus::fail("Unexpected stencil value in result buffer; check log for details");
790
791 return tcu::TestStatus::pass("Pass");
792 }
793
initDoubleBindPrograms(vk::SourceCollections & dst)794 void initDoubleBindPrograms(vk::SourceCollections &dst)
795 {
796 std::ostringstream vert;
797 vert << "#version 460\n"
798 << "const vec4 vertices[] = vec4[](\n"
799 << " vec4(-1.0, -1.0, 0.0, 1.0),\n"
800 << " vec4(-1.0, 3.0, 0.0, 1.0),\n"
801 << " vec4( 3.0, -1.0, 0.0, 1.0)\n"
802 << ");\n"
803 << "void main (void) {\n"
804 << " gl_Position = vertices[gl_VertexIndex % 3];\n"
805 << "}\n";
806 dst.glslSources.add("vert") << glu::VertexSource(vert.str());
807
808 std::ostringstream frag;
809 frag << "#version 460\n"
810 << "layout (location=0) out vec4 outColor;\n"
811 << "void main (void) {\n"
812 << " outColor = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"
813 << "}\n";
814 dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
815 }
816
817 // The test does:
818 // - bind pipeline with some static state.
819 // - set state command for that static state (to a bad value).
820 // - bind the same pipeline again.
821 // - draw.
822 // - verify the good value has been used.
823 // In this case, the bad state and value will be the scissor, but the pipeline will also have a dynamic viewport.
doubleBindTest(Context & context)824 tcu::TestStatus doubleBindTest(Context &context)
825 {
826 const auto &ctx = context.getContextCommonData();
827 const tcu::IVec3 fbExtent(2, 2, 1);
828 const auto vkExtent = vk::makeExtent3D(fbExtent);
829 const auto fbFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
830 const auto tcuFormat = mapVkFormat(fbFormat);
831 const auto fbUsage = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
832 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
833 const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
834 const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
835 const auto bindPoint = vk::VK_PIPELINE_BIND_POINT_GRAPHICS;
836
837 // Color buffer with verification buffer.
838 vk::ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage,
839 vk::VK_IMAGE_TYPE_2D);
840
841 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
842 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, fbFormat);
843 const auto framebuffer =
844 makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height);
845
846 // Modules.
847 const auto &binaries = context.getBinaryCollection();
848 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
849 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
850
851 const std::vector<vk::VkDynamicState> dynamicStates{
852 vk::VK_DYNAMIC_STATE_VIEWPORT,
853 };
854
855 const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
856 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
857 nullptr, // const void* pNext;
858 0u, // VkPipelineDynamicStateCreateFlags flags;
859 de::sizeU32(dynamicStates), // uint32_t dynamicStateCount;
860 de::dataOrNull(dynamicStates), // const VkDynamicState* pDynamicStates;
861 };
862
863 const auto goodViewport = makeViewport(vkExtent);
864 const auto goodScissor = vk::makeRect2D(vkExtent);
865 const auto badViewport = vk::makeViewport(1u, 1u); // Needs to be smaller than the framebuffer.
866 const auto badScissor = vk::makeRect2D(1u, 1u); // Needs to be smaller than the framebuffer.
867
868 const std::vector<vk::VkViewport> staticViewports(1u, badViewport);
869 const std::vector<vk::VkRect2D> staticScissors(1u, goodScissor);
870
871 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = vk::initVulkanStructure();
872
873 const auto pipeline = makeGraphicsPipeline(
874 ctx.vkd, ctx.device, *pipelineLayout, *vertModule, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, *fragModule,
875 *renderPass, staticViewports, staticScissors, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
876 &vertexInputStateCreateInfo, nullptr, nullptr, nullptr, nullptr, &dynamicStateCreateInfo);
877
878 vk::CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
879 const auto cmdBuffer = *cmd.cmdBuffer;
880
881 beginCommandBuffer(ctx.vkd, cmdBuffer);
882 beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, goodScissor, clearColor);
883 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
884 ctx.vkd.cmdSetScissor(cmdBuffer, 0u, 1u, &badScissor); // This should not be taken into account.
885 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
886 ctx.vkd.cmdSetViewport(cmdBuffer, 0u, 1u, &goodViewport); // The static one was bad too.
887 ctx.vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
888 endRenderPass(ctx.vkd, cmdBuffer);
889 copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
890 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
891 vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_ASPECT_COLOR_BIT,
892 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
893 endCommandBuffer(ctx.vkd, cmdBuffer);
894 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
895
896 // Verify color output.
897 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
898 tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
899
900 tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
901 auto referenceAccess = referenceLevel.getAccess();
902 tcu::clear(referenceAccess, geomColor);
903
904 auto &log = context.getTestContext().getLog();
905 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
906 tcu::COMPARE_LOG_ON_ERROR))
907 return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
908
909 return tcu::TestStatus::pass("Pass");
910 }
911
912 } // namespace
913
914 // General tests for dynamic states
DynamicStateGeneralTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)915 DynamicStateGeneralTests::DynamicStateGeneralTests(tcu::TestContext &testCtx,
916 vk::PipelineConstructionType pipelineConstructionType)
917 : TestCaseGroup(testCtx, "general_state")
918 , m_pipelineConstructionType(pipelineConstructionType)
919 {
920 /* Left blank on purpose */
921 }
922
~DynamicStateGeneralTests(void)923 DynamicStateGeneralTests::~DynamicStateGeneralTests(void)
924 {
925 }
926
init(void)927 void DynamicStateGeneralTests::init(void)
928 {
929 ShaderMap basePaths;
930 basePaths[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
931 basePaths[glu::SHADERTYPE_MESH] = nullptr;
932 basePaths[glu::SHADERTYPE_VERTEX] = nullptr;
933
934 for (int i = 0; i < 2; ++i)
935 {
936 const bool isMesh = (i > 0);
937 ShaderMap shaderPaths(basePaths);
938 std::string nameSuffix;
939 FunctionSupport0::Function checkSupportFunc;
940
941 if (isMesh)
942 {
943 #ifndef CTS_USES_VULKANSC
944 shaderPaths[glu::SHADERTYPE_MESH] = "vulkan/dynamic_state/VertexFetch.mesh";
945 nameSuffix = "_mesh";
946 checkSupportFunc = checkMeshShaderSupport;
947 #else
948 continue;
949 #endif // CTS_USES_VULKANSC
950 }
951 else
952 {
953 shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
954 checkSupportFunc = checkNothing;
955 }
956
957 // Perform multiple draws with different VP states (scissor test)
958 addChild(new InstanceFactory<StateSwitchTestInstance, FunctionSupport0>(
959 m_testCtx, "state_switch" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
960 // Check if binding order is not important for pipeline configuration
961 addChild(new InstanceFactory<BindOrderTestInstance, FunctionSupport0>(
962 m_testCtx, "bind_order" + nameSuffix, m_pipelineConstructionType, shaderPaths, checkSupportFunc));
963 if (!isMesh)
964 {
965 // Check if bound states are persistent across pipelines
966 addChild(new InstanceFactory<StatePersistenceTestInstance>(m_testCtx, "state_persistence" + nameSuffix,
967 m_pipelineConstructionType, shaderPaths));
968 }
969 }
970
971 addFunctionCaseWithPrograms(this, "static_stencil_mask_zero", checkStaticStencilMaskZeroSupport,
972 initStaticStencilMaskZeroPrograms, staticStencilMaskZeroProgramsTest,
973 m_pipelineConstructionType);
974
975 if (!vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
976 {
977 addFunctionCaseWithPrograms(this, "double_static_bind", initDoubleBindPrograms, doubleBindTest);
978 }
979 }
980
981 } // namespace DynamicState
982 } // namespace vkt
983