• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &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 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                              &copyRegion);
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 &params)
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 &param : 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