1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 Google 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 Fragment Operations Occlusion Query Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktFragmentOperationsOcclusionQueryTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 
28 #include "vkDefs.hpp"
29 #include "vkRef.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkPlatform.hpp"
32 #include "vkPrograms.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkStrUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkBarrierUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 
43 #include "tcuTestLog.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuTextureUtil.hpp"
46 
47 #include "deUniquePtr.hpp"
48 #include "deStringUtil.hpp"
49 #include "deMath.h"
50 
51 #include <string>
52 
53 namespace vkt
54 {
55 namespace FragmentOperations
56 {
57 namespace
58 {
59 using namespace vk;
60 using de::UniquePtr;
61 
62 //! Basic 2D image.
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)63 inline VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const VkFormat format,
64                                              const VkImageUsageFlags usage)
65 {
66     const VkImageCreateInfo imageParams = {
67         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
68         DE_NULL,                             // const void* pNext;
69         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
70         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
71         format,                              // VkFormat format;
72         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
73         1u,                                  // uint32_t mipLevels;
74         1u,                                  // uint32_t arrayLayers;
75         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
76         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
77         usage,                               // VkImageUsageFlags usage;
78         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
79         0u,                                  // uint32_t queueFamilyIndexCount;
80         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
81         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
82     };
83 
84     return imageParams;
85 }
86 
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,const bool useDepthStencilAttachment,const VkFormat depthStencilFormat)87 Move<VkRenderPass> makeRenderPass(const DeviceInterface &vk, const VkDevice device, const VkFormat colorFormat,
88                                   const bool useDepthStencilAttachment, const VkFormat depthStencilFormat)
89 {
90     return makeRenderPass(vk, device, colorFormat,
91                           useDepthStencilAttachment ? depthStencilFormat : VK_FORMAT_UNDEFINED);
92 }
93 
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 enableScissorTest,const bool enableDepthTest,const bool enableStencilTest,const bool enableStencilWrite)94 Move<VkPipeline> makeGraphicsPipeline(const DeviceInterface &vk, const VkDevice device,
95                                       const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass,
96                                       const VkShaderModule vertexModule, const VkShaderModule fragmentModule,
97                                       const tcu::IVec2 &renderSize, const bool enableScissorTest,
98                                       const bool enableDepthTest, const bool enableStencilTest,
99                                       const bool enableStencilWrite)
100 {
101     const std::vector<VkViewport> viewports(1, makeViewport(renderSize));
102     const std::vector<VkRect2D> scissors(
103         1, enableScissorTest ?
104                makeRect2D(renderSize.x() / 4, renderSize.y() / 4, renderSize.x() / 4 * 2, renderSize.y() / 4 * 2) :
105                makeRect2D(renderSize));
106 
107     const VkStencilOpState stencilOpState =
108         makeStencilOpState(VK_STENCIL_OP_KEEP,                                              // stencil fail
109                            enableStencilWrite ? VK_STENCIL_OP_REPLACE : VK_STENCIL_OP_KEEP, // depth & stencil pass
110                            VK_STENCIL_OP_KEEP,                                              // depth only fail
111                            enableStencilWrite ? VK_COMPARE_OP_ALWAYS : VK_COMPARE_OP_EQUAL, // compare op
112                            0xff,                                                            // compare mask
113                            0xff,                                                            // write mask
114                            enableStencilWrite ? 0u : 1u);                                   // reference
115 
116     VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
117         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType                            sType
118         DE_NULL,                                                    // const void*                                pNext
119         0u,                                                         // VkPipelineDepthStencilStateCreateFlags    flags
120         enableDepthTest ? VK_TRUE : VK_FALSE,   // VkBool32                                    depthTestEnable
121         enableDepthTest ? VK_TRUE : VK_FALSE,   // VkBool32                                    depthWriteEnable
122         VK_COMPARE_OP_LESS,                     // VkCompareOp                                depthCompareOp
123         VK_FALSE,                               // VkBool32                                    depthBoundsTestEnable
124         enableStencilTest ? VK_TRUE : VK_FALSE, // VkBool32                                    stencilTestEnable
125         enableStencilTest ? stencilOpState : VkStencilOpState{}, // VkStencilOpState                            front
126         enableStencilTest ? stencilOpState : VkStencilOpState{}, // VkStencilOpState                            back
127         0.0f, // float                                    minDepthBounds
128         1.0f  // float                                    maxDepthBounds
129     };
130 
131     return vk::makeGraphicsPipeline(
132         vk,             // const DeviceInterface&                            vk
133         device,         // const VkDevice                                    device
134         pipelineLayout, // const VkPipelineLayout                            pipelineLayout
135         vertexModule,   // const VkShaderModule                                vertexShaderModule
136         DE_NULL,        // const VkShaderModule                                tessellationControlModule
137         DE_NULL,        // const VkShaderModule                                tessellationEvalModule
138         DE_NULL,        // const VkShaderModule                                geometryShaderModule
139         fragmentModule, // const VkShaderModule                                fragmentShaderModule
140         renderPass,     // const VkRenderPass                                renderPass
141         viewports,      // const std::vector<VkViewport>&                    viewports
142         scissors,       // const std::vector<VkRect2D>&                        scissors
143         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology                        topology
144         0u,                                  // const uint32_t                                    subpass
145         0u,                                  // const uint32_t                                    patchControlPoints
146         DE_NULL,                       // const VkPipelineVertexInputStateCreateInfo*        vertexInputStateCreateInfo
147         DE_NULL,                       // const VkPipelineRasterizationStateCreateInfo*    rasterizationStateCreateInfo
148         DE_NULL,                       // const VkPipelineMultisampleStateCreateInfo*        multisampleStateCreateInfo
149         &depthStencilStateCreateInfo); // const VkPipelineDepthStencilStateCreateInfo*        depthStencilStateCreateInfo
150 }
151 
commandClearDepthAttachment(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const VkOffset2D & offset,const VkExtent2D & extent,const uint32_t clearValue)152 void commandClearDepthAttachment(const DeviceInterface &vk, const VkCommandBuffer commandBuffer,
153                                  const VkOffset2D &offset, const VkExtent2D &extent, const uint32_t clearValue)
154 {
155     const VkClearAttachment depthAttachment = {
156         VK_IMAGE_ASPECT_DEPTH_BIT,                    // VkImageAspectFlags aspectMask;
157         0u,                                           // uint32_t colorAttachment;
158         makeClearValueDepthStencil(0.0f, clearValue), // VkClearValue clearValue;
159     };
160 
161     const VkClearRect rect = {
162         {offset, extent}, // VkRect2D rect;
163         0u,               // uint32_t baseArrayLayer;
164         1u,               // uint32_t layerCount;
165     };
166 
167     vk.cmdClearAttachments(commandBuffer, 1u, &depthAttachment, 1u, &rect);
168 }
169 
commandClearStencilAttachment(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const VkOffset2D & offset,const VkExtent2D & extent,const uint32_t clearValue)170 void commandClearStencilAttachment(const DeviceInterface &vk, const VkCommandBuffer commandBuffer,
171                                    const VkOffset2D &offset, const VkExtent2D &extent, const uint32_t clearValue)
172 {
173     const VkClearAttachment stencilAttachment = {
174         VK_IMAGE_ASPECT_STENCIL_BIT,                  // VkImageAspectFlags aspectMask;
175         0u,                                           // uint32_t colorAttachment;
176         makeClearValueDepthStencil(0.0f, clearValue), // VkClearValue clearValue;
177     };
178 
179     const VkClearRect rect = {
180         {offset, extent}, // VkRect2D rect;
181         0u,               // uint32_t baseArrayLayer;
182         1u,               // uint32_t layerCount;
183     };
184 
185     vk.cmdClearAttachments(commandBuffer, 1u, &stencilAttachment, 1u, &rect);
186 }
187 
getImageAspectFlags(const VkFormat format)188 VkImageAspectFlags getImageAspectFlags(const VkFormat format)
189 {
190     const tcu::TextureFormat tcuFormat = mapVkFormat(format);
191 
192     if (tcuFormat.order == tcu::TextureFormat::DS)
193         return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
194     else if (tcuFormat.order == tcu::TextureFormat::D)
195         return VK_IMAGE_ASPECT_DEPTH_BIT;
196     else if (tcuFormat.order == tcu::TextureFormat::S)
197         return VK_IMAGE_ASPECT_STENCIL_BIT;
198 
199     DE_ASSERT(false);
200     return 0u;
201 }
202 
isSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device,const VkFormat format)203 bool isSupportedDepthStencilFormat(const InstanceInterface &instanceInterface, const VkPhysicalDevice device,
204                                    const VkFormat format)
205 {
206     VkFormatProperties formatProps;
207     instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
208     return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
209 }
210 
pickSupportedDepthStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device)211 VkFormat pickSupportedDepthStencilFormat(const InstanceInterface &instanceInterface, const VkPhysicalDevice device)
212 {
213     static const VkFormat dsFormats[] = {
214         VK_FORMAT_D16_UNORM_S8_UINT,
215         VK_FORMAT_D24_UNORM_S8_UINT,
216         VK_FORMAT_D32_SFLOAT_S8_UINT,
217     };
218 
219     for (uint32_t i = 0; i < DE_LENGTH_OF_ARRAY(dsFormats); ++i)
220         if (isSupportedDepthStencilFormat(instanceInterface, device, dsFormats[i]))
221             return dsFormats[i];
222 
223     return VK_FORMAT_UNDEFINED;
224 }
225 
226 enum Flags
227 {
228     TEST_NO_FLAGS      = 0,
229     TEST_SCISSOR       = 1u << 0,
230     TEST_DEPTH_WRITE   = 1u << 1,
231     TEST_DEPTH_CLEAR   = 1u << 2,
232     TEST_STENCIL_WRITE = 1u << 3,
233     TEST_STENCIL_CLEAR = 1u << 4,
234     TEST_ALL           = 1u << 5,
235     TEST_PRECISE_BIT   = 1u << 6
236 };
237 
238 class OcclusionQueryTestInstance : public TestInstance
239 {
240 public:
241     OcclusionQueryTestInstance(Context &context, const tcu::IVec2 renderSize, const bool preciseBitEnabled,
242                                const bool scissorTestEnabled, const bool depthTestEnabled,
243                                const bool stencilTestEnabled, const bool depthWriteEnabled,
244                                const bool stencilWriteEnabled);
245 
246     tcu::TestStatus iterate(void);
247 
248 private:
249     const tcu::IVec2 m_renderSize;
250     const bool m_preciseBitEnabled;
251     const bool m_scissorTestEnabled;
252     const bool m_depthClearTestEnabled;
253     const bool m_stencilClearTestEnabled;
254     const bool m_depthWriteTestEnabled;
255     const bool m_stencilWriteTestEnabled;
256 };
257 
OcclusionQueryTestInstance(Context & context,const tcu::IVec2 renderSize,const bool preciseBitEnabled,const bool scissorTestEnabled,const bool depthClearTestEnabled,const bool stencilClearTestEnabled,const bool depthWriteTestEnabled,const bool stencilWriteTestEnabled)258 OcclusionQueryTestInstance::OcclusionQueryTestInstance(Context &context, const tcu::IVec2 renderSize,
259                                                        const bool preciseBitEnabled, const bool scissorTestEnabled,
260                                                        const bool depthClearTestEnabled,
261                                                        const bool stencilClearTestEnabled,
262                                                        const bool depthWriteTestEnabled,
263                                                        const bool stencilWriteTestEnabled)
264     : TestInstance(context)
265     , m_renderSize(renderSize)
266     , m_preciseBitEnabled(preciseBitEnabled)
267     , m_scissorTestEnabled(scissorTestEnabled)
268     , m_depthClearTestEnabled(depthClearTestEnabled)
269     , m_stencilClearTestEnabled(stencilClearTestEnabled)
270     , m_depthWriteTestEnabled(depthWriteTestEnabled)
271     , m_stencilWriteTestEnabled(stencilWriteTestEnabled)
272 {
273 }
274 
iterate(void)275 tcu::TestStatus OcclusionQueryTestInstance::iterate(void)
276 {
277     const DeviceInterface &vk         = m_context.getDeviceInterface();
278     const InstanceInterface &vki      = m_context.getInstanceInterface();
279     const VkDevice device             = m_context.getDevice();
280     const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
281     const VkQueue queue               = m_context.getUniversalQueue();
282     const uint32_t queueFamilyIndex   = m_context.getUniversalQueueFamilyIndex();
283     Allocator &allocator              = m_context.getDefaultAllocator();
284     VkQueryPool queryPool;
285     const uint32_t queryCount = 1u;
286     std::vector<VkDeviceSize> sampleCounts(queryCount);
287 
288     // Create a query pool for storing the occlusion query result
289     {
290         VkQueryPoolCreateInfo queryPoolInfo{
291             VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // VkStructureType sType;
292             DE_NULL,                                  // const void* pNext;
293             (VkQueryPoolCreateFlags)0,                // VkQueryPoolCreateFlags flags;
294             VK_QUERY_TYPE_OCCLUSION,                  // VkQueryType queryType;
295             queryCount,                               // uint32_t queryCount;
296             0u,                                       // VkQueryPipelineStatisticFlags pipelineStatistics;
297         };
298         VK_CHECK(vk.createQueryPool(device, &queryPoolInfo, NULL, &queryPool));
299     }
300 
301     // Color attachment
302     const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
303     const VkImageSubresourceRange colorSubresourceRange =
304         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
305     const Unique<VkImage> colorImage(
306         makeImage(vk, device,
307                   makeImageCreateInfo(m_renderSize, colorFormat,
308                                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
309     const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
310     const Unique<VkImageView> colorImageView(
311         makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
312 
313     std::vector<VkImageView> attachmentImages = {*colorImageView};
314 
315     bool depthTestsEnabled   = (m_depthClearTestEnabled || m_depthWriteTestEnabled);
316     bool stencilTestsEnabled = (m_stencilClearTestEnabled || m_stencilWriteTestEnabled);
317 
318     const VkFormat testFormat =
319         (depthTestsEnabled && stencilTestsEnabled  ? pickSupportedDepthStencilFormat(vki, physDevice) :
320          !depthTestsEnabled && stencilTestsEnabled ? VK_FORMAT_S8_UINT :
321                                                      VK_FORMAT_D16_UNORM);
322 
323     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Using depth/stencil format "
324                                         << getFormatName(testFormat) << tcu::TestLog::EndMessage;
325 
326     const VkImageSubresourceRange testSubresourceRange =
327         makeImageSubresourceRange(getImageAspectFlags(testFormat), 0u, 1u, 0u, 1u);
328     const Unique<VkImage> testImage(makeImage(
329         vk, device, makeImageCreateInfo(m_renderSize, testFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)));
330     const UniquePtr<Allocation> testImageAlloc(bindImage(vk, device, allocator, *testImage, MemoryRequirement::Any));
331     const Unique<VkImageView> testImageView(
332         makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, testFormat, testSubresourceRange));
333 
334     if (depthTestsEnabled || stencilTestsEnabled)
335         attachmentImages.push_back(*testImageView);
336 
337     const uint32_t numUsedAttachmentImages = uint32_t(attachmentImages.size());
338 
339     // Depth occluder vertex buffer
340     const uint32_t numDepthOccVertices       = 6;
341     const VkDeviceSize dOccVertBuffSizeBytes = 256;
342     const Unique<VkBuffer> dOccluderVertexBuffer(
343         makeBuffer(vk, device, dOccVertBuffSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
344     const UniquePtr<Allocation> dOccVertexBufferAlloc(
345         bindBuffer(vk, device, allocator, *dOccluderVertexBuffer, MemoryRequirement::HostVisible));
346 
347     {
348         tcu::Vec4 *const pVertices = reinterpret_cast<tcu::Vec4 *>(dOccVertexBufferAlloc->getHostPtr());
349 
350         pVertices[0] = tcu::Vec4(-0.25f, -0.50f, 0.0f, 1.0f); // Top Right
351         pVertices[1] = tcu::Vec4(-0.50f, -0.50f, 0.0f, 1.0f); // Top Left
352         pVertices[2] = tcu::Vec4(-0.25f, -0.25f, 0.0f, 1.0f); // Bottom Right
353         pVertices[3] = tcu::Vec4(-0.50f, -0.25f, 0.0f, 1.0f); // Bottom Left
354         pVertices[4] = tcu::Vec4(-0.25f, -0.25f, 0.0f, 1.0f); // Bottom Right
355         pVertices[5] = tcu::Vec4(-0.50f, -0.50f, 0.0f, 1.0f); // Top Left
356 
357         flushAlloc(vk, device, *dOccVertexBufferAlloc);
358     }
359 
360     // Stencil occluder vertex buffer
361     const uint32_t numStencilOccVertices     = 6;
362     const VkDeviceSize sOccVertBuffSizeBytes = 256;
363     const Unique<VkBuffer> sOccluderVertexBuffer(
364         makeBuffer(vk, device, sOccVertBuffSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
365     const UniquePtr<Allocation> sOccVertexBufferAlloc(
366         bindBuffer(vk, device, allocator, *sOccluderVertexBuffer, MemoryRequirement::HostVisible));
367 
368     {
369         tcu::Vec4 *const pVertices = reinterpret_cast<tcu::Vec4 *>(sOccVertexBufferAlloc->getHostPtr());
370 
371         pVertices[0] = tcu::Vec4(-0.25f, -0.25f, 0.0f, 1.0f); // Top Right
372         pVertices[1] = tcu::Vec4(-0.50f, -0.25f, 0.0f, 1.0f); // Top Left
373         pVertices[2] = tcu::Vec4(-0.25f, 0.00f, 0.0f, 1.0f);  // Bottom Right
374         pVertices[3] = tcu::Vec4(-0.50f, 0.00f, 0.0f, 1.0f);  // Bottom Left
375         pVertices[4] = tcu::Vec4(-0.25f, 0.00f, 0.0f, 1.0f);  // Bottom Right
376         pVertices[5] = tcu::Vec4(-0.50f, -0.25f, 0.0f, 1.0f); // Top Left
377 
378         flushAlloc(vk, device, *sOccVertexBufferAlloc);
379     }
380 
381     // Main vertex buffer
382     const uint32_t numVertices               = 6;
383     const VkDeviceSize vertexBufferSizeBytes = 256;
384     const Unique<VkBuffer> vertexBuffer(
385         makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
386     const UniquePtr<Allocation> vertexBufferAlloc(
387         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
388 
389     {
390         tcu::Vec4 *const pVertices = reinterpret_cast<tcu::Vec4 *>(vertexBufferAlloc->getHostPtr());
391 
392         pVertices[0] = tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f);
393         pVertices[1] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
394         pVertices[2] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f);
395         pVertices[3] = tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f);
396         pVertices[4] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
397         pVertices[5] = tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f);
398 
399         flushAlloc(vk, device, *vertexBufferAlloc);
400     }
401 
402     // Render result buffer (to retrieve color attachment contents)
403     const VkDeviceSize colorBufferSizeBytes =
404         tcu::getPixelSize(mapVkFormat(colorFormat)) * m_renderSize.x() * m_renderSize.y();
405     const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
406     const UniquePtr<Allocation> colorBufferAlloc(
407         bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
408 
409     // Pipeline
410     const Unique<VkShaderModule> vertexModule(
411         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
412     const Unique<VkShaderModule> fragmentModule(
413         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
414     const Unique<VkRenderPass> renderPass(
415         makeRenderPass(vk, device, colorFormat, (depthTestsEnabled || stencilTestsEnabled), testFormat));
416     const Unique<VkFramebuffer> framebuffer(makeFramebuffer(
417         vk, device, *renderPass, numUsedAttachmentImages, attachmentImages.data(), m_renderSize.x(), m_renderSize.y()));
418     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, DE_NULL));
419     const Unique<VkPipeline> pipeline(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule,
420                                                            *fragmentModule, m_renderSize, m_scissorTestEnabled,
421                                                            depthTestsEnabled, stencilTestsEnabled, false));
422 
423     const Unique<VkPipeline> pipelineStencilWrite(
424         makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, m_renderSize,
425                              m_scissorTestEnabled, false, stencilTestsEnabled, true));
426 
427     // Command buffer
428     const Unique<VkCommandPool> cmdPool(
429         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
430     const Unique<VkCommandBuffer> cmdBuffer(
431         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
432 
433     {
434         const tcu::Vec4 clearColor            = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
435         const float clearDepth                = 0.5f;
436         const uint32_t clearStencil           = 1u;
437         const VkDeviceSize vertexBufferOffset = 0ull;
438 
439         const VkRect2D renderArea = {
440             makeOffset2D(0, 0),
441             makeExtent2D(m_renderSize.x(), m_renderSize.y()),
442         };
443 
444         beginCommandBuffer(vk, *cmdBuffer);
445 
446         vk.cmdResetQueryPool(*cmdBuffer, queryPool, 0, queryCount);
447 
448         // Will clear the attachments with specified depth and stencil values.
449         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor, clearDepth, clearStencil);
450 
451         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
452 
453         // Mask half of the attachment image with value that will pass the stencil test.
454         if (m_depthClearTestEnabled)
455             commandClearDepthAttachment(vk, *cmdBuffer, makeOffset2D(0, m_renderSize.y() / 2),
456                                         makeExtent2D(m_renderSize.x(), m_renderSize.y() / 2), 1u);
457 
458         // Mask half of the attachment image with value that will pass the stencil test.
459         if (m_stencilClearTestEnabled)
460             commandClearStencilAttachment(vk, *cmdBuffer, makeOffset2D(m_renderSize.x() / 2, 0),
461                                           makeExtent2D(m_renderSize.x() / 2, m_renderSize.y()), 0u);
462 
463         if (m_depthWriteTestEnabled)
464         {
465             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &dOccluderVertexBuffer.get(), &vertexBufferOffset);
466             vk.cmdDraw(*cmdBuffer, numDepthOccVertices, 1u, 0u, 0u);
467         }
468 
469         if (m_stencilWriteTestEnabled)
470         {
471             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineStencilWrite);
472             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &sOccluderVertexBuffer.get(), &vertexBufferOffset);
473             vk.cmdDraw(*cmdBuffer, numStencilOccVertices, 1u, 0u, 0u);
474             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
475         }
476 
477         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
478 
479         if (m_preciseBitEnabled)
480         {
481             vk.cmdBeginQuery(cmdBuffer.get(), queryPool, 0, VK_QUERY_CONTROL_PRECISE_BIT);
482         }
483         else
484         {
485             vk.cmdBeginQuery(cmdBuffer.get(), queryPool, 0, DE_NULL);
486         }
487 
488         vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
489         vk.cmdEndQuery(cmdBuffer.get(), queryPool, 0);
490 
491         endRenderPass(vk, *cmdBuffer);
492 
493         copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, m_renderSize,
494                           VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
495 
496         endCommandBuffer(vk, *cmdBuffer);
497         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
498     }
499 
500     // Check results
501     {
502         uint64_t expResult = 0;
503 
504         if (m_preciseBitEnabled)
505         {
506             const uint64_t imageSize = m_scissorTestEnabled ?
507                                            uint64_t(m_renderSize.x()) * uint64_t(m_renderSize.y()) / 4u :
508                                            uint64_t(m_renderSize.x()) * uint64_t(m_renderSize.y());
509 
510             const uint64_t renderHeight =
511                 m_scissorTestEnabled ? uint64_t(m_renderSize.y() / 2u) : uint64_t(m_renderSize.y());
512 
513             const uint64_t occluderWriteSize = uint64_t(m_renderSize.x()) * uint64_t(m_renderSize.y()) / 64u;
514 
515             if (m_depthClearTestEnabled || m_stencilClearTestEnabled)
516             {
517                 if (m_depthClearTestEnabled && m_stencilClearTestEnabled)
518                 {
519                     expResult = imageSize / 4;
520                 }
521 
522                 if (!m_depthClearTestEnabled && m_stencilClearTestEnabled)
523                 {
524                     expResult = imageSize / 2;
525                 }
526 
527                 if (m_depthClearTestEnabled && !m_stencilClearTestEnabled)
528                 {
529                     expResult = imageSize / 2 - imageSize / 8 - renderHeight / 4;
530                 }
531             }
532             else if (m_depthWriteTestEnabled)
533             {
534                 expResult = imageSize / 2 - renderHeight / 2;
535             }
536             else
537             {
538                 expResult = imageSize;
539             }
540 
541             if (m_depthWriteTestEnabled)
542             {
543                 expResult -= occluderWriteSize;
544 
545                 if (m_stencilClearTestEnabled && !m_depthClearTestEnabled)
546                 {
547                     expResult -= (imageSize / 8 + renderHeight / 4);
548                 }
549             }
550 
551             if (m_stencilWriteTestEnabled)
552             {
553                 expResult -= occluderWriteSize;
554             }
555         }
556 
557         VK_CHECK(vk.getQueryPoolResults(device, queryPool, 0u, queryCount, queryCount * sizeof(VkDeviceSize),
558                                         sampleCounts.data(), sizeof(VkDeviceSize),
559                                         VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT));
560 
561         // Log test results
562         {
563             tcu::TestLog &log = m_context.getTestContext().getLog();
564             log << tcu::TestLog::Message << "Passed Samples : " << de::toString(sampleCounts[0]) << " / " << expResult
565                 << tcu::TestLog::EndMessage;
566         }
567 
568 #ifndef CTS_USES_VULKANSC
569         vk.destroyQueryPool(device, queryPool, nullptr);
570 #endif // CTS_USES_VULKANSC
571 
572         if ((m_preciseBitEnabled && sampleCounts[0] == expResult) || (!m_preciseBitEnabled && sampleCounts[0] > 0))
573         {
574             return tcu::TestStatus::pass("Success");
575         }
576         else
577         {
578 
579             invalidateAlloc(vk, device, *colorBufferAlloc);
580 
581             const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), m_renderSize.x(),
582                                                                m_renderSize.y(), 1, colorBufferAlloc->getHostPtr());
583             tcu::TestLog &log = m_context.getTestContext().getLog();
584 
585             log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
586 
587             return tcu::TestStatus::fail("Failure");
588         }
589     }
590 }
591 
592 class OcclusionQueryTest : public TestCase
593 {
594 public:
595     OcclusionQueryTest(tcu::TestContext &testCtx, const std::string name, const uint32_t flags, const int renderWidth,
596                        const int renderHeight);
597 
598     void initPrograms(SourceCollections &programCollection) const;
599     TestInstance *createInstance(Context &context) const;
600     virtual void checkSupport(Context &context) const;
601 
602 private:
603     const bool m_preciseBitEnabled;
604     const bool m_scissorTestEnabled;
605     const bool m_depthClearTestEnabled;
606     const bool m_stencilClearTestEnabled;
607     const bool m_depthWriteTestEnabled;
608     const bool m_stencilWriteTestEnabled;
609     const int m_renderWidth;
610     const int m_renderHeight;
611 };
612 
OcclusionQueryTest(tcu::TestContext & testCtx,const std::string name,const uint32_t flags,const int renderWidth,const int renderHeight)613 OcclusionQueryTest::OcclusionQueryTest(tcu::TestContext &testCtx, const std::string name, const uint32_t flags,
614                                        const int renderWidth, const int renderHeight)
615     : TestCase(testCtx, name)
616     , m_preciseBitEnabled(flags & TEST_PRECISE_BIT)
617     , m_scissorTestEnabled(flags & TEST_SCISSOR)
618     , m_depthClearTestEnabled(flags & TEST_DEPTH_CLEAR || flags & TEST_ALL)
619     , m_stencilClearTestEnabled(flags & TEST_STENCIL_CLEAR || flags & TEST_ALL)
620     , m_depthWriteTestEnabled(flags & TEST_DEPTH_WRITE || flags & TEST_ALL)
621     , m_stencilWriteTestEnabled(flags & TEST_STENCIL_WRITE || flags & TEST_ALL)
622     , m_renderWidth(renderWidth)
623     , m_renderHeight(renderHeight)
624 {
625 }
626 
initPrograms(SourceCollections & programCollection) const627 void OcclusionQueryTest::initPrograms(SourceCollections &programCollection) const
628 {
629     // Vertex
630     {
631         std::ostringstream src;
632 
633         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
634             << "\n"
635             << "layout(location = 0) in highp vec4 position;\n"
636             << "\n"
637             << "out gl_PerVertex\n"
638             << "{\n"
639             << "   vec4 gl_Position;\n"
640             << "};\n"
641             << "\n"
642             << "void main (void)\n"
643             << "{\n"
644             << "    gl_Position = position;\n"
645             << "}\n";
646 
647         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
648     }
649 
650     // Fragment
651     {
652         std::ostringstream src;
653 
654         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
655             << "\n"
656             << "layout(location = 0) out highp vec4 fragColor;\n"
657             << "\n"
658             << "void main (void)\n"
659             << "{\n"
660             << "    fragColor = vec4(gl_FragCoord.x / " << m_renderWidth << ", gl_FragCoord.y / " << m_renderHeight
661             << ", 0.0, 1.0); \n"
662             << "}\n";
663 
664         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
665     }
666 }
667 
createInstance(Context & context) const668 TestInstance *OcclusionQueryTest::createInstance(Context &context) const
669 {
670     return new OcclusionQueryTestInstance(context, tcu::IVec2(m_renderWidth, m_renderHeight), m_preciseBitEnabled,
671                                           m_scissorTestEnabled, m_depthClearTestEnabled, m_stencilClearTestEnabled,
672                                           m_depthWriteTestEnabled, m_stencilWriteTestEnabled);
673 }
674 
checkSupport(Context & context) const675 void OcclusionQueryTest::checkSupport(Context &context) const
676 {
677     const InstanceInterface &vki      = context.getInstanceInterface();
678     const VkPhysicalDevice physDevice = context.getPhysicalDevice();
679     VkImageFormatProperties formatProperties;
680 
681     bool depthTestsEnabled   = (m_depthClearTestEnabled || m_depthWriteTestEnabled);
682     bool stencilTestsEnabled = (m_stencilClearTestEnabled || m_stencilWriteTestEnabled);
683 
684     const VkFormat testFormat =
685         (stencilTestsEnabled && depthTestsEnabled ? pickSupportedDepthStencilFormat(vki, physDevice) :
686          stencilTestsEnabled                      ? VK_FORMAT_S8_UINT :
687                                                     VK_FORMAT_D16_UNORM);
688 
689     if (m_preciseBitEnabled)
690     {
691         vk::VkQueryControlFlags queryControlFlags = {VK_QUERY_CONTROL_PRECISE_BIT};
692 
693         if (queryControlFlags && vk::VK_QUERY_CONTROL_PRECISE_BIT != context.getDeviceFeatures().occlusionQueryPrecise)
694             TCU_THROW(NotSupportedError, "Precise occlusion queries are not supported");
695     }
696 
697     vki.getPhysicalDeviceImageFormatProperties(
698         physDevice, testFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
699         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u, &formatProperties);
700     if (formatProperties.sampleCounts == 0 || testFormat == VK_FORMAT_UNDEFINED)
701         TCU_THROW(NotSupportedError, de::toString(testFormat) + " not supported");
702 }
703 
704 } // namespace
705 
createOcclusionQueryTests(tcu::TestContext & testCtx)706 tcu::TestCaseGroup *createOcclusionQueryTests(tcu::TestContext &testCtx)
707 {
708     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "occlusion_query"));
709 
710     {
711         static const struct
712         {
713             std::string caseName;
714             uint32_t flags;
715         } cases[] = {
716             {"_test_scissors_clear_color", TEST_SCISSOR},
717             {"_test_scissors_depth_clear", TEST_SCISSOR | TEST_DEPTH_CLEAR},
718             {"_test_scissors_depth_write", TEST_SCISSOR | TEST_DEPTH_WRITE},
719             {"_test_scissors_depth_clear_depth_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE},
720             {"_test_scissors_stencil_clear", TEST_SCISSOR | TEST_STENCIL_CLEAR},
721             {"_test_scissors_stencil_write", TEST_SCISSOR | TEST_STENCIL_WRITE},
722             {"_test_scissors_stencil_clear_stencil_write", TEST_SCISSOR | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE},
723             {"_test_scissors_depth_clear_stencil_clear", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR},
724             {"_test_scissors_depth_write_stencil_clear", TEST_SCISSOR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR},
725             {"_test_scissors_depth_clear_stencil_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_STENCIL_WRITE},
726             {"_test_scissors_depth_write_stencil_write", TEST_SCISSOR | TEST_DEPTH_WRITE | TEST_STENCIL_WRITE},
727             {"_test_scissors_depth_clear_stencil_clear_depth_write",
728              TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR},
729             {"_test_scissors_depth_clear_stencil_clear_stencil_write",
730              TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE},
731             {"_test_scissors_depth_clear_depth_write_stencil_write",
732              TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_WRITE},
733             {"_test_scissors_depth_write_stencil_clear_stencil_write",
734              TEST_SCISSOR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE},
735             {"_test_scissors_test_all", TEST_SCISSOR | TEST_ALL},
736             {"_test_clear_color", TEST_NO_FLAGS},
737             {"_test_depth_clear", TEST_DEPTH_CLEAR},
738             {"_test_depth_write", TEST_DEPTH_WRITE},
739             {"_test_depth_clear_depth_write", TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE},
740             {"_test_stencil_clear", TEST_STENCIL_CLEAR},
741             {"_test_stencil_write", TEST_STENCIL_WRITE},
742             {"_test_stencil_clear_stencil_write", TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE},
743             {"_test_depth_clear_stencil_clear", TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR},
744             {"_test_depth_write_stencil_clear", TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR},
745             {"_test_depth_clear_stencil_write", TEST_DEPTH_CLEAR | TEST_STENCIL_WRITE},
746             {"_test_depth_write_stencil_write", TEST_DEPTH_WRITE | TEST_STENCIL_WRITE},
747             {"_test_depth_clear_stencil_clear_depth_write", TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR},
748             {"_test_depth_clear_stencil_clear_stencil_write",
749              TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE},
750             {"_test_depth_clear_depth_write_stencil_write", TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_WRITE},
751             {"_test_depth_write_stencil_clear_stencil_write",
752              TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE},
753             {"_test_test_all", TEST_ALL}};
754 
755         // Conservative tests
756         for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
757             testGroup->addChild(
758                 new OcclusionQueryTest(testCtx, "conservative" + cases[i].caseName, cases[i].flags, 32, 32));
759 
760         // Precise tests
761         for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
762             testGroup->addChild(new OcclusionQueryTest(testCtx, "precise" + cases[i].caseName,
763                                                        cases[i].flags | TEST_PRECISE_BIT, 32, 32));
764     }
765 
766     return testGroup.release();
767 }
768 
769 } // namespace FragmentOperations
770 } // namespace vkt
771