1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group Inc.
6 * Copyright (c) 2023 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Fragment Shading Rate miscellaneous tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentShadingRateMiscTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27
28 #include "vkImageUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkBarrierUtil.hpp"
32
33 #include "tcuImageCompare.hpp"
34
35 #include "deUniquePtr.hpp"
36
37 #include <sstream>
38 #include <vector>
39 #include <cstddef>
40
41 namespace vkt
42 {
43 namespace FragmentShadingRate
44 {
45
46 namespace
47 {
48
49 using namespace vk;
50
51 struct PositionColor
52 {
PositionColorvkt::FragmentShadingRate::__anonb99e3c9d0111::PositionColor53 PositionColor (const tcu::Vec4& position_, const tcu::Vec4& color_)
54 : position(position_), color(color_)
55 {}
56
57 tcu::Vec4 position;
58 tcu::Vec4 color;
59 };
60
getDefaultExtent(void)61 VkExtent3D getDefaultExtent (void)
62 {
63 return makeExtent3D(8u, 8u, 1u);
64 }
65
checkShadingRateSupport(Context & context,bool pipeline=false,bool primitive=false,bool attachment=false)66 void checkShadingRateSupport (Context& context, bool pipeline = false, bool primitive = false, bool attachment = false)
67 {
68 context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
69 const auto& fsrFeatures = context.getFragmentShadingRateFeatures();
70
71 if (pipeline && !fsrFeatures.pipelineFragmentShadingRate)
72 TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
73
74 if (primitive && !fsrFeatures.primitiveFragmentShadingRate)
75 TCU_THROW(NotSupportedError, "primitiveFragmentShadingRate not supported");
76
77 if (attachment && !fsrFeatures.attachmentFragmentShadingRate)
78 TCU_THROW(NotSupportedError, "attachmentFragmentShadingRate not supported");
79 }
80
checkEnableDisableSupport(Context & context)81 void checkEnableDisableSupport (Context& context)
82 {
83 checkShadingRateSupport(context, true, false, true);
84 }
85
checkNoFragSupport(Context & context)86 void checkNoFragSupport (Context& context)
87 {
88 checkShadingRateSupport(context, true);
89 }
90
initDefaultVertShader(vk::SourceCollections & programCollection,const std::string & shaderName)91 void initDefaultVertShader (vk::SourceCollections& programCollection, const std::string& shaderName)
92 {
93 // Default vertex shader, including vertex color.
94 std::ostringstream vert;
95 vert
96 << "#version 460\n"
97 << "#extension GL_EXT_fragment_shading_rate : enable\n"
98 << "layout (location=0) in vec4 inPos;\n"
99 << "layout (location=1) in vec4 inColor;\n"
100 << "layout (location=0) out vec4 outColor;\n"
101 << "void main (void) {\n"
102 << " gl_Position = inPos;\n"
103 << " outColor = inColor;\n"
104 << "}\n"
105 ;
106 DE_ASSERT(!shaderName.empty());
107 programCollection.glslSources.add(shaderName) << glu::VertexSource(vert.str());
108 }
109
initDefaultFragShader(vk::SourceCollections & programCollection,const std::string & shaderName)110 void initDefaultFragShader (vk::SourceCollections& programCollection, const std::string& shaderName)
111 {
112 // Default fragment shader, with vertex color.
113 std::ostringstream frag;
114 frag
115 << "#version 460\n"
116 << "layout (location=0) in vec4 inColor;\n"
117 << "layout (location=0) out vec4 outColor;\n"
118 << "void main (void) {\n"
119 << " outColor = inColor;\n"
120 << "}\n"
121 ;
122 DE_ASSERT(!shaderName.empty());
123 programCollection.glslSources.add(shaderName) << glu::FragmentSource(frag.str());
124 }
125
initEnableDisableShaders(vk::SourceCollections & programCollection)126 void initEnableDisableShaders (vk::SourceCollections& programCollection)
127 {
128 initDefaultVertShader(programCollection, "vert");
129 initDefaultFragShader(programCollection, "frag");
130 }
131
initNoFragShaders(vk::SourceCollections & programCollection)132 void initNoFragShaders (vk::SourceCollections& programCollection)
133 {
134 initDefaultVertShader(programCollection, "vert");
135 }
136
getDefaultVertexInputStateCreateInfo(void)137 const VkPipelineVertexInputStateCreateInfo* getDefaultVertexInputStateCreateInfo (void)
138 {
139 static VkVertexInputBindingDescription vertexBinding =
140 {
141 0u, // uint32_t binding;
142 static_cast<uint32_t>(sizeof(PositionColor)), // uint32_t stride;
143 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
144 };
145
146 static VkVertexInputAttributeDescription inputAttributes[] =
147 {
148 {
149 // position
150 0u, // uint32_t location;
151 0u, // uint32_t binding;
152 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
153 static_cast<uint32_t>(offsetof(PositionColor, position)), // uint32_t offset;
154 },
155 {
156 // color
157 1u, // uint32_t location;
158 0u, // uint32_t binding;
159 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
160 static_cast<uint32_t>(offsetof(PositionColor, color)), // uint32_t offset;
161 },
162 };
163
164 static const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
165 {
166 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
167 nullptr, // const void* pNext;
168 0u, // VkPipelineVertexInputStateCreateFlags flags;
169 1u, // uint32_t vertexBindingDescriptionCount;
170 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
171 static_cast<uint32_t>(de::arrayLength(inputAttributes)), // uint32_t vertexAttributeDescriptionCount;
172 inputAttributes, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
173 };
174
175 return &vertexInputStateCreateInfo;
176 }
177
makeFragmentShadingRateStateCreateInfo(uint32_t width,uint32_t height,VkFragmentShadingRateCombinerOpKHR combiner0,VkFragmentShadingRateCombinerOpKHR combiner1)178 VkPipelineFragmentShadingRateStateCreateInfoKHR makeFragmentShadingRateStateCreateInfo (uint32_t width, uint32_t height, VkFragmentShadingRateCombinerOpKHR combiner0, VkFragmentShadingRateCombinerOpKHR combiner1)
179 {
180 const VkPipelineFragmentShadingRateStateCreateInfoKHR fragmentShadingRateStateCreateInfo =
181 {
182 VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
183 nullptr, // const void* pNext;
184 makeExtent2D(width, height), // VkExtent2D fragmentSize;
185 { // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
186 combiner0,
187 combiner1,
188 },
189 };
190
191 return fragmentShadingRateStateCreateInfo;
192 }
193
194 // Test idea: draw with VRS enabled by a fragment shading rate attachment, then bind a pipeline with VRS disabled and draw again.
195 // This was being incorrectly handled in RADV. Ref: https://gitlab.freedesktop.org/mesa/mesa/-/issues/9005
testEnableDisable(Context & context)196 tcu::TestStatus testEnableDisable (Context& context)
197 {
198 const auto ctx = context.getContextCommonData();
199 const auto& fsrProperties = context.getFragmentShadingRateProperties();
200 const auto& minSize = fsrProperties.minFragmentShadingRateAttachmentTexelSize;
201 const auto& maxSize = fsrProperties.maxFragmentShadingRateAttachmentTexelSize;
202 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
203 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
204 const auto colorSRR = makeDefaultImageSubresourceRange();
205 const auto colorSRL = makeDefaultImageSubresourceLayers();
206 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
207 const auto fsrFormat = VK_FORMAT_R8_UINT;
208 const auto fsrExtent = makeExtent3D(1u, 1u, 1u); // 1 pixel for the whole image.
209 const auto fsrUsage = (VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR);
210 const auto sampleCount = VK_SAMPLE_COUNT_1_BIT;
211
212 // Adjust image extent to an acceptable range so it's covered by a single FSR attachment pixel.
213 auto vkExtent = getDefaultExtent();
214 {
215 de::clamp(vkExtent.width, minSize.width, maxSize.width);
216 de::clamp(vkExtent.height, minSize.height, maxSize.height);
217 }
218 const tcu::IVec3 fbExtent (static_cast<int>(vkExtent.width), static_cast<int>(vkExtent.height), static_cast<int>(vkExtent.depth));
219
220 vk::ImageWithBuffer colorBuffer (ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, VK_IMAGE_TYPE_2D);
221
222 // Fragment shading rate attachment.
223 const VkImageCreateInfo fsrAttachmentCreateInfo =
224 {
225 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
226 nullptr, // const void* pNext;
227 0u, // VkImageCreateFlags flags;
228 VK_IMAGE_TYPE_2D, // VkImageType imageType;
229 fsrFormat, // VkFormat format;
230 fsrExtent, // VkExtent3D extent;
231 1u, // uint32_t mipLevels;
232 1u, // uint32_t arrayLayers;
233 sampleCount, // VkSampleCountFlagBits samples;
234 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
235 fsrUsage, // VkImageUsageFlags usage;
236 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
237 0u, // uint32_t queueFamilyIndexCount;
238 nullptr, // const uint32_t* pQueueFamilyIndices;
239 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
240 };
241 ImageWithMemory fsrAttachment (ctx.vkd, ctx.device, ctx.allocator, fsrAttachmentCreateInfo, MemoryRequirement::Any);
242 const auto fsrAttView = makeImageView(ctx.vkd, ctx.device, fsrAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, fsrFormat, colorSRR);
243
244 const auto& binaries = context.getBinaryCollection();
245 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
246 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
247
248 const std::vector<VkAttachmentDescription2> attachmentDescriptions
249 {
250 // Color attachment.
251 {
252 VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
253 nullptr, // const void* pNext;
254 0u, // VkAttachmentDescriptionFlags flags;
255 colorFormat, // VkFormat format;
256 sampleCount, // VkSampleCountFlagBits samples;
257 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
258 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
259 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
260 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
261 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
262 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
263 },
264 // FSR attachment.
265 {
266 VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
267 nullptr, // const void* pNext;
268 0u, // VkAttachmentDescriptionFlags flags;
269 fsrFormat, // VkFormat format;
270 sampleCount, // VkSampleCountFlagBits samples;
271 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
272 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
273 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
274 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
275 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
276 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout finalLayout;
277 },
278 };
279
280 const VkAttachmentReference2 colorAttRef =
281 {
282 VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
283 nullptr, // const void* pNext;
284 0u, // uint32_t attachment;
285 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
286 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
287 };
288
289 const VkAttachmentReference2 fsrAttRef =
290 {
291 VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
292 nullptr, // const void* pNext;
293 1u, // uint32_t attachment;
294 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout layout;
295 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
296 };
297
298 const VkFragmentShadingRateAttachmentInfoKHR fsrAttInfo =
299 {
300 VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, // VkStructureType sType;
301 nullptr, // const void* pNext;
302 &fsrAttRef, // const VkAttachmentReference2* pFragmentShadingRateAttachment;
303 makeExtent2D(vkExtent.width, vkExtent.height), // VkExtent2D shadingRateAttachmentTexelSize;
304 };
305
306 const VkSubpassDescription2 subpassDescription
307 {
308 VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, // VkStructureType sType;
309 &fsrAttInfo, // const void* pNext;
310 0u, // VkSubpassDescriptionFlags flags;
311 bindPoint, // VkPipelineBindPoint pipelineBindPoint;
312 0u, // uint32_t viewMask;
313 0u, // uint32_t inputAttachmentCount;
314 nullptr, // const VkAttachmentReference2* pInputAttachments;
315 1u, // uint32_t colorAttachmentCount;
316 &colorAttRef, // const VkAttachmentReference2* pColorAttachments;
317 nullptr, // const VkAttachmentReference2* pResolveAttachments;
318 nullptr, // const VkAttachmentReference2* pDepthStencilAttachment;
319 0u, // uint32_t preserveAttachmentCount;
320 nullptr, // const uint32_t* pPreserveAttachments;
321 };
322
323 const VkRenderPassCreateInfo2 renderPassCreateInfo =
324 {
325 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, // VkStructureType sType;
326 nullptr, // const void* pNext;
327 0u, // VkRenderPassCreateFlags flags;
328 de::sizeU32(attachmentDescriptions), // uint32_t attachmentCount;
329 de::dataOrNull(attachmentDescriptions), // const VkAttachmentDescription2* pAttachments;
330 1u, // uint32_t subpassCount;
331 &subpassDescription, // const VkSubpassDescription2* pSubpasses;
332 0u, // uint32_t dependencyCount;
333 nullptr, // const VkSubpassDependency2* pDependencies;
334 0u, // uint32_t correlatedViewMaskCount;
335 nullptr, // const uint32_t* pCorrelatedViewMasks;
336 };
337
338 const auto renderPass = createRenderPass2(ctx.vkd, ctx.device, &renderPassCreateInfo);
339
340 const std::vector<VkImageView> attachmentViews { colorBuffer.getImageView(), fsrAttView.get() };
341 const auto framebuffer = makeFramebuffer(
342 ctx.vkd, ctx.device, renderPass.get(),
343 de::sizeU32(attachmentViews), de::dataOrNull(attachmentViews),
344 vkExtent.width, vkExtent.height);
345
346 const std::vector<VkViewport> viewports (1u, makeViewport(fbExtent));
347 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent));
348
349 // Use the rate according to the attachment.
350 const auto fragmentShadingRateStateCreateInfo = makeFragmentShadingRateStateCreateInfo(
351 1u, 1u,
352 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
353 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR);
354
355 const std::vector<tcu::Vec4> vertices
356 {
357 tcu::Vec4(-1.0, -1.0f, 0.0f, 1.0f),
358 tcu::Vec4(-1.0, 1.0f, 0.0f, 1.0f),
359 tcu::Vec4( 1.0, -1.0f, 0.0f, 1.0f),
360 tcu::Vec4( 1.0, 1.0f, 0.0f, 1.0f),
361 };
362
363 const std::vector<tcu::Vec4> colors
364 {
365 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
366 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
367 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
368 tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f),
369 };
370
371 DE_ASSERT(vertices.size() == colors.size());
372
373 // We mix them reversing the color order for the first draw.
374 std::vector<PositionColor> vrsVertices;
375 std::vector<PositionColor> noVrsVertices;
376
377 vrsVertices.reserve(vertices.size());
378 noVrsVertices.reserve(vertices.size());
379
380 for (size_t i = 0; i < vertices.size(); ++i)
381 {
382 vrsVertices.push_back(PositionColor(vertices.at(i), colors.at(colors.size() - 1 - i)));
383 noVrsVertices.push_back(PositionColor(vertices.at(i), colors.at(i)));
384 }
385
386 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vrsVertices));
387 const auto vertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
388 const auto vertexBufferCreateInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
389 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
390
391 BufferWithMemory vrsVerticesBuffer (ctx.vkd, ctx.device, ctx.allocator, vertexBufferCreateInfo, MemoryRequirement::HostVisible);
392 BufferWithMemory noVrsVerticesBuffer (ctx.vkd, ctx.device, ctx.allocator, vertexBufferCreateInfo, MemoryRequirement::HostVisible);
393 auto& vrsVertAlloc = vrsVerticesBuffer.getAllocation();
394 auto& noVrsVertAlloc = noVrsVerticesBuffer.getAllocation();
395
396 deMemcpy(vrsVertAlloc.getHostPtr(), de::dataOrNull(vrsVertices), de::dataSize(vrsVertices));
397 deMemcpy(noVrsVertAlloc.getHostPtr(), de::dataOrNull(noVrsVertices), de::dataSize(noVrsVertices));
398 flushAlloc(ctx.vkd, ctx.device, vrsVertAlloc);
399 flushAlloc(ctx.vkd, ctx.device, noVrsVertAlloc);
400
401 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
402
403 // Pipeline with and without VRS.
404 const auto pipelineVRS = makeGraphicsPipeline(ctx.vkd, ctx.device, pipelineLayout.get(),
405 vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(),
406 renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u,
407 getDefaultVertexInputStateCreateInfo(), nullptr, nullptr, nullptr, nullptr, nullptr, &fragmentShadingRateStateCreateInfo);
408
409 const auto pipelineNoVRS = makeGraphicsPipeline(ctx.vkd, ctx.device, pipelineLayout.get(),
410 vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(),
411 renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u,
412 getDefaultVertexInputStateCreateInfo());
413
414 CommandPoolWithBuffer cmd (ctx.vkd, ctx.device, ctx.qfIndex);
415 const auto cmdBuffer = cmd.cmdBuffer.get();
416
417 #if 0
418 const int gl_ShadingRateFlag2VerticalPixelsEXT = 1;
419 const int gl_ShadingRateFlag4VerticalPixelsEXT = 2;
420 const int gl_ShadingRateFlag2HorizontalPixelsEXT = 4;
421 const int gl_ShadingRateFlag4HorizontalPixelsEXT = 8;
422 #endif
423 using ClearValueVec = std::vector<VkClearValue>;
424 const uint32_t clearAttRate = 5u; // 2x2: (gl_ShadingRateFlag2HorizontalPixelsEXT | gl_ShadingRateFlag2VerticalPixelsEXT)
425 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
426 const ClearValueVec clearValues
427 {
428 makeClearValueColor(clearColor),
429 makeClearValueColorU32(clearAttRate, 0u, 0u, 0u),
430 };
431 const auto colorCompThreshold = 0.005f; // between 1/255 and 2/255.
432 const tcu::Vec4 colorThreshold (colorCompThreshold, colorCompThreshold, colorCompThreshold, colorCompThreshold);
433 const auto vertexCount = de::sizeU32(vertices);
434
435 const struct
436 {
437 VkBuffer vertexBuffer;
438 VkPipeline pipeline;
439 } iterations[] =
440 {
441 { vrsVerticesBuffer.get(), pipelineVRS.get() },
442 { noVrsVerticesBuffer.get(), pipelineNoVRS.get() },
443 };
444
445 beginCommandBuffer(ctx.vkd, cmdBuffer);
446 {
447 // Render pass.
448 beginRenderPass(ctx.vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), de::sizeU32(clearValues), de::dataOrNull(clearValues));
449 for (const auto& iteration : iterations)
450 {
451 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &iteration.vertexBuffer, &vertexBufferOffset);
452 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, iteration.pipeline);
453 ctx.vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
454 }
455 endRenderPass(ctx.vkd, cmdBuffer);
456 }
457 {
458 // Copy image to verification buffer after rendering.
459 const auto preTransferBarrier = makeImageMemoryBarrier(
460 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
461 VK_ACCESS_TRANSFER_READ_BIT,
462 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
463 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
464 colorBuffer.getImage(), colorSRR);
465 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preTransferBarrier);
466 const auto copyRegion = makeBufferImageCopy(vkExtent, colorSRL);
467 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getBuffer(), 1u, ©Region);
468 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
469 cmdPipelineMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
470 }
471 endCommandBuffer(ctx.vkd, cmdBuffer);
472 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
473 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
474
475 // Create expected reference image.
476 const auto tcuFormat = mapVkFormat(colorFormat);
477 tcu::TextureLevel referenceLevel (tcuFormat, fbExtent.x(), fbExtent.y());
478 tcu::PixelBufferAccess referenceAccess = referenceLevel.getAccess();
479
480 const auto& xSize = fbExtent.x();
481 const auto& ySize = fbExtent.y();
482 const auto xSizeF = static_cast<float>(xSize);
483 const auto ySizeF = static_cast<float>(ySize);
484
485 // This must match the vertex+color combination for the second draw.
486 // Red goes from 0 to 1 on the X axis, Blue goes from 0 to 1 on the Y axis.
487 for (int y = 0; y < fbExtent.y(); ++y)
488 for (int x = 0; x < fbExtent.x(); ++x)
489 {
490 const float red = (static_cast<float>(y) + 0.5f) / ySizeF;
491 const float blue = (static_cast<float>(x) + 0.5f) / xSizeF;
492 const tcu::Vec4 refColor (red, 0.0f, blue, 1.0f);
493
494 referenceAccess.setPixel(refColor, x, y);
495 }
496
497 auto& log = context.getTestContext().getLog();
498 const tcu::ConstPixelBufferAccess resultAccess (tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
499
500 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, colorThreshold, tcu::COMPARE_LOG_ON_ERROR))
501 return tcu::TestStatus::fail("Unexpected color buffer contents -- check log for details");
502 return tcu::TestStatus::pass("Pass");
503 }
504
testNoFrag(Context & context)505 tcu::TestStatus testNoFrag (Context& context)
506 {
507 const auto ctx = context.getContextCommonData();
508 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
509 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
510 const auto colorSRR = makeDefaultImageSubresourceRange();
511 const auto colorSRL = makeDefaultImageSubresourceLayers();
512 const auto depthFormat = VK_FORMAT_D16_UNORM;
513 const auto depthUsage = (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
514 const auto depthSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
515 const auto depthSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u);
516 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
517 const auto vkExtent = makeExtent3D(8u, 1u, 1u);
518 const tcu::IVec3 fbExtent (static_cast<int>(vkExtent.width), static_cast<int>(vkExtent.height), static_cast<int>(vkExtent.depth));
519 const auto imageType = VK_IMAGE_TYPE_2D;
520 const tcu::IVec2 tileSize (2, 2);
521
522 vk::ImageWithBuffer colorBuffer (ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType, colorSRR);
523 vk::ImageWithBuffer depthBuffer (ctx.vkd, ctx.device, ctx.allocator, vkExtent, depthFormat, depthUsage, imageType, depthSRR);
524
525 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, context.getBinaryCollection().get("vert"));
526 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat, depthFormat);
527
528 const std::vector<VkImageView> attachmentViews { colorBuffer.getImageView(), depthBuffer.getImageView() };
529 const auto framebuffer = makeFramebuffer(
530 ctx.vkd, ctx.device, renderPass.get(),
531 de::sizeU32(attachmentViews), de::dataOrNull(attachmentViews),
532 vkExtent.width, vkExtent.height);
533
534 const std::vector<VkViewport> viewports (1u, makeViewport(fbExtent));
535 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent));
536
537 // Use the rate from the pipeline.
538 const auto fragmentShadingRateStateCreateInfo = makeFragmentShadingRateStateCreateInfo(
539 static_cast<uint32_t>(tileSize.x()), static_cast<uint32_t>(tileSize.y()), // This has mandatory support.
540 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
541 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR);
542
543 const std::vector<PositionColor> vertices
544 {
545 // Colors (second column) are irrelevant due to the lack of a frag shader.
546 // In the first column we increase depth as we advance from left to right.
547 { tcu::Vec4(-1.0, -1.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
548 { tcu::Vec4(-1.0, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) },
549 { tcu::Vec4( 1.0, -1.0f, 1.0f, 1.0f), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f) },
550 { tcu::Vec4( 1.0, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f) },
551 };
552
553 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
554 const auto vertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
555 const auto vertexBufferCreateInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
556 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
557 BufferWithMemory vertexBuffer (ctx.vkd, ctx.device, ctx.allocator, vertexBufferCreateInfo, MemoryRequirement::HostVisible);
558 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
559
560 deMemcpy(vertexBufferAlloc.getHostPtr(), de::dataOrNull(vertices), de::dataSize(vertices));
561 flushAlloc(ctx.vkd, ctx.device, vertexBufferAlloc);
562
563 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
564
565 const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
566 {
567 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
568 nullptr, // const void* pNext;
569 0u, // VkPipelineDepthStencilStateCreateFlags flags;
570 VK_TRUE, // VkBool32 depthTestEnable;
571 VK_TRUE, // VkBool32 depthWriteEnable;
572 VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp;
573 VK_FALSE, // VkBool32 depthBoundsTestEnable;
574 VK_FALSE, // VkBool32 stencilTestEnable;
575 {}, // VkStencilOpState front;
576 {}, // VkStencilOpState back;
577 0.0f, // float minDepthBounds;
578 1.0f, // float maxDepthBounds;
579 };
580
581 // We need to force-enable rasterization at this step, otherwise the helper will disable it due to missing frag shader.
582 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
583 {
584 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
585 nullptr, // const void* pNext;
586 0u, // VkPipelineRasterizationStateCreateFlags flags;
587 VK_FALSE, // VkBool32 depthClampEnable;
588 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
589 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
590 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
591 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
592 VK_FALSE, // VkBool32 depthBiasEnable;
593 0.0f, // float depthBiasConstantFactor;
594 0.0f, // float depthBiasClamp;
595 0.0f, // float depthBiasSlopeFactor;
596 1.0f, // float lineWidth;
597 };
598
599 // Pipeline.
600 const auto pipeline = makeGraphicsPipeline(ctx.vkd, ctx.device, pipelineLayout.get(),
601 vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE,
602 renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u,
603 getDefaultVertexInputStateCreateInfo(), &rasterizationStateCreateInfo, nullptr, &depthStencilStateCreateInfo, nullptr, nullptr, &fragmentShadingRateStateCreateInfo);
604
605 CommandPoolWithBuffer cmd (ctx.vkd, ctx.device, ctx.qfIndex);
606 const auto cmdBuffer = cmd.cmdBuffer.get();
607
608 using ClearValueVec = std::vector<VkClearValue>;
609 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
610 const float clearDepth = 1.0f;
611 const ClearValueVec clearValues
612 {
613 makeClearValueColor(clearColor),
614 makeClearValueDepthStencil(clearDepth, 0u),
615 };
616 const auto colorCompThreshold = 0.0f; // Expect exact results.
617 const tcu::Vec4 colorThreshold (colorCompThreshold, colorCompThreshold, colorCompThreshold, colorCompThreshold);
618 const float depthThreshold = 0.000025f; // Between 1/65535 and 2/65535.
619 const auto vertexCount = de::sizeU32(vertices);
620
621 beginCommandBuffer(ctx.vkd, cmdBuffer);
622 {
623 // Render pass.
624 beginRenderPass(ctx.vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), de::sizeU32(clearValues), de::dataOrNull(clearValues));
625 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
626 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
627 ctx.vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
628 endRenderPass(ctx.vkd, cmdBuffer);
629 }
630 {
631 // Copy images to verification buffers after rendering.
632 const std::vector<VkImageMemoryBarrier> preTransferBarriers =
633 {
634 makeImageMemoryBarrier(
635 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
636 VK_ACCESS_TRANSFER_READ_BIT,
637 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
638 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
639 colorBuffer.getImage(), colorSRR),
640
641 makeImageMemoryBarrier(
642 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
643 VK_ACCESS_TRANSFER_READ_BIT,
644 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
645 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
646 depthBuffer.getImage(), depthSRR),
647 };
648 const auto preTransferStages = (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
649 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, preTransferStages, VK_PIPELINE_STAGE_TRANSFER_BIT, de::dataOrNull(preTransferBarriers), preTransferBarriers.size());
650
651 const auto copyColorRegion = makeBufferImageCopy(vkExtent, colorSRL);
652 const auto copyDepthRegion = makeBufferImageCopy(vkExtent, depthSRL);
653 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getBuffer(), 1u, ©ColorRegion);
654 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, depthBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, depthBuffer.getBuffer(), 1u, ©DepthRegion);
655
656 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
657 cmdPipelineMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
658 }
659 endCommandBuffer(ctx.vkd, cmdBuffer);
660 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
661 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
662 invalidateAlloc(ctx.vkd, ctx.device, depthBuffer.getBufferAllocation());
663
664 // Check results:
665 // - Color image shouldn't have been touched.
666 // - Depth buffer should have values in pairs of 2, within the accepted range.
667 const auto colorTcuFormat = mapVkFormat(colorFormat);
668 const auto depthTcuFormat = mapVkFormat(depthFormat);
669 const tcu::ConstPixelBufferAccess colorResultAccess (colorTcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
670 const tcu::ConstPixelBufferAccess depthResultAccess (depthTcuFormat, fbExtent, depthBuffer.getBufferAllocation().getHostPtr());
671
672 auto& log = context.getTestContext().getLog();
673 if (!tcu::floatThresholdCompare(log, "ColorResult", "", clearColor, colorResultAccess, colorThreshold, tcu::COMPARE_LOG_ON_ERROR))
674 return tcu::TestStatus::fail("Unexpected color buffer contents (expected transparent black) -- check log for details");
675
676 // Note fragment shading rate does not affect the depth buffer, only frag shader invocations.
677 // When verifying the depth buffer, we'll generate the reference values normally.
678 tcu::TextureLevel refDepthLevel (depthTcuFormat, fbExtent.x(), fbExtent.y(), fbExtent.z());
679 tcu::PixelBufferAccess refDepthAccess = refDepthLevel.getAccess();
680 const float fWidth = static_cast<float>(fbExtent.x());
681
682 for (int y = 0; y < fbExtent.y(); ++y)
683 for (int x = 0; x < fbExtent.x(); ++x)
684 {
685 // This needs to match vertex depths.
686 const float depth = (static_cast<float>(x) + 0.5f) / fWidth;
687 refDepthAccess.setPixDepth(depth, x, y);
688 }
689
690 if (!tcu::dsThresholdCompare(log, "DepthResult", "", refDepthAccess, depthResultAccess, depthThreshold, tcu::COMPARE_LOG_ON_ERROR))
691 return tcu::TestStatus::fail("Unexpected depth buffer contents -- check log for details");
692
693 return tcu::TestStatus::pass("Pass");
694 }
695
696 } // anonymous
697
createFragmentShadingRateMiscTests(tcu::TestCaseGroup * group)698 void createFragmentShadingRateMiscTests (tcu::TestCaseGroup* group)
699 {
700 {
701 const char* testName = "enable_disable_attachment";
702 // Test drawing with VRS enabled by an attachment and then disabled
703 addFunctionCaseWithPrograms(group, testName, checkEnableDisableSupport, initEnableDisableShaders, testEnableDisable);
704 }
705 {
706 const char* testName = "no_frag_shader";
707 // Test drawing with VRS enabled and no frag shader
708 addFunctionCaseWithPrograms(group, testName, checkNoFragSupport, initNoFragShaders, testNoFrag);
709 }
710 }
711
712 } // FragmentShadingRate
713 } // vkt
714