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 ¶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 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 ©Region);
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 ¶ms)
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 ¶m : 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