blob: 8795cecd55b064752126a047920ac3a55554d496 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 The Khronos Group Inc.
* Copyright (c) 2021 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Fragment Operations Occlusion Query Tests
*//*--------------------------------------------------------------------*/
#include "vktFragmentOperationsOcclusionQueryTests.hpp"
#include "vktFragmentOperationsMakeUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkDefs.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkStrUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTextureUtil.hpp"
#include "deUniquePtr.hpp"
#include "deStringUtil.hpp"
#include "deMath.h"
#include <string>
namespace vkt
{
namespace FragmentOperations
{
namespace
{
using namespace vk;
using de::UniquePtr;
//! Basic 2D image.
inline VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage)
{
const VkImageCreateInfo imageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkImageCreateFlags)0, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
format, // VkFormat format;
makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
usage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
0u, // deUint32 queueFamilyIndexCount;
DE_NULL, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
return imageParams;
}
Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk,
const VkDevice device,
const VkFormat colorFormat,
const bool useDepthStencilAttachment,
const VkFormat depthStencilFormat)
{
return makeRenderPass(vk, device, colorFormat, useDepthStencilAttachment ? depthStencilFormat : VK_FORMAT_UNDEFINED);
}
Move<VkPipeline> 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)
{
const std::vector<VkViewport> viewports (1, makeViewport(renderSize));
const std::vector<VkRect2D> scissors (1, enableScissorTest
? makeRect2D(renderSize.x() / 4, renderSize.y() / 4, renderSize.x() / 4 * 2, renderSize.y() / 4 * 2)
: makeRect2D(renderSize));
const VkStencilOpState stencilOpState = makeStencilOpState(VK_STENCIL_OP_KEEP, // stencil fail
enableStencilWrite ? VK_STENCIL_OP_REPLACE : VK_STENCIL_OP_KEEP, // depth & stencil pass
VK_STENCIL_OP_KEEP, // depth only fail
enableStencilWrite ? VK_COMPARE_OP_ALWAYS : VK_COMPARE_OP_EQUAL, // compare op
0xff, // compare mask
0xff, // write mask
enableStencilWrite ? 0u : 1u); // reference
VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineDepthStencilStateCreateFlags flags
enableDepthTest ? VK_TRUE : VK_FALSE, // VkBool32 depthTestEnable
enableDepthTest ? VK_TRUE : VK_FALSE, // VkBool32 depthWriteEnable
VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp
VK_FALSE, // VkBool32 depthBoundsTestEnable
enableStencilTest ? VK_TRUE : VK_FALSE, // VkBool32 stencilTestEnable
enableStencilTest ? stencilOpState : VkStencilOpState{}, // VkStencilOpState front
enableStencilTest ? stencilOpState : VkStencilOpState{}, // VkStencilOpState back
0.0f, // float minDepthBounds
1.0f // float maxDepthBounds
};
return vk::makeGraphicsPipeline(vk, // const DeviceInterface& vk
device, // const VkDevice device
pipelineLayout, // const VkPipelineLayout pipelineLayout
vertexModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlModule
DE_NULL, // const VkShaderModule tessellationEvalModule
DE_NULL, // const VkShaderModule geometryShaderModule
fragmentModule, // const VkShaderModule fragmentShaderModule
renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
DE_NULL, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
&depthStencilStateCreateInfo); // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
}
void commandClearDepthAttachment (const DeviceInterface& vk,
const VkCommandBuffer commandBuffer,
const VkOffset2D& offset,
const VkExtent2D& extent,
const deUint32 clearValue)
{
const VkClearAttachment depthAttachment =
{
VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags aspectMask;
0u, // uint32_t colorAttachment;
makeClearValueDepthStencil(0.0f, clearValue), // VkClearValue clearValue;
};
const VkClearRect rect =
{
{ offset, extent }, // VkRect2D rect;
0u, // uint32_t baseArrayLayer;
1u, // uint32_t layerCount;
};
vk.cmdClearAttachments(commandBuffer, 1u, &depthAttachment, 1u, &rect);
}
void commandClearStencilAttachment (const DeviceInterface& vk,
const VkCommandBuffer commandBuffer,
const VkOffset2D& offset,
const VkExtent2D& extent,
const deUint32 clearValue)
{
const VkClearAttachment stencilAttachment =
{
VK_IMAGE_ASPECT_STENCIL_BIT, // VkImageAspectFlags aspectMask;
0u, // uint32_t colorAttachment;
makeClearValueDepthStencil(0.0f, clearValue), // VkClearValue clearValue;
};
const VkClearRect rect =
{
{ offset, extent }, // VkRect2D rect;
0u, // uint32_t baseArrayLayer;
1u, // uint32_t layerCount;
};
vk.cmdClearAttachments(commandBuffer, 1u, &stencilAttachment, 1u, &rect);
}
VkImageAspectFlags getImageAspectFlags (const VkFormat format)
{
const tcu::TextureFormat tcuFormat = mapVkFormat(format);
if (tcuFormat.order == tcu::TextureFormat::DS) return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
else if (tcuFormat.order == tcu::TextureFormat::D) return VK_IMAGE_ASPECT_DEPTH_BIT;
else if (tcuFormat.order == tcu::TextureFormat::S) return VK_IMAGE_ASPECT_STENCIL_BIT;
DE_ASSERT(false);
return 0u;
}
bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, const VkPhysicalDevice device, const VkFormat format)
{
VkFormatProperties formatProps;
instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
}
VkFormat pickSupportedDepthStencilFormat (const InstanceInterface& instanceInterface,
const VkPhysicalDevice device)
{
static const VkFormat dsFormats[] =
{
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT,
};
for (deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(dsFormats); ++i)
if (isSupportedDepthStencilFormat(instanceInterface, device, dsFormats[i]))
return dsFormats[i];
return VK_FORMAT_UNDEFINED;
}
enum Flags
{
TEST_NO_FLAGS = 0,
TEST_SCISSOR = 1u << 0,
TEST_DEPTH_WRITE = 1u << 1,
TEST_DEPTH_CLEAR = 1u << 2,
TEST_STENCIL_WRITE = 1u << 3,
TEST_STENCIL_CLEAR = 1u << 4,
TEST_ALL = 1u << 5,
TEST_PRECISE_BIT = 1u << 6
};
class OcclusionQueryTestInstance : public TestInstance
{
public:
OcclusionQueryTestInstance (Context& context,
const tcu::IVec2 renderSize,
const bool preciseBitEnabled,
const bool scissorTestEnabled,
const bool depthTestEnabled,
const bool stencilTestEnabled,
const bool depthWriteEnabled,
const bool stencilWriteEnabled);
tcu::TestStatus iterate (void);
private:
const tcu::IVec2 m_renderSize;
const bool m_preciseBitEnabled;
const bool m_scissorTestEnabled;
const bool m_depthClearTestEnabled;
const bool m_stencilClearTestEnabled;
const bool m_depthWriteTestEnabled;
const bool m_stencilWriteTestEnabled;
};
OcclusionQueryTestInstance::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)
: TestInstance (context)
, m_renderSize (renderSize)
, m_preciseBitEnabled (preciseBitEnabled)
, m_scissorTestEnabled (scissorTestEnabled)
, m_depthClearTestEnabled (depthClearTestEnabled)
, m_stencilClearTestEnabled (stencilClearTestEnabled)
, m_depthWriteTestEnabled (depthWriteTestEnabled)
, m_stencilWriteTestEnabled (stencilWriteTestEnabled)
{
}
tcu::TestStatus OcclusionQueryTestInstance::iterate (void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const InstanceInterface& vki = m_context.getInstanceInterface();
const VkDevice device = m_context.getDevice();
const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
Allocator& allocator = m_context.getDefaultAllocator();
VkQueryPool queryPool;
const deUint32 queryCount = 1u;
std::vector<VkDeviceSize> sampleCounts (queryCount);
// Create a query pool for storing the occlusion query result
{
VkQueryPoolCreateInfo queryPoolInfo
{
VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkQueryPoolCreateFlags)0, // VkQueryPoolCreateFlags flags;
VK_QUERY_TYPE_OCCLUSION, // VkQueryType queryType;
queryCount, // uint32_t queryCount;
0u, // VkQueryPipelineStatisticFlags pipelineStatistics;
};
VK_CHECK(vk.createQueryPool(device, &queryPoolInfo, NULL, &queryPool));
}
// Color attachment
const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
const VkImageSubresourceRange colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
const Unique<VkImage> colorImage (makeImage(vk, device, makeImageCreateInfo(m_renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
const UniquePtr<Allocation> colorImageAlloc (bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
const Unique<VkImageView> colorImageView (makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
std::vector<VkImageView> attachmentImages = { *colorImageView };
bool depthTestsEnabled = (m_depthClearTestEnabled || m_depthWriteTestEnabled);
bool stencilTestsEnabled = (m_stencilClearTestEnabled || m_stencilWriteTestEnabled);
const VkFormat testFormat = (depthTestsEnabled && stencilTestsEnabled
? pickSupportedDepthStencilFormat(vki, physDevice)
: !depthTestsEnabled && stencilTestsEnabled
? VK_FORMAT_S8_UINT
: VK_FORMAT_D16_UNORM);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Using depth/stencil format " << getFormatName(testFormat) << tcu::TestLog::EndMessage;
const VkImageSubresourceRange testSubresourceRange = makeImageSubresourceRange(getImageAspectFlags(testFormat), 0u, 1u, 0u, 1u);
const Unique<VkImage> testImage(makeImage(vk, device, makeImageCreateInfo(m_renderSize, testFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)));
const UniquePtr<Allocation> testImageAlloc(bindImage(vk, device, allocator, *testImage, MemoryRequirement::Any));
const Unique<VkImageView> testImageView(makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, testFormat, testSubresourceRange));
if (depthTestsEnabled || stencilTestsEnabled)
attachmentImages.push_back(*testImageView);
const deUint32 numUsedAttachmentImages = deUint32(attachmentImages.size());
// Depth occluder vertex buffer
const deUint32 numDepthOccVertices = 6;
const VkDeviceSize dOccVertBuffSizeBytes = 256;
const Unique<VkBuffer> dOccluderVertexBuffer (makeBuffer(vk, device, dOccVertBuffSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
const UniquePtr<Allocation> dOccVertexBufferAlloc (bindBuffer(vk, device, allocator, *dOccluderVertexBuffer, MemoryRequirement::HostVisible));
{
tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(dOccVertexBufferAlloc->getHostPtr());
pVertices[0] = tcu::Vec4(-0.25f, -0.50f , 0.0f, 1.0f); // Top Right
pVertices[1] = tcu::Vec4(-0.50f, -0.50f , 0.0f, 1.0f); // Top Left
pVertices[2] = tcu::Vec4(-0.25f, -0.25f, 0.0f, 1.0f); // Bottom Right
pVertices[3] = tcu::Vec4(-0.50f, -0.25f, 0.0f, 1.0f); // Bottom Left
pVertices[4] = tcu::Vec4(-0.25f, -0.25f, 0.0f, 1.0f); // Bottom Right
pVertices[5] = tcu::Vec4(-0.50f, -0.50f, 0.0f, 1.0f); // Top Left
flushAlloc(vk, device, *dOccVertexBufferAlloc);
}
// Stencil occluder vertex buffer
const deUint32 numStencilOccVertices = 6;
const VkDeviceSize sOccVertBuffSizeBytes = 256;
const Unique<VkBuffer> sOccluderVertexBuffer (makeBuffer(vk, device, sOccVertBuffSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
const UniquePtr<Allocation> sOccVertexBufferAlloc (bindBuffer(vk, device, allocator, *sOccluderVertexBuffer, MemoryRequirement::HostVisible));
{
tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(sOccVertexBufferAlloc->getHostPtr());
pVertices[0] = tcu::Vec4(-0.25f, -0.25f, 0.0f, 1.0f); // Top Right
pVertices[1] = tcu::Vec4(-0.50f, -0.25f, 0.0f, 1.0f); // Top Left
pVertices[2] = tcu::Vec4(-0.25f, 0.00f, 0.0f, 1.0f); // Bottom Right
pVertices[3] = tcu::Vec4(-0.50f, 0.00f, 0.0f, 1.0f); // Bottom Left
pVertices[4] = tcu::Vec4(-0.25f, 0.00f, 0.0f, 1.0f); // Bottom Right
pVertices[5] = tcu::Vec4(-0.50f, -0.25f, 0.0f, 1.0f); // Top Left
flushAlloc(vk, device, *sOccVertexBufferAlloc);
}
// Main vertex buffer
const deUint32 numVertices = 6;
const VkDeviceSize vertexBufferSizeBytes = 256;
const Unique<VkBuffer> vertexBuffer (makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
const UniquePtr<Allocation> vertexBufferAlloc (bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
{
tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(vertexBufferAlloc->getHostPtr());
pVertices[0] = tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f);
pVertices[1] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
pVertices[2] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f);
pVertices[3] = tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f);
pVertices[4] = tcu::Vec4( 1.0f, 1.0f, 1.0f, 1.0f);
pVertices[5] = tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f);
flushAlloc(vk, device, *vertexBufferAlloc);
}
// Result buffer
const VkDeviceSize resultBufferSizeBytes = sizeof(deUint32);
const Unique<VkBuffer> resultBuffer (makeBuffer(vk, device, resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
const UniquePtr<Allocation> resultBufferAlloc (bindBuffer(vk, device, allocator, *resultBuffer, MemoryRequirement::HostVisible));
{
deUint32* const pData = static_cast<deUint32*>(resultBufferAlloc->getHostPtr());
*pData = 0;
flushAlloc(vk, device, *resultBufferAlloc);
}
// Render result buffer (to retrieve color attachment contents)
const VkDeviceSize colorBufferSizeBytes = tcu::getPixelSize(mapVkFormat(colorFormat)) * m_renderSize.x() * m_renderSize.y();
const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
// Pipeline
const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
const Unique<VkRenderPass> renderPass (makeRenderPass(vk, device, colorFormat, (depthTestsEnabled || stencilTestsEnabled), testFormat));
const Unique<VkFramebuffer> framebuffer (makeFramebuffer(vk, device, *renderPass, numUsedAttachmentImages, attachmentImages.data(), m_renderSize.x(), m_renderSize.y()));
const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, DE_NULL));
const Unique<VkPipeline> pipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, m_renderSize,
m_scissorTestEnabled, depthTestsEnabled, stencilTestsEnabled, false));
const Unique<VkPipeline> pipelineStencilWrite (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, m_renderSize,
m_scissorTestEnabled, false, stencilTestsEnabled, true));
// Command buffer
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
{
const tcu::Vec4 clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
const float clearDepth = 0.5f;
const deUint32 clearStencil = 1u;
const VkDeviceSize vertexBufferOffset = 0ull;
const VkRect2D renderArea =
{
makeOffset2D(0, 0),
makeExtent2D(m_renderSize.x(), m_renderSize.y()),
};
beginCommandBuffer(vk, *cmdBuffer);
vk.cmdResetQueryPool(*cmdBuffer, queryPool, 0, queryCount);
// Will clear the attachments with specified depth and stencil values.
beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor, clearDepth, clearStencil);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
// Mask half of the attachment image with value that will pass the stencil test.
if (m_depthClearTestEnabled)
commandClearDepthAttachment(vk, *cmdBuffer, makeOffset2D(0, m_renderSize.y() / 2), makeExtent2D(m_renderSize.x(), m_renderSize.y() / 2), 1u);
// Mask half of the attachment image with value that will pass the stencil test.
if (m_stencilClearTestEnabled)
commandClearStencilAttachment(vk, *cmdBuffer, makeOffset2D(m_renderSize.x() / 2, 0), makeExtent2D(m_renderSize.x() / 2, m_renderSize.y()), 0u);
if (m_depthWriteTestEnabled)
{
vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &dOccluderVertexBuffer.get(), &vertexBufferOffset);
vk.cmdDraw(*cmdBuffer, numDepthOccVertices, 1u, 0u, 0u);
}
if (m_stencilWriteTestEnabled)
{
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineStencilWrite);
vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &sOccluderVertexBuffer.get(), &vertexBufferOffset);
vk.cmdDraw(*cmdBuffer, numStencilOccVertices, 1u, 0u, 0u);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
}
vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
if (m_preciseBitEnabled)
{
vk.cmdBeginQuery(cmdBuffer.get(), queryPool, 0, VK_QUERY_CONTROL_PRECISE_BIT);
}
else
{
vk.cmdBeginQuery(cmdBuffer.get(), queryPool, 0, DE_NULL);
}
vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
vk.cmdEndQuery(cmdBuffer.get(), queryPool, 0);
endRenderPass(vk, *cmdBuffer);
copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, m_renderSize, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
endCommandBuffer(vk, *cmdBuffer);
submitCommandsAndWait(vk, device, queue, *cmdBuffer);
}
// Check results
{
deUint64 expResult = 0;
if (m_preciseBitEnabled)
{
const deUint64 imageSize = m_scissorTestEnabled ? deUint64(m_renderSize.x()) * deUint64(m_renderSize.y()) / 4u
: deUint64(m_renderSize.x()) * deUint64(m_renderSize.y());
const deUint64 renderHeight = m_scissorTestEnabled ? deUint64(m_renderSize.y() / 2u)
: deUint64(m_renderSize.y());
const deUint64 occluderWriteSize = deUint64(m_renderSize.x()) * deUint64(m_renderSize.y()) / 64u;
if (m_depthClearTestEnabled || m_stencilClearTestEnabled)
{
if (m_depthClearTestEnabled && m_stencilClearTestEnabled)
{
expResult = imageSize / 4;
}
if (!m_depthClearTestEnabled && m_stencilClearTestEnabled)
{
expResult = imageSize / 2;
}
if (m_depthClearTestEnabled && !m_stencilClearTestEnabled)
{
expResult = imageSize / 2 - imageSize / 8 - renderHeight / 4;
}
}
else if (m_depthWriteTestEnabled)
{
expResult = imageSize / 2 - renderHeight / 2;
}
else
{
expResult = imageSize;
}
if (m_depthWriteTestEnabled)
{
expResult -= occluderWriteSize;
if (m_stencilClearTestEnabled && !m_depthClearTestEnabled)
{
expResult -= (imageSize / 8 + renderHeight / 4);
}
}
if (m_stencilWriteTestEnabled)
{
expResult -= occluderWriteSize;
}
}
VK_CHECK(vk.getQueryPoolResults(device, queryPool, 0u, queryCount, queryCount * sizeof(VkDeviceSize), sampleCounts.data(), sizeof(VkDeviceSize), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT));
// Log test results
{
tcu::TestLog& log = m_context.getTestContext().getLog();
log << tcu::TestLog::Message << "Passed Samples : " << de::toString(sampleCounts[0]) << " / " << expResult << tcu::TestLog::EndMessage;
}
vk.destroyQueryPool(device, queryPool, nullptr);
if ((m_preciseBitEnabled && sampleCounts[0] == expResult) || (!m_preciseBitEnabled && sampleCounts[0] > 0))
{
return tcu::TestStatus::pass("Success");
}
else
{
invalidateAlloc(vk, device, *colorBufferAlloc);
const tcu::ConstPixelBufferAccess imagePixelAccess (mapVkFormat(colorFormat), m_renderSize.x(), m_renderSize.y(), 1, colorBufferAlloc->getHostPtr());
tcu::TestLog& log = m_context.getTestContext().getLog();
log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
return tcu::TestStatus::fail("Failure");
}
}
}
class OcclusionQueryTest : public TestCase
{
public:
OcclusionQueryTest (tcu::TestContext& testCtx,
const std::string name,
const deUint32 flags,
const int renderWidth,
const int renderHeight);
void initPrograms (SourceCollections& programCollection) const;
TestInstance* createInstance (Context& context) const;
virtual void checkSupport (Context& context) const;
private:
const bool m_preciseBitEnabled;
const bool m_scissorTestEnabled;
const bool m_depthClearTestEnabled;
const bool m_stencilClearTestEnabled;
const bool m_depthWriteTestEnabled;
const bool m_stencilWriteTestEnabled;
const int m_renderWidth;
const int m_renderHeight;
};
OcclusionQueryTest::OcclusionQueryTest (tcu::TestContext& testCtx, const std::string name, const deUint32 flags, const int renderWidth, const int renderHeight)
: TestCase (testCtx, name, "")
, m_preciseBitEnabled (flags & TEST_PRECISE_BIT)
, m_scissorTestEnabled (flags & TEST_SCISSOR)
, m_depthClearTestEnabled (flags & TEST_DEPTH_CLEAR || flags & TEST_ALL)
, m_stencilClearTestEnabled (flags & TEST_STENCIL_CLEAR || flags & TEST_ALL)
, m_depthWriteTestEnabled (flags & TEST_DEPTH_WRITE || flags & TEST_ALL)
, m_stencilWriteTestEnabled (flags & TEST_STENCIL_WRITE || flags & TEST_ALL)
, m_renderWidth (renderWidth)
, m_renderHeight (renderHeight)
{
}
void OcclusionQueryTest::initPrograms (SourceCollections& programCollection) const
{
// Vertex
{
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(location = 0) in highp vec4 position;\n"
<< "\n"
<< "out gl_PerVertex\n"
<< "{\n"
<< " vec4 gl_Position;\n"
<< "};\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< " gl_Position = position;\n"
<< "}\n";
programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
}
// Fragment
{
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(location = 0) out highp vec4 fragColor;\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< " fragColor = vec4(gl_FragCoord.x / " << m_renderWidth << ", gl_FragCoord.y / " << m_renderHeight << ", 0.0, 1.0); \n"
<< "}\n";
programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
}
}
TestInstance* OcclusionQueryTest::createInstance (Context& context) const
{
return new OcclusionQueryTestInstance (context, tcu::IVec2(m_renderWidth, m_renderHeight),
m_preciseBitEnabled, m_scissorTestEnabled,
m_depthClearTestEnabled, m_stencilClearTestEnabled,
m_depthWriteTestEnabled, m_stencilWriteTestEnabled);
}
void OcclusionQueryTest::checkSupport (Context& context) const
{
const InstanceInterface& vki = context.getInstanceInterface();
const VkPhysicalDevice physDevice = context.getPhysicalDevice();
VkImageFormatProperties formatProperties;
bool depthTestsEnabled = (m_depthClearTestEnabled || m_depthWriteTestEnabled);
bool stencilTestsEnabled = (m_stencilClearTestEnabled || m_stencilWriteTestEnabled);
const VkFormat testFormat = (stencilTestsEnabled && depthTestsEnabled
? pickSupportedDepthStencilFormat(vki, physDevice)
: stencilTestsEnabled
? VK_FORMAT_S8_UINT
: VK_FORMAT_D16_UNORM);
if (m_preciseBitEnabled)
{
vk::VkQueryControlFlags queryControlFlags = { VK_QUERY_CONTROL_PRECISE_BIT };
if (queryControlFlags && vk::VK_QUERY_CONTROL_PRECISE_BIT != context.getDeviceFeatures().occlusionQueryPrecise)
TCU_THROW(NotSupportedError, "Precise occlusion queries are not supported");
}
vki.getPhysicalDeviceImageFormatProperties(physDevice, testFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u, &formatProperties);
if (formatProperties.sampleCounts == 0 || testFormat == VK_FORMAT_UNDEFINED)
TCU_THROW(NotSupportedError, de::toString(testFormat) + " not supported");
}
} // anonymous ns
tcu::TestCaseGroup* createOcclusionQueryTests(tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "occlusion_query", "occlusion query test cases"));
{
static const struct
{
std::string caseName;
deUint32 flags;
} cases[] =
{
{ "_test_scissors_clear_color", TEST_SCISSOR },
{ "_test_scissors_depth_clear", TEST_SCISSOR | TEST_DEPTH_CLEAR },
{ "_test_scissors_depth_write", TEST_SCISSOR | TEST_DEPTH_WRITE },
{ "_test_scissors_depth_clear_depth_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE },
{ "_test_scissors_stencil_clear", TEST_SCISSOR | TEST_STENCIL_CLEAR },
{ "_test_scissors_stencil_write", TEST_SCISSOR | TEST_STENCIL_WRITE },
{ "_test_scissors_stencil_clear_stencil_write", TEST_SCISSOR | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE },
{ "_test_scissors_depth_clear_stencil_clear", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR },
{ "_test_scissors_depth_write_stencil_clear", TEST_SCISSOR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR },
{ "_test_scissors_depth_clear_stencil_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_STENCIL_WRITE },
{ "_test_scissors_depth_write_stencil_write", TEST_SCISSOR | TEST_DEPTH_WRITE | TEST_STENCIL_WRITE },
{ "_test_scissors_depth_clear_stencil_clear_depth_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR },
{ "_test_scissors_depth_clear_stencil_clear_stencil_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE },
{ "_test_scissors_depth_clear_depth_write_stencil_write", TEST_SCISSOR | TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_WRITE },
{ "_test_scissors_depth_write_stencil_clear_stencil_write", TEST_SCISSOR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE },
{ "_test_scissors_test_all", TEST_SCISSOR | TEST_ALL },
{ "_test_clear_color", TEST_NO_FLAGS },
{ "_test_depth_clear", TEST_DEPTH_CLEAR },
{ "_test_depth_write", TEST_DEPTH_WRITE },
{ "_test_depth_clear_depth_write", TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE },
{ "_test_stencil_clear", TEST_STENCIL_CLEAR },
{ "_test_stencil_write", TEST_STENCIL_WRITE },
{ "_test_stencil_clear_stencil_write", TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE },
{ "_test_depth_clear_stencil_clear", TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR },
{ "_test_depth_write_stencil_clear", TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR },
{ "_test_depth_clear_stencil_write", TEST_DEPTH_CLEAR | TEST_STENCIL_WRITE },
{ "_test_depth_write_stencil_write", TEST_DEPTH_WRITE | TEST_STENCIL_WRITE },
{ "_test_depth_clear_stencil_clear_depth_write", TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR },
{ "_test_depth_clear_stencil_clear_stencil_write", TEST_DEPTH_CLEAR | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE },
{ "_test_depth_clear_depth_write_stencil_write", TEST_DEPTH_CLEAR | TEST_DEPTH_WRITE | TEST_STENCIL_WRITE },
{ "_test_depth_write_stencil_clear_stencil_write", TEST_DEPTH_WRITE | TEST_STENCIL_CLEAR | TEST_STENCIL_WRITE },
{ "_test_test_all", TEST_ALL }
};
// Conservative tests
for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
testGroup->addChild(new OcclusionQueryTest(testCtx, "conservative" + cases[i].caseName, cases[i].flags, 32, 32));
// Precise tests
for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
testGroup->addChild(new OcclusionQueryTest(testCtx, "precise" + cases[i].caseName, cases[i].flags | TEST_PRECISE_BIT, 32, 32));
}
return testGroup.release();
}
} // FragmentOperations
} // vkt