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::__anon3a7d035f0111::LineWidthInstance61     LineWidthInstance(Context &context, PipelineConstructionType pipelineConstructionType,
62                       const TestLineWidthParams &params)
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 attribute = makeVertexInputAttributeDescription(0u, subpass, VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
261     const auto binding   = makeVertexInputBindingDescription(subpass, static_cast<uint32_t>(sizeof(tcu::Vec4)),
262                                                              VK_VERTEX_INPUT_RATE_VERTEX);
263     VkPipelineVertexInputStateCreateInfo inputCreateInfo = initVulkanStructure();
264     inputCreateInfo.flags                                = VkPipelineVertexInputStateCreateFlags(0);
265     inputCreateInfo.vertexAttributeDescriptionCount      = 1u;
266     inputCreateInfo.pVertexAttributeDescriptions         = &attribute;
267     inputCreateInfo.vertexBindingDescriptionCount        = 1u;
268     inputCreateInfo.pVertexBindingDescriptions           = &binding;
269 
270     return makeGraphicsPipeline(m_context.getDeviceInterface(), m_context.getDevice(), layout, vertexModule,
271                                 VkShaderModule(0), VkShaderModule(0), VkShaderModule(0), fragmentModule, renderPass,
272                                 viewports, scissors, lineTopology, subpass,
273                                 0u, // patchControlPoints
274                                 &inputCreateInfo, &rasterizationCreateInfo,
275                                 nullptr, // multisampleStateCreateInfo
276                                 nullptr, // depthStencilStateCreateInfo
277                                 nullptr, // colorBlendStateCreateInfo
278                                 dynamic ? &dynamicCreateInfo : nullptr);
279 }
280 
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)281 bool LineWidthInstance::verifyResults(const BufferWithMemory &resultBuffer, const tcu::Vec4 &dynamicColor,
282                                       const tcu::Vec4 &staticColor, const VkFormat format, const uint32_t width,
283                                       const uint32_t height, const uint32_t dynamicWidth, const uint32_t staticWidth)
284 {
285     tcu::ConstPixelBufferAccess pixels(mapVkFormat(format), int32_t(width), int32_t(height), 1,
286                                        resultBuffer.getAllocation().getHostPtr());
287 
288     // count pixels in vertical line
289     uint32_t staticLineWidth = 0u;
290     for (int32_t x = 0; x < int32_t(width); ++x)
291     {
292         if (pixels.getPixel(x, 0) == staticColor)
293             ++staticLineWidth;
294     }
295 
296     // count pixels in horizontal line
297     uint32_t dynamicLineWidth = 0u;
298     for (int32_t y = 0; y < int32_t(height); ++y)
299     {
300         if (pixels.getPixel(0, y) == dynamicColor)
301             ++dynamicLineWidth;
302     }
303 
304     return ((dynamicWidth == dynamicLineWidth) && (staticWidth == staticLineWidth));
305 }
306 
iterate()307 tcu::TestStatus LineWidthInstance::iterate()
308 {
309     const DeviceInterface &vkd = m_context.getDeviceInterface();
310     const VkDevice device      = m_context.getDevice();
311     Allocator &allocator       = m_context.getDefaultAllocator();
312     const uint32_t familyIndex = m_context.getUniversalQueueFamilyIndex();
313     const VkQueue queue        = m_context.getUniversalQueue();
314 
315     uint32_t dynamicVertCount(0);
316     uint32_t staticVertCount(0);
317     Move<VkShaderModule> vertex   = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"));
318     Move<VkShaderModule> fragment = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"));
319     // note that dynamic lines are always drawn horizontally
320     de::MovePtr<BufferWithMemory> dynamicVertices =
321         buildVertices(m_params.dynamicTopo, (m_params.dynamicFirst == true), &dynamicVertCount);
322     DE_ASSERT(dynamicVertCount);
323     de::MovePtr<BufferWithMemory> staticVertices =
324         buildVertices(m_params.staticTopo, (m_params.dynamicFirst == false), &staticVertCount);
325     DE_ASSERT(staticVertCount);
326     const VkBuffer dynamicBuffs[2]{**dynamicVertices, **staticVertices};
327     const VkBuffer *vertexBuffers = dynamicBuffs;
328     const VkDeviceSize vertexOffsets[]{0u, 0u};
329     const tcu::Vec4 dynamicColor(1, 0, 1, 1);
330     const tcu::Vec4 staticColor(0, 1, 0, 1);
331     de::MovePtr<ImageWithMemory> image = buildImage(m_params.format, m_params.width, m_params.height);
332     const VkImageMemoryBarrier prepareCopy =
333         makeImageMemoryBarrier(VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
334                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **image,
335                                makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
336     const VkBufferImageCopy copyRegion =
337         makeBufferImageCopy(makeExtent3D(m_params.width, m_params.height, 1u),
338                             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
339     Move<VkImageView> attachment  = buildView(**image, m_params.format);
340     Move<VkRenderPass> renderPass = buildRenderPass(m_params.format);
341     Move<VkFramebuffer> framebuffer =
342         makeFramebuffer(vkd, device, *renderPass, *attachment, m_params.width, m_params.height);
343     const VkDeviceSize resultByteSize =
344         m_params.width * m_params.height * tcu::getPixelSize(mapVkFormat(m_params.format));
345     const VkBufferCreateInfo resultInfo        = makeBufferCreateInfo(resultByteSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
346     de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
347         vkd, device, allocator, resultInfo, MemoryRequirement::HostVisible | MemoryRequirement::Coherent));
348     const VkPushConstantRange pcRange{VK_SHADER_STAGE_FRAGMENT_BIT, 0u, static_cast<uint32_t>(sizeof(tcu::Vec4))};
349     Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, VK_NULL_HANDLE, &pcRange);
350     Move<VkPipeline> dynamicPipeline =
351         buildPipeline(m_params.dynamicTopo, float(m_params.dynamicWidth), true, m_params.dynamicFirst ? 0u : 1u,
352                       *pipelineLayout, *vertex, *fragment, *renderPass, m_params.width, m_params.height);
353     Move<VkPipeline> staticPipeline =
354         buildPipeline(m_params.staticTopo, float(m_params.staticWidth), false, m_params.dynamicFirst ? 1u : 0u,
355                       *pipelineLayout, *vertex, *fragment, *renderPass, m_params.width, m_params.height);
356     Move<VkCommandPool> cmdPool     = makeCommandPool(vkd, device, familyIndex);
357     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
358 
359     auto putDynamics = [&]() -> void
360     {
361         vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *dynamicPipeline);
362         vkd.cmdPushConstants(*cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size,
363                              &dynamicColor);
364         vkd.cmdSetLineWidth(*cmdBuffer, float(m_params.dynamicWidth));
365         vkd.cmdDraw(*cmdBuffer, dynamicVertCount, 1u, 0u, 0u);
366     };
367     std::function<void()> putDynamicsRecords(putDynamics);
368     auto putStatics = [&]() -> void
369     {
370         vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *staticPipeline);
371         vkd.cmdPushConstants(*cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size,
372                              &staticColor);
373         vkd.cmdDraw(*cmdBuffer, staticVertCount, 1u, 0u, 0u);
374     };
375     std::function<void()> putStaticsRecords(putStatics);
376 
377     beginCommandBuffer(vkd, *cmdBuffer);
378     vkd.cmdBindVertexBuffers(*cmdBuffer, 0u, 2u, vertexBuffers, vertexOffsets);
379     beginColorRenderPass(*cmdBuffer, *renderPass, *framebuffer, m_params.width, m_params.height);
380     (m_params.dynamicFirst ? putDynamicsRecords : putStaticsRecords)();
381     vkd.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
382     (m_params.dynamicFirst ? putStaticsRecords : putDynamicsRecords)();
383     endRenderPass(vkd, *cmdBuffer);
384     vkd.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
385                            VK_DEPENDENCY_BY_REGION_BIT, 0u, nullptr, 0u, nullptr, 1u, &prepareCopy);
386     vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u,
387                              &copyRegion);
388     endCommandBuffer(vkd, *cmdBuffer);
389     submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
390 
391     const bool status = verifyResults(*resultBuffer, dynamicColor, staticColor, m_params.format, m_params.width,
392                                       m_params.height, m_params.dynamicWidth, m_params.staticWidth);
393     return status ? tcu::TestStatus::pass(std::string()) : tcu::TestStatus::fail(std::string());
394 }
395 
396 struct LineWidthCase : public TestCase
397 {
LineWidthCasevkt::DynamicState::__anon3a7d035f0111::LineWidthCase398     LineWidthCase(tcu::TestContext &testCtx, const std::string &name, PipelineConstructionType pipelineConstructionType,
399                   const TestLineWidthParams &params)
400         : TestCase(testCtx, name)
401         , m_pipelineConstructionType(pipelineConstructionType)
402         , m_params(params)
403     { /* Intentionally empty */
404     }
405 
406     void checkSupport(Context &context) const override;
407     void initPrograms(SourceCollections &programs) const override;
createInstancevkt::DynamicState::__anon3a7d035f0111::LineWidthCase408     TestInstance *createInstance(Context &context) const override
409     {
410         return new LineWidthInstance(context, m_pipelineConstructionType, m_params);
411     }
412 
413 private:
414     const PipelineConstructionType m_pipelineConstructionType;
415     const TestLineWidthParams m_params;
416 };
417 
initPrograms(SourceCollections & programs) const418 void LineWidthCase::initPrograms(SourceCollections &programs) const
419 {
420     const std::string vert(
421         R"glsl(#version 450
422     layout(location = 0) in vec4 pos;
423     void main() {
424         gl_Position = vec4(pos.xy, 0.0, 1.0);
425     })glsl");
426 
427     const std::string frag(
428         R"glsl(#version 450
429     layout(push_constant) uniform PC { vec4 color; };
430     layout(location = 0) out vec4 attachment;
431     void main() {
432         attachment = vec4(color.rgb, 1.0);
433     })glsl");
434 
435     programs.glslSources.add("frag") << glu::FragmentSource(frag);
436     programs.glslSources.add("vert") << glu::VertexSource(vert);
437 }
438 
checkSupport(Context & context) const439 void LineWidthCase::checkSupport(Context &context) const
440 {
441     VkPhysicalDeviceFeatures fts{};
442     const InstanceInterface &vki = context.getInstanceInterface();
443     const VkPhysicalDevice dev   = context.getPhysicalDevice();
444 
445     checkPipelineConstructionRequirements(vki, dev, m_pipelineConstructionType);
446 
447     if (float(m_params.staticWidth) < context.getDeviceProperties().limits.lineWidthRange[0] ||
448         float(m_params.staticWidth) > context.getDeviceProperties().limits.lineWidthRange[1] ||
449         float(m_params.dynamicWidth) < context.getDeviceProperties().limits.lineWidthRange[0] ||
450         float(m_params.dynamicWidth) > context.getDeviceProperties().limits.lineWidthRange[1])
451     {
452         TCU_THROW(NotSupportedError, "Line widths don't meet VkPhysicalDeviceLimits::lineWidthRange");
453     }
454 
455     vki.getPhysicalDeviceFeatures(dev, &fts);
456     if (!context.getDeviceFeatures().wideLines)
457     {
458         TCU_THROW(NotSupportedError, "VkPhysicalDeviceFeatures::wideLines not supported");
459     }
460 
461     DE_ASSERT(context.getDeviceFeatures().wideLines);
462 }
463 
464 } // anonymous namespace
465 
466 // Test for VK_DYNAMIC_STATE_LINE_WIDTH
DynamicStateLWTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)467 DynamicStateLWTests::DynamicStateLWTests(tcu::TestContext &testCtx, PipelineConstructionType pipelineConstructionType)
468     : tcu::TestCaseGroup(testCtx, "line_width")
469     , m_pipelineConstructionType(pipelineConstructionType)
470 {
471     /* Consciously empty */
472 }
473 
rep() const474 std::string TestLineWidthParams::rep() const
475 {
476     auto topo = [](VkPrimitiveTopology topology) -> const char *
477     {
478         switch (topology)
479         {
480         case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
481             return "list";
482         case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
483             return "strip";
484         default:
485             DE_ASSERT(VK_FALSE);
486         }
487         return "";
488     };
489     std::ostringstream os;
490     if (dynamicFirst)
491         os << topo(dynamicTopo) << dynamicWidth << '_' << topo(staticTopo) << staticWidth;
492     else
493         os << topo(staticTopo) << staticWidth << '_' << topo(dynamicTopo) << dynamicWidth;
494     os.flush();
495     return os.str();
496 }
497 
init(void)498 void DynamicStateLWTests::init(void)
499 {
500     TestLineWidthParams const params[]{
501         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT,
502          128, 128},
503         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, false,
504          VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
505         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT,
506          128, 128},
507         {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT,
508          128, 128},
509 
510         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, true, VK_FORMAT_R32G32B32A32_SFLOAT,
511          128, 128},
512         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0u, 0u, false,
513          VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
514         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, true,
515          VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
516         {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, false,
517          VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128},
518     };
519     de::MovePtr<tcu::TestCaseGroup> dynaStatic(new tcu::TestCaseGroup(m_testCtx, "dyna_static"));
520     de::MovePtr<tcu::TestCaseGroup> staticDyna(new tcu::TestCaseGroup(m_testCtx, "static_dyna"));
521     uint32_t lineWidth = 0u;
522     for (const TestLineWidthParams &param : params)
523     {
524         TestLineWidthParams p(param);
525         p.staticWidth  = ++lineWidth;
526         p.dynamicWidth = ++lineWidth;
527         if (param.dynamicFirst)
528             dynaStatic->addChild(new LineWidthCase(m_testCtx, p.rep(), m_pipelineConstructionType, p));
529         else
530             staticDyna->addChild(new LineWidthCase(m_testCtx, p.rep(), m_pipelineConstructionType, p));
531     }
532     addChild(dynaStatic.release());
533     addChild(staticDyna.release());
534 }
535 
536 } // namespace DynamicState
537 } // namespace vkt
538