1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 * Copyright (c) 2015 The Khronos Group Inc.
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 Early fragment tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentOperationsEarlyFragmentTests.hpp"
26 #include "vktFragmentOperationsMakeUtil.hpp"
27 #include "vktTestCaseUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkStrUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkImageUtil.hpp"
40
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
43
44 #include <string>
45
46 namespace vkt
47 {
48 namespace FragmentOperations
49 {
50 namespace
51 {
52 using namespace vk;
53 using de::UniquePtr;
54
55 //! Basic 2D image.
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)56 inline VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage)
57 {
58 const VkImageCreateInfo imageParams =
59 {
60 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
61 DE_NULL, // const void* pNext;
62 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
63 VK_IMAGE_TYPE_2D, // VkImageType imageType;
64 format, // VkFormat format;
65 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
66 1u, // deUint32 mipLevels;
67 1u, // deUint32 arrayLayers;
68 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
69 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
70 usage, // VkImageUsageFlags usage;
71 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
72 0u, // deUint32 queueFamilyIndexCount;
73 DE_NULL, // const deUint32* pQueueFamilyIndices;
74 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
75 };
76 return imageParams;
77 }
78
beginRenderPass(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const VkRenderPass renderPass,const VkFramebuffer framebuffer,const VkRect2D & renderArea,const tcu::Vec4 & clearColor,const float clearDepth,const deUint32 clearStencil)79 void beginRenderPass (const DeviceInterface& vk,
80 const VkCommandBuffer commandBuffer,
81 const VkRenderPass renderPass,
82 const VkFramebuffer framebuffer,
83 const VkRect2D& renderArea,
84 const tcu::Vec4& clearColor,
85 const float clearDepth,
86 const deUint32 clearStencil)
87 {
88 const VkClearValue clearValues[] =
89 {
90 makeClearValueColor(clearColor), // attachment 0
91 makeClearValueDepthStencil(clearDepth, clearStencil), // attachment 1
92 };
93
94 const VkRenderPassBeginInfo renderPassBeginInfo = {
95 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
96 DE_NULL, // const void* pNext;
97 renderPass, // VkRenderPass renderPass;
98 framebuffer, // VkFramebuffer framebuffer;
99 renderArea, // VkRect2D renderArea;
100 DE_LENGTH_OF_ARRAY(clearValues), // uint32_t clearValueCount;
101 clearValues, // const VkClearValue* pClearValues;
102 };
103
104 vk.cmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
105 }
106
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,const bool useDepthStencilAttachment,const VkFormat depthStencilFormat)107 Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk,
108 const VkDevice device,
109 const VkFormat colorFormat,
110 const bool useDepthStencilAttachment,
111 const VkFormat depthStencilFormat)
112 {
113 const VkAttachmentDescription attachments[] =
114 {
115 // color
116 {
117 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
118 colorFormat, // VkFormat format;
119 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
120 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
121 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
122 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
123 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
124 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
125 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
126 },
127 // depth/stencil
128 {
129 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
130 depthStencilFormat, // VkFormat format;
131 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
132 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
133 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
134 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
135 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
136 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
137 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
138 }
139 };
140
141 const VkAttachmentReference unusedAttachmentReference =
142 {
143 VK_ATTACHMENT_UNUSED, // deUint32 attachment;
144 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout layout;
145 };
146
147 const VkAttachmentReference colorAttachmentReference =
148 {
149 0u, // deUint32 attachment;
150 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
151 };
152
153 const VkAttachmentReference depthStencilAttachmentReference =
154 {
155 1u, // deUint32 attachment;
156 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout;
157 };
158
159 const VkAttachmentReference* pDepthStencilAttachment = (useDepthStencilAttachment ? &depthStencilAttachmentReference : &unusedAttachmentReference);
160
161 const VkSubpassDescription subpassDescription =
162 {
163 0u, // VkSubpassDescriptionFlags flags;
164 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
165 0u, // deUint32 inputAttachmentCount;
166 DE_NULL, // const VkAttachmentReference* pInputAttachments;
167 1u, // deUint32 colorAttachmentCount;
168 &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
169 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
170 pDepthStencilAttachment, // const VkAttachmentReference* pDepthStencilAttachment;
171 0u, // deUint32 preserveAttachmentCount;
172 DE_NULL // const deUint32* pPreserveAttachments;
173 };
174
175 const VkRenderPassCreateInfo renderPassInfo =
176 {
177 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
178 DE_NULL, // const void* pNext;
179 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
180 (useDepthStencilAttachment ? 2u : 1u), // deUint32 attachmentCount;
181 attachments, // const VkAttachmentDescription* pAttachments;
182 1u, // deUint32 subpassCount;
183 &subpassDescription, // const VkSubpassDescription* pSubpasses;
184 0u, // deUint32 dependencyCount;
185 DE_NULL // const VkSubpassDependency* pDependencies;
186 };
187
188 return createRenderPass(vk, device, &renderPassInfo);
189 }
190
makeFramebuffer(const DeviceInterface & vk,const VkDevice device,const VkRenderPass renderPass,const deUint32 attachmentCount,const VkImageView * pAttachments,const tcu::IVec2 size)191 Move<VkFramebuffer> makeFramebuffer (const DeviceInterface& vk,
192 const VkDevice device,
193 const VkRenderPass renderPass,
194 const deUint32 attachmentCount,
195 const VkImageView* pAttachments,
196 const tcu::IVec2 size)
197 {
198 const VkFramebufferCreateInfo framebufferInfo = {
199 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
200 DE_NULL, // const void* pNext;
201 (VkFramebufferCreateFlags)0, // VkFramebufferCreateFlags flags;
202 renderPass, // VkRenderPass renderPass;
203 attachmentCount, // uint32_t attachmentCount;
204 pAttachments, // const VkImageView* pAttachments;
205 static_cast<deUint32>(size.x()), // uint32_t width;
206 static_cast<deUint32>(size.y()), // uint32_t height;
207 1u, // uint32_t layers;
208 };
209
210 return createFramebuffer(vk, device, &framebufferInfo);
211 }
212
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const tcu::IVec2 & renderSize,const bool enableDepthTest,const bool enableStencilTest)213 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
214 const VkDevice device,
215 const VkPipelineLayout pipelineLayout,
216 const VkRenderPass renderPass,
217 const VkShaderModule vertexModule,
218 const VkShaderModule fragmentModule,
219 const tcu::IVec2& renderSize,
220 const bool enableDepthTest,
221 const bool enableStencilTest)
222 {
223 const VkVertexInputBindingDescription vertexInputBindingDescription =
224 {
225 0u, // uint32_t binding;
226 sizeof(tcu::Vec4), // uint32_t stride; // Vertex is a 4-element vector XYZW, position only
227 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
228 };
229
230 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
231 {
232 0u, // uint32_t location;
233 0u, // uint32_t binding;
234 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
235 0u, // uint32_t offset;
236 };
237
238 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
239 {
240 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
241 DE_NULL, // const void* pNext;
242 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
243 1u, // uint32_t vertexBindingDescriptionCount;
244 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
245 1u, // uint32_t vertexAttributeDescriptionCount;
246 &vertexInputAttributeDescription, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
247 };
248
249 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
250 {
251 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
252 DE_NULL, // const void* pNext;
253 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags;
254 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
255 VK_FALSE, // VkBool32 primitiveRestartEnable;
256 };
257
258 const VkViewport viewport = makeViewport(
259 0.0f, 0.0f,
260 static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
261 0.0f, 1.0f);
262
263 const VkRect2D scissor = {
264 makeOffset2D(0, 0),
265 makeExtent2D(renderSize.x(), renderSize.y()),
266 };
267
268 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
269 {
270 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
271 DE_NULL, // const void* pNext;
272 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags;
273 1u, // uint32_t viewportCount;
274 &viewport, // const VkViewport* pViewports;
275 1u, // uint32_t scissorCount;
276 &scissor, // const VkRect2D* pScissors;
277 };
278
279 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
280 {
281 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
282 DE_NULL, // const void* pNext;
283 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags;
284 VK_FALSE, // VkBool32 depthClampEnable;
285 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
286 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
287 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
288 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
289 VK_FALSE, // VkBool32 depthBiasEnable;
290 0.0f, // float depthBiasConstantFactor;
291 0.0f, // float depthBiasClamp;
292 0.0f, // float depthBiasSlopeFactor;
293 1.0f, // float lineWidth;
294 };
295
296 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
297 {
298 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
299 DE_NULL, // const void* pNext;
300 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
301 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
302 VK_FALSE, // VkBool32 sampleShadingEnable;
303 0.0f, // float minSampleShading;
304 DE_NULL, // const VkSampleMask* pSampleMask;
305 VK_FALSE, // VkBool32 alphaToCoverageEnable;
306 VK_FALSE // VkBool32 alphaToOneEnable;
307 };
308
309 const VkStencilOpState stencilOpState = makeStencilOpState(
310 VK_STENCIL_OP_KEEP, // stencil fail
311 VK_STENCIL_OP_KEEP, // depth & stencil pass
312 VK_STENCIL_OP_KEEP, // depth only fail
313 VK_COMPARE_OP_EQUAL, // compare op
314 1u, // compare mask
315 1u, // write mask
316 1u); // reference
317
318 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
319 {
320 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
321 DE_NULL, // const void* pNext;
322 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
323 enableDepthTest, // VkBool32 depthTestEnable;
324 VK_TRUE, // VkBool32 depthWriteEnable;
325 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
326 VK_FALSE, // VkBool32 depthBoundsTestEnable;
327 enableStencilTest, // VkBool32 stencilTestEnable;
328 stencilOpState, // VkStencilOpState front;
329 stencilOpState, // VkStencilOpState back;
330 0.0f, // float minDepthBounds;
331 1.0f, // float maxDepthBounds;
332 };
333
334 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
335 // Number of blend attachments must equal the number of color attachments.
336 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
337 {
338 VK_FALSE, // VkBool32 blendEnable;
339 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
340 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
341 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
342 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
343 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
344 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
345 colorComponentsAll, // VkColorComponentFlags colorWriteMask;
346 };
347
348 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
349 {
350 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
351 DE_NULL, // const void* pNext;
352 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
353 VK_FALSE, // VkBool32 logicOpEnable;
354 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
355 1u, // deUint32 attachmentCount;
356 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
357 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
358 };
359
360 const VkPipelineShaderStageCreateInfo pShaderStages[] =
361 {
362 {
363 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
364 DE_NULL, // const void* pNext;
365 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
366 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
367 vertexModule, // VkShaderModule module;
368 "main", // const char* pName;
369 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
370 },
371 {
372 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
373 DE_NULL, // const void* pNext;
374 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
375 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
376 fragmentModule, // VkShaderModule module;
377 "main", // const char* pName;
378 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
379 }
380 };
381
382 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
383 {
384 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
385 DE_NULL, // const void* pNext;
386 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
387 DE_LENGTH_OF_ARRAY(pShaderStages), // deUint32 stageCount;
388 pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages;
389 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
390 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
391 DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
392 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState;
393 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
394 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
395 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
396 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
397 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
398 pipelineLayout, // VkPipelineLayout layout;
399 renderPass, // VkRenderPass renderPass;
400 0u, // deUint32 subpass;
401 DE_NULL, // VkPipeline basePipelineHandle;
402 0, // deInt32 basePipelineIndex;
403 };
404
405 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
406 }
407
makeBufferImageCopy(const VkImageAspectFlags aspectFlags,const tcu::IVec2 & renderSize)408 VkBufferImageCopy makeBufferImageCopy (const VkImageAspectFlags aspectFlags, const tcu::IVec2& renderSize)
409 {
410 const VkBufferImageCopy copyParams =
411 {
412 0ull, // VkDeviceSize bufferOffset;
413 0u, // deUint32 bufferRowLength;
414 0u, // deUint32 bufferImageHeight;
415 makeImageSubresourceLayers(aspectFlags, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource;
416 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
417 makeExtent3D(renderSize.x(), renderSize.y(), 1u), // VkExtent3D imageExtent;
418 };
419 return copyParams;
420 }
421
commandClearStencilAttachment(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const VkOffset2D & offset,const VkExtent2D & extent,const deUint32 clearValue)422 void commandClearStencilAttachment (const DeviceInterface& vk,
423 const VkCommandBuffer commandBuffer,
424 const VkOffset2D& offset,
425 const VkExtent2D& extent,
426 const deUint32 clearValue)
427 {
428 const VkClearAttachment stencilAttachment =
429 {
430 VK_IMAGE_ASPECT_STENCIL_BIT, // VkImageAspectFlags aspectMask;
431 0u, // uint32_t colorAttachment;
432 makeClearValueDepthStencil(0.0f, clearValue), // VkClearValue clearValue;
433 };
434
435 const VkClearRect rect =
436 {
437 { offset, extent }, // VkRect2D rect;
438 0u, // uint32_t baseArrayLayer;
439 1u, // uint32_t layerCount;
440 };
441
442 vk.cmdClearAttachments(commandBuffer, 1u, &stencilAttachment, 1u, &rect);
443 }
444
getImageAspectFlags(const VkFormat format)445 VkImageAspectFlags getImageAspectFlags (const VkFormat format)
446 {
447 const tcu::TextureFormat tcuFormat = mapVkFormat(format);
448
449 if (tcuFormat.order == tcu::TextureFormat::DS) return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
450 else if (tcuFormat.order == tcu::TextureFormat::D) return VK_IMAGE_ASPECT_DEPTH_BIT;
451 else if (tcuFormat.order == tcu::TextureFormat::S) return VK_IMAGE_ASPECT_STENCIL_BIT;
452
453 DE_ASSERT(false);
454 return 0u;
455 }
456
isSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device,const VkFormat format)457 bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, const VkPhysicalDevice device, const VkFormat format)
458 {
459 VkFormatProperties formatProps;
460 instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
461 return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
462 }
463
pickSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device,const deUint32 numFormats,const VkFormat * pFormats)464 VkFormat pickSupportedDepthStencilFormat (const InstanceInterface& instanceInterface,
465 const VkPhysicalDevice device,
466 const deUint32 numFormats,
467 const VkFormat* pFormats)
468 {
469 for (deUint32 i = 0; i < numFormats; ++i)
470 if (isSupportedDepthStencilFormat(instanceInterface, device, pFormats[i]))
471 return pFormats[i];
472 return VK_FORMAT_UNDEFINED;
473 }
474
475 enum Flags
476 {
477 FLAG_TEST_DEPTH = 1u << 0,
478 FLAG_TEST_STENCIL = 1u << 1,
479 FLAG_DONT_USE_TEST_ATTACHMENT = 1u << 2,
480 FLAG_DONT_USE_EARLY_FRAGMENT_TESTS = 1u << 3,
481 };
482
483 class EarlyFragmentTest : public TestCase
484 {
485 public:
486 EarlyFragmentTest (tcu::TestContext& testCtx,
487 const std::string name,
488 const deUint32 flags);
489
490 void initPrograms (SourceCollections& programCollection) const;
491 TestInstance* createInstance (Context& context) const;
492
493 private:
494 const deUint32 m_flags;
495 };
496
EarlyFragmentTest(tcu::TestContext & testCtx,const std::string name,const deUint32 flags)497 EarlyFragmentTest::EarlyFragmentTest (tcu::TestContext& testCtx, const std::string name, const deUint32 flags)
498 : TestCase (testCtx, name, "")
499 , m_flags (flags)
500 {
501 }
502
initPrograms(SourceCollections & programCollection) const503 void EarlyFragmentTest::initPrograms (SourceCollections& programCollection) const
504 {
505 // Vertex
506 {
507 std::ostringstream src;
508 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
509 << "\n"
510 << "layout(location = 0) in highp vec4 position;\n"
511 << "\n"
512 << "out gl_PerVertex {\n"
513 << " vec4 gl_Position;\n"
514 << "};\n"
515 << "\n"
516 << "void main (void)\n"
517 << "{\n"
518 << " gl_Position = position;\n"
519 << "}\n";
520
521 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
522 }
523
524 // Fragment
525 {
526 const bool useEarlyTests = (m_flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0;
527 std::ostringstream src;
528 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
529 << "\n"
530 << (useEarlyTests ? "layout(early_fragment_tests) in;\n" : "")
531 << "layout(location = 0) out highp vec4 fragColor;\n"
532 << "\n"
533 << "layout(binding = 0) coherent buffer Output {\n"
534 << " uint result;\n"
535 << "} sb_out;\n"
536 << "\n"
537 << "void main (void)\n"
538 << "{\n"
539 << " atomicAdd(sb_out.result, 1u);\n"
540 << " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
541 << "}\n";
542
543 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
544 }
545 }
546
547 class EarlyFragmentTestInstance : public TestInstance
548 {
549 public:
550 EarlyFragmentTestInstance (Context& context, const deUint32 flags);
551
552 tcu::TestStatus iterate (void);
553
554 private:
555 enum TestMode
556 {
557 MODE_INVALID,
558 MODE_DEPTH,
559 MODE_STENCIL,
560 };
561
562 const TestMode m_testMode;
563 const bool m_useTestAttachment;
564 const bool m_useEarlyTests;
565 };
566
EarlyFragmentTestInstance(Context & context,const deUint32 flags)567 EarlyFragmentTestInstance::EarlyFragmentTestInstance (Context& context, const deUint32 flags)
568 : TestInstance (context)
569 , m_testMode (flags & FLAG_TEST_DEPTH ? MODE_DEPTH :
570 flags & FLAG_TEST_STENCIL ? MODE_STENCIL : MODE_INVALID)
571 , m_useTestAttachment ((flags & FLAG_DONT_USE_TEST_ATTACHMENT) == 0)
572 , m_useEarlyTests ((flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0)
573 {
574 DE_ASSERT(m_testMode != MODE_INVALID);
575 }
576
iterate(void)577 tcu::TestStatus EarlyFragmentTestInstance::iterate (void)
578 {
579 const DeviceInterface& vk = m_context.getDeviceInterface();
580 const InstanceInterface& vki = m_context.getInstanceInterface();
581 const VkDevice device = m_context.getDevice();
582 const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
583 const VkQueue queue = m_context.getUniversalQueue();
584 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
585 Allocator& allocator = m_context.getDefaultAllocator();
586
587 // Color attachment
588
589 const tcu::IVec2 renderSize = tcu::IVec2(32, 32);
590 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
591 const VkImageSubresourceRange colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
592 const Unique<VkImage> colorImage (makeImage(vk, device, makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
593 const UniquePtr<Allocation> colorImageAlloc (bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
594 const Unique<VkImageView> colorImageView (makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
595
596 // Test attachment (depth or stencil)
597 static const VkFormat stencilFormats[] =
598 {
599 // One of the following formats must be supported, as per spec requirement.
600 VK_FORMAT_S8_UINT,
601 VK_FORMAT_D16_UNORM_S8_UINT,
602 VK_FORMAT_D24_UNORM_S8_UINT,
603 VK_FORMAT_D32_SFLOAT_S8_UINT,
604 };
605
606 const VkFormat testFormat = (m_testMode == MODE_STENCIL ? pickSupportedDepthStencilFormat(vki, physDevice, DE_LENGTH_OF_ARRAY(stencilFormats), stencilFormats)
607 : VK_FORMAT_D16_UNORM); // spec requires this format to be supported
608 if (testFormat == VK_FORMAT_UNDEFINED)
609 return tcu::TestStatus::fail("Required depth/stencil format not supported");
610
611 if (m_useTestAttachment)
612 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Using depth/stencil format " << getFormatName(testFormat) << tcu::TestLog::EndMessage;
613
614 const VkImageSubresourceRange testSubresourceRange = makeImageSubresourceRange(getImageAspectFlags(testFormat), 0u, 1u, 0u, 1u);
615 const Unique<VkImage> testImage (makeImage(vk, device, makeImageCreateInfo(renderSize, testFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)));
616 const UniquePtr<Allocation> testImageAlloc (bindImage(vk, device, allocator, *testImage, MemoryRequirement::Any));
617 const Unique<VkImageView> testImageView (makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, testFormat, testSubresourceRange));
618 const VkImageView attachmentImages[] = { *colorImageView, *testImageView };
619 const deUint32 numUsedAttachmentImages = (m_useTestAttachment ? 2u : 1u);
620
621 // Vertex buffer
622
623 const deUint32 numVertices = 6;
624 const VkDeviceSize vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices;
625 const Unique<VkBuffer> vertexBuffer (makeBuffer(vk, device, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)));
626 const UniquePtr<Allocation> vertexBufferAlloc (bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
627
628 {
629 tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(vertexBufferAlloc->getHostPtr());
630
631 pVertices[0] = tcu::Vec4( 1.0f, -1.0f, 0.5f, 1.0f);
632 pVertices[1] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
633 pVertices[2] = tcu::Vec4(-1.0f, 1.0f, 0.5f, 1.0f);
634
635 pVertices[3] = tcu::Vec4(-1.0f, 1.0f, 0.5f, 1.0f);
636 pVertices[4] = tcu::Vec4( 1.0f, 1.0f, 1.0f, 1.0f);
637 pVertices[5] = tcu::Vec4( 1.0f, -1.0f, 0.5f, 1.0f);
638
639 flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSizeBytes);
640 // No barrier needed, flushed memory is automatically visible
641 }
642
643 // Result buffer
644
645 const VkDeviceSize resultBufferSizeBytes = sizeof(deUint32);
646 const Unique<VkBuffer> resultBuffer (makeBuffer(vk, device, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)));
647 const UniquePtr<Allocation> resultBufferAlloc (bindBuffer(vk, device, allocator, *resultBuffer, MemoryRequirement::HostVisible));
648
649 {
650 deUint32* const pData = static_cast<deUint32*>(resultBufferAlloc->getHostPtr());
651
652 *pData = 0;
653 flushMappedMemoryRange(vk, device, resultBufferAlloc->getMemory(), resultBufferAlloc->getOffset(), resultBufferSizeBytes);
654 }
655
656 // Render result buffer (to retrieve color attachment contents)
657
658 const VkDeviceSize colorBufferSizeBytes = tcu::getPixelSize(mapVkFormat(colorFormat)) * renderSize.x() * renderSize.y();
659 const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
660 const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
661
662 // Descriptors
663
664 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
665 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
666 .build(vk, device));
667
668 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
669 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
670 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
671
672 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
673 const VkDescriptorBufferInfo resultBufferDescriptorInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
674
675 DescriptorSetUpdateBuilder()
676 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferDescriptorInfo)
677 .update(vk, device);
678
679 // Pipeline
680
681 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
682 const Unique<VkShaderModule> fragmentModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
683 const Unique<VkRenderPass> renderPass (makeRenderPass(vk, device, colorFormat, m_useTestAttachment, testFormat));
684 const Unique<VkFramebuffer> framebuffer (makeFramebuffer(vk, device, *renderPass, numUsedAttachmentImages, attachmentImages, renderSize));
685 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
686 const Unique<VkPipeline> pipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, renderSize,
687 (m_testMode == MODE_DEPTH), (m_testMode == MODE_STENCIL)));
688 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
689 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
690
691 // Draw commands
692
693 {
694 const VkRect2D renderArea = {
695 makeOffset2D(0, 0),
696 makeExtent2D(renderSize.x(), renderSize.y()),
697 };
698 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
699 const VkDeviceSize vertexBufferOffset = 0ull;
700
701 beginCommandBuffer(vk, *cmdBuffer);
702
703 {
704 const VkImageMemoryBarrier barriers[] = {
705 makeImageMemoryBarrier(
706 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
707 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
708 *colorImage, colorSubresourceRange),
709 makeImageMemoryBarrier(
710 0u, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
711 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
712 *testImage, testSubresourceRange),
713 };
714
715 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
716 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
717 }
718
719 // Will clear the attachments with specified depth and stencil values.
720 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor, 0.5f, 0u);
721
722 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
723 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
724 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
725
726 // Mask half of the attachment image with value that will pass the stencil test.
727 if (m_useTestAttachment && m_testMode == MODE_STENCIL)
728 commandClearStencilAttachment(vk, *cmdBuffer, makeOffset2D(0, 0), makeExtent2D(renderSize.x()/2, renderSize.y()), 1u);
729
730 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
731 vk.cmdEndRenderPass(*cmdBuffer);
732
733 {
734 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
735 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
736
737 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
738 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
739
740 const VkImageMemoryBarrier preCopyColorImageBarrier = makeImageMemoryBarrier(
741 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
742 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
743 *colorImage, colorSubresourceRange);
744
745 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
746 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyColorImageBarrier);
747
748 const VkBufferImageCopy copyRegion = makeBufferImageCopy(VK_IMAGE_ASPECT_COLOR_BIT, renderSize);
749 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ©Region);
750
751 const VkBufferMemoryBarrier postCopyColorBufferBarrier = makeBufferMemoryBarrier(
752 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
753
754 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
755 0u, DE_NULL, 1u, &postCopyColorBufferBarrier, 0u, DE_NULL);
756 }
757
758 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
759 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
760 }
761
762 // Log result image
763 {
764 invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), colorBufferSizeBytes);
765
766 const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc->getHostPtr());
767
768 tcu::TestLog& log = m_context.getTestContext().getLog();
769 log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
770 }
771
772 // Verify results
773 {
774 invalidateMappedMemoryRange(vk, device, resultBufferAlloc->getMemory(), resultBufferAlloc->getOffset(), resultBufferSizeBytes);
775
776 const int actualCounter = *static_cast<deInt32*>(resultBufferAlloc->getHostPtr());
777 const bool expectPartialResult = (m_useEarlyTests && m_useTestAttachment);
778 const int expectedCounter = expectPartialResult ? renderSize.x() * renderSize.y() / 2 : renderSize.x() * renderSize.y();
779 const int tolerance = expectPartialResult ? de::max(renderSize.x(), renderSize.y()) * 3 : 0;
780 const int expectedMin = de::max(0, expectedCounter - tolerance);
781 const int expectedMax = expectedCounter + tolerance;
782
783 tcu::TestLog& log = m_context.getTestContext().getLog();
784 log << tcu::TestLog::Message << "Expected value"
785 << (expectPartialResult ? " in range: [" + de::toString(expectedMin) + ", " + de::toString(expectedMax) + "]" : ": " + de::toString(expectedCounter))
786 << tcu::TestLog::EndMessage;
787 log << tcu::TestLog::Message << "Result value: " << de::toString(actualCounter) << tcu::TestLog::EndMessage;
788
789 if (expectedMin <= actualCounter && actualCounter <= expectedMax)
790 return tcu::TestStatus::pass("Success");
791 else
792 return tcu::TestStatus::fail("Value out of range");
793 }
794 }
795
createInstance(Context & context) const796 TestInstance* EarlyFragmentTest::createInstance (Context& context) const
797 {
798 // Check required features
799 {
800 VkPhysicalDeviceFeatures features;
801 context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
802
803 // SSBO writes in fragment shader
804 if (!features.fragmentStoresAndAtomics)
805 throw tcu::NotSupportedError("Missing required feature: fragmentStoresAndAtomics");
806 }
807
808 return new EarlyFragmentTestInstance(context, m_flags);
809 }
810
811 } // anonymous ns
812
createEarlyFragmentTests(tcu::TestContext & testCtx)813 tcu::TestCaseGroup* createEarlyFragmentTests (tcu::TestContext& testCtx)
814 {
815 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "early_fragment", "early fragment test cases"));
816
817 static const struct
818 {
819 std::string caseName;
820 deUint32 flags;
821 } cases[] =
822 {
823 { "no_early_fragment_tests_depth", FLAG_TEST_DEPTH | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS },
824 { "no_early_fragment_tests_stencil", FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS },
825 { "early_fragment_tests_depth", FLAG_TEST_DEPTH },
826 { "early_fragment_tests_stencil", FLAG_TEST_STENCIL },
827 { "no_early_fragment_tests_depth_no_attachment", FLAG_TEST_DEPTH | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT },
828 { "no_early_fragment_tests_stencil_no_attachment", FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT },
829 { "early_fragment_tests_depth_no_attachment", FLAG_TEST_DEPTH | FLAG_DONT_USE_TEST_ATTACHMENT },
830 { "early_fragment_tests_stencil_no_attachment", FLAG_TEST_STENCIL | FLAG_DONT_USE_TEST_ATTACHMENT },
831 };
832
833 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
834 testGroup->addChild(new EarlyFragmentTest(testCtx, cases[i].caseName, cases[i].flags));
835
836 return testGroup.release();
837 }
838
839 } // FragmentOperations
840 } // vkt
841