1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group 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 DYnamic State Line Width Tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktDynamicStateLineWidthTests.hpp"
25 #include "vktDynamicStateBaseClass.hpp"
26 #include "vkTypeUtil.hpp"
27 #include "vkObjUtil.hpp"
28 #include "vkBufferWithMemory.hpp"
29 #include "vkImageWithMemory.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33
34 #include <array>
35 #include <functional>
36 #include <sstream>
37
38 using namespace vk;
39
40 namespace vkt
41 {
42 namespace DynamicState
43 {
44 namespace
45 {
46 struct TestLineWidthParams
47 {
48 VkPrimitiveTopology staticTopo;
49 VkPrimitiveTopology dynamicTopo;
50 uint32_t staticWidth;
51 uint32_t dynamicWidth;
52 bool dynamicFirst;
53 VkFormat format;
54 uint32_t width;
55 uint32_t height;
56 std::string rep() const;
57 };
58
59 struct LineWidthInstance : public DynamicStateBaseClass
60 {
LineWidthInstancevkt::DynamicState::__anonbf6ccddf0111::LineWidthInstance61 LineWidthInstance(Context &context, PipelineConstructionType pipelineConstructionType,
62 const TestLineWidthParams ¶ms)
63 : DynamicStateBaseClass(context, pipelineConstructionType, "vert", "frag")
64 , m_params(params)
65 { /* Intentionally empty */
66 }
67 de::MovePtr<BufferWithMemory> buildVertices(VkPrimitiveTopology lineTopology, bool horizontal,
68 uint32_t *vertexCount);
69 Move<VkRenderPass> buildRenderPass(VkFormat format);
70 void beginColorRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer,
71 const uint32_t width, const uint32_t height);
72 de::MovePtr<ImageWithMemory> buildImage(VkFormat format, uint32_t width, uint32_t height);
73 Move<VkImageView> buildView(const VkImage image, VkFormat format);
74 Move<VkPipeline> buildPipeline(VkPrimitiveTopology lineTopology, float lineWidth, bool dynamic, uint32_t subpass,
75 VkPipelineLayout layout, VkShaderModule vertexModule, VkShaderModule fragmentModule,
76 VkRenderPass renderPass, uint32_t width, uint32_t height);
77 tcu::TestStatus iterate() override;
78 bool verifyResults(const BufferWithMemory &resultBuffer, const tcu::Vec4 &dynamicColor,
79 const tcu::Vec4 &staticColor, const VkFormat format, const uint32_t width, const uint32_t height,
80 const uint32_t dynamicWidth, const uint32_t staticWidth);
81
82 private:
83 const TestLineWidthParams m_params;
84 };
85
86 template <class T, class P = T (*)[1], class R = decltype(std::begin(*std::declval<P>()))>
makeStdBeginEnd(void * p,uint32_t n)87 auto makeStdBeginEnd(void *p, uint32_t n) -> std::pair<R, R>
88 {
89 auto tmp = std::begin(*P(p));
90 auto begin = tmp;
91 std::advance(tmp, n);
92 return {begin, tmp};
93 }
94
buildVertices(VkPrimitiveTopology lineTopology,bool horizontal,uint32_t * vertexCount)95 de::MovePtr<BufferWithMemory> LineWidthInstance::buildVertices(VkPrimitiveTopology lineTopology, bool horizontal,
96 uint32_t *vertexCount)
97 {
98 typedef tcu::Vec4 ElementType;
99 std::vector<ElementType> vertices;
100 if (lineTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
101 {
102 if (horizontal)
103 {
104 vertices.emplace_back(-1.0f, 0.0f, 0.0f, 0.0f);
105 vertices.emplace_back(0.0f, 0.0f, 0.0f, 0.0f);
106 vertices.emplace_back(0.0f, 0.0f, 0.0f, 0.0f);
107 vertices.emplace_back(+1.0f, 0.0f, 0.0f, 0.0f);
108 }
109 else
110 {
111 vertices.emplace_back(0.0f, -1.0f, 0.0f, 0.0f);
112 vertices.emplace_back(0.0f, 0.0f, 0.0f, 0.0f);
113 vertices.emplace_back(0.0f, 0.0f, 0.0f, 0.0f);
114 vertices.emplace_back(0.0f, +1.0f, 0.0f, 0.0f);
115 }
116 }
117 else if (lineTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)
118 {
119 if (horizontal)
120 {
121 vertices.emplace_back(-1.0f, 0.0f, 0.0f, 0.0f);
122 vertices.emplace_back(0.0f, 0.0f, 0.0f, 0.0f);
123 vertices.emplace_back(+1.0f, 0.0f, 0.0f, 0.0f);
124 }
125 else
126 {
127 vertices.emplace_back(0.0f, -1.0f, 0.0f, 0.0f);
128 vertices.emplace_back(0.0f, 0.0f, 0.0f, 0.0f);
129 vertices.emplace_back(0.0f, +1.0f, 0.0f, 0.0f);
130 }
131 }
132 else
133 {
134 DE_ASSERT(VK_FALSE);
135 }
136 const VkBufferCreateInfo createInfo =
137 makeBufferCreateInfo(vertices.size() * sizeof(ElementType), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
138 BufferWithMemory *pBuffer =
139 new BufferWithMemory(m_context.getDeviceInterface(), m_context.getDevice(), m_context.getDefaultAllocator(),
140 createInfo, (MemoryRequirement::HostVisible | MemoryRequirement::Coherent));
141 DE_ASSERT(vertexCount);
142 *vertexCount = static_cast<uint32_t>(vertices.size());
143 auto range = makeStdBeginEnd<ElementType>(pBuffer->getAllocation().getHostPtr(), *vertexCount);
144 std::copy(vertices.begin(), vertices.end(), range.first);
145
146 return de::MovePtr<BufferWithMemory>(pBuffer);
147 }
148
buildRenderPass(VkFormat format)149 Move<VkRenderPass> LineWidthInstance::buildRenderPass(VkFormat format)
150 {
151 VkAttachmentDescription desc{};
152 desc.flags = VkAttachmentDescriptionFlags(0);
153 desc.format = format;
154 desc.samples = VK_SAMPLE_COUNT_1_BIT;
155 desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
156 desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
157 desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
158 desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
159 desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
160 desc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
161
162 VkAttachmentReference ref{};
163 ref.attachment = 0u;
164 ref.layout = desc.finalLayout;
165
166 VkSubpassDescription subpassTemplate{};
167 subpassTemplate.flags = VkSubpassDescriptionFlags(0);
168 subpassTemplate.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
169 subpassTemplate.colorAttachmentCount = 1u;
170 subpassTemplate.pColorAttachments = &ref;
171 subpassTemplate.pDepthStencilAttachment = nullptr;
172 subpassTemplate.inputAttachmentCount = 0;
173 subpassTemplate.pInputAttachments = nullptr;
174 subpassTemplate.preserveAttachmentCount = 0;
175 subpassTemplate.pPreserveAttachments = nullptr;
176 subpassTemplate.pResolveAttachments = nullptr;
177
178 std::array<VkSubpassDescription, 2> subpasses{subpassTemplate, subpassTemplate};
179
180 VkSubpassDependency dependency{};
181 dependency.srcSubpass = 0u;
182 dependency.dstSubpass = 1u;
183 dependency.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
184 dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
185 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
186 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
187
188 VkRenderPassCreateInfo renderPassInfo = initVulkanStructure();
189 renderPassInfo.attachmentCount = 1u;
190 renderPassInfo.pAttachments = &desc;
191 renderPassInfo.subpassCount = 2u;
192 renderPassInfo.pSubpasses = subpasses.data();
193 renderPassInfo.dependencyCount = 1u;
194 renderPassInfo.pDependencies = &dependency;
195
196 return createRenderPass(m_context.getDeviceInterface(), m_context.getDevice(), &renderPassInfo, nullptr);
197 }
198
beginColorRenderPass(VkCommandBuffer commandBuffer,VkRenderPass renderPass,VkFramebuffer framebuffer,const uint32_t width,const uint32_t height)199 void LineWidthInstance::beginColorRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass,
200 VkFramebuffer framebuffer, const uint32_t width, const uint32_t height)
201 {
202 const VkClearValue clearColor{{{0.f, 0.f, 0.f, 0.f}}};
203 const VkRenderPassBeginInfo renderPassBeginInfo = {
204 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
205 nullptr, // const void* pNext;
206 renderPass, // VkRenderPass renderPass;
207 framebuffer, // VkFramebuffer framebuffer;
208 makeRect2D(width, height), // VkRect2D renderArea;
209 1u, // uint32_t clearValueCount;
210 &clearColor // const VkClearValue* pClearValues;
211 };
212 m_context.getDeviceInterface().cmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
213 }
214
buildImage(VkFormat format,uint32_t width,uint32_t height)215 de::MovePtr<ImageWithMemory> LineWidthInstance::buildImage(VkFormat format, uint32_t width, uint32_t height)
216 {
217 VkImageCreateInfo createInfo = initVulkanStructure();
218 createInfo.flags = VkImageCreateFlags(0);
219 createInfo.imageType = VK_IMAGE_TYPE_2D;
220 createInfo.format = format;
221 createInfo.extent = makeExtent3D(width, height, 1u);
222 createInfo.mipLevels = 1u;
223 createInfo.arrayLayers = 1u;
224 createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
225 createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
226 createInfo.usage =
227 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
228 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
229 createInfo.queueFamilyIndexCount = 0u;
230 createInfo.pQueueFamilyIndices = nullptr;
231 createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
232
233 return de::MovePtr<ImageWithMemory>(new ImageWithMemory(m_context.getDeviceInterface(), m_context.getDevice(),
234 m_context.getDefaultAllocator(), createInfo,
235 MemoryRequirement::Any));
236 }
237
buildView(const VkImage image,VkFormat format)238 Move<VkImageView> LineWidthInstance::buildView(const VkImage image, VkFormat format)
239 {
240 return makeImageView(m_context.getDeviceInterface(), m_context.getDevice(), image, VK_IMAGE_VIEW_TYPE_2D, format,
241 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u), nullptr);
242 }
243
buildPipeline(VkPrimitiveTopology lineTopology,float lineWidth,bool dynamic,uint32_t subpass,VkPipelineLayout layout,VkShaderModule vertexModule,VkShaderModule fragmentModule,VkRenderPass renderPass,uint32_t width,uint32_t height)244 Move<VkPipeline> LineWidthInstance::buildPipeline(VkPrimitiveTopology lineTopology, float lineWidth, bool dynamic,
245 uint32_t subpass, VkPipelineLayout layout,
246 VkShaderModule vertexModule, VkShaderModule fragmentModule,
247 VkRenderPass renderPass, uint32_t width, uint32_t height)
248 {
249 const std::vector<VkRect2D> scissors{makeRect2D(width, height)};
250 const std::vector<VkViewport> viewports{makeViewport(0.f, 0.f, float(width), float(height), 0.f, 1.f)};
251
252 VkPipelineRasterizationStateCreateInfo rasterizationCreateInfo = initVulkanStructure();
253 rasterizationCreateInfo.lineWidth = dynamic ? 0.0f : lineWidth;
254
255 const VkDynamicState dynamicStates[1]{VK_DYNAMIC_STATE_LINE_WIDTH};
256 VkPipelineDynamicStateCreateInfo dynamicCreateInfo = initVulkanStructure();
257 dynamicCreateInfo.pDynamicStates = dynamicStates;
258 dynamicCreateInfo.dynamicStateCount = 1u;
259
260 const auto bindingIdx = (dynamic ? 0u : 1u);
261 const auto attribute = makeVertexInputAttributeDescription(0u, bindingIdx, VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
262 const auto binding = makeVertexInputBindingDescription(bindingIdx, static_cast<uint32_t>(sizeof(tcu::Vec4)),
263 VK_VERTEX_INPUT_RATE_VERTEX);
264 VkPipelineVertexInputStateCreateInfo inputCreateInfo = initVulkanStructure();
265 inputCreateInfo.flags = VkPipelineVertexInputStateCreateFlags(0);
266 inputCreateInfo.vertexAttributeDescriptionCount = 1u;
267 inputCreateInfo.pVertexAttributeDescriptions = &attribute;
268 inputCreateInfo.vertexBindingDescriptionCount = 1u;
269 inputCreateInfo.pVertexBindingDescriptions = &binding;
270
271 return makeGraphicsPipeline(m_context.getDeviceInterface(), m_context.getDevice(), layout, vertexModule,
272 VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragmentModule, renderPass, viewports,
273 scissors, lineTopology, subpass,
274 0u, // patchControlPoints
275 &inputCreateInfo, &rasterizationCreateInfo,
276 nullptr, // multisampleStateCreateInfo
277 nullptr, // depthStencilStateCreateInfo
278 nullptr, // colorBlendStateCreateInfo
279 dynamic ? &dynamicCreateInfo : nullptr);
280 }
281
verifyResults(const BufferWithMemory & resultBuffer,const tcu::Vec4 & dynamicColor,const tcu::Vec4 & staticColor,const VkFormat format,const uint32_t width,const uint32_t height,const uint32_t dynamicWidth,const uint32_t staticWidth)282 bool LineWidthInstance::verifyResults(const BufferWithMemory &resultBuffer, const tcu::Vec4 &dynamicColor,
283 const tcu::Vec4 &staticColor, const VkFormat format, const uint32_t width,
284 const uint32_t height, const uint32_t dynamicWidth, const uint32_t staticWidth)
285 {
286 tcu::ConstPixelBufferAccess pixels(mapVkFormat(format), int32_t(width), int32_t(height), 1,
287 resultBuffer.getAllocation().getHostPtr());
288
289 // count pixels in vertical line
290 uint32_t resultStaticWidth = 0u;
291 for (int32_t x = 0; x < int32_t(width); ++x)
292 {
293 if (pixels.getPixel(x, 0) == staticColor)
294 ++resultStaticWidth;
295 }
296
297 // count pixels in horizontal line
298 uint32_t resultDynamicWidth = 0u;
299 for (int32_t y = 0; y < int32_t(height); ++y)
300 {
301 if (pixels.getPixel(0, y) == dynamicColor)
302 ++resultDynamicWidth;
303 }
304
305 const auto pass = ((dynamicWidth == resultDynamicWidth) && (staticWidth == resultStaticWidth));
306
307 if (!pass)
308 {
309 auto &log = m_context.getTestContext().getLog();
310 log << tcu::TestLog::Message << "pass=" << pass << " (dynamicWidth=" << dynamicWidth
311 << " resultDynamicWidth=" << resultDynamicWidth << " staticWidth=" << staticWidth
312 << " resultStaticWidth=" << resultStaticWidth << ")" << tcu::TestLog::EndMessage;
313 log << tcu::TestLog::Image("Result", "", pixels);
314 }
315
316 return pass;
317 }
318
iterate()319 tcu::TestStatus LineWidthInstance::iterate()
320 {
321 const DeviceInterface &vkd = m_context.getDeviceInterface();
322 const VkDevice device = m_context.getDevice();
323 Allocator &allocator = m_context.getDefaultAllocator();
324 const uint32_t familyIndex = m_context.getUniversalQueueFamilyIndex();
325 const VkQueue queue = m_context.getUniversalQueue();
326
327 uint32_t dynamicVertCount(0);
328 uint32_t staticVertCount(0);
329 Move<VkShaderModule> vertex = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"));
330 Move<VkShaderModule> fragment = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"));
331 // note that dynamic lines are always drawn horizontally
332 de::MovePtr<BufferWithMemory> dynamicVertices = buildVertices(m_params.dynamicTopo, true, &dynamicVertCount);
333 DE_ASSERT(dynamicVertCount);
334 de::MovePtr<BufferWithMemory> staticVertices = buildVertices(m_params.staticTopo, false, &staticVertCount);
335 DE_ASSERT(staticVertCount);
336 const VkBuffer dynamicBuffs[2]{**dynamicVertices, **staticVertices};
337 const VkBuffer *vertexBuffers = dynamicBuffs;
338 const VkDeviceSize vertexOffsets[]{0u, 0u};
339 const tcu::Vec4 dynamicColor(1, 0, 1, 1);
340 const tcu::Vec4 staticColor(0, 1, 0, 1);
341 de::MovePtr<ImageWithMemory> image = buildImage(m_params.format, m_params.width, m_params.height);
342 const VkImageMemoryBarrier prepareCopy =
343 makeImageMemoryBarrier(VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
344 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **image,
345 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
346 const VkBufferImageCopy copyRegion =
347 makeBufferImageCopy(makeExtent3D(m_params.width, m_params.height, 1u),
348 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
349 Move<VkImageView> attachment = buildView(**image, m_params.format);
350 Move<VkRenderPass> renderPass = buildRenderPass(m_params.format);
351 Move<VkFramebuffer> framebuffer =
352 makeFramebuffer(vkd, device, *renderPass, *attachment, m_params.width, m_params.height);
353 const VkDeviceSize resultByteSize =
354 m_params.width * m_params.height * tcu::getPixelSize(mapVkFormat(m_params.format));
355 const VkBufferCreateInfo resultInfo = makeBufferCreateInfo(resultByteSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
356 de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
357 vkd, device, allocator, resultInfo, MemoryRequirement::HostVisible | MemoryRequirement::Coherent));
358 const VkPushConstantRange pcRange{VK_SHADER_STAGE_FRAGMENT_BIT, 0u, static_cast<uint32_t>(sizeof(tcu::Vec4))};
359 Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, VK_NULL_HANDLE, &pcRange);
360 Move<VkPipeline> dynamicPipeline =
361 buildPipeline(m_params.dynamicTopo, float(m_params.dynamicWidth), true, m_params.dynamicFirst ? 0u : 1u,
362 *pipelineLayout, *vertex, *fragment, *renderPass, m_params.width, m_params.height);
363 Move<VkPipeline> staticPipeline =
364 buildPipeline(m_params.staticTopo, float(m_params.staticWidth), false, m_params.dynamicFirst ? 1u : 0u,
365 *pipelineLayout, *vertex, *fragment, *renderPass, m_params.width, m_params.height);
366 Move<VkCommandPool> cmdPool = makeCommandPool(vkd, device, familyIndex);
367 Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
368
369 auto putDynamics = [&]() -> void
370 {
371 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *dynamicPipeline);
372 vkd.cmdPushConstants(*cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size,
373 &dynamicColor);
374 vkd.cmdSetLineWidth(*cmdBuffer, float(m_params.dynamicWidth));
375 vkd.cmdDraw(*cmdBuffer, dynamicVertCount, 1u, 0u, 0u);
376 };
377 std::function<void()> putDynamicsRecords(putDynamics);
378 auto putStatics = [&]() -> void
379 {
380 vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *staticPipeline);
381 vkd.cmdPushConstants(*cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size,
382 &staticColor);
383 vkd.cmdDraw(*cmdBuffer, staticVertCount, 1u, 0u, 0u);
384 };
385 std::function<void()> putStaticsRecords(putStatics);
386
387 beginCommandBuffer(vkd, *cmdBuffer);
388 vkd.cmdBindVertexBuffers(*cmdBuffer, 0u, 2u, vertexBuffers, vertexOffsets);
389 beginColorRenderPass(*cmdBuffer, *renderPass, *framebuffer, m_params.width, m_params.height);
390 (m_params.dynamicFirst ? putDynamicsRecords : putStaticsRecords)();
391 vkd.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
392 (m_params.dynamicFirst ? putStaticsRecords : putDynamicsRecords)();
393 endRenderPass(vkd, *cmdBuffer);
394 vkd.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
395 VK_DEPENDENCY_BY_REGION_BIT, 0u, nullptr, 0u, nullptr, 1u, &prepareCopy);
396 vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u,
397 ©Region);
398 endCommandBuffer(vkd, *cmdBuffer);
399 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
400
401 const bool status = verifyResults(*resultBuffer, dynamicColor, staticColor, m_params.format, m_params.width,
402 m_params.height, m_params.dynamicWidth, m_params.staticWidth);
403 return status ? tcu::TestStatus::pass(std::string()) : tcu::TestStatus::fail(std::string());
404 }
405
406 struct LineWidthCase : public TestCase
407 {
LineWidthCasevkt::DynamicState::__anonbf6ccddf0111::LineWidthCase408 LineWidthCase(tcu::TestContext &testCtx, const std::string &name, PipelineConstructionType pipelineConstructionType,
409 const TestLineWidthParams ¶ms)
410 : TestCase(testCtx, name)
411 , m_pipelineConstructionType(pipelineConstructionType)
412 , m_params(params)
413 { /* Intentionally empty */
414 }
415
416 void checkSupport(Context &context) const override;
417 void initPrograms(SourceCollections &programs) const override;
createInstancevkt::DynamicState::__anonbf6ccddf0111::LineWidthCase418 TestInstance *createInstance(Context &context) const override
419 {
420 return new LineWidthInstance(context, m_pipelineConstructionType, m_params);
421 }
422
423 private:
424 const PipelineConstructionType m_pipelineConstructionType;
425 const TestLineWidthParams m_params;
426 };
427
initPrograms(SourceCollections & programs) const428 void LineWidthCase::initPrograms(SourceCollections &programs) const
429 {
430 const std::string vert(
431 R"glsl(#version 450
432 layout(location = 0) in vec4 pos;
433 void main() {
434 gl_Position = vec4(pos.xy, 0.0, 1.0);
435 })glsl");
436
437 const std::string frag(
438 R"glsl(#version 450
439 layout(push_constant) uniform PC { vec4 color; };
440 layout(location = 0) out vec4 attachment;
441 void main() {
442 attachment = vec4(color.rgb, 1.0);
443 })glsl");
444
445 programs.glslSources.add("frag") << glu::FragmentSource(frag);
446 programs.glslSources.add("vert") << glu::VertexSource(vert);
447 }
448
checkSupport(Context & context) const449 void LineWidthCase::checkSupport(Context &context) const
450 {
451 VkPhysicalDeviceFeatures fts{};
452 const InstanceInterface &vki = context.getInstanceInterface();
453 const VkPhysicalDevice dev = context.getPhysicalDevice();
454
455 checkPipelineConstructionRequirements(vki, dev, m_pipelineConstructionType);
456
457 if (float(m_params.staticWidth) < context.getDeviceProperties().limits.lineWidthRange[0] ||
458 float(m_params.staticWidth) > context.getDeviceProperties().limits.lineWidthRange[1] ||
459 float(m_params.dynamicWidth) < context.getDeviceProperties().limits.lineWidthRange[0] ||
460 float(m_params.dynamicWidth) > context.getDeviceProperties().limits.lineWidthRange[1])
461 {
462 TCU_THROW(NotSupportedError, "Line widths don't meet VkPhysicalDeviceLimits::lineWidthRange");
463 }
464
465 vki.getPhysicalDeviceFeatures(dev, &fts);
466 if (!context.getDeviceFeatures().wideLines)
467 {
468 TCU_THROW(NotSupportedError, "VkPhysicalDeviceFeatures::wideLines not supported");
469 }
470
471 DE_ASSERT(context.getDeviceFeatures().wideLines);
472 }
473
474 } // anonymous namespace
475
476 // Test for VK_DYNAMIC_STATE_LINE_WIDTH
DynamicStateLWTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)477 DynamicStateLWTests::DynamicStateLWTests(tcu::TestContext &testCtx, PipelineConstructionType pipelineConstructionType)
478 : tcu::TestCaseGroup(testCtx, "line_width")
479 , m_pipelineConstructionType(pipelineConstructionType)
480 {
481 /* Consciously empty */
482 }
483
rep() const484 std::string TestLineWidthParams::rep() const
485 {
486 auto topo = [](VkPrimitiveTopology topology) -> const char *
487 {
488 switch (topology)
489 {
490 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
491 return "list";
492 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
493 return "strip";
494 default:
495 DE_ASSERT(VK_FALSE);
496 }
497 return "";
498 };
499 std::ostringstream os;
500 if (dynamicFirst)
501 os << topo(dynamicTopo) << dynamicWidth << '_' << topo(staticTopo) << staticWidth;
502 else
503 os << topo(staticTopo) << staticWidth << '_' << topo(dynamicTopo) << dynamicWidth;
504 os.flush();
505 return os.str();
506 }
507
init(void)508 void DynamicStateLWTests::init(void)
509 {
510 TestLineWidthParams const params[]{
511 // clang-format off
512 {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
513 {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
514 {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
515 {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
516
517 {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
518 {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
519 {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
520 {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
521 // clang-format on
522 };
523 de::MovePtr<tcu::TestCaseGroup> dynaStatic(new tcu::TestCaseGroup(m_testCtx, "dyna_static"));
524 de::MovePtr<tcu::TestCaseGroup> staticDyna(new tcu::TestCaseGroup(m_testCtx, "static_dyna"));
525 uint32_t lineWidth = 0u;
526 for (const TestLineWidthParams ¶m : params)
527 {
528 TestLineWidthParams p(param);
529 p.staticWidth = ++lineWidth;
530 p.dynamicWidth = ++lineWidth;
531 if (param.dynamicFirst)
532 dynaStatic->addChild(new LineWidthCase(m_testCtx, p.rep(), m_pipelineConstructionType, p));
533 else
534 staticDyna->addChild(new LineWidthCase(m_testCtx, p.rep(), m_pipelineConstructionType, p));
535 }
536 addChild(dynaStatic.release());
537 addChild(staticDyna.release());
538 }
539
540 } // namespace DynamicState
541 } // namespace vkt
542