| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2015 The Khronos Group Inc. |
| * Copyright (c) 2015 Samsung Electronics Co., Ltd. |
| * Copyright (c) 2016 The Android Open Source Project |
| * |
| * 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 Shader builtin variable tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktShaderRenderBuiltinVarTests.hpp" |
| |
| #include "tcuFloat.hpp" |
| #include "deUniquePtr.hpp" |
| #include "vkDefs.hpp" |
| #include "vktShaderRender.hpp" |
| #include "gluShaderUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuStringTemplate.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuTestLog.hpp" |
| #include "vktDrawUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| |
| #include "deMath.h" |
| #include "deRandom.hpp" |
| |
| #include <map> |
| |
| using namespace std; |
| using namespace tcu; |
| using namespace vk; |
| using namespace de; |
| |
| namespace vkt |
| { |
| using namespace drawutil; |
| |
| namespace sr |
| { |
| |
| namespace |
| { |
| |
| enum |
| { |
| FRONTFACE_RENDERWIDTH = 16, |
| FRONTFACE_RENDERHEIGHT = 16 |
| }; |
| |
| class FrontFacingVertexShader : public rr::VertexShader |
| { |
| public: |
| FrontFacingVertexShader (void) |
| : rr::VertexShader(1, 0) |
| { |
| m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0], |
| packets[packetNdx]->instanceNdx, |
| packets[packetNdx]->vertexNdx); |
| } |
| } |
| }; |
| |
| class FrontFacingFragmentShader : public rr::FragmentShader |
| { |
| public: |
| FrontFacingFragmentShader (void) |
| : rr::FragmentShader(0, 1) |
| { |
| m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void shadeFragments (rr::FragmentPacket* , const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| tcu::Vec4 color; |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx) |
| { |
| if (context.visibleFace == rr::FACETYPE_FRONT) |
| color = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f); |
| else |
| color = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color); |
| } |
| } |
| } |
| }; |
| |
| class BuiltinGlFrontFacingCaseInstance : public ShaderRenderCaseInstance |
| { |
| public: |
| BuiltinGlFrontFacingCaseInstance (Context& context, VkPrimitiveTopology topology); |
| |
| TestStatus iterate (void); |
| private: |
| const VkPrimitiveTopology m_topology; |
| }; |
| |
| BuiltinGlFrontFacingCaseInstance::BuiltinGlFrontFacingCaseInstance (Context& context, VkPrimitiveTopology topology) |
| : ShaderRenderCaseInstance (context) |
| , m_topology (topology) |
| { |
| } |
| |
| |
| TestStatus BuiltinGlFrontFacingCaseInstance::iterate (void) |
| { |
| TestLog& log = m_context.getTestContext().getLog(); |
| std::vector<Vec4> vertices; |
| std::vector<VulkanShader> shaders; |
| FrontFacingVertexShader vertexShader; |
| FrontFacingFragmentShader fragmentShader; |
| std::string testDesc; |
| |
| vertices.push_back(Vec4( -0.75f, -0.75f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 0.0f, -0.75f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( -0.37f, 0.75f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 0.37f, 0.75f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 0.75f, -0.75f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 0.0f, -0.75f, 0.0f, 1.0f)); |
| |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"))); |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"))); |
| |
| testDesc = "gl_FrontFacing " + getPrimitiveTopologyShortName(m_topology) + " "; |
| |
| DrawState drawState (m_topology, FRONTFACE_RENDERWIDTH, FRONTFACE_RENDERHEIGHT); |
| DrawCallData drawCallData (vertices); |
| VulkanProgram vulkanProgram (shaders); |
| |
| VulkanDrawContext dc(m_context, drawState, drawCallData, vulkanProgram); |
| dc.draw(); |
| |
| ReferenceDrawContext refDrawContext(drawState, drawCallData, vertexShader, fragmentShader); |
| refDrawContext.draw(); |
| |
| log << TestLog::Image( "reference", |
| "reference", |
| tcu::ConstPixelBufferAccess(tcu::TextureFormat( |
| refDrawContext.getColorPixels().getFormat()), |
| refDrawContext.getColorPixels().getWidth(), |
| refDrawContext.getColorPixels().getHeight(), |
| 1, |
| refDrawContext.getColorPixels().getDataPtr())); |
| |
| log << TestLog::Image( "result", |
| "result", |
| tcu::ConstPixelBufferAccess(tcu::TextureFormat( |
| dc.getColorPixels().getFormat()), |
| dc.getColorPixels().getWidth(), |
| dc.getColorPixels().getHeight(), |
| 1, |
| dc.getColorPixels().getDataPtr())); |
| |
| if (tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(), |
| "ComparisonResult", |
| "Image comparison result", |
| refDrawContext.getColorPixels(), |
| dc.getColorPixels(), |
| UVec4(0u), |
| IVec3(1,1,0), |
| false, |
| tcu::COMPARE_LOG_RESULT)) |
| { |
| testDesc += "passed"; |
| return tcu::TestStatus::pass(testDesc.c_str()); |
| } |
| else |
| { |
| testDesc += "failed"; |
| return tcu::TestStatus::fail(testDesc.c_str()); |
| } |
| } |
| |
| class BuiltinGlFrontFacingCase : public TestCase |
| { |
| public: |
| BuiltinGlFrontFacingCase (TestContext& testCtx, VkPrimitiveTopology topology, const char* name, const char* description); |
| virtual ~BuiltinGlFrontFacingCase (void); |
| |
| void initPrograms (SourceCollections& dst) const; |
| TestInstance* createInstance (Context& context) const; |
| |
| private: |
| BuiltinGlFrontFacingCase (const BuiltinGlFrontFacingCase&); // not allowed! |
| BuiltinGlFrontFacingCase& operator= (const BuiltinGlFrontFacingCase&); // not allowed! |
| |
| const VkPrimitiveTopology m_topology; |
| }; |
| |
| BuiltinGlFrontFacingCase::BuiltinGlFrontFacingCase (TestContext& testCtx, VkPrimitiveTopology topology, const char* name, const char* description) |
| : TestCase (testCtx, name, description) |
| , m_topology (topology) |
| { |
| } |
| |
| BuiltinGlFrontFacingCase::~BuiltinGlFrontFacingCase (void) |
| { |
| } |
| |
| void BuiltinGlFrontFacingCase::initPrograms (SourceCollections& programCollection) const |
| { |
| { |
| std::ostringstream vertexSource; |
| vertexSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" |
| << "\n" |
| << "layout(location = 0) in highp vec4 position;\n" |
| << "void main()\n" |
| << "{\n" |
| << "gl_Position = position;\n" |
| << "gl_PointSize = 1.0;\n" |
| << "}\n"; |
| programCollection.glslSources.add("vert") << glu::VertexSource(vertexSource.str()); |
| } |
| |
| { |
| std::ostringstream fragmentSource; |
| fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" |
| << "\n" |
| << "layout(location = 0) out mediump vec4 color;\n" |
| << "void main()\n" |
| << "{\n" |
| << "if (gl_FrontFacing)\n" |
| << " color = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| << "else\n" |
| << " color = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| << "}\n"; |
| programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSource.str()); |
| } |
| } |
| |
| TestInstance* BuiltinGlFrontFacingCase::createInstance (Context& context) const |
| { |
| return new BuiltinGlFrontFacingCaseInstance(context, m_topology); |
| } |
| |
| class BuiltinFragDepthCaseInstance : public TestInstance |
| { |
| public: |
| enum |
| { |
| RENDERWIDTH = 16, |
| RENDERHEIGHT = 16 |
| }; |
| BuiltinFragDepthCaseInstance (Context& context, VkPrimitiveTopology topology, VkFormat format, bool largeDepthEnable, float defaultDepth, bool depthClampEnable, const VkSampleCountFlagBits samples); |
| TestStatus iterate (void); |
| |
| bool validateDepthBuffer (const tcu::ConstPixelBufferAccess& validationBuffer, const tcu::ConstPixelBufferAccess& markerBuffer, const float tolerance) const; |
| private: |
| const VkPrimitiveTopology m_topology; |
| const VkFormat m_format; |
| const bool m_largeDepthEnable; |
| const float m_defaultDepthValue; |
| const bool m_depthClampEnable; |
| const VkSampleCountFlagBits m_samples; |
| const tcu::UVec2 m_renderSize; |
| const float m_largeDepthBase; |
| }; |
| |
| BuiltinFragDepthCaseInstance::BuiltinFragDepthCaseInstance (Context& context, VkPrimitiveTopology topology, VkFormat format, bool largeDepthEnable, float defaultDepth, bool depthClampEnable, const VkSampleCountFlagBits samples) |
| : TestInstance (context) |
| , m_topology (topology) |
| , m_format (format) |
| , m_largeDepthEnable (largeDepthEnable) |
| , m_defaultDepthValue (defaultDepth) |
| , m_depthClampEnable (depthClampEnable) |
| , m_samples (samples) |
| , m_renderSize (RENDERWIDTH, RENDERHEIGHT) |
| , m_largeDepthBase (20.0f) |
| { |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); |
| |
| try |
| { |
| VkImageFormatProperties imageFormatProperties; |
| VkFormatProperties formatProperties; |
| |
| if (m_context.getDeviceFeatures().fragmentStoresAndAtomics == VK_FALSE) |
| throw tcu::NotSupportedError("fragmentStoresAndAtomics not supported"); |
| |
| if (m_context.getDeviceFeatures().sampleRateShading == VK_FALSE) |
| throw tcu::NotSupportedError("sampleRateShading not supported"); |
| |
| imageFormatProperties = getPhysicalDeviceImageFormatProperties(vki, physicalDevice, m_format, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, (VkImageCreateFlags)0); |
| |
| if ((imageFormatProperties.sampleCounts & m_samples) == 0) |
| throw tcu::NotSupportedError("Image format and sample count not supported"); |
| |
| formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, VK_FORMAT_R8G8B8A8_UINT); |
| |
| if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) |
| throw tcu::NotSupportedError("MarkerImage format not supported as storage image"); |
| |
| if (m_largeDepthEnable && !de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_EXT_depth_range_unrestricted")) |
| throw tcu::NotSupportedError("large_depth test variants require the VK_EXT_depth_range_unrestricted extension"); |
| |
| if (m_context.getDeviceFeatures().depthClamp == VK_FALSE && m_depthClampEnable) |
| throw tcu::NotSupportedError("Depthclamp is not supported."); |
| } |
| catch (const vk::Error& e) |
| { |
| if (e.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| throw tcu::NotSupportedError("Image format not supported"); |
| else |
| throw; |
| |
| } |
| } |
| |
| TestStatus BuiltinFragDepthCaseInstance::iterate (void) |
| { |
| const VkDevice device = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| TestLog& log = m_context.getTestContext().getLog(); |
| const deUint32 scale = 4; // To account for std140 stride |
| const VkDeviceSize pixelCount = m_renderSize.x() * m_renderSize.y(); |
| std::string testDesc; |
| Move<VkImage> depthResolveImage; |
| Move<VkImageView> depthResolveImageView; |
| MovePtr<Allocation> depthResolveAllocation; |
| Move<VkImage> depthImage; |
| Move<VkImageView> depthImageView; |
| MovePtr<Allocation> depthImageAllocation; |
| Move<VkBuffer> controlBuffer; |
| MovePtr<Allocation> controlBufferAllocation; |
| Move<VkImage> markerImage; |
| Move<VkImageView> markerImageView; |
| MovePtr<Allocation> markerImageAllocation; |
| Move<VkBuffer> markerBuffer; |
| MovePtr<Allocation> markerBufferAllocation; |
| Move<VkBuffer> validationBuffer; |
| MovePtr<Allocation> validationAlloc; |
| MovePtr<Allocation> depthInitAllocation; |
| Move<VkCommandPool> cmdPool; |
| Move<VkCommandBuffer> transferCmdBuffer; |
| Move<VkSampler> depthSampler; |
| |
| // Create Buffer/Image for validation |
| { |
| VkFormat resolvedBufferFormat = VK_FORMAT_R32_SFLOAT; |
| const VkBufferCreateInfo validationBufferCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkBufferCreateFlags)0, // VkBufferCreateFlags flags |
| m_samples * pixelCount * getPixelSize(mapVkFormat(resolvedBufferFormat)), // VkDeviceSize size |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount, |
| DE_NULL // const uint32_t* pQueueFamilyIndices |
| }; |
| |
| validationBuffer = createBuffer(vk, device, &validationBufferCreateInfo); |
| validationAlloc = allocator.allocate(getBufferMemoryRequirements(vk, device, *validationBuffer), MemoryRequirement::HostVisible); |
| VK_CHECK(vk.bindBufferMemory(device, *validationBuffer, validationAlloc->getMemory(), validationAlloc->getOffset())); |
| |
| const VkImageCreateInfo depthResolveImageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkIMageType imageType |
| resolvedBufferFormat, // VkFormat format |
| makeExtent3D(m_samples * m_renderSize.x(), m_renderSize.y(), 1u), // VkExtent3D extent |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagsBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | // VkImageUsageFlags usage |
| VK_IMAGE_USAGE_STORAGE_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL, // const uint32_t pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| depthResolveImage = createImage(vk, device, &depthResolveImageCreateInfo, DE_NULL); |
| depthResolveAllocation = allocator.allocate(getImageMemoryRequirements(vk, device, *depthResolveImage), MemoryRequirement::Any); |
| VK_CHECK(vk.bindImageMemory(device, *depthResolveImage, depthResolveAllocation->getMemory(), depthResolveAllocation->getOffset())); |
| |
| const VkImageViewCreateInfo depthResolveImageViewCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageViewCreateFlags)0, // VkImageViewCreateFlags flags |
| *depthResolveImage, // VkImage image |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType type |
| resolvedBufferFormat, // VkFormat format |
| makeComponentMappingRGBA(), // VkComponentMapping componentMapping |
| makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u) // VkImageSUbresourceRange subresourceRange |
| }; |
| |
| depthResolveImageView = createImageView(vk, device, &depthResolveImageViewCreateInfo, DE_NULL); |
| } |
| |
| // Marker Buffer |
| { |
| const VkDeviceSize size = m_samples * m_renderSize.x() * m_renderSize.y() * getPixelSize(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT)); |
| |
| const VkBufferCreateInfo markerBufferCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkBufferCreateFlags)0, // VkBufferCreateFlags flags |
| size, // VkDeviceSize size |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL // const uint32_t* pQueueFamilyIndices |
| }; |
| |
| markerBuffer = createBuffer(vk, device, &markerBufferCreateInfo, DE_NULL); |
| markerBufferAllocation = allocator.allocate(getBufferMemoryRequirements(vk, device, *markerBuffer), MemoryRequirement::HostVisible); |
| VK_CHECK(vk.bindBufferMemory(device, *markerBuffer, markerBufferAllocation->getMemory(), markerBufferAllocation->getOffset())); |
| |
| const VkImageCreateInfo markerImageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| VK_FORMAT_R8G8B8A8_UINT, // VkFormat format |
| makeExtent3D(m_samples * m_renderSize.x(), m_renderSize.y(), 1),// VkExtent3D extent |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagsBit smaples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| VK_IMAGE_USAGE_STORAGE_BIT | // VkImageUsageFlags usage |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharing |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| markerImage = createImage(vk, device, &markerImageCreateInfo, DE_NULL); |
| markerImageAllocation = allocator.allocate(getImageMemoryRequirements(vk, device, *markerImage), MemoryRequirement::Any); |
| VK_CHECK(vk.bindImageMemory(device, *markerImage, markerImageAllocation->getMemory(), markerImageAllocation->getOffset())); |
| |
| const VkImageViewCreateInfo markerViewCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageViewCreateFlags)0, // VkImageViewCreateFlags flags |
| *markerImage, // VkImage image |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType |
| VK_FORMAT_R8G8B8A8_UINT, // VkFormat format |
| makeComponentMappingRGBA(), // VkComponentMapping components |
| makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u) |
| }; |
| |
| markerImageView = createImageView(vk, device, &markerViewCreateInfo, DE_NULL); |
| } |
| |
| // Control Buffer |
| { |
| const VkBufferCreateInfo controlBufferCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkBufferCreateFlags)0, // VkBufferCreateFlags flags |
| pixelCount * sizeof(float)* scale, // VkDeviceSize size |
| VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // deUint32 queueFamilyIndexCount |
| |
| DE_NULL // pQueueFamilyIndices |
| }; |
| |
| controlBuffer = createBuffer(vk, device, &controlBufferCreateInfo, DE_NULL); |
| controlBufferAllocation = allocator.allocate( getBufferMemoryRequirements(vk, device, *controlBuffer), MemoryRequirement::HostVisible); |
| VK_CHECK(vk.bindBufferMemory(device, *controlBuffer, controlBufferAllocation->getMemory(), controlBufferAllocation->getOffset())); |
| |
| { |
| float* bufferData = (float*)(controlBufferAllocation->getHostPtr()); |
| float sign = m_depthClampEnable ? -1.0f : 1.0f; |
| for (deUint32 ndx = 0; ndx < m_renderSize.x() * m_renderSize.y(); ndx++) |
| { |
| bufferData[ndx * scale] = (float)ndx / 256.0f * sign; |
| if (m_largeDepthEnable) |
| bufferData[ndx * scale] += m_largeDepthBase; |
| } |
| |
| const VkMappedMemoryRange range = |
| { |
| VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, |
| DE_NULL, |
| controlBufferAllocation->getMemory(), |
| 0u, |
| VK_WHOLE_SIZE |
| }; |
| |
| VK_CHECK(vk.flushMappedMemoryRanges(device, 1u, &range)); |
| } |
| } |
| |
| // Depth Buffer |
| { |
| VkImageSubresourceRange depthSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u); |
| const VkImageCreateInfo depthImageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| m_format, // VkFormat format |
| makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u), // VkExtent3D extent |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| m_samples, // VkSampleCountFlagsBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| VK_IMAGE_USAGE_SAMPLED_BIT | |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, // VkImageUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkShaderingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| depthImage = createImage(vk, device, &depthImageCreateInfo, DE_NULL); |
| depthImageAllocation = allocator.allocate(getImageMemoryRequirements(vk, device, *depthImage), MemoryRequirement::Any); |
| VK_CHECK(vk.bindImageMemory(device, *depthImage, depthImageAllocation->getMemory(), depthImageAllocation->getOffset())); |
| |
| const VkImageViewCreateInfo imageViewParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkImageViewCreateFlags)0, // VkImageViewCreateFlags flags; |
| *depthImage, // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| m_format, // VkFormat format; |
| makeComponentMappingRGBA(), // VkComponentMapping components; |
| depthSubresourceRange, // VkImageSubresourceRange subresourceRange; |
| }; |
| depthImageView = createImageView(vk, device, &imageViewParams); |
| |
| const VkSamplerCreateInfo depthSamplerCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags |
| VK_FILTER_NEAREST, // VkFilter minFilter |
| VK_FILTER_NEAREST, // VkFilter magFilter |
| VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipMapMode mipMapMode |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressmodeW |
| 0.0f, // float mipLodBias |
| VK_FALSE, // VkBool32 anisotropyEnable |
| 0.0f, // float maxAnisotropy |
| VK_FALSE, // VkBool32 compareEnable |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp |
| 0.0f, // float minLod |
| 0.0f, // float maxLod |
| VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor |
| VK_FALSE // VkBool32 unnormalizedCoordinates |
| }; |
| |
| depthSampler = createSampler(vk, device, &depthSamplerCreateInfo, DE_NULL); |
| } |
| |
| // Command Pool |
| { |
| const VkCommandPoolCreateInfo cmdPoolCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // VkCommandPoolCreateFlags flags |
| queueFamilyIndex // uint32_t queueFamilyIndex |
| }; |
| |
| cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo); |
| } |
| |
| // Command buffer for data transfers |
| { |
| const VkCommandBufferAllocateInfo cmdBufferAllocInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType, |
| DE_NULL, // const void* pNext |
| *cmdPool, // VkCommandPool commandPool |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level |
| 1u // uint32_t bufferCount |
| }; |
| |
| transferCmdBuffer = allocateCommandBuffer(vk, device, &cmdBufferAllocInfo); |
| } |
| |
| // Initialize Marker Buffer |
| { |
| VkImageAspectFlags depthImageAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; |
| if (hasStencilComponent(mapVkFormat(m_format).order)) |
| depthImageAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; |
| |
| const VkImageMemoryBarrier imageBarrier[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0, // VkAccessMask srcAccessMask |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessMask dstAccessMask |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| *markerImage, // VkImage image |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // uint32_t baseMipLevel |
| 1u, // uint32_t mipLevels |
| 0u, // uint32_t baseArray |
| 1u // uint32_t arraySize |
| } |
| }, |
| }; |
| |
| const VkImageMemoryBarrier imagePostBarrier[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlagBits srcAccessMask |
| VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlagBits dstAccessMask |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| *markerImage, // VkImage image |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // uint32_t baseMipLevel |
| 1u, // uint32_t mipLevels |
| 0u, // uint32_t baseArray |
| 1u // uint32_t arraySize |
| } |
| }, |
| }; |
| |
| beginCommandBuffer(vk, *transferCmdBuffer); |
| vk.cmdPipelineBarrier(*transferCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, |
| (VkDependencyFlags)0, |
| 0, (const VkMemoryBarrier*)DE_NULL, |
| 0, (const VkBufferMemoryBarrier*)DE_NULL, |
| DE_LENGTH_OF_ARRAY(imageBarrier), imageBarrier); |
| |
| const VkClearValue colorClearValue = makeClearValueColor(Vec4(0.0f, 0.0f, 0.0f, 0.0f)); |
| const VkImageSubresourceRange colorClearRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| |
| vk.cmdClearColorImage(*transferCmdBuffer, *markerImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colorClearValue.color, 1u, &colorClearRange); |
| |
| vk.cmdPipelineBarrier(*transferCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, |
| (VkDependencyFlags)0, |
| 0, (const VkMemoryBarrier*)DE_NULL, |
| 0, (const VkBufferMemoryBarrier*)DE_NULL, |
| DE_LENGTH_OF_ARRAY(imagePostBarrier), imagePostBarrier); |
| |
| endCommandBuffer(vk, *transferCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, transferCmdBuffer.get()); |
| } |
| |
| |
| // Perform Draw |
| { |
| std::vector<Vec4> vertices; |
| std::vector<VulkanShader> shaders; |
| Move<VkDescriptorSetLayout> descriptorSetLayout; |
| Move<VkDescriptorPool> descriptorPool; |
| Move<VkDescriptorSet> descriptorSet; |
| |
| // Descriptors |
| { |
| DescriptorSetLayoutBuilder layoutBuilder; |
| layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT); |
| layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); |
| descriptorSetLayout = layoutBuilder.build(vk, device); |
| descriptorPool = DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| const VkDescriptorSetAllocateInfo descriptorSetAllocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| *descriptorPool, |
| 1u, |
| &descriptorSetLayout.get() |
| }; |
| |
| descriptorSet = allocateDescriptorSet(vk, device, &descriptorSetAllocInfo); |
| |
| const VkDescriptorBufferInfo bufferInfo = |
| { |
| *controlBuffer, |
| 0u, |
| VK_WHOLE_SIZE |
| }; |
| |
| const VkDescriptorImageInfo imageInfo = |
| { |
| (VkSampler)DE_NULL, |
| *markerImageView, |
| VK_IMAGE_LAYOUT_GENERAL |
| }; |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &bufferInfo) |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfo) |
| .update(vk, device); |
| } |
| |
| vertices.push_back(Vec4( -0.70f, 0.5f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 0.45f, -0.75f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 0.78f, 0.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( -0.1f, 0.6f, 0.0f, 1.0f)); |
| |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("FragDepthVert"))); |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("FragDepthFrag"))); |
| |
| DrawState drawState(m_topology, m_renderSize.x(), m_renderSize.y()); |
| DrawCallData drawCallData(vertices); |
| VulkanProgram vulkanProgram(shaders); |
| |
| drawState.depthClampEnable = m_depthClampEnable; |
| drawState.depthFormat = m_format; |
| drawState.numSamples = m_samples; |
| drawState.compareOp = rr::TESTFUNC_ALWAYS; |
| drawState.depthTestEnable = true; |
| drawState.depthWriteEnable = true; |
| drawState.sampleShadingEnable = true; |
| vulkanProgram.depthImageView = *depthImageView; |
| vulkanProgram.descriptorSetLayout = *descriptorSetLayout; |
| vulkanProgram.descriptorSet = *descriptorSet; |
| |
| VulkanDrawContext vulkanDrawContext(m_context, drawState, drawCallData, vulkanProgram); |
| vulkanDrawContext.draw(); |
| |
| log << TestLog::Image( "resultColor", |
| "Result Color Buffer", |
| tcu::ConstPixelBufferAccess(tcu::TextureFormat( |
| vulkanDrawContext.getColorPixels().getFormat()), |
| vulkanDrawContext.getColorPixels().getWidth(), |
| vulkanDrawContext.getColorPixels().getHeight(), |
| 1, |
| vulkanDrawContext.getColorPixels().getDataPtr())); |
| } |
| |
| // Barrier to transition between first and second pass |
| { |
| VkImageAspectFlags depthImageAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; |
| if (hasStencilComponent(mapVkFormat(m_format).order)) |
| depthImageAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; |
| |
| const VkImageMemoryBarrier imageBarrier[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout |
| 0u, // deUint32 srcQueueFamilyIndex |
| 0u, // deUint32 dstQueueFamilyIndex |
| *depthImage, // VkImage image |
| { |
| depthImageAspectFlags, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 baseMipLevel |
| 1u, // deUint32 levelCount |
| 0u, // deUint32 baseArrayLayer |
| 1u // deUint32 layerCount |
| } |
| }, |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkAccessFlags srcAccessMask |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout |
| 0u, // deUint32 srcQueueFamilyIndex |
| 0u, // deUint32 dstQueueFamilyIndex |
| *depthResolveImage, // VkImage image |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 baseMipLevel |
| 1u, // deUint32 levelCount |
| 0u, // deUint32 baseArrayLayer |
| 1u, // deUint32 layerCount |
| |
| } |
| } |
| }; |
| |
| beginCommandBuffer(vk, *transferCmdBuffer); |
| vk.cmdPipelineBarrier(*transferCmdBuffer, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_HOST_BIT, |
| (VkDependencyFlags)0, |
| 0, (const VkMemoryBarrier*)DE_NULL, |
| 0, (const VkBufferMemoryBarrier*)DE_NULL, |
| DE_LENGTH_OF_ARRAY(imageBarrier), imageBarrier); |
| endCommandBuffer(vk, *transferCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, transferCmdBuffer.get()); |
| } |
| |
| // Resolve Depth Buffer |
| { |
| std::vector<Vec4> vertices; |
| std::vector<VulkanShader> shaders; |
| Move<VkDescriptorSetLayout> descriptorSetLayout; |
| Move<VkDescriptorPool> descriptorPool; |
| Move<VkDescriptorSet> descriptorSet; |
| |
| // Descriptors |
| { |
| DescriptorSetLayoutBuilder layoutBuilder; |
| layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); |
| layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); |
| descriptorSetLayout = layoutBuilder.build(vk, device); |
| descriptorPool = DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| const VkDescriptorSetAllocateInfo descriptorSetAllocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| *descriptorPool, |
| 1u, |
| &descriptorSetLayout.get() |
| }; |
| |
| descriptorSet = allocateDescriptorSet(vk, device, &descriptorSetAllocInfo); |
| |
| const VkDescriptorImageInfo depthImageInfo = |
| { |
| *depthSampler, |
| *depthImageView, |
| VK_IMAGE_LAYOUT_GENERAL |
| }; |
| |
| const VkDescriptorImageInfo imageInfo = |
| { |
| (VkSampler)DE_NULL, |
| *depthResolveImageView, |
| VK_IMAGE_LAYOUT_GENERAL |
| }; |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &depthImageInfo) |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfo) |
| .update(vk, device); |
| } |
| |
| vertices.push_back(Vec4( -1.0f, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( -1.0f, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); |
| |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("FragDepthVertPass2"))); |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("FragDepthFragPass2"))); |
| |
| DrawState drawState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, m_renderSize.x(), m_renderSize.y()); |
| DrawCallData drawCallData(vertices); |
| VulkanProgram vulkanProgram(shaders); |
| |
| drawState.numSamples = m_samples; |
| drawState.sampleShadingEnable = true; |
| vulkanProgram.descriptorSetLayout = *descriptorSetLayout; |
| vulkanProgram.descriptorSet = *descriptorSet; |
| |
| VulkanDrawContext vulkanDrawContext(m_context, drawState, drawCallData, vulkanProgram); |
| vulkanDrawContext.draw(); |
| } |
| |
| // Transfer marker buffer |
| { |
| beginCommandBuffer(vk, *transferCmdBuffer); |
| copyImageToBuffer(vk, *transferCmdBuffer, *markerImage, *markerBuffer, tcu::IVec2(m_renderSize.x() * m_samples, m_renderSize.y()), VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); |
| endCommandBuffer(vk, *transferCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, transferCmdBuffer.get()); |
| } |
| |
| // Verify depth buffer |
| { |
| bool status; |
| |
| beginCommandBuffer(vk, *transferCmdBuffer, 0u); |
| copyImageToBuffer(vk, *transferCmdBuffer, *depthResolveImage, *validationBuffer, tcu::IVec2(m_renderSize.x() * m_samples, m_renderSize.y()), VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); |
| endCommandBuffer(vk, *transferCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, transferCmdBuffer.get()); |
| |
| invalidateMappedMemoryRange(vk, device, validationAlloc->getMemory(), validationAlloc->getOffset(), VK_WHOLE_SIZE); |
| invalidateMappedMemoryRange(vk, device, markerBufferAllocation->getMemory(), markerBufferAllocation->getOffset(), VK_WHOLE_SIZE); |
| |
| tcu::ConstPixelBufferAccess resultPixelBuffer(mapVkFormat(VK_FORMAT_R32_SFLOAT), m_renderSize.x() * m_samples, m_renderSize.y(), 1u, validationAlloc->getHostPtr()); |
| tcu::ConstPixelBufferAccess markerPixelBuffer(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), m_renderSize.x() * m_samples, m_renderSize.y(), 1u, markerBufferAllocation->getHostPtr()); |
| status = validateDepthBuffer(resultPixelBuffer, markerPixelBuffer, 0.001f); |
| testDesc = "gl_FragDepth " + getPrimitiveTopologyShortName(m_topology) + " "; |
| if (status) |
| { |
| testDesc += "passed"; |
| return tcu::TestStatus::pass(testDesc.c_str()); |
| } |
| else |
| { |
| log << TestLog::Image("resultDepth", "Result Depth Buffer", resultPixelBuffer); |
| testDesc += "failed"; |
| return tcu::TestStatus::fail(testDesc.c_str()); |
| } |
| } |
| } |
| |
| bool BuiltinFragDepthCaseInstance::validateDepthBuffer (const tcu::ConstPixelBufferAccess& validationBuffer, const tcu::ConstPixelBufferAccess& markerBuffer, const float tolerance) const |
| { |
| TestLog& log = m_context.getTestContext().getLog(); |
| |
| for (deUint32 rowNdx = 0; rowNdx < m_renderSize.y(); rowNdx++) |
| { |
| for (deUint32 colNdx = 0; colNdx < m_renderSize.x(); colNdx++) |
| { |
| const float multiplier = m_depthClampEnable ? 0.0f : 1.0f; |
| float expectedValue = (float)(rowNdx * m_renderSize.x() + colNdx)/256.0f * multiplier; |
| |
| if (m_largeDepthEnable) |
| expectedValue += m_largeDepthBase; |
| |
| for (deUint32 sampleNdx = 0; sampleNdx < (deUint32)m_samples; sampleNdx++) |
| { |
| const float actualValue = validationBuffer.getPixel(sampleNdx + m_samples * colNdx, rowNdx).x(); |
| const float markerValue = markerBuffer.getPixel(sampleNdx + m_samples * colNdx, rowNdx).x(); |
| |
| if (markerValue != 0) |
| { |
| if (de::abs(expectedValue - actualValue) > tolerance) |
| { |
| log << TestLog::Message << "Mismatch at pixel (" << colNdx << "," << rowNdx << "," << sampleNdx << "): expected " << expectedValue << " but got " << actualValue << TestLog::EndMessage; |
| return false; |
| } |
| } |
| else |
| { |
| if (de::abs(actualValue - m_defaultDepthValue) > tolerance) |
| { |
| log << TestLog::Message << "Mismatch at pixel (" << colNdx << "," << rowNdx << "," << sampleNdx << "): expected " << expectedValue << " but got " << actualValue << TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| class BuiltinFragCoordMsaaCaseInstance : public TestInstance |
| { |
| public: |
| enum |
| { |
| RENDERWIDTH = 16, |
| RENDERHEIGHT = 16 |
| }; |
| BuiltinFragCoordMsaaCaseInstance (Context& context, VkSampleCountFlagBits sampleCount); |
| TestStatus iterate (void); |
| private: |
| bool validateSampleLocations (const ConstPixelBufferAccess& sampleLocationBuffer) const; |
| |
| const tcu::UVec2 m_renderSize; |
| const VkSampleCountFlagBits m_sampleCount; |
| }; |
| |
| BuiltinFragCoordMsaaCaseInstance::BuiltinFragCoordMsaaCaseInstance (Context& context, VkSampleCountFlagBits sampleCount) |
| : TestInstance (context) |
| , m_renderSize (RENDERWIDTH, RENDERHEIGHT) |
| , m_sampleCount (sampleCount) |
| { |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); |
| |
| try |
| { |
| VkImageFormatProperties imageFormatProperties; |
| VkFormatProperties formatProperties; |
| |
| if (m_context.getDeviceFeatures().fragmentStoresAndAtomics == VK_FALSE) |
| throw tcu::NotSupportedError("fragmentStoresAndAtomics not supported"); |
| |
| if (m_context.getDeviceFeatures().sampleRateShading == VK_FALSE) |
| throw tcu::NotSupportedError("sampleRateShading not supported"); |
| |
| imageFormatProperties = getPhysicalDeviceImageFormatProperties(vki, physicalDevice, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, (VkImageCreateFlags)0); |
| |
| if ((imageFormatProperties.sampleCounts & m_sampleCount) == 0) |
| throw tcu::NotSupportedError("Image format and sample count not supported"); |
| |
| formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, VK_FORMAT_R32G32B32A32_SFLOAT); |
| |
| if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) |
| throw tcu::NotSupportedError("Output format not supported as storage image"); |
| } |
| catch (const vk::Error& e) |
| { |
| if (e.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| throw tcu::NotSupportedError("Image format not supported"); |
| else |
| throw; |
| |
| } |
| } |
| |
| TestStatus BuiltinFragCoordMsaaCaseInstance::iterate (void) |
| { |
| const VkDevice device = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| TestLog& log = m_context.getTestContext().getLog(); |
| Move<VkImage> outputImage; |
| Move<VkImageView> outputImageView; |
| MovePtr<Allocation> outputImageAllocation; |
| Move<VkDescriptorSetLayout> descriptorSetLayout; |
| Move<VkDescriptorPool> descriptorPool; |
| Move<VkDescriptorSet> descriptorSet; |
| Move<VkBuffer> sampleLocationBuffer; |
| MovePtr<Allocation> sampleLocationBufferAllocation; |
| Move<VkCommandPool> cmdPool; |
| Move<VkCommandBuffer> transferCmdBuffer; |
| |
| // Coordinate result image |
| { |
| const VkImageCreateInfo outputImageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format |
| makeExtent3D(m_sampleCount * m_renderSize.x(), m_renderSize.y(), 1u), // VkExtent3D extent3d |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| VK_IMAGE_USAGE_STORAGE_BIT | // VkImageUsageFlags usage |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT, |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| outputImage = createImage(vk, device, &outputImageCreateInfo, DE_NULL); |
| outputImageAllocation = allocator.allocate(getImageMemoryRequirements(vk, device, *outputImage), MemoryRequirement::Any); |
| vk.bindImageMemory(device, *outputImage, outputImageAllocation->getMemory(), outputImageAllocation->getOffset()); |
| |
| VkImageSubresourceRange imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| const VkImageViewCreateInfo outputImageViewCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkImageViewCreateFlags)0, // VkImageViewCreateFlags flags |
| *outputImage, // VkImage image |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format, |
| makeComponentMappingRGBA(), // VkComponentMapping components |
| imageSubresourceRange // VkImageSubresourceRange imageSubresourceRange |
| }; |
| |
| outputImageView = createImageView(vk, device, &outputImageViewCreateInfo); |
| } |
| |
| // Validation buffer |
| { |
| VkDeviceSize pixelSize = getPixelSize(mapVkFormat(VK_FORMAT_R32G32B32A32_SFLOAT)); |
| const VkBufferCreateInfo sampleLocationBufferCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkBufferCreateFlags)0, // VkBufferCreateFlags flags |
| m_sampleCount * m_renderSize.x() * m_renderSize.y() * pixelSize, // VkDeviceSize size |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode mode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL // const uint32_t* pQueueFamilyIndices |
| }; |
| |
| sampleLocationBuffer = createBuffer(vk, device, &sampleLocationBufferCreateInfo, DE_NULL); |
| sampleLocationBufferAllocation = allocator.allocate(getBufferMemoryRequirements(vk, device, *sampleLocationBuffer), MemoryRequirement::HostVisible); |
| vk.bindBufferMemory(device, *sampleLocationBuffer, sampleLocationBufferAllocation->getMemory(), sampleLocationBufferAllocation->getOffset()); |
| } |
| |
| // Descriptors |
| { |
| DescriptorSetLayoutBuilder layoutBuilder; |
| layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); |
| descriptorSetLayout = layoutBuilder.build(vk, device); |
| descriptorPool = DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| const VkDescriptorSetAllocateInfo descriptorSetAllocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| *descriptorPool, |
| 1u, |
| &*descriptorSetLayout |
| }; |
| |
| descriptorSet = allocateDescriptorSet(vk, device, &descriptorSetAllocInfo); |
| |
| const VkDescriptorImageInfo imageInfo = |
| { |
| (VkSampler)DE_NULL, |
| *outputImageView, |
| VK_IMAGE_LAYOUT_GENERAL |
| }; |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfo) |
| .update(vk, device); |
| } |
| |
| // Command Pool |
| { |
| const VkCommandPoolCreateInfo cmdPoolCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // VkCommandPoolCreateFlags flags |
| queueFamilyIndex // uint32_t queueFamilyIndex |
| }; |
| |
| cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo); |
| } |
| |
| // Command buffer for data transfers |
| { |
| const VkCommandBufferAllocateInfo cmdBufferAllocInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType, |
| DE_NULL, // const void* pNext |
| *cmdPool, // VkCommandPool commandPool |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level |
| 1u // uint32_t bufferCount |
| }; |
| |
| transferCmdBuffer = allocateCommandBuffer(vk, device, &cmdBufferAllocInfo); |
| } |
| |
| // Transition the output image to LAYOUT_GENERAL |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkAccessFlags srcAccessMask |
| VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| *outputImage, // VkImage image |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // uint32_t baseMipLevel |
| 1u, // uint32_t mipLevels |
| 0u, // uint32_t baseArray |
| 1u // uint32_t arraySize |
| } |
| }; |
| |
| beginCommandBuffer(vk, *transferCmdBuffer); |
| vk.cmdPipelineBarrier(*transferCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, |
| (VkDependencyFlags)0, |
| 0, (const VkMemoryBarrier*)DE_NULL, |
| 0, (const VkBufferMemoryBarrier*)DE_NULL, |
| 1, &barrier); |
| |
| endCommandBuffer(vk, *transferCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, transferCmdBuffer.get()); |
| } |
| |
| // Perform draw |
| { |
| std::vector<Vec4> vertices; |
| std::vector<VulkanShader> shaders; |
| |
| vertices.push_back(Vec4( -1.0f, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( -1.0f, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); |
| |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("FragCoordMsaaVert"))); |
| shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("FragCoordMsaaFrag"))); |
| |
| DrawState drawState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, m_renderSize.x(), m_renderSize.y()); |
| DrawCallData drawCallData(vertices); |
| VulkanProgram vulkanProgram(shaders); |
| |
| drawState.numSamples = m_sampleCount; |
| drawState.sampleShadingEnable = true; |
| vulkanProgram.descriptorSetLayout = *descriptorSetLayout; |
| vulkanProgram.descriptorSet = *descriptorSet; |
| |
| VulkanDrawContext vulkanDrawContext(m_context, drawState, drawCallData, vulkanProgram); |
| vulkanDrawContext.draw(); |
| |
| log << TestLog::Image( "result", |
| "result", |
| tcu::ConstPixelBufferAccess(tcu::TextureFormat( |
| vulkanDrawContext.getColorPixels().getFormat()), |
| vulkanDrawContext.getColorPixels().getWidth(), |
| vulkanDrawContext.getColorPixels().getHeight(), |
| 1, |
| vulkanDrawContext.getColorPixels().getDataPtr())); |
| } |
| |
| // Transfer location image to buffer |
| { |
| beginCommandBuffer(vk, *transferCmdBuffer); |
| copyImageToBuffer(vk, *transferCmdBuffer, *outputImage, *sampleLocationBuffer, tcu::IVec2(m_renderSize.x() * m_sampleCount, m_renderSize.y()), VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); |
| endCommandBuffer(vk, *transferCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, transferCmdBuffer.get()); |
| |
| invalidateAlloc(vk, device, *sampleLocationBufferAllocation); |
| } |
| |
| // Validate result |
| { |
| bool status; |
| |
| ConstPixelBufferAccess sampleLocationPixelBuffer(mapVkFormat(VK_FORMAT_R32G32B32A32_SFLOAT), m_sampleCount * m_renderSize.x(), |
| m_renderSize.y(), 1u, sampleLocationBufferAllocation->getHostPtr()); |
| |
| status = validateSampleLocations(sampleLocationPixelBuffer); |
| if (status) |
| return TestStatus::pass("FragCoordMsaa passed"); |
| else |
| return TestStatus::fail("FragCoordMsaa failed"); |
| } |
| } |
| |
| static bool pixelOffsetCompare (const Vec2& a, const Vec2& b) |
| { |
| return a.x() < b.x(); |
| } |
| |
| bool BuiltinFragCoordMsaaCaseInstance::validateSampleLocations (const ConstPixelBufferAccess& sampleLocationBuffer) const |
| { |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| TestLog& log = m_context.getTestContext().getLog(); |
| const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); |
| deUint32 logSampleCount = deLog2Floor32(m_sampleCount); |
| VkPhysicalDeviceProperties physicalDeviceProperties; |
| |
| static const Vec2 sampleCount1Bit[] = |
| { |
| Vec2(0.5f, 0.5f) |
| }; |
| |
| static const Vec2 sampleCount2Bit[] = |
| { |
| Vec2(0.25f, 0.25f), Vec2(0.75f, 0.75f) |
| }; |
| |
| static const Vec2 sampleCount4Bit[] = |
| { |
| Vec2(0.375f, 0.125f), Vec2(0.875f, 0.375f), Vec2(0.125f, 0.625f), Vec2(0.625f, 0.875f) |
| }; |
| |
| static const Vec2 sampleCount8Bit[] = |
| { |
| Vec2(0.5625f, 0.3125f), Vec2(0.4375f, 0.6875f), Vec2(0.8125f,0.5625f), Vec2(0.3125f, 0.1875f), |
| Vec2(0.1875f, 0.8125f), Vec2(0.0625f, 0.4375f), Vec2(0.6875f,0.9375f), Vec2(0.9375f, 0.0625f) |
| }; |
| |
| static const Vec2 sampleCount16Bit[] = |
| { |
| Vec2(0.5625f, 0.5625f), Vec2(0.4375f, 0.3125f), Vec2(0.3125f,0.6250f), Vec2(0.7500f, 0.4375f), |
| Vec2(0.1875f, 0.3750f), Vec2(0.6250f, 0.8125f), Vec2(0.8125f,0.6875f), Vec2(0.6875f, 0.1875f), |
| Vec2(0.3750f, 0.8750f), Vec2(0.5000f, 0.0625f), Vec2(0.2500f,0.1250f), Vec2(0.1250f, 0.7500f), |
| Vec2(0.0000f, 0.5000f), Vec2(0.9375f, 0.2500f), Vec2(0.8750f,0.9375f), Vec2(0.0625f, 0.0000f) |
| }; |
| |
| static const Vec2* standardSampleLocationTable[] = |
| { |
| sampleCount1Bit, |
| sampleCount2Bit, |
| sampleCount4Bit, |
| sampleCount8Bit, |
| sampleCount16Bit |
| }; |
| |
| vki.getPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); |
| |
| for (deInt32 rowNdx = 0; rowNdx < (deInt32)m_renderSize.y(); rowNdx++) |
| { |
| for (deInt32 colNdx = 0; colNdx < (deInt32)m_renderSize.x(); colNdx++) |
| { |
| std::vector<Vec2> locations; |
| |
| for (deUint32 sampleNdx = 0; sampleNdx < (deUint32)m_sampleCount; sampleNdx++) |
| { |
| const UVec2 pixelAddress = UVec2(sampleNdx + m_sampleCount * colNdx, rowNdx); |
| const Vec4 pixelData = sampleLocationBuffer.getPixel(pixelAddress.x(), pixelAddress.y()); |
| |
| locations.push_back(Vec2(pixelData.x(), pixelData.y())); |
| } |
| |
| std::sort(locations.begin(), locations.end(), pixelOffsetCompare); |
| for (std::vector<Vec2>::const_iterator sampleIt = locations.begin(); sampleIt != locations.end(); sampleIt++) |
| { |
| IVec2 sampleFloor(deFloorFloatToInt32((*sampleIt).x()), deFloorFloatToInt32((*sampleIt).y())); |
| IVec2 sampleCeil(deCeilFloatToInt32((*sampleIt).x()), deCeilFloatToInt32((*sampleIt).y())); |
| |
| if ( (sampleFloor.x() < colNdx) || (sampleCeil.x() > colNdx + 1) || (sampleFloor.y() < rowNdx) || (sampleCeil.y() > rowNdx + 1) ) |
| { |
| log << TestLog::Message << "Pixel (" << colNdx << "," << rowNdx << "): " << *sampleIt << TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| std::vector<Vec2>::iterator last = std::unique(locations.begin(), locations.end()); |
| if (last != locations.end()) |
| { |
| log << TestLog::Message << "Fail: Sample locations contains non-unique entry" << TestLog::EndMessage; |
| return false; |
| } |
| |
| // Check standard sample locations |
| if (logSampleCount < DE_LENGTH_OF_ARRAY(standardSampleLocationTable)) |
| { |
| if (physicalDeviceProperties.limits.standardSampleLocations) |
| { |
| for (deUint32 sampleNdx = 0; sampleNdx < (deUint32)m_sampleCount; sampleNdx++) |
| { |
| if (!de::contains(locations.begin(), locations.end(), standardSampleLocationTable[logSampleCount][sampleNdx] + Vec2(float(colNdx), float(rowNdx)))) |
| { |
| log << TestLog::Message << "Didn't match sample locations " << standardSampleLocationTable[logSampleCount][sampleNdx] << TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| class BuiltinFragCoordMsaaTestCase : public TestCase |
| { |
| public: |
| BuiltinFragCoordMsaaTestCase (TestContext& testCtx, const char* name, const char* description, VkSampleCountFlagBits sampleCount); |
| virtual ~BuiltinFragCoordMsaaTestCase (void); |
| void initPrograms (SourceCollections& sourceCollections) const; |
| TestInstance* createInstance (Context& context) const; |
| private: |
| const VkSampleCountFlagBits m_sampleCount; |
| }; |
| |
| BuiltinFragCoordMsaaTestCase::BuiltinFragCoordMsaaTestCase (TestContext& testCtx, const char* name, const char* description, VkSampleCountFlagBits sampleCount) |
| : TestCase (testCtx, name, description) |
| , m_sampleCount (sampleCount) |
| { |
| } |
| |
| BuiltinFragCoordMsaaTestCase::~BuiltinFragCoordMsaaTestCase (void) |
| { |
| } |
| |
| void BuiltinFragCoordMsaaTestCase::initPrograms (SourceCollections& programCollection) const |
| { |
| { |
| std::ostringstream vertexSource; |
| vertexSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout (location = 0) in vec4 position;\n" |
| << "void main()\n" |
| << "{\n" |
| << " gl_Position = position;\n" |
| << "}\n"; |
| programCollection.glslSources.add("FragCoordMsaaVert") << glu::VertexSource(vertexSource.str()); |
| } |
| |
| { |
| std::ostringstream fragmentSource; |
| fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout(location = 0) out mediump vec4 color;\n" |
| << "layout (set = 0, binding = 0, rgba32f) writeonly uniform image2D storageImage;\n" |
| << "void main()\n" |
| << "{\n" |
| << " const int sampleNdx = int(gl_SampleID);\n" |
| << " ivec2 imageCoord = ivec2(sampleNdx + int(gl_FragCoord.x) * " << m_sampleCount << ", int(gl_FragCoord.y));\n" |
| << " imageStore(storageImage, imageCoord, vec4(gl_FragCoord.xy,vec2(0)));\n" |
| << " color = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| << "}\n"; |
| programCollection.glslSources.add("FragCoordMsaaFrag") << glu::FragmentSource(fragmentSource.str()); |
| } |
| } |
| |
| TestInstance* BuiltinFragCoordMsaaTestCase::createInstance (Context& context) const |
| { |
| return new BuiltinFragCoordMsaaCaseInstance(context, m_sampleCount); |
| } |
| |
| class BuiltinFragDepthCase : public TestCase |
| { |
| public: |
| BuiltinFragDepthCase (TestContext& testCtx, const char* name, const char* description, VkPrimitiveTopology topology, VkFormat format, bool largeDepthEnable, bool depthClampEnable, const VkSampleCountFlagBits samples); |
| virtual ~BuiltinFragDepthCase (void); |
| |
| void initPrograms (SourceCollections& dst) const; |
| TestInstance* createInstance (Context& context) const; |
| |
| private: |
| const VkPrimitiveTopology m_topology; |
| const VkFormat m_format; |
| const bool m_largeDepthEnable; |
| const float m_defaultDepth; |
| const bool m_depthClampEnable; |
| const VkSampleCountFlagBits m_samples; |
| }; |
| |
| BuiltinFragDepthCase::BuiltinFragDepthCase (TestContext& testCtx, const char* name, const char* description, VkPrimitiveTopology topology, VkFormat format, bool largeDepthEnable, bool depthClampEnable, const VkSampleCountFlagBits samples) |
| : TestCase (testCtx, name, description) |
| , m_topology (topology) |
| , m_format (format) |
| , m_largeDepthEnable (largeDepthEnable) |
| , m_defaultDepth (0.0f) |
| , m_depthClampEnable (depthClampEnable) |
| , m_samples (samples) |
| { |
| } |
| |
| BuiltinFragDepthCase::~BuiltinFragDepthCase(void) |
| { |
| } |
| |
| void BuiltinFragDepthCase::initPrograms (SourceCollections& programCollection) const |
| { |
| // Vertex |
| { |
| // Pass 1 |
| { |
| std::ostringstream vertexSource; |
| vertexSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout (location = 0) in vec4 position;\n" |
| << "void main()\n" |
| << "{\n" |
| << " gl_Position = position;\n" |
| << " gl_PointSize = 1.0;\n" |
| << "}\n"; |
| programCollection.glslSources.add("FragDepthVert") << glu::VertexSource(vertexSource.str()); |
| } |
| |
| // Pass 2 |
| { |
| std::ostringstream vertexSource; |
| vertexSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout (location = 0) in vec4 position;\n" |
| << "layout (location = 1) out vec2 texCoord;\n" |
| << "void main()\n" |
| << "{\n" |
| << " gl_Position = position;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " texCoord = position.xy/2 + vec2(0.5);\n" |
| << "}\n"; |
| programCollection.glslSources.add("FragDepthVertPass2") << glu::VertexSource(vertexSource.str()); |
| } |
| } |
| |
| // Fragment |
| { |
| // Pass 1 |
| { |
| std::ostringstream fragmentSource; |
| fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout(location = 0) out mediump vec4 color;\n" |
| << "layout (std140, set = 0, binding = 0) uniform control_buffer_t\n" |
| << "{\n" |
| << " float data[256];\n" |
| << "} control_buffer;\n" |
| << "layout (set = 0, binding = 1, rgba8ui) writeonly uniform uimage2D storageImage;\n" |
| << "float controlDepthValue;\n" |
| << "void recheck(float controlDepthValue)\n" |
| << "{\n" |
| << " if (gl_FragDepth != controlDepthValue)\n" |
| << " gl_FragDepth = 1.0;\n" |
| << "}\n" |
| << "void main()\n" |
| << "{\n" |
| << " const int numSamples = " << m_samples << ";\n" |
| << " if (int(gl_FragCoord.x) == " << BuiltinFragDepthCaseInstance::RENDERWIDTH/4 << ")\n" |
| << " discard;\n" |
| << " highp int index =int(gl_FragCoord.y) * " << BuiltinFragDepthCaseInstance::RENDERHEIGHT << " + int(gl_FragCoord.x);\n" |
| << " controlDepthValue = control_buffer.data[index];\n" |
| << " gl_FragDepth = controlDepthValue;\n" |
| << " const int sampleNdx = int(gl_SampleID);\n" |
| << " ivec2 imageCoord = ivec2(sampleNdx + int(gl_FragCoord.x) * " << m_samples << ", int(gl_FragCoord.y));\n" |
| << " imageStore(storageImage, imageCoord, uvec4(1));\n" |
| << " recheck(controlDepthValue);\n" |
| << " color = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| << "}\n"; |
| programCollection.glslSources.add("FragDepthFrag") << glu::FragmentSource(fragmentSource.str()); |
| } |
| |
| // Pass 2 |
| { |
| const char* multisampleDecoration = m_samples != VK_SAMPLE_COUNT_1_BIT ? "MS" : ""; |
| std::ostringstream fragmentSource; |
| fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout (location = 0) out mediump vec4 color;\n" |
| << "layout (location = 1) in vec2 texCoord;\n" |
| << "layout (binding = 0, set = 0) uniform sampler2D" << multisampleDecoration << " u_depthTex;\n" |
| << "layout (binding = 1, set = 0, r32f) writeonly uniform image2D u_outImage;\n" |
| << "void main (void)\n" |
| << "{\n" |
| << " const int numSamples = " << m_samples << ";\n" |
| << " const int sampleNdx = int(gl_SampleID);\n" |
| << " ivec2 renderSize = ivec2(" << BuiltinFragDepthCaseInstance::RENDERWIDTH << "," << BuiltinFragDepthCaseInstance::RENDERHEIGHT << ");\n" |
| << " ivec2 imageCoord = ivec2(int(texCoord.x * renderSize.x), int(texCoord.y * renderSize.y));\n" |
| << " vec4 depthVal = texelFetch(u_depthTex, imageCoord, sampleNdx);\n" |
| << " imageStore(u_outImage, ivec2(sampleNdx + int(texCoord.x * renderSize.x) * numSamples, int(texCoord.y * renderSize.y)), depthVal);\n" |
| << " color = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| << "}\n"; |
| programCollection.glslSources.add("FragDepthFragPass2") << glu::FragmentSource(fragmentSource.str()); |
| } |
| } |
| } |
| |
| TestInstance* BuiltinFragDepthCase::createInstance (Context& context) const |
| { |
| return new BuiltinFragDepthCaseInstance(context, m_topology, m_format, m_largeDepthEnable, m_defaultDepth, m_depthClampEnable, m_samples); |
| } |
| |
| class BuiltinGlFragCoordXYZCaseInstance : public ShaderRenderCaseInstance |
| { |
| public: |
| BuiltinGlFragCoordXYZCaseInstance (Context& context); |
| |
| TestStatus iterate (void); |
| virtual void setupDefaultInputs (void); |
| }; |
| |
| BuiltinGlFragCoordXYZCaseInstance::BuiltinGlFragCoordXYZCaseInstance (Context& context) |
| : ShaderRenderCaseInstance (context) |
| { |
| m_colorFormat = VK_FORMAT_R16G16B16A16_UNORM; |
| } |
| |
| TestStatus BuiltinGlFragCoordXYZCaseInstance::iterate (void) |
| { |
| const UVec2 viewportSize = getViewportSize(); |
| const int width = viewportSize.x(); |
| const int height = viewportSize.y(); |
| const tcu::Vec3 scale (1.f / float(width), 1.f / float(height), 1.0f); |
| const float precision = 0.00001f; |
| const deUint16 indices[6] = |
| { |
| 2, 1, 3, |
| 0, 1, 2, |
| }; |
| |
| setup(); |
| addUniform(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, scale); |
| |
| render(4, 2, indices); |
| |
| // Reference image |
| for (int y = 0; y < height; y++) |
| { |
| for (int x = 0; x < width; x++) |
| { |
| const float xf = (float(x) + .5f) / float(width); |
| const float yf = (float(height - y - 1) + .5f) / float(height); |
| const float z = (xf + yf) / 2.0f; |
| const Vec3 fragCoord (float(x) + .5f, float(y) + .5f, z); |
| const Vec3 scaledFC = fragCoord*scale; |
| const Vec4 color (scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f); |
| const Vec4 resultColor = getResultImage().getAccess().getPixel(x, y); |
| |
| if (de::abs(color.x() - resultColor.x()) > precision || |
| de::abs(color.y() - resultColor.y()) > precision || |
| de::abs(color.z() - resultColor.z()) > precision) |
| return TestStatus::fail("Image mismatch"); |
| } |
| } |
| |
| return TestStatus::pass("Result image matches reference"); |
| } |
| |
| void BuiltinGlFragCoordXYZCaseInstance::setupDefaultInputs (void) |
| { |
| const float vertices[] = |
| { |
| -1.0f, 1.0f, 0.0f, 1.0f, |
| -1.0f, -1.0f, 0.5f, 1.0f, |
| 1.0f, 1.0f, 0.5f, 1.0f, |
| 1.0f, -1.0f, 1.0f, 1.0f, |
| }; |
| |
| addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 4, vertices); |
| } |
| |
| class BuiltinGlFragCoordXYZCase : public TestCase |
| { |
| public: |
| BuiltinGlFragCoordXYZCase (TestContext& testCtx, const string& name, const string& description); |
| virtual ~BuiltinGlFragCoordXYZCase (void); |
| |
| void initPrograms (SourceCollections& dst) const; |
| TestInstance* createInstance (Context& context) const; |
| |
| private: |
| BuiltinGlFragCoordXYZCase (const BuiltinGlFragCoordXYZCase&); // not allowed! |
| BuiltinGlFragCoordXYZCase& operator= (const BuiltinGlFragCoordXYZCase&); // not allowed! |
| }; |
| |
| BuiltinGlFragCoordXYZCase::BuiltinGlFragCoordXYZCase (TestContext& testCtx, const string& name, const string& description) |
| : TestCase(testCtx, name, description) |
| { |
| } |
| |
| BuiltinGlFragCoordXYZCase::~BuiltinGlFragCoordXYZCase (void) |
| { |
| } |
| |
| void BuiltinGlFragCoordXYZCase::initPrograms (SourceCollections& dst) const |
| { |
| dst.glslSources.add("vert") << glu::VertexSource( |
| "#version 310 es\n" |
| "layout(location = 0) in highp vec4 a_position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| "}\n"); |
| |
| dst.glslSources.add("frag") << glu::FragmentSource( |
| "#version 310 es\n" |
| "layout(set=0, binding=0) uniform Scale { highp vec3 u_scale; };\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " o_color = vec4(gl_FragCoord.xyz * u_scale, 1.0);\n" |
| "}\n"); |
| } |
| |
| TestInstance* BuiltinGlFragCoordXYZCase::createInstance (Context& context) const |
| { |
| return new BuiltinGlFragCoordXYZCaseInstance(context); |
| } |
| |
| inline float projectedTriInterpolate (const Vec3& s, const Vec3& w, float nx, float ny) |
| { |
| return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]); |
| } |
| |
| class BuiltinGlFragCoordWCaseInstance : public ShaderRenderCaseInstance |
| { |
| public: |
| BuiltinGlFragCoordWCaseInstance (Context& context); |
| |
| TestStatus iterate (void); |
| virtual void setupDefaultInputs (void); |
| |
| private: |
| |
| const Vec4 m_w; |
| |
| }; |
| |
| BuiltinGlFragCoordWCaseInstance::BuiltinGlFragCoordWCaseInstance (Context& context) |
| : ShaderRenderCaseInstance (context) |
| , m_w (1.7f, 2.0f, 1.2f, 1.0f) |
| { |
| m_colorFormat = VK_FORMAT_R16G16B16A16_UNORM; |
| } |
| |
| TestStatus BuiltinGlFragCoordWCaseInstance::iterate (void) |
| { |
| const UVec2 viewportSize = getViewportSize(); |
| const int width = viewportSize.x(); |
| const int height = viewportSize.y(); |
| const float precision = 0.00001f; |
| const deUint16 indices[6] = |
| { |
| 2, 1, 3, |
| 0, 1, 2, |
| }; |
| |
| setup(); |
| render(4, 2, indices); |
| |
| // Reference image |
| for (int y = 0; y < height; y++) |
| { |
| for (int x = 0; x < width; x++) |
| { |
| const float xf = (float(x) + .5f) / float(width); |
| const float yf = (float(height - y - 1) +.5f) / float(height); |
| const float oow = ((xf + yf) < 1.0f) |
| ? projectedTriInterpolate(Vec3(m_w[0], m_w[1], m_w[2]), Vec3(m_w[0], m_w[1], m_w[2]), xf, yf) |
| : projectedTriInterpolate(Vec3(m_w[3], m_w[2], m_w[1]), Vec3(m_w[3], m_w[2], m_w[1]), 1.0f - xf, 1.0f - yf); |
| const Vec4 color (0.0f, oow - 1.0f, 0.0f, 1.0f); |
| const Vec4 resultColor = getResultImage().getAccess().getPixel(x, y); |
| |
| if (de::abs(color.x() - resultColor.x()) > precision || |
| de::abs(color.y() - resultColor.y()) > precision || |
| de::abs(color.z() - resultColor.z()) > precision) |
| return TestStatus::fail("Image mismatch"); |
| } |
| } |
| |
| return TestStatus::pass("Result image matches reference"); |
| } |
| |
| void BuiltinGlFragCoordWCaseInstance::setupDefaultInputs (void) |
| { |
| const float vertices[] = |
| { |
| -m_w[0], m_w[0], 0.0f, m_w[0], |
| -m_w[1], -m_w[1], 0.0f, m_w[1], |
| m_w[2], m_w[2], 0.0f, m_w[2], |
| m_w[3], -m_w[3], 0.0f, m_w[3] |
| }; |
| |
| addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 4, vertices); |
| } |
| |
| class BuiltinGlFragCoordWCase : public TestCase |
| { |
| public: |
| BuiltinGlFragCoordWCase (TestContext& testCtx, const string& name, const string& description); |
| virtual ~BuiltinGlFragCoordWCase (void); |
| |
| void initPrograms (SourceCollections& dst) const; |
| TestInstance* createInstance (Context& context) const; |
| |
| private: |
| BuiltinGlFragCoordWCase (const BuiltinGlFragCoordWCase&); // not allowed! |
| BuiltinGlFragCoordWCase& operator= (const BuiltinGlFragCoordWCase&); // not allowed! |
| }; |
| |
| BuiltinGlFragCoordWCase::BuiltinGlFragCoordWCase (TestContext& testCtx, const string& name, const string& description) |
| : TestCase(testCtx, name, description) |
| { |
| } |
| |
| BuiltinGlFragCoordWCase::~BuiltinGlFragCoordWCase (void) |
| { |
| } |
| |
| void BuiltinGlFragCoordWCase::initPrograms (SourceCollections& dst) const |
| { |
| dst.glslSources.add("vert") << glu::VertexSource( |
| "#version 310 es\n" |
| "layout(location = 0) in highp vec4 a_position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| "}\n"); |
| |
| dst.glslSources.add("frag") << glu::FragmentSource( |
| "#version 310 es\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " o_color = vec4(0.0, 1.0 / gl_FragCoord.w - 1.0, 0.0, 1.0);\n" |
| "}\n"); |
| } |
| |
| TestInstance* BuiltinGlFragCoordWCase::createInstance (Context& context) const |
| { |
| return new BuiltinGlFragCoordWCaseInstance(context); |
| } |
| |
| class BuiltinGlPointCoordCaseInstance : public ShaderRenderCaseInstance |
| { |
| public: |
| BuiltinGlPointCoordCaseInstance (Context& context); |
| |
| TestStatus iterate (void); |
| virtual void setupDefaultInputs (void); |
| }; |
| |
| BuiltinGlPointCoordCaseInstance::BuiltinGlPointCoordCaseInstance (Context& context) |
| : ShaderRenderCaseInstance (context) |
| { |
| } |
| |
| TestStatus BuiltinGlPointCoordCaseInstance::iterate (void) |
| { |
| const UVec2 viewportSize = getViewportSize(); |
| const int width = viewportSize.x(); |
| const int height = viewportSize.y(); |
| const float threshold = 0.02f; |
| const int numPoints = 16; |
| vector<Vec3> coords (numPoints); |
| de::Random rnd (0x145fa); |
| Surface resImage (width, height); |
| Surface refImage (width, height); |
| bool compareOk = false; |
| |
| // Compute coordinates. |
| { |
| const VkPhysicalDeviceLimits& limits = m_context.getDeviceProperties().limits; |
| const float minPointSize = limits.pointSizeRange[0]; |
| const float maxPointSize = limits.pointSizeRange[1]; |
| const int pointSizeDeltaMultiples = de::max(1, deCeilFloatToInt32((maxPointSize - minPointSize) / limits.pointSizeGranularity)); |
| |
| TCU_CHECK(minPointSize <= maxPointSize); |
| |
| for (vector<Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord) |
| { |
| coord->x() = rnd.getFloat(-0.9f, 0.9f); |
| coord->y() = rnd.getFloat(-0.9f, 0.9f); |
| coord->z() = de::min(maxPointSize, minPointSize + float(rnd.getInt(0, pointSizeDeltaMultiples)) * limits.pointSizeGranularity); |
| } |
| } |
| |
| setup(); |
| addAttribute(0u, VK_FORMAT_R32G32B32_SFLOAT, deUint32(sizeof(Vec3)), numPoints, &coords[0]); |
| render(numPoints, 0, DE_NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST); |
| copy(resImage.getAccess(), getResultImage().getAccess()); |
| |
| // Draw reference |
| clear(refImage.getAccess(), m_clearColor); |
| |
| for (vector<Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter) |
| { |
| const float centerX = float(width) *(pointIter->x()*0.5f + 0.5f); |
| const float centerY = float(height)*(pointIter->y()*0.5f + 0.5f); |
| const float size = pointIter->z(); |
| const int x0 = deRoundFloatToInt32(centerX - size*0.5f); |
| const int y0 = deRoundFloatToInt32(centerY - size*0.5f); |
| const int x1 = deRoundFloatToInt32(centerX + size*0.5f); |
| const int y1 = deRoundFloatToInt32(centerY + size*0.5f); |
| const int w = x1-x0; |
| const int h = y1-y0; |
| |
| for (int yo = 0; yo < h; yo++) |
| { |
| for (int xo = 0; xo < w; xo++) |
| { |
| const int dx = x0+xo; |
| const int dy = y0+yo; |
| const float fragX = float(dx) + 0.5f; |
| const float fragY = float(dy) + 0.5f; |
| const float s = 0.5f + (fragX - centerX) / size; |
| const float t = 0.5f + (fragY - centerY) / size; |
| const Vec4 color (s, t, 0.0f, 1.0f); |
| |
| if (de::inBounds(dx, 0, refImage.getWidth()) && de::inBounds(dy, 0, refImage.getHeight())) |
| refImage.setPixel(dx, dy, RGBA(color)); |
| } |
| } |
| } |
| |
| compareOk = fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT); |
| |
| if (compareOk) |
| return TestStatus::pass("Result image matches reference"); |
| else |
| return TestStatus::fail("Image mismatch"); |
| } |
| |
| void BuiltinGlPointCoordCaseInstance::setupDefaultInputs (void) |
| { |
| } |
| |
| class BuiltinGlPointCoordCase : public TestCase |
| { |
| public: |
| BuiltinGlPointCoordCase (TestContext& testCtx, const string& name, const string& description); |
| virtual ~BuiltinGlPointCoordCase (void); |
| |
| void initPrograms (SourceCollections& dst) const; |
| TestInstance* createInstance (Context& context) const; |
| |
| private: |
| BuiltinGlPointCoordCase (const BuiltinGlPointCoordCase&); // not allowed! |
| BuiltinGlPointCoordCase& operator= (const BuiltinGlPointCoordCase&); // not allowed! |
| }; |
| |
| BuiltinGlPointCoordCase::BuiltinGlPointCoordCase (TestContext& testCtx, const string& name, const string& description) |
| : TestCase(testCtx, name, description) |
| { |
| } |
| |
| BuiltinGlPointCoordCase::~BuiltinGlPointCoordCase (void) |
| { |
| } |
| |
| void BuiltinGlPointCoordCase::initPrograms (SourceCollections& dst) const |
| { |
| dst.glslSources.add("vert") << glu::VertexSource( |
| "#version 310 es\n" |
| "layout(location = 0) in highp vec3 a_position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = vec4(a_position.xy, 0.0, 1.0);\n" |
| " gl_PointSize = a_position.z;\n" |
| "}\n"); |
| |
| dst.glslSources.add("frag") << glu::FragmentSource( |
| "#version 310 es\n" |
| "layout(location = 0) out lowp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " o_color = vec4(gl_PointCoord, 0.0, 1.0);\n" |
| "}\n"); |
| } |
| |
| TestInstance* BuiltinGlPointCoordCase::createInstance (Context& context) const |
| { |
| return new BuiltinGlPointCoordCaseInstance(context); |
| } |
| |
| enum ShaderInputTypeBits |
| { |
| SHADER_INPUT_BUILTIN_BIT = 0x01, |
| SHADER_INPUT_VARYING_BIT = 0x02, |
| SHADER_INPUT_CONSTANT_BIT = 0x04 |
| }; |
| |
| typedef deUint16 ShaderInputTypes; |
| |
| string shaderInputTypeToString (ShaderInputTypes type) |
| { |
| string typeString = "input"; |
| |
| if (type == 0) |
| return "input_none"; |
| |
| if (type & SHADER_INPUT_BUILTIN_BIT) |
| typeString += "_builtin"; |
| |
| if (type & SHADER_INPUT_VARYING_BIT) |
| typeString += "_varying"; |
| |
| if (type & SHADER_INPUT_CONSTANT_BIT) |
| typeString += "_constant"; |
| |
| return typeString; |
| } |
| |
| class BuiltinInputVariationsCaseInstance : public ShaderRenderCaseInstance |
| { |
| public: |
| BuiltinInputVariationsCaseInstance (Context& context, const ShaderInputTypes shaderInputTypes); |
| |
| TestStatus iterate (void); |
| virtual void setupDefaultInputs (void); |
| virtual void updatePushConstants (vk::VkCommandBuffer commandBuffer, vk::VkPipelineLayout pipelineLayout); |
| |
| private: |
| const ShaderInputTypes m_shaderInputTypes; |
| const Vec4 m_constantColor; |
| }; |
| |
| BuiltinInputVariationsCaseInstance::BuiltinInputVariationsCaseInstance (Context& context, const ShaderInputTypes shaderInputTypes) |
| : ShaderRenderCaseInstance (context) |
| , m_shaderInputTypes (shaderInputTypes) |
| , m_constantColor (0.1f, 0.05f, 0.2f, 0.0f) |
| { |
| } |
| |
| TestStatus BuiltinInputVariationsCaseInstance::iterate (void) |
| { |
| const UVec2 viewportSize = getViewportSize(); |
| const int width = viewportSize.x(); |
| const int height = viewportSize.y(); |
| const tcu::RGBA threshold (2, 2, 2, 2); |
| Surface resImage (width, height); |
| Surface refImage (width, height); |
| bool compareOk = false; |
| const VkPushConstantRange pcRanges = |
| { |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags; |
| 0u, // deUint32 offset; |
| sizeof(Vec4) // deUint32 size; |
| }; |
| const deUint16 indices[12] = |
| { |
| 0, 4, 1, |
| 0, 5, 4, |
| 1, 2, 3, |
| 1, 3, 4 |
| }; |
| |
| setup(); |
| |
| if (m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT) |
| setPushConstantRanges(1, &pcRanges); |
| |
| render(6, 4, indices); |
| copy(resImage.getAccess(), getResultImage().getAccess()); |
| |
| // Reference image |
| for (int y = 0; y < refImage.getHeight(); y++) |
| { |
| for (int x = 0; x < refImage.getWidth(); x++) |
| { |
| Vec4 color (0.1f, 0.2f, 0.3f, 1.0f); |
| |
| if (((m_shaderInputTypes & SHADER_INPUT_BUILTIN_BIT) && (x < refImage.getWidth() / 2)) || |
| !(m_shaderInputTypes & SHADER_INPUT_BUILTIN_BIT)) |
| { |
| if (m_shaderInputTypes & SHADER_INPUT_VARYING_BIT) |
| { |
| const float xf = (float(x)+.5f) / float(refImage.getWidth()); |
| color += Vec4(0.6f * (1 - xf), 0.6f * xf, 0.0f, 0.0f); |
| } |
| else |
| color += Vec4(0.3f, 0.2f, 0.1f, 0.0f); |
| } |
| |
| if (m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT) |
| color += m_constantColor; |
| |
| refImage.setPixel(x, y, RGBA(color)); |
| } |
| } |
| |
| compareOk = pixelThresholdCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT); |
| |
| if (compareOk) |
| return TestStatus::pass("Result image matches reference"); |
| else |
| return TestStatus::fail("Image mismatch"); |
| } |
| |
| void BuiltinInputVariationsCaseInstance::setupDefaultInputs (void) |
| { |
| const float vertices[] = |
| { |
| -1.0f, -1.0f, 0.0f, 1.0f, |
| 0.0f, -1.0f, 0.0f, 1.0f, |
| 1.0f, -1.0f, 0.0f, 1.0f, |
| 1.0f, 1.0f, 0.0f, 1.0f, |
| 0.0f, 1.0f, 0.0f, 1.0f, |
| -1.0f, 1.0f, 0.0f, 1.0f |
| }; |
| |
| addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 6, vertices); |
| |
| if (m_shaderInputTypes & SHADER_INPUT_VARYING_BIT) |
| { |
| const float colors[] = |
| { |
| 0.6f, 0.0f, 0.0f, 1.0f, |
| 0.3f, 0.3f, 0.0f, 1.0f, |
| 0.0f, 0.6f, 0.0f, 1.0f, |
| 0.0f, 0.6f, 0.0f, 1.0f, |
| 0.3f, 0.3f, 0.0f, 1.0f, |
| 0.6f, 0.0f, 0.0f, 1.0f |
| }; |
| addAttribute(1u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 6, colors); |
| } |
| } |
| |
| void BuiltinInputVariationsCaseInstance::updatePushConstants (vk::VkCommandBuffer commandBuffer, vk::VkPipelineLayout pipelineLayout) |
| { |
| if (m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| vk.cmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(Vec4), &m_constantColor); |
| } |
| } |
| |
| class BuiltinInputVariationsCase : public TestCase |
| { |
| public: |
| BuiltinInputVariationsCase (TestContext& testCtx, const string& name, const string& description, const ShaderInputTypes shaderInputTypes); |
| virtual ~BuiltinInputVariationsCase (void); |
| |
| void initPrograms (SourceCollections& dst) const; |
| TestInstance* createInstance (Context& context) const; |
| |
| private: |
| BuiltinInputVariationsCase (const BuiltinInputVariationsCase&); // not allowed! |
| BuiltinInputVariationsCase& operator= (const BuiltinInputVariationsCase&); // not allowed! |
| const ShaderInputTypes m_shaderInputTypes; |
| }; |
| |
| BuiltinInputVariationsCase::BuiltinInputVariationsCase (TestContext& testCtx, const string& name, const string& description, ShaderInputTypes shaderInputTypes) |
| : TestCase (testCtx, name, description) |
| , m_shaderInputTypes (shaderInputTypes) |
| { |
| } |
| |
| BuiltinInputVariationsCase::~BuiltinInputVariationsCase (void) |
| { |
| } |
| |
| void BuiltinInputVariationsCase::initPrograms (SourceCollections& dst) const |
| { |
| map<string, string> vertexParams; |
| map<string, string> fragmentParams; |
| const tcu::StringTemplate vertexCodeTemplate ( |
| "#version 450\n" |
| "layout(location = 0) in highp vec4 a_position;\n" |
| "out gl_PerVertex {\n" |
| " vec4 gl_Position;\n" |
| "};\n" |
| "${VARYING_DECL}" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " ${VARYING_USAGE}" |
| "}\n"); |
| |
| const tcu::StringTemplate fragmentCodeTemplate ( |
| "#version 450\n" |
| "${VARYING_DECL}" |
| "${CONSTANT_DECL}" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " o_color = vec4(0.1, 0.2, 0.3, 1.0);\n" |
| " ${BUILTIN_USAGE}" |
| " ${VARYING_USAGE}" |
| " ${CONSTANT_USAGE}" |
| "}\n"); |
| |
| vertexParams["VARYING_DECL"] = |
| m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "layout(location = 1) in highp vec4 a_color;\n" |
| "layout(location = 0) out highp vec4 v_color;\n" |
| : ""; |
| |
| vertexParams["VARYING_USAGE"] = |
| m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "v_color = a_color;\n" |
| : ""; |
| |
| fragmentParams["VARYING_DECL"] = |
| m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "layout(location = 0) in highp vec4 a_color;\n" |
| : ""; |
| |
| fragmentParams["CONSTANT_DECL"] = |
| m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT ? "layout(push_constant) uniform PCBlock {\n" |
| " vec4 color;\n" |
| "} pc;\n" |
| : ""; |
| |
| fragmentParams["BUILTIN_USAGE"] = |
| m_shaderInputTypes & SHADER_INPUT_BUILTIN_BIT ? "if (gl_FrontFacing)\n" |
| : ""; |
| |
| fragmentParams["VARYING_USAGE"] = |
| m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "o_color += vec4(a_color.xyz, 0.0);\n" |
| : "o_color += vec4(0.3, 0.2, 0.1, 0.0);\n"; |
| |
| |
| fragmentParams["CONSTANT_USAGE"] = |
| m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT ? "o_color += pc.color;\n" |
| : ""; |
| |
| dst.glslSources.add("vert") << glu::VertexSource(vertexCodeTemplate.specialize(vertexParams)); |
| dst.glslSources.add("frag") << glu::FragmentSource(fragmentCodeTemplate.specialize(fragmentParams)); |
| } |
| |
| TestInstance* BuiltinInputVariationsCase::createInstance (Context& context) const |
| { |
| return new BuiltinInputVariationsCaseInstance(context, m_shaderInputTypes); |
| } |
| |
| } // anonymous |
| |
| TestCaseGroup* createBuiltinVarTests (TestContext& testCtx) |
| { |
| de::MovePtr<TestCaseGroup> builtinGroup (new TestCaseGroup(testCtx, "builtin_var", "Shader builtin variable tests.")); |
| de::MovePtr<TestCaseGroup> simpleGroup (new TestCaseGroup(testCtx, "simple", "Simple cases.")); |
| de::MovePtr<TestCaseGroup> inputVariationsGroup (new TestCaseGroup(testCtx, "input_variations", "Input type variation tests.")); |
| de::MovePtr<TestCaseGroup> frontFacingGroup (new TestCaseGroup(testCtx, "frontfacing", "Test gl_Frontfacing keyword.")); |
| de::MovePtr<TestCaseGroup> fragDepthGroup (new TestCaseGroup(testCtx, "fragdepth", "Test gl_FragDepth keyword.")); |
| de::MovePtr<TestCaseGroup> fragCoordMsaaGroup (new TestCaseGroup(testCtx, "fragcoord_msaa", "Test interation between gl_FragCoord and msaa")); |
| |
| simpleGroup->addChild(new BuiltinGlFragCoordXYZCase(testCtx, "fragcoord_xyz", "FragCoord xyz test")); |
| simpleGroup->addChild(new BuiltinGlFragCoordWCase(testCtx, "fragcoord_w", "FragCoord w test")); |
| simpleGroup->addChild(new BuiltinGlPointCoordCase(testCtx, "pointcoord", "PointCoord test")); |
| |
| // FragCoord_msaa |
| { |
| static const struct FragCoordMsaaCaseList |
| { |
| const char* name; |
| const char* description; |
| VkSampleCountFlagBits sampleCount; |
| } fragCoordMsaaCaseList[] = |
| { |
| { "1_bit", "Test FragCoord locations with 2 samples", VK_SAMPLE_COUNT_1_BIT }, |
| { "2_bit", "Test FragCoord locations with 2 samples", VK_SAMPLE_COUNT_2_BIT }, |
| { "4_bit", "Test FragCoord locations with 4 samples", VK_SAMPLE_COUNT_4_BIT }, |
| { "8_bit", "Test FragCoord locations with 8 samples", VK_SAMPLE_COUNT_8_BIT }, |
| { "16_bit", "Test FragCoord locations with 16 samples", VK_SAMPLE_COUNT_16_BIT }, |
| { "32_bit", "Test FragCoord locations with 32 samples", VK_SAMPLE_COUNT_32_BIT }, |
| { "64-bit", "Test FragCoord locaitons with 64 samples", VK_SAMPLE_COUNT_64_BIT } |
| }; |
| |
| for (deUint32 caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(fragCoordMsaaCaseList); caseNdx++) |
| fragCoordMsaaGroup->addChild(new BuiltinFragCoordMsaaTestCase(testCtx, fragCoordMsaaCaseList[caseNdx].name, fragCoordMsaaCaseList[caseNdx].description, fragCoordMsaaCaseList[caseNdx].sampleCount)); |
| } |
| |
| // gl_FrontFacing tests |
| { |
| static const struct PrimitiveTable |
| { |
| const char* name; |
| const char* desc; |
| VkPrimitiveTopology primitive; |
| } frontfacingCases[] = |
| { |
| { "point_list", "Test that points are frontfacing", VK_PRIMITIVE_TOPOLOGY_POINT_LIST }, |
| { "line_list", "Test that lines are frontfacing", VK_PRIMITIVE_TOPOLOGY_LINE_LIST }, |
| { "triangle_list", "Test that triangles can be frontfacing or backfacing", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST }, |
| { "triangle_strip", "Test that traiangle strips can be front or back facing", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }, |
| { "triangle_fan", "Test that triangle fans can be front or back facing", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN }, |
| }; |
| |
| for (deUint32 ndx = 0; ndx < DE_LENGTH_OF_ARRAY(frontfacingCases); ndx++) |
| frontFacingGroup->addChild(new BuiltinGlFrontFacingCase(testCtx, frontfacingCases[ndx].primitive, frontfacingCases[ndx].name, frontfacingCases[ndx].desc)); |
| } |
| |
| // gl_FragDepth |
| { |
| static const struct PrimitiveTopologyTable |
| { |
| std::string name; |
| std::string desc; |
| VkPrimitiveTopology prim; |
| } primitiveTopologyTable[] = |
| { |
| { "point_list", "test that points respect gl_fragdepth", VK_PRIMITIVE_TOPOLOGY_POINT_LIST }, |
| { "line_list", "test taht lines respect gl_fragdepth", VK_PRIMITIVE_TOPOLOGY_LINE_LIST }, |
| { "triangle_list", "test that triangles respect gl_fragdepth", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }, |
| }; |
| |
| static const struct TestCaseTable |
| { |
| VkFormat format; |
| std::string name; |
| bool largeDepthEnable; |
| bool depthClampEnable; |
| VkSampleCountFlagBits samples; |
| } testCaseTable[] = |
| { |
| { VK_FORMAT_D16_UNORM, "d16_unorm_no_depth_clamp", false, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_X8_D24_UNORM_PACK32, "x8_d24_unorm_pack32_no_depth_clamp", false, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_no_depth_clamp", false, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D16_UNORM_S8_UINT, "d16_unorm_s8_uint_no_depth_clamp", false, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D24_UNORM_S8_UINT, "d24_unorm_s8_uint_no_depth_clamp", false, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D32_SFLOAT_S8_UINT, "d32_sfloat_s8_uint_no_depth_clamp", false, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_large_depth", true, false, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat", false, true, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D32_SFLOAT_S8_UINT, "d32_sfloat_s8_uint", false, true, VK_SAMPLE_COUNT_1_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_multisample_2", false, false, VK_SAMPLE_COUNT_2_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_multisample_4", false, false, VK_SAMPLE_COUNT_4_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_multisample_8", false, false, VK_SAMPLE_COUNT_8_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_multisample_16", false, false, VK_SAMPLE_COUNT_16_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_multisample_32", false, false, VK_SAMPLE_COUNT_32_BIT }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat_multisample_64", false, false, VK_SAMPLE_COUNT_64_BIT }, |
| }; |
| |
| for (deUint32 primNdx = 0; primNdx < DE_LENGTH_OF_ARRAY(primitiveTopologyTable); primNdx++) |
| { |
| for (deUint32 caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCaseTable); caseNdx++) |
| fragDepthGroup->addChild(new BuiltinFragDepthCase(testCtx, (primitiveTopologyTable[primNdx].name+"_" + testCaseTable[caseNdx].name).c_str(), primitiveTopologyTable[primNdx].desc.c_str(), |
| primitiveTopologyTable[primNdx].prim, testCaseTable[caseNdx].format, testCaseTable[caseNdx].largeDepthEnable, testCaseTable[caseNdx].depthClampEnable, testCaseTable[caseNdx].samples)); |
| |
| } |
| } |
| |
| builtinGroup->addChild(frontFacingGroup.release()); |
| builtinGroup->addChild(fragDepthGroup.release()); |
| builtinGroup->addChild(fragCoordMsaaGroup.release()); |
| builtinGroup->addChild(simpleGroup.release()); |
| |
| for (deUint16 shaderType = 0; shaderType <= (SHADER_INPUT_BUILTIN_BIT | SHADER_INPUT_VARYING_BIT | SHADER_INPUT_CONSTANT_BIT); ++shaderType) |
| { |
| inputVariationsGroup->addChild(new BuiltinInputVariationsCase(testCtx, shaderInputTypeToString(shaderType), "Input variation test", shaderType)); |
| } |
| |
| builtinGroup->addChild(inputVariationsGroup.release()); |
| return builtinGroup.release(); |
| } |
| |
| } // sr |
| } // vkt |