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