| /*------------------------------------------------------------------------- |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2017 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 Tests for render pass multisample resolve |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktRenderPassMultisampleResolveTests.hpp" |
| #include "vktRenderPassTestsUtil.hpp" |
| |
| #include "vktTestCaseUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| |
| #include "vkDefs.hpp" |
| #include "vkDeviceUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkPlatform.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkRef.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkObjUtil.hpp" |
| |
| #include "tcuFloat.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuFormatUtil.hpp" |
| #include "tcuMaybe.hpp" |
| #include "tcuResultCollector.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuStringTemplate.hpp" |
| |
| #include "deUniquePtr.hpp" |
| #include "deSharedPtr.hpp" |
| |
| using namespace vk; |
| |
| using tcu::BVec4; |
| using tcu::IVec2; |
| using tcu::IVec4; |
| using tcu::UVec2; |
| using tcu::UVec4; |
| using tcu::Vec2; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| |
| using tcu::ConstPixelBufferAccess; |
| using tcu::PixelBufferAccess; |
| using tcu::TestLog; |
| |
| using std::vector; |
| |
| typedef de::SharedPtr<Allocation> AllocationSp; |
| typedef de::SharedPtr<vk::Unique<VkImage> > VkImageSp; |
| typedef de::SharedPtr<vk::Unique<VkImageView> > VkImageViewSp; |
| typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp; |
| typedef de::SharedPtr<vk::Unique<VkSampler> > VkSamplerSp; |
| typedef de::SharedPtr<vk::Unique<VkPipeline> > VkPipelineSp; |
| typedef de::SharedPtr<vk::Unique<VkDescriptorSetLayout> > VkDescriptorSetLayoutSp; |
| typedef de::SharedPtr<vk::Unique<VkDescriptorPool> > VkDescriptorPoolSp; |
| typedef de::SharedPtr<vk::Unique<VkDescriptorSet> > VkDescriptorSetSp; |
| |
| namespace vkt |
| { |
| namespace |
| { |
| |
| using namespace renderpass; |
| |
| template<typename T> |
| de::SharedPtr<T> safeSharedPtr (T* ptr) |
| { |
| try |
| { |
| return de::SharedPtr<T>(ptr); |
| } |
| catch (...) |
| { |
| delete ptr; |
| throw; |
| } |
| } |
| |
| enum TestType |
| { |
| RESOLVE = 0, |
| MAX_ATTACHMENTS, |
| COMPATIBILITY |
| }; |
| |
| struct TestConfig |
| { |
| TestType testType; |
| VkFormat format; |
| deUint32 sampleCount; |
| deUint32 layerCount; |
| deUint32 attachmentCount; |
| deUint32 width; |
| deUint32 height; |
| RenderingType renderingType; |
| }; |
| |
| struct TestConfig2 : TestConfig |
| { |
| TestConfig2(const TestConfig& src, deUint32 level) |
| : TestConfig (src) |
| , resolveLevel (level) |
| { |
| } |
| deUint32 resolveLevel; |
| }; |
| |
| // Render pass traits that groups render pass related types together and by that help |
| // to reduce number of template parrameters passed to number of functions in those tests |
| struct RenderPass1Trait |
| { |
| typedef AttachmentDescription1 AttDesc; |
| typedef AttachmentReference1 AttRef; |
| typedef SubpassDescription1 SubpassDesc; |
| typedef SubpassDependency1 SubpassDep; |
| typedef RenderPassCreateInfo1 RenderPassCreateInfo; |
| }; |
| struct RenderPass2Trait |
| { |
| typedef AttachmentDescription2 AttDesc; |
| typedef AttachmentReference2 AttRef; |
| typedef SubpassDescription2 SubpassDesc; |
| typedef SubpassDependency2 SubpassDep; |
| typedef RenderPassCreateInfo2 RenderPassCreateInfo; |
| }; |
| |
| class MultisampleRenderPassTestBase : public TestInstance |
| { |
| public: |
| MultisampleRenderPassTestBase (Context& context, TestConfig config); |
| ~MultisampleRenderPassTestBase (void); |
| |
| protected: |
| |
| Move<VkImage> createImage (VkSampleCountFlagBits sampleCountBit, |
| VkImageUsageFlags usage) const; |
| Move<VkImage> createImage (VkSampleCountFlagBits sampleCountBit, |
| VkImageUsageFlags usage, |
| deUint32 width, |
| deUint32 height, |
| deUint32 mipLevels) const; |
| vector<VkImageSp> createImages (VkSampleCountFlagBits sampleCountBit, |
| VkImageUsageFlags usage) const; |
| vector<VkImageSp> createImages (VkSampleCountFlagBits sampleCountBit, |
| VkImageUsageFlags usage, |
| deUint32 width, |
| deUint32 height, |
| deUint32 mipLevels) const; |
| vector<AllocationSp> createImageMemory (const vector<VkImageSp>& images) const; |
| vector<VkImageViewSp> createImageViews (const vector<VkImageSp>& images, |
| deUint32 mipLevel = 0) const; |
| |
| vector<VkBufferSp> createBuffers () const; |
| vector<VkBufferSp> createBuffers (deUint32 width, |
| deUint32 height, |
| deUint32 mipLevels) const; |
| vector<AllocationSp> createBufferMemory (const vector<VkBufferSp>& buffers) const; |
| |
| Move<VkFramebuffer> createFramebuffer (const std::vector<VkImageViewSp> multisampleImageViews, |
| const std::vector<VkImageViewSp> singlesampleImageViews, |
| VkRenderPass renderPass) const; |
| |
| void clearAttachments (VkCommandBuffer commandBuffer) const; |
| VkDeviceSize getPixelSize () const; |
| tcu::Vec4 getFormatThreshold () const; |
| VkSampleCountFlagBits sampleCountBitFromSampleCount (deUint32 count) const; |
| void logImage (const std::string& name, |
| const tcu::ConstPixelBufferAccess& image) const; |
| |
| protected: |
| |
| const bool m_testCompatibility; |
| const RenderingType m_renderingType; |
| |
| const VkFormat m_format; |
| const VkSampleCountFlagBits m_sampleCount; |
| const deUint32 m_layerCount; |
| const deUint32 m_attachmentsCount; |
| const deUint32 m_width; |
| const deUint32 m_height; |
| }; |
| |
| MultisampleRenderPassTestBase::MultisampleRenderPassTestBase (Context& context, TestConfig config) |
| : TestInstance (context) |
| , m_testCompatibility (config.testType == COMPATIBILITY) |
| , m_renderingType (config.renderingType) |
| , m_format (config.format) |
| , m_sampleCount (sampleCountBitFromSampleCount(config.sampleCount)) |
| , m_layerCount (config.layerCount) |
| , m_attachmentsCount (config.attachmentCount) |
| , m_width (config.width) |
| , m_height (config.height) |
| { |
| } |
| |
| MultisampleRenderPassTestBase::~MultisampleRenderPassTestBase () |
| { |
| } |
| |
| Move<VkImage> MultisampleRenderPassTestBase::createImage (VkSampleCountFlagBits sampleCountBit, VkImageUsageFlags usage) const |
| { |
| return createImage(sampleCountBit, usage, m_width, m_height, 1u); |
| } |
| |
| Move<VkImage> MultisampleRenderPassTestBase::createImage (VkSampleCountFlagBits sampleCountBit, |
| VkImageUsageFlags usage, |
| deUint32 width, |
| deUint32 height, |
| deUint32 mipLevels) const |
| { |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const VkImageType imageType (VK_IMAGE_TYPE_2D); |
| const VkImageTiling imageTiling (VK_IMAGE_TILING_OPTIMAL); |
| const VkFormatProperties formatProperties (getPhysicalDeviceFormatProperties(vki, physicalDevice, m_format)); |
| const VkExtent3D imageExtent = |
| { |
| width, |
| height, |
| 1u |
| }; |
| |
| try |
| { |
| const VkImageFormatProperties imageFormatProperties(getPhysicalDeviceImageFormatProperties(vki, physicalDevice, m_format, imageType, imageTiling, usage, 0u)); |
| |
| if ((tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) |
| && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) |
| TCU_THROW(NotSupportedError, "Format can't be used as depth stencil attachment"); |
| |
| if (!(tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) |
| && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) |
| TCU_THROW(NotSupportedError, "Format can't be used as color attachment"); |
| |
| if (imageFormatProperties.maxExtent.width < imageExtent.width |
| || imageFormatProperties.maxExtent.height < imageExtent.height |
| || ((imageFormatProperties.sampleCounts & m_sampleCount) == 0) |
| || imageFormatProperties.maxArrayLayers < m_layerCount) |
| { |
| TCU_THROW(NotSupportedError, "Image type not supported"); |
| } |
| |
| const VkImageCreateInfo pCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| imageType, |
| m_format, |
| imageExtent, |
| mipLevels, |
| m_layerCount, |
| sampleCountBit, |
| imageTiling, |
| usage, |
| VK_SHARING_MODE_EXCLUSIVE, |
| 0u, |
| DE_NULL, |
| VK_IMAGE_LAYOUT_UNDEFINED |
| }; |
| |
| return ::createImage(vkd, device, &pCreateInfo); |
| } |
| catch (const vk::Error& error) |
| { |
| if (error.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| TCU_THROW(NotSupportedError, "Image format not supported"); |
| |
| throw; |
| } |
| } |
| |
| vector<VkImageSp> MultisampleRenderPassTestBase::createImages (VkSampleCountFlagBits sampleCountBit, VkImageUsageFlags usage) const |
| { |
| std::vector<VkImageSp> images (m_attachmentsCount); |
| for (size_t imageNdx = 0; imageNdx < m_attachmentsCount; imageNdx++) |
| images[imageNdx] = safeSharedPtr(new Unique<VkImage>(createImage(sampleCountBit, usage))); |
| return images; |
| } |
| |
| vector<VkImageSp> MultisampleRenderPassTestBase::createImages (VkSampleCountFlagBits sampleCountBit, |
| VkImageUsageFlags usage, |
| deUint32 width, |
| deUint32 height, |
| deUint32 mipLevels) const |
| { |
| std::vector<VkImageSp> images (m_attachmentsCount); |
| for (size_t imageNdx = 0; imageNdx < m_attachmentsCount; imageNdx++) |
| images[imageNdx] = safeSharedPtr(new Unique<VkImage>(createImage(sampleCountBit, usage, width, height, mipLevels))); |
| return images; |
| } |
| |
| vector<AllocationSp> MultisampleRenderPassTestBase::createImageMemory (const vector<VkImageSp>& images) const |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| std::vector<AllocationSp> memory (images.size()); |
| |
| for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++) |
| { |
| VkImage image = **images[memoryNdx]; |
| VkMemoryRequirements requirements = getImageMemoryRequirements(vkd, device, image); |
| |
| de::MovePtr<Allocation> allocation (allocator.allocate(requirements, MemoryRequirement::Any)); |
| VK_CHECK(vkd.bindImageMemory(device, image, allocation->getMemory(), allocation->getOffset())); |
| memory[memoryNdx] = safeSharedPtr(allocation.release()); |
| } |
| return memory; |
| } |
| |
| vector<VkImageViewSp> MultisampleRenderPassTestBase::createImageViews (const vector<VkImageSp>& images, deUint32 mipLevel) const |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| std::vector<VkImageViewSp> views (images.size()); |
| const VkImageSubresourceRange range = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| mipLevel, |
| 1u, |
| 0u, |
| m_layerCount |
| }; |
| |
| for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) |
| { |
| const VkImageViewCreateInfo pCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| **images[imageNdx], |
| VK_IMAGE_VIEW_TYPE_2D_ARRAY, |
| m_format, |
| makeComponentMappingRGBA(), |
| range, |
| }; |
| views[imageNdx] = safeSharedPtr(new Unique<VkImageView>(createImageView(vkd, device, &pCreateInfo))); |
| } |
| |
| return views; |
| } |
| |
| vector<VkBufferSp> MultisampleRenderPassTestBase::createBuffers () const |
| { |
| return createBuffers(m_width, m_height, 1u); |
| } |
| |
| vector<VkBufferSp> MultisampleRenderPassTestBase::createBuffers (deUint32 width, deUint32 height, deUint32 mipLevels) const |
| { |
| DE_ASSERT(mipLevels); |
| |
| VkDeviceSize size = 0; |
| for (deUint32 level = 0; level < mipLevels; ++level) |
| { |
| DE_ASSERT(width && height); |
| |
| size += (width * height); |
| height /= 2; |
| width /=2; |
| } |
| |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| std::vector<VkBufferSp> buffers (m_attachmentsCount); |
| const VkDeviceSize pixelSize (getPixelSize()); |
| const VkBufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| |
| size * m_layerCount * pixelSize, |
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| |
| VK_SHARING_MODE_EXCLUSIVE, |
| 0u, |
| DE_NULL |
| }; |
| |
| for (size_t bufferNdx = 0; bufferNdx < buffers.size(); bufferNdx++) |
| buffers[bufferNdx] = safeSharedPtr(new Unique<VkBuffer>(createBuffer(vkd, device, &createInfo))); |
| |
| return buffers; |
| } |
| |
| vector<AllocationSp> MultisampleRenderPassTestBase::createBufferMemory (const vector<VkBufferSp>& buffers) const |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| std::vector<de::SharedPtr<Allocation> > memory (buffers.size()); |
| |
| for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++) |
| { |
| VkBuffer buffer = **buffers[memoryNdx]; |
| VkMemoryRequirements requirements = getBufferMemoryRequirements(vkd, device, buffer); |
| de::MovePtr<Allocation> allocation (allocator.allocate(requirements, MemoryRequirement::HostVisible)); |
| |
| VK_CHECK(vkd.bindBufferMemory(device, buffer, allocation->getMemory(), allocation->getOffset())); |
| memory[memoryNdx] = safeSharedPtr(allocation.release()); |
| } |
| return memory; |
| } |
| |
| Move<VkFramebuffer> MultisampleRenderPassTestBase::createFramebuffer (const std::vector<VkImageViewSp> multisampleImageViews, |
| const std::vector<VkImageViewSp> singlesampleImageViews, |
| VkRenderPass renderPass) const |
| { |
| // when RenderPass was not created then we are testing dynamic rendering |
| // and we can't create framebuffer without valid RenderPass object |
| if (!renderPass) |
| return Move<VkFramebuffer>(); |
| |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| |
| std::vector<VkImageView> attachments; |
| attachments.reserve(multisampleImageViews.size() + singlesampleImageViews.size()); |
| |
| DE_ASSERT(multisampleImageViews.size() == singlesampleImageViews.size()); |
| |
| for (size_t ndx = 0; ndx < multisampleImageViews.size(); ndx++) |
| { |
| attachments.push_back(**multisampleImageViews[ndx]); |
| attachments.push_back(**singlesampleImageViews[ndx]); |
| } |
| |
| const VkFramebufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| |
| renderPass, |
| (deUint32)attachments.size(), |
| &attachments[0], |
| |
| m_width, |
| m_height, |
| m_layerCount |
| }; |
| |
| return ::createFramebuffer(vkd, device, &createInfo); |
| } |
| |
| void MultisampleRenderPassTestBase::clearAttachments (VkCommandBuffer commandBuffer) const |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); |
| VkClearValue value; |
| |
| // Clear everything to black |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| value = makeClearValueColorF32(-1.0f, -1.0f, -1.0f, -1.0f); |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| value = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 0.0f); |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| value = makeClearValueColorF32(-1.0f, -1.0f, -1.0f, -1.0f); |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| value = makeClearValueColorI32(-128, -128, -128, -128); |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| value = makeClearValueColorU32(0u, 0u, 0u, 0u); |
| break; |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| std::vector<VkClearAttachment> colors(m_attachmentsCount); |
| for (deUint32 attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| { |
| colors[attachmentNdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| colors[attachmentNdx].colorAttachment = attachmentNdx; |
| colors[attachmentNdx].clearValue = value; |
| } |
| const VkClearRect rect = |
| { |
| { |
| { 0u, 0u }, |
| { m_width, m_height } |
| }, |
| 0u, |
| m_layerCount, |
| }; |
| vkd.cmdClearAttachments(commandBuffer, deUint32(colors.size()), &colors[0], 1u, &rect); |
| } |
| |
| VkDeviceSize MultisampleRenderPassTestBase::getPixelSize () const |
| { |
| const tcu::TextureFormat format(mapVkFormat(m_format)); |
| return format.getPixelSize(); |
| } |
| |
| tcu::Vec4 MultisampleRenderPassTestBase::getFormatThreshold () const |
| { |
| const tcu::TextureFormat tcuFormat (mapVkFormat(m_format)); |
| const deUint32 componentCount (tcu::getNumUsedChannels(tcuFormat.order)); |
| |
| if (isSnormFormat(m_format)) |
| { |
| return Vec4((componentCount >= 1) ? 1.5f * getRepresentableDiffSnorm(m_format, 0) : 0.0f, |
| (componentCount >= 2) ? 1.5f * getRepresentableDiffSnorm(m_format, 1) : 0.0f, |
| (componentCount >= 3) ? 1.5f * getRepresentableDiffSnorm(m_format, 2) : 0.0f, |
| (componentCount == 4) ? 1.5f * getRepresentableDiffSnorm(m_format, 3) : 0.0f); |
| } |
| else if (isUnormFormat(m_format)) |
| { |
| return Vec4((componentCount >= 1) ? 1.5f * getRepresentableDiffUnorm(m_format, 0) : 0.0f, |
| (componentCount >= 2) ? 1.5f * getRepresentableDiffUnorm(m_format, 1) : 0.0f, |
| (componentCount >= 3) ? 1.5f * getRepresentableDiffUnorm(m_format, 2) : 0.0f, |
| (componentCount == 4) ? 1.5f * getRepresentableDiffUnorm(m_format, 3) : 0.0f); |
| } |
| else if (isFloatFormat(m_format)) |
| { |
| return (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT) ? tcu::Vec4(0.005f) : Vec4(0.00001f); |
| } |
| else |
| return Vec4(0.001f); |
| } |
| |
| VkSampleCountFlagBits MultisampleRenderPassTestBase::sampleCountBitFromSampleCount (deUint32 count) const |
| { |
| switch (count) |
| { |
| case 1: return VK_SAMPLE_COUNT_1_BIT; |
| case 2: return VK_SAMPLE_COUNT_2_BIT; |
| case 4: return VK_SAMPLE_COUNT_4_BIT; |
| case 8: return VK_SAMPLE_COUNT_8_BIT; |
| case 16: return VK_SAMPLE_COUNT_16_BIT; |
| case 32: return VK_SAMPLE_COUNT_32_BIT; |
| case 64: return VK_SAMPLE_COUNT_64_BIT; |
| |
| default: |
| DE_FATAL("Invalid sample count"); |
| return (VkSampleCountFlagBits)0x0; |
| } |
| } |
| |
| void MultisampleRenderPassTestBase::logImage (const std::string& name, const tcu::ConstPixelBufferAccess& image) const |
| { |
| m_context.getTestContext().getLog() << tcu::LogImage(name.c_str(), name.c_str(), image); |
| |
| for (deUint32 layerNdx = 0; layerNdx < m_layerCount; ++layerNdx) |
| { |
| const std::string layerName (name + " Layer:" + de::toString(layerNdx)); |
| tcu::ConstPixelBufferAccess layerImage (image.getFormat(), m_width, m_height, 1, image.getPixelPtr(0, 0, layerNdx)); |
| |
| m_context.getTestContext().getLog() << tcu::LogImage(layerName.c_str(), layerName.c_str(), layerImage); |
| } |
| } |
| |
| class MultisampleRenderPassTestInstance : public MultisampleRenderPassTestBase |
| { |
| public: |
| MultisampleRenderPassTestInstance (Context& context, TestConfig config); |
| ~MultisampleRenderPassTestInstance (void); |
| |
| tcu::TestStatus iterate (void); |
| |
| private: |
| |
| template<typename RenderpassSubpass> |
| void submit (void); |
| void submitSwitch (RenderingType renderingType); |
| void verify (void); |
| |
| template<typename RenderPassTrait> |
| Move<VkRenderPass> createRenderPass (bool usedResolveAttachment); |
| Move<VkRenderPass> createRenderPassSwitch (bool usedResolveAttachment); |
| Move<VkRenderPass> createRenderPassCompatible (void); |
| Move<VkPipelineLayout> createRenderPipelineLayout (void); |
| Move<VkPipeline> createRenderPipeline (void); |
| |
| private: |
| |
| const std::vector<VkImageSp> m_multisampleImages; |
| const std::vector<AllocationSp> m_multisampleImageMemory; |
| const std::vector<VkImageViewSp> m_multisampleImageViews; |
| |
| const std::vector<VkImageSp> m_singlesampleImages; |
| const std::vector<AllocationSp> m_singlesampleImageMemory; |
| const std::vector<VkImageViewSp> m_singlesampleImageViews; |
| |
| const Unique<VkRenderPass> m_renderPass; |
| const Unique<VkRenderPass> m_renderPassCompatible; |
| const Unique<VkFramebuffer> m_framebuffer; |
| |
| const Unique<VkPipelineLayout> m_renderPipelineLayout; |
| const Unique<VkPipeline> m_renderPipeline; |
| |
| const std::vector<VkBufferSp> m_buffers; |
| const std::vector<AllocationSp> m_bufferMemory; |
| |
| const Unique<VkCommandPool> m_commandPool; |
| tcu::TextureLevel m_sum; |
| tcu::TextureLevel m_sumSrgb; |
| deUint32 m_sampleMask; |
| tcu::ResultCollector m_resultCollector; |
| |
| protected: |
| MultisampleRenderPassTestInstance (Context& context, TestConfig config, deUint32 renderLevel); |
| |
| const deUint32 m_renderLevel; |
| }; |
| |
| MultisampleRenderPassTestInstance::MultisampleRenderPassTestInstance (Context& context, TestConfig config) |
| : MultisampleRenderPassTestInstance (context, config, /*defaulf render level*/0u) |
| { |
| } |
| |
| MultisampleRenderPassTestInstance::MultisampleRenderPassTestInstance (Context& context, TestConfig config, deUint32 renderLevel) |
| : MultisampleRenderPassTestBase(context, config) |
| |
| , m_multisampleImages (createImages(m_sampleCount, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) |
| , m_multisampleImageMemory (createImageMemory(m_multisampleImages)) |
| , m_multisampleImageViews (createImageViews(m_multisampleImages)) |
| |
| , m_singlesampleImages (createImages(VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, (1u << renderLevel)*m_width, (1u << renderLevel)*m_height, renderLevel+1 )) |
| , m_singlesampleImageMemory (createImageMemory(m_singlesampleImages)) |
| , m_singlesampleImageViews (createImageViews(m_singlesampleImages, renderLevel)) |
| |
| // The "normal" render pass has an unused resolve attachment when testing compatibility. |
| , m_renderPass (createRenderPassSwitch(!m_testCompatibility)) |
| , m_renderPassCompatible (createRenderPassCompatible()) |
| , m_framebuffer (createFramebuffer(m_multisampleImageViews, m_singlesampleImageViews, *m_renderPass)) |
| |
| , m_renderPipelineLayout (createRenderPipelineLayout()) |
| , m_renderPipeline (createRenderPipeline()) |
| |
| , m_buffers (createBuffers((1u << renderLevel)*m_width, (1u << renderLevel)*m_height, renderLevel+1 )) |
| , m_bufferMemory (createBufferMemory(m_buffers)) |
| |
| , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) |
| , m_sum (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), m_width, m_height, m_layerCount) |
| , m_sumSrgb (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), m_width, m_height, m_layerCount) |
| , m_sampleMask (0x0u) |
| |
| , m_renderLevel (renderLevel) |
| { |
| tcu::clear(m_sum.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 0.0f)); |
| tcu::clear(m_sumSrgb.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 0.0f)); |
| } |
| |
| MultisampleRenderPassTestInstance::~MultisampleRenderPassTestInstance (void) |
| { |
| } |
| |
| template<typename RenderpassSubpass> |
| void MultisampleRenderPassTestInstance::submit (void) |
| { |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| const VkDevice device (m_context.getDevice()); |
| const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| beginCommandBuffer(vkd, *commandBuffer); |
| |
| // Memory barriers between previous copies and rendering |
| { |
| std::vector<VkImageMemoryBarrier> barriers; |
| |
| for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_TRANSFER_READ_BIT, |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| |
| VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_singlesampleImages[dstNdx], |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| m_renderLevel, |
| 1u, |
| 0u, |
| m_layerCount |
| } |
| }; |
| |
| barriers.push_back(barrier); |
| } |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); |
| } |
| |
| // Memory barriers to set multisample image layout to COLOR_ATTACHMENT_OPTIMAL |
| if (m_renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) |
| { |
| std::vector<VkImageMemoryBarrier> barriers; |
| |
| for (size_t dstNdx = 0; dstNdx < m_multisampleImages.size(); dstNdx++) |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| |
| 0, |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| |
| VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_multisampleImages[dstNdx], |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| 0u, |
| 1u, |
| 0u, |
| m_layerCount |
| } |
| }; |
| |
| barriers.push_back(barrier); |
| } |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); |
| } |
| |
| VkRect2D renderArea = makeRect2D(m_width, m_height); |
| if (m_renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) |
| { |
| const VkClearValue clearValue = makeClearValueColor( { 0.0f, 0.0f, 0.0f, 1.0f } ); |
| std::vector<vk::VkRenderingAttachmentInfoKHR> colorAttachments(m_attachmentsCount, |
| { |
| vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| DE_NULL, // VkImageView imageView; |
| vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout; |
| vk::VK_RESOLVE_MODE_NONE, // VkResolveModeFlagBits resolveMode; |
| DE_NULL, // VkImageView resolveImageView; |
| vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout resolveImageLayout; |
| vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; |
| vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; |
| clearValue // VkClearValue clearValue; |
| }); |
| |
| for (deUint32 i = 0; i < m_attachmentsCount; ++i) |
| { |
| colorAttachments[i].imageView = **m_multisampleImageViews[i]; |
| colorAttachments[i].resolveImageView = **m_singlesampleImageViews[i]; |
| if (isIntFormat(m_format) || isUintFormat(m_format)) |
| colorAttachments[i].resolveMode = vk::VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; |
| else |
| colorAttachments[i].resolveMode = vk::VK_RESOLVE_MODE_AVERAGE_BIT; |
| } |
| |
| vk::VkRenderingInfoKHR renderingInfo |
| { |
| vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR, |
| DE_NULL, |
| 0, // VkRenderingFlagsKHR flags; |
| renderArea, // VkRect2D renderArea; |
| m_layerCount, // deUint32 layerCount; |
| 0u, // deUint32 viewMask; |
| m_attachmentsCount, // deUint32 colorAttachmentCount; |
| colorAttachments.data(), // const VkRenderingAttachmentInfoKHR* pColorAttachments; |
| DE_NULL, // const VkRenderingAttachmentInfoKHR* pDepthAttachment; |
| DE_NULL, // const VkRenderingAttachmentInfoKHR* pStencilAttachment; |
| }; |
| |
| vkd.cmdBeginRendering(*commandBuffer, &renderingInfo); |
| } |
| else |
| { |
| const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo(DE_NULL, VK_SUBPASS_CONTENTS_INLINE); |
| const VkRenderPassBeginInfo beginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| DE_NULL, |
| |
| m_testCompatibility ? *m_renderPassCompatible : *m_renderPass, |
| *m_framebuffer, |
| renderArea, |
| |
| 0u, |
| DE_NULL |
| }; |
| RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); |
| } |
| |
| // Clear everything to black |
| clearAttachments(*commandBuffer); |
| |
| // Render black samples |
| { |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline); |
| vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(m_sampleMask), &m_sampleMask); |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| } |
| |
| if (m_renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) |
| vkd.cmdEndRendering(*commandBuffer); |
| else |
| { |
| const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo(DE_NULL); |
| RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); |
| } |
| |
| // Memory barriers to set single-sample image layout to TRANSFER_SRC_OPTIMAL |
| if (m_renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) |
| { |
| std::vector<VkImageMemoryBarrier> barriers; |
| |
| for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| VK_ACCESS_TRANSFER_READ_BIT, |
| |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_singlesampleImages[dstNdx], |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| m_renderLevel, |
| 1u, |
| 0u, |
| m_layerCount |
| } |
| }; |
| |
| barriers.push_back(barrier); |
| } |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); |
| } |
| |
| for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) |
| { |
| // assume that buffer(s) have enough memory to store desired amount of mipmaps |
| copyImageToBuffer(vkd, *commandBuffer, **m_singlesampleImages[dstNdx], **m_buffers[dstNdx], |
| m_format, tcu::IVec2((1u << m_renderLevel)*m_width, (1u << m_renderLevel)*m_height), m_renderLevel, |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_layerCount); |
| } |
| |
| endCommandBuffer(vkd, *commandBuffer); |
| |
| submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer); |
| |
| for (size_t memoryBufferNdx = 0; memoryBufferNdx < m_bufferMemory.size(); memoryBufferNdx++) |
| invalidateMappedMemoryRange(vkd, device, m_bufferMemory[memoryBufferNdx]->getMemory(), 0u, VK_WHOLE_SIZE); |
| } |
| |
| void MultisampleRenderPassTestInstance::submitSwitch (RenderingType renderingType) |
| { |
| switch (renderingType) |
| { |
| case RENDERING_TYPE_RENDERPASS_LEGACY: |
| submit<RenderpassSubpass1>(); |
| break; |
| case RENDERING_TYPE_RENDERPASS2: |
| case RENDERING_TYPE_DYNAMIC_RENDERING: |
| submit<RenderpassSubpass2>(); |
| break; |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| void MultisampleRenderPassTestInstance::verify (void) |
| { |
| const Vec4 errorColor (1.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 okColor (0.0f, 1.0f, 0.0f, 1.0f); |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); |
| |
| deUint32 offset (0u); |
| deUint32 width ((1u << m_renderLevel) * m_width); |
| deUint32 height ((1u << m_renderLevel) * m_height); |
| deUint32 pixelSize (static_cast<deUint32>(getPixelSize())); |
| for (deUint32 level = 0; level < m_renderLevel; ++level) |
| { |
| offset += (width * height * pixelSize); |
| height /= 2; |
| width /= 2; |
| } |
| |
| std::vector<tcu::ConstPixelBufferAccess> accesses; |
| for (deUint32 attachmentIdx = 0; attachmentIdx < m_attachmentsCount; ++attachmentIdx) |
| { |
| void* const ptr = static_cast<deUint8*>(m_bufferMemory[attachmentIdx]->getHostPtr()) + offset; |
| accesses.push_back(tcu::ConstPixelBufferAccess(format, m_width, m_height, m_layerCount, ptr)); |
| } |
| |
| tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height, m_layerCount); |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| { |
| const int componentCount (tcu::getNumUsedChannels(format.order)); |
| bool isOk = true; |
| float clearValue; |
| float renderValue; |
| |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| clearValue = -1.0f; |
| renderValue = 1.0f; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| clearValue = 0.0f; |
| renderValue = 1.0f; |
| break; |
| |
| default: |
| clearValue = 0.0f; |
| renderValue = 0.0f; |
| DE_FATAL("Unknown channel class"); |
| } |
| |
| for (deUint32 z = 0; z < m_layerCount; z++) |
| for (deUint32 y = 0; y < m_height; y++) |
| for (deUint32 x = 0; x < m_width; x++) |
| { |
| // Color has to be black if no samples were covered, white if all samples were covered or same in every attachment |
| const Vec4 firstColor (accesses[0].getPixel(x, y, z)); |
| const Vec4 refColor (m_sampleMask == 0x0u |
| ? Vec4(clearValue, |
| componentCount > 1 ? clearValue : 0.0f, |
| componentCount > 2 ? clearValue : 0.0f, |
| componentCount > 3 ? clearValue : 1.0f) |
| : m_sampleMask == ((0x1u << m_sampleCount) - 1u) |
| ? Vec4(renderValue, |
| componentCount > 1 ? renderValue : 0.0f, |
| componentCount > 2 ? renderValue : 0.0f, |
| componentCount > 3 ? renderValue : 1.0f) |
| : firstColor); |
| |
| errorMask.getAccess().setPixel(okColor, x, y, z); |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| { |
| const Vec4 color (accesses[attachmentNdx].getPixel(x, y, z)); |
| |
| if (refColor != color) |
| { |
| isOk = false; |
| errorMask.getAccess().setPixel(errorColor, x, y, z); |
| break; |
| } |
| } |
| |
| { |
| const Vec4 old = m_sum.getAccess().getPixel(x, y, z); |
| m_sum.getAccess().setPixel(old + (tcu::isSRGB(format) ? tcu::sRGBToLinear(firstColor) : firstColor), x, y, z); |
| |
| const Vec4 oldSrgb = m_sumSrgb.getAccess().getPixel(x, y, z); |
| m_sumSrgb.getAccess().setPixel(oldSrgb + firstColor, x, y, z); |
| } |
| } |
| |
| if (!isOk) |
| { |
| const std::string sectionName ("ResolveVerifyWithMask" + de::toString(m_sampleMask)); |
| const tcu::ScopedLogSection section (log, sectionName, sectionName); |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| logImage(std::string("Attachment") + de::toString(attachmentNdx), accesses[attachmentNdx]); |
| |
| logImage("ErrorMask", errorMask.getAccess()); |
| |
| if (m_sampleMask == 0x0u) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Empty sample mask didn't produce correct pixel values"); |
| } |
| else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Full sample mask didn't produce correct pixel values"); |
| } |
| else |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve is inconsistent between attachments" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Resolve is inconsistent between attachments"); |
| } |
| } |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| { |
| const int componentCount (tcu::getNumUsedChannels(format.order)); |
| const UVec4 bitDepth (tcu::getTextureFormatBitDepth(format).cast<deUint32>()); |
| const UVec4 renderValue (tcu::select((UVec4(1u) << tcu::min(UVec4(8u), bitDepth)) - UVec4(1u), |
| UVec4(0u, 0u, 0u, 1u), |
| tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); |
| const UVec4 clearValue (tcu::select(UVec4(0u), |
| UVec4(0u, 0u, 0u, 1u), |
| tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); |
| bool unexpectedValues = false; |
| bool inconsistentComponents = false; |
| bool inconsistentAttachments = false; |
| |
| for (deUint32 z = 0; z < m_layerCount; z++) |
| for (deUint32 y = 0; y < m_height; y++) |
| for (deUint32 x = 0; x < m_width; x++) |
| { |
| // Color has to be all zeros if no samples were covered, all 255 if all samples were covered or consistent across all attachments |
| const UVec4 refColor (m_sampleMask == 0x0u |
| ? clearValue |
| : m_sampleMask == ((0x1u << m_sampleCount) - 1u) |
| ? renderValue |
| : accesses[0].getPixelUint(x, y, z)); |
| bool isOk = true; |
| |
| // If reference value was taken from first attachment, check that it is valid value i.e. clear or render value |
| if (m_sampleMask != 0x0u && m_sampleMask != ((0x1u << m_sampleCount) - 1u)) |
| { |
| // Each component must be resolved same way |
| const BVec4 isRenderValue (refColor == renderValue); |
| const BVec4 isClearValue (refColor == clearValue); |
| const bool unexpectedValue (tcu::anyNotEqual(tcu::logicalOr(isRenderValue, isClearValue), BVec4(true))); |
| const bool inconsistentComponent (!(tcu::allEqual(isRenderValue, BVec4(true)) || tcu::allEqual(isClearValue, BVec4(true)))); |
| |
| unexpectedValues |= unexpectedValue; |
| inconsistentComponents |= inconsistentComponent; |
| |
| if (unexpectedValue || inconsistentComponent) |
| isOk = false; |
| } |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| { |
| const UVec4 color (accesses[attachmentNdx].getPixelUint(x, y, z)); |
| |
| if (refColor != color) |
| { |
| isOk = false; |
| inconsistentAttachments = true; |
| break; |
| } |
| } |
| |
| errorMask.getAccess().setPixel((isOk ? okColor : errorColor), x, y, z); |
| } |
| |
| if (unexpectedValues || inconsistentComponents || inconsistentAttachments) |
| { |
| const std::string sectionName ("ResolveVerifyWithMask" + de::toString(m_sampleMask)); |
| const tcu::ScopedLogSection section (log, sectionName, sectionName); |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| logImage(std::string("Attachment") + de::toString(attachmentNdx), accesses[attachmentNdx]); |
| |
| logImage("ErrorMask", errorMask.getAccess()); |
| |
| if (m_sampleMask == 0x0u) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Empty sample mask didn't produce correct pixels"); |
| } |
| else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Full sample mask didn't produce correct pixels"); |
| } |
| else |
| { |
| if (unexpectedValues) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve produced unexpected values i.e. not " << clearValue << " or " << renderValue << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Resolve produced unexpected values"); |
| } |
| |
| if (inconsistentComponents) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different components of attachment were resolved to different values." << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Different components of attachment were resolved to different values."); |
| } |
| |
| if (inconsistentAttachments) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different attachments were resolved to different values." << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Different attachments were resolved to different values."); |
| } |
| } |
| } |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| { |
| const int componentCount (tcu::getNumUsedChannels(format.order)); |
| const IVec4 bitDepth (tcu::getTextureFormatBitDepth(format)); |
| const IVec4 renderValue (tcu::select((IVec4(1) << (tcu::min(IVec4(8), bitDepth) - IVec4(1))) - IVec4(1), |
| IVec4(0, 0, 0, 1), |
| tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); |
| const IVec4 clearValue (tcu::select(-(IVec4(1) << (tcu::min(IVec4(8), bitDepth) - IVec4(1))), |
| IVec4(0, 0, 0, 1), |
| tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); |
| bool unexpectedValues = false; |
| bool inconsistentComponents = false; |
| bool inconsistentAttachments = false; |
| |
| for (deUint32 z = 0; z < m_layerCount; z++) |
| for (deUint32 y = 0; y < m_height; y++) |
| for (deUint32 x = 0; x < m_width; x++) |
| { |
| // Color has to be all zeros if no samples were covered, all 255 if all samples were covered or consistent across all attachments |
| const IVec4 refColor (m_sampleMask == 0x0u |
| ? clearValue |
| : m_sampleMask == ((0x1u << m_sampleCount) - 1u) |
| ? renderValue |
| : accesses[0].getPixelInt(x, y, z)); |
| bool isOk = true; |
| |
| // If reference value was taken from first attachment, check that it is valid value i.e. clear or render value |
| if (m_sampleMask != 0x0u && m_sampleMask != ((0x1u << m_sampleCount) - 1u)) |
| { |
| // Each component must be resolved same way |
| const BVec4 isRenderValue (refColor == renderValue); |
| const BVec4 isClearValue (refColor == clearValue); |
| const bool unexpectedValue (tcu::anyNotEqual(tcu::logicalOr(isRenderValue, isClearValue), BVec4(true))); |
| const bool inconsistentComponent (!(tcu::allEqual(isRenderValue, BVec4(true)) || tcu::allEqual(isClearValue, BVec4(true)))); |
| |
| unexpectedValues |= unexpectedValue; |
| inconsistentComponents |= inconsistentComponent; |
| |
| if (unexpectedValue || inconsistentComponent) |
| isOk = false; |
| } |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| { |
| const IVec4 color (accesses[attachmentNdx].getPixelInt(x, y, z)); |
| |
| if (refColor != color) |
| { |
| isOk = false; |
| inconsistentAttachments = true; |
| break; |
| } |
| } |
| |
| errorMask.getAccess().setPixel((isOk ? okColor : errorColor), x, y, z); |
| } |
| |
| if (unexpectedValues || inconsistentComponents || inconsistentAttachments) |
| { |
| const std::string sectionName ("ResolveVerifyWithMask" + de::toString(m_sampleMask)); |
| const tcu::ScopedLogSection section (log, sectionName, sectionName); |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| logImage(std::string("Attachment") + de::toString(attachmentNdx), accesses[attachmentNdx]); |
| |
| logImage("ErrorMask", errorMask.getAccess()); |
| |
| if (m_sampleMask == 0x0u) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Empty sample mask didn't produce correct pixels"); |
| } |
| else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Full sample mask didn't produce correct pixels"); |
| } |
| else |
| { |
| if (unexpectedValues) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve produced unexpected values i.e. not " << clearValue << " or " << renderValue << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Resolve produced unexpected values"); |
| } |
| |
| if (inconsistentComponents) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different components of attachment were resolved to different values." << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Different components of attachment were resolved to different values."); |
| } |
| |
| if (inconsistentAttachments) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different attachments were resolved to different values." << tcu::TestLog::EndMessage; |
| m_resultCollector.fail("Different attachments were resolved to different values."); |
| } |
| } |
| } |
| break; |
| } |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| } |
| |
| tcu::TestStatus MultisampleRenderPassTestInstance::iterate (void) |
| { |
| if (m_sampleMask == 0u) |
| { |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| log << TestLog::Message << "Clearing target to zero and rendering 255 pixels with every possible sample mask" << TestLog::EndMessage; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| log << TestLog::Message << "Clearing target to -128 and rendering 127 pixels with every possible sample mask" << TestLog::EndMessage; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| log << TestLog::Message << "Clearing target to black and rendering white pixels with every possible sample mask" << TestLog::EndMessage; |
| break; |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| } |
| |
| submitSwitch(m_renderingType); |
| verify(); |
| |
| if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) |
| { |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); |
| const Vec4 threshold (getFormatThreshold()); |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| |
| if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT |
| || channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT |
| || channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) |
| { |
| const int componentCount (tcu::getNumUsedChannels(format.order)); |
| const Vec4 errorColor (1.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 okColor (0.0f, 1.0f, 0.0f, 1.0f); |
| tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height, m_layerCount); |
| bool isOk = true; |
| Vec4 maxDiff (0.0f); |
| Vec4 expectedAverage; |
| |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| { |
| expectedAverage = Vec4(0.5f, componentCount > 1 ? 0.5f : 0.0f, componentCount > 2 ? 0.5f : 0.0f, componentCount > 3 ? 0.5f : 1.0f); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| { |
| expectedAverage = Vec4(0.0f, 0.0f, 0.0f, componentCount > 3 ? 0.0f : 1.0f); |
| break; |
| } |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| |
| for (deUint32 z = 0; z < m_layerCount; z++) |
| for (deUint32 y = 0; y < m_height; y++) |
| for (deUint32 x = 0; x < m_width; x++) |
| { |
| const Vec4 sum (m_sum.getAccess().getPixel(x, y, z)); |
| const Vec4 average (sum / Vec4((float)(0x1u << m_sampleCount))); |
| const Vec4 diff (tcu::abs(average - expectedAverage)); |
| |
| m_sum.getAccess().setPixel(average, x, y, z); |
| errorMask.getAccess().setPixel(okColor, x, y, z); |
| |
| bool failThreshold; |
| |
| if (!tcu::isSRGB(format)) |
| { |
| failThreshold = (diff[0] > threshold.x() |
| || diff[1] > threshold.y() |
| || diff[2] > threshold.z() |
| || diff[3] > threshold.w()); |
| } |
| else |
| { |
| const Vec4 sumSrgb(m_sumSrgb.getAccess().getPixel(x, y, z)); |
| const Vec4 averageSrgb(sumSrgb / Vec4((float)(0x1u << m_sampleCount))); |
| const Vec4 diffSrgb(tcu::abs(averageSrgb - expectedAverage)); |
| |
| m_sumSrgb.getAccess().setPixel(averageSrgb, x, y, z); |
| |
| // Spec doesn't restrict implementation to downsample in linear color space. So, comparing both non linear and |
| // linear diff's in case of srgb formats. |
| failThreshold = ((diff[0] > threshold.x() |
| || diff[1] > threshold.y() |
| || diff[2] > threshold.z() |
| || diff[3] > threshold.w()) && |
| (diffSrgb[0] > threshold.x() |
| || diffSrgb[1] > threshold.y() |
| || diffSrgb[2] > threshold.z() |
| || diffSrgb[3] > threshold.w())); |
| |
| } |
| |
| if (failThreshold) |
| { |
| isOk = false; |
| maxDiff = tcu::max(maxDiff, diff); |
| errorMask.getAccess().setPixel(errorColor, x, y, z); |
| } |
| } |
| |
| log << TestLog::Image("Average resolved values in attachment 0", "Average resolved values in attachment 0", m_sum); |
| |
| if (!isOk) |
| { |
| std::stringstream message; |
| |
| m_context.getTestContext().getLog() << tcu::LogImage("ErrorMask", "ErrorMask", errorMask.getAccess()); |
| |
| message << "Average resolved values differ from expected average values by more than "; |
| |
| switch (componentCount) |
| { |
| case 1: |
| message << threshold.x(); |
| break; |
| case 2: |
| message << "vec2" << Vec2(threshold.x(), threshold.y()); |
| break; |
| case 3: |
| message << "vec3" << Vec3(threshold.x(), threshold.y(), threshold.z()); |
| break; |
| default: |
| message << "vec4" << threshold; |
| } |
| |
| message << ". Max diff " << maxDiff; |
| log << TestLog::Message << message.str() << TestLog::EndMessage; |
| |
| m_resultCollector.fail("Average resolved values differ from expected average values"); |
| } |
| } |
| |
| return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); |
| } |
| else |
| { |
| m_sampleMask++; |
| return tcu::TestStatus::incomplete(); |
| } |
| } |
| |
| template<typename RenderPassTrait> |
| Move<VkRenderPass> MultisampleRenderPassTestInstance::createRenderPass (bool usedResolveAttachment) |
| { |
| // make name for RenderPass1Trait or RenderPass2Trait shorter |
| typedef RenderPassTrait RPT; |
| typedef typename RPT::AttDesc AttDesc; |
| typedef typename RPT::AttRef AttRef; |
| typedef typename RPT::SubpassDesc SubpassDesc; |
| typedef typename RPT::RenderPassCreateInfo RenderPassCreateInfo; |
| |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| std::vector<AttDesc> attachments; |
| std::vector<AttRef> colorAttachmentRefs; |
| std::vector<AttRef> resolveAttachmentRefs; |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| { |
| { |
| const AttDesc multisampleAttachment |
| ( |
| // sType |
| DE_NULL, // pNext |
| 0u, // flags |
| m_format, // format |
| m_sampleCount, // samples |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // loadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp |
| VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // finalLayout |
| ); |
| const AttRef attachmentRef |
| ( |
| // sType |
| DE_NULL, // pNext |
| (deUint32)attachments.size(), // attachment |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // layout |
| 0u // aspectMask |
| ); |
| colorAttachmentRefs.push_back(attachmentRef); |
| attachments.push_back(multisampleAttachment); |
| } |
| { |
| const AttDesc singlesampleAttachment |
| ( |
| // sType |
| DE_NULL, // pNext |
| 0u, // flags |
| m_format, // format |
| VK_SAMPLE_COUNT_1_BIT, // samples |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // loadOp |
| VK_ATTACHMENT_STORE_OP_STORE, // storeOp |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp |
| VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // finalLayout |
| ); |
| const auto attachmentId = (usedResolveAttachment ? static_cast<deUint32>(attachments.size()) : VK_ATTACHMENT_UNUSED); |
| const AttRef attachmentRef |
| ( |
| // sType |
| DE_NULL, // pNext |
| attachmentId, // attachment |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // layout |
| 0u // aspectMask |
| ); |
| resolveAttachmentRefs.push_back(attachmentRef); |
| attachments.push_back(singlesampleAttachment); |
| } |
| } |
| |
| DE_ASSERT(colorAttachmentRefs.size() == resolveAttachmentRefs.size()); |
| DE_ASSERT(attachments.size() == colorAttachmentRefs.size() + resolveAttachmentRefs.size()); |
| |
| const SubpassDesc subpass |
| ( |
| // sType |
| DE_NULL, // pNext |
| (VkSubpassDescriptionFlags)0, // flags |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint |
| 0u, // viewMask |
| 0u, // inputAttachmentCount |
| DE_NULL, // pInputAttachments |
| (deUint32)colorAttachmentRefs.size(), // colorAttachmentCount |
| &colorAttachmentRefs[0], // pColorAttachments |
| &resolveAttachmentRefs[0], // pResolveAttachments |
| DE_NULL, // pDepthStencilAttachment |
| 0u, // preserveAttachmentCount |
| DE_NULL // pPreserveAttachments |
| ); |
| const RenderPassCreateInfo renderPassCreator |
| ( |
| // sType |
| DE_NULL, // pNext |
| (VkRenderPassCreateFlags)0u, // flags |
| (deUint32)attachments.size(), // attachmentCount |
| &attachments[0], // pAttachments |
| 1u, // subpassCount |
| &subpass, // pSubpasses |
| 0u, // dependencyCount |
| DE_NULL, // pDependencies |
| 0u, // correlatedViewMaskCount |
| DE_NULL // pCorrelatedViewMasks |
| ); |
| |
| return renderPassCreator.createRenderPass(vkd, device); |
| } |
| |
| Move<VkRenderPass> MultisampleRenderPassTestInstance::createRenderPassSwitch (bool usedResolveAttachment) |
| { |
| switch (m_renderingType) |
| { |
| case RENDERING_TYPE_RENDERPASS_LEGACY: |
| return createRenderPass<RenderPass1Trait>(usedResolveAttachment); |
| case RENDERING_TYPE_RENDERPASS2: |
| return createRenderPass<RenderPass2Trait>(usedResolveAttachment); |
| case RENDERING_TYPE_DYNAMIC_RENDERING: |
| return Move<VkRenderPass>(); |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| Move<VkRenderPass> MultisampleRenderPassTestInstance::createRenderPassCompatible (void) |
| { |
| if (m_testCompatibility) |
| { |
| // The compatible render pass is always created with a used resolve attachment. |
| return createRenderPassSwitch(true); |
| } |
| else |
| { |
| return {}; |
| } |
| } |
| |
| Move<VkPipelineLayout> MultisampleRenderPassTestInstance::createRenderPipelineLayout (void) |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| |
| const VkPushConstantRange pushConstant = |
| { |
| VK_SHADER_STAGE_FRAGMENT_BIT, |
| 0u, |
| 4u |
| }; |
| const VkPipelineLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| DE_NULL, |
| (vk::VkPipelineLayoutCreateFlags)0, |
| |
| 0u, |
| DE_NULL, |
| |
| 1u, |
| &pushConstant |
| }; |
| |
| return createPipelineLayout(vkd, device, &createInfo); |
| } |
| |
| Move<VkPipeline> MultisampleRenderPassTestInstance::createRenderPipeline (void) |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| const vk::BinaryCollection& binaryCollection = m_context.getBinaryCollection(); |
| const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u)); |
| const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-frag"), 0u)); |
| const Move<VkShaderModule> geometryShaderModule (m_layerCount == 1 ? Move<VkShaderModule>() : createShaderModule(vkd, device, binaryCollection.get("geom"), 0u)); |
| // Disable blending |
| const VkPipelineColorBlendAttachmentState attachmentBlendState = |
| { |
| VK_FALSE, |
| VK_BLEND_FACTOR_SRC_ALPHA, |
| VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, |
| VK_BLEND_OP_ADD, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_OP_ADD, |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT |
| }; |
| std::vector<VkPipelineColorBlendAttachmentState> attachmentBlendStates(m_attachmentsCount, attachmentBlendState); |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineVertexInputStateCreateFlags)0u, |
| |
| 0u, |
| DE_NULL, |
| |
| 0u, |
| DE_NULL |
| }; |
| const tcu::UVec2 renderArea (m_width, m_height); |
| const std::vector<VkViewport> viewports (1, makeViewport(renderArea)); |
| const std::vector<VkRect2D> scissors (1, makeRect2D(renderArea)); |
| |
| const VkPipelineMultisampleStateCreateInfo multisampleState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineMultisampleStateCreateFlags)0u, |
| |
| sampleCountBitFromSampleCount(m_sampleCount), |
| VK_FALSE, |
| 0.0f, |
| DE_NULL, |
| VK_FALSE, |
| VK_FALSE, |
| }; |
| const VkPipelineDepthStencilStateCreateInfo depthStencilState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineDepthStencilStateCreateFlags)0u, |
| |
| VK_FALSE, |
| VK_TRUE, |
| VK_COMPARE_OP_ALWAYS, |
| VK_FALSE, |
| VK_TRUE, |
| { |
| VK_STENCIL_OP_KEEP, |
| VK_STENCIL_OP_INCREMENT_AND_WRAP, |
| VK_STENCIL_OP_KEEP, |
| VK_COMPARE_OP_ALWAYS, |
| ~0u, |
| ~0u, |
| 0xFFu / (m_sampleCount + 1) |
| }, |
| { |
| VK_STENCIL_OP_KEEP, |
| VK_STENCIL_OP_INCREMENT_AND_WRAP, |
| VK_STENCIL_OP_KEEP, |
| VK_COMPARE_OP_ALWAYS, |
| ~0u, |
| ~0u, |
| 0xFFu / (m_sampleCount + 1) |
| }, |
| |
| 0.0f, |
| 1.0f |
| }; |
| const VkPipelineColorBlendStateCreateInfo blendState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineColorBlendStateCreateFlags)0u, |
| |
| VK_FALSE, |
| VK_LOGIC_OP_COPY, |
| deUint32(attachmentBlendStates.size()), |
| &attachmentBlendStates[0], |
| { 0.0f, 0.0f, 0.0f, 0.0f } |
| }; |
| |
| VkPipelineRenderingCreateInfoKHR* pNext = DE_NULL; |
| std::vector<VkFormat> attachmentFormats(m_attachmentsCount, m_format); |
| VkPipelineRenderingCreateInfoKHR renderingCreateInfo |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, |
| DE_NULL, |
| 0u, |
| m_attachmentsCount, |
| attachmentFormats.data(), |
| VK_FORMAT_UNDEFINED, |
| VK_FORMAT_UNDEFINED |
| }; |
| if (m_renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) |
| pNext = &renderingCreateInfo; |
| |
| return makeGraphicsPipeline(vkd, // const DeviceInterface& vk |
| device, // const VkDevice device |
| *m_renderPipelineLayout, // const VkPipelineLayout pipelineLayout |
| *vertexShaderModule, // const VkShaderModule vertexShaderModule |
| DE_NULL, // const VkShaderModule tessellationControlShaderModule |
| DE_NULL, // const VkShaderModule tessellationEvalShaderModule |
| m_layerCount != 1 ? *geometryShaderModule : DE_NULL,// const VkShaderModule geometryShaderModule |
| *fragmentShaderModule, // const VkShaderModule fragmentShaderModule |
| *m_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 |
| &vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo |
| DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo |
| &multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo |
| &depthStencilState, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo |
| &blendState, // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo |
| DE_NULL, // const VkPipelineDynamicStateCreateInfo* dynamicStateCreateInfo |
| pNext); // const void* pNext |
| } |
| |
| class MaxAttachmenstsRenderPassTestInstance : public MultisampleRenderPassTestBase |
| { |
| public: |
| MaxAttachmenstsRenderPassTestInstance (Context& context, TestConfig config); |
| ~MaxAttachmenstsRenderPassTestInstance (void); |
| |
| tcu::TestStatus iterate (void); |
| |
| private: |
| |
| template<typename RenderpassSubpass> |
| void submit (void); |
| void submitSwitch (RenderingType renderingType); |
| void verify (void); |
| |
| Move<VkDescriptorSetLayout> createDescriptorSetLayout (void); |
| Move<VkDescriptorPool> createDescriptorPool (void); |
| Move<VkDescriptorSet> createDescriptorSet (void); |
| |
| template<typename RenderPassTrait> |
| Move<VkRenderPass> createRenderPass (void); |
| Move<VkRenderPass> createRenderPassSwitch (const RenderingType renderingType); |
| Move<VkPipelineLayout> createRenderPipelineLayout (bool secondSubpass); |
| Move<VkPipeline> createRenderPipeline (bool secondSubpass); |
| |
| private: |
| |
| const std::vector<VkImageSp> m_multisampleImages; |
| const std::vector<AllocationSp> m_multisampleImageMemory; |
| const std::vector<VkImageViewSp> m_multisampleImageViews; |
| |
| const std::vector<VkImageSp> m_singlesampleImages; |
| const std::vector<AllocationSp> m_singlesampleImageMemory; |
| const std::vector<VkImageViewSp> m_singlesampleImageViews; |
| |
| const Unique<VkDescriptorSetLayout> m_descriptorSetLayout; |
| const Unique<VkDescriptorPool> m_descriptorPool; |
| const Unique<VkDescriptorSet> m_descriptorSet; |
| |
| const Unique<VkRenderPass> m_renderPass; |
| const Unique<VkFramebuffer> m_framebuffer; |
| |
| const Unique<VkPipelineLayout> m_pipelineLayoutPass0; |
| const Unique<VkPipeline> m_pipelinePass0; |
| const Unique<VkPipelineLayout> m_pipelineLayoutPass1; |
| const Unique<VkPipeline> m_pipelinePass1; |
| |
| const std::vector<VkBufferSp> m_buffers; |
| const std::vector<AllocationSp> m_bufferMemory; |
| |
| const Unique<VkCommandPool> m_commandPool; |
| tcu::ResultCollector m_resultCollector; |
| }; |
| |
| MaxAttachmenstsRenderPassTestInstance::MaxAttachmenstsRenderPassTestInstance (Context& context, TestConfig config) |
| : MultisampleRenderPassTestBase(context, config) |
| |
| , m_multisampleImages (createImages(m_sampleCount, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) |
| , m_multisampleImageMemory (createImageMemory(m_multisampleImages)) |
| , m_multisampleImageViews (createImageViews(m_multisampleImages)) |
| |
| , m_singlesampleImages (createImages(VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) |
| , m_singlesampleImageMemory (createImageMemory(m_singlesampleImages)) |
| , m_singlesampleImageViews (createImageViews(m_singlesampleImages)) |
| |
| , m_descriptorSetLayout (createDescriptorSetLayout()) |
| , m_descriptorPool (createDescriptorPool()) |
| , m_descriptorSet (createDescriptorSet()) |
| |
| , m_renderPass (createRenderPassSwitch(config.renderingType)) |
| , m_framebuffer (createFramebuffer(m_multisampleImageViews, m_singlesampleImageViews, *m_renderPass)) |
| |
| , m_pipelineLayoutPass0 (createRenderPipelineLayout(0)) |
| , m_pipelinePass0 (createRenderPipeline(0)) |
| , m_pipelineLayoutPass1 (createRenderPipelineLayout(1)) |
| , m_pipelinePass1 (createRenderPipeline(1)) |
| |
| , m_buffers (createBuffers()) |
| , m_bufferMemory (createBufferMemory(m_buffers)) |
| |
| , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) |
| { |
| } |
| |
| MaxAttachmenstsRenderPassTestInstance::~MaxAttachmenstsRenderPassTestInstance (void) |
| { |
| } |
| |
| template<typename RenderpassSubpass> |
| void MaxAttachmenstsRenderPassTestInstance::submit (void) |
| { |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| const VkDevice device (m_context.getDevice()); |
| const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); |
| const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); |
| |
| beginCommandBuffer(vkd, *commandBuffer); |
| |
| // Memory barriers between previous copies and rendering |
| { |
| std::vector<VkImageMemoryBarrier> barriers; |
| |
| for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_TRANSFER_READ_BIT, |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| |
| VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_singlesampleImages[dstNdx], |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| 0u, |
| 1u, |
| 0u, |
| m_layerCount |
| } |
| }; |
| |
| barriers.push_back(barrier); |
| } |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); |
| } |
| |
| { |
| const VkRenderPassBeginInfo beginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| DE_NULL, |
| |
| *m_renderPass, |
| *m_framebuffer, |
| |
| { |
| { 0u, 0u }, |
| { m_width, m_height } |
| }, |
| |
| 0u, |
| DE_NULL |
| }; |
| RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); |
| } |
| |
| // Clear everything to black |
| clearAttachments(*commandBuffer); |
| |
| // First subpass - render black samples |
| { |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelinePass0); |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| } |
| |
| // Second subpasss - merge attachments |
| { |
| RenderpassSubpass::cmdNextSubpass(vkd, *commandBuffer, &subpassBeginInfo, &subpassEndInfo); |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelinePass1); |
| vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutPass1, 0, 1u, &*m_descriptorSet, 0, NULL); |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| } |
| |
| RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); |
| |
| // Memory barriers between rendering and copies |
| { |
| std::vector<VkImageMemoryBarrier> barriers; |
| |
| for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| VK_ACCESS_TRANSFER_READ_BIT, |
| |
| VK_IMAGE_LAYOUT_GENERAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_singlesampleImages[dstNdx], |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| 0u, |
| 1u, |
| 0u, |
| m_layerCount |
| } |
| }; |
| |
| barriers.push_back(barrier); |
| } |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); |
| } |
| |
| // Copy image memory to buffers |
| for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) |
| { |
| const VkBufferImageCopy region = |
| { |
| 0u, |
| 0u, |
| 0u, |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| 0u, |
| 0u, |
| m_layerCount, |
| }, |
| { 0u, 0u, 0u }, |
| { m_width, m_height, 1u } |
| }; |
| |
| vkd.cmdCopyImageToBuffer(*commandBuffer, **m_singlesampleImages[dstNdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_buffers[dstNdx], 1u, ®ion); |
| } |
| |
| // Memory barriers between copies and host access |
| { |
| std::vector<VkBufferMemoryBarrier> barriers; |
| |
| for (size_t dstNdx = 0; dstNdx < m_buffers.size(); dstNdx++) |
| { |
| const VkBufferMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_TRANSFER_WRITE_BIT, |
| VK_ACCESS_HOST_READ_BIT, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_buffers[dstNdx], |
| 0u, |
| VK_WHOLE_SIZE |
| }; |
| |
| barriers.push_back(barrier); |
| } |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0], 0u, DE_NULL); |
| } |
| |
| endCommandBuffer(vkd, *commandBuffer); |
| |
| submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer); |
| |
| for (size_t memoryBufferNdx = 0; memoryBufferNdx < m_bufferMemory.size(); memoryBufferNdx++) |
| invalidateMappedMemoryRange(vkd, device, m_bufferMemory[memoryBufferNdx]->getMemory(), 0u, VK_WHOLE_SIZE); |
| } |
| |
| void MaxAttachmenstsRenderPassTestInstance::submitSwitch (RenderingType renderingType) |
| { |
| switch (renderingType) |
| { |
| case RENDERING_TYPE_RENDERPASS_LEGACY: |
| submit<RenderpassSubpass1>(); |
| break; |
| case RENDERING_TYPE_RENDERPASS2: |
| submit<RenderpassSubpass2>(); |
| break; |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| template <typename VecType> |
| bool isValueAboveThreshold1 (const VecType& vale, const VecType& threshold) |
| { |
| return (vale[0] > threshold[0]); |
| } |
| |
| template <typename VecType> |
| bool isValueAboveThreshold2 (const VecType& vale, const VecType& threshold) |
| { |
| return (vale[0] > threshold[0]) || (vale[1] > threshold[1]); |
| } |
| |
| template <typename VecType> |
| bool isValueAboveThreshold3 (const VecType& vale, const VecType& threshold) |
| { |
| return (vale[0] > threshold[0]) || (vale[1] > threshold[1]) || (vale[2] > threshold[2]); |
| } |
| |
| template <typename VecType> |
| bool isValueAboveThreshold4 (const VecType& vale, const VecType& threshold) |
| { |
| return (vale[0] > threshold[0]) || (vale[1] > threshold[1]) || (vale[2] > threshold[2]) || (vale[3] > threshold[3]); |
| } |
| |
| void MaxAttachmenstsRenderPassTestInstance::verify (void) |
| { |
| const Vec4 errorColor (1.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 okColor (0.0f, 1.0f, 0.0f, 1.0f); |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); |
| const int componentCount (tcu::getNumUsedChannels(format.order)); |
| const int outputsCount = m_attachmentsCount / 2; |
| |
| DE_ASSERT((componentCount >= 0) && (componentCount < 5)); |
| |
| std::vector<tcu::ConstPixelBufferAccess> accesses; |
| for (int outputNdx = 0; outputNdx < outputsCount; ++outputNdx) |
| { |
| void* const ptr = m_bufferMemory[outputNdx]->getHostPtr(); |
| accesses.push_back(tcu::ConstPixelBufferAccess(format, m_width, m_height, 1, ptr)); |
| } |
| |
| tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height, outputsCount); |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| bool isOk = true; |
| |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| { |
| const Vec4 refColor(0.0f, 0.3f, 0.6f, 0.75f); |
| const Vec4 threshold(getFormatThreshold()); |
| |
| typedef bool(*ValueAboveThresholdFn)(const Vec4&, const Vec4&); |
| ValueAboveThresholdFn componentToFnMap[4] = |
| { |
| isValueAboveThreshold1<Vec4>, |
| isValueAboveThreshold2<Vec4>, |
| isValueAboveThreshold3<Vec4>, |
| isValueAboveThreshold4<Vec4> |
| }; |
| ValueAboveThresholdFn isValueAboveThreshold = componentToFnMap[componentCount - 1]; |
| bool isSRGBFormat = tcu::isSRGB(format); |
| |
| for (int outputNdx = 0; outputNdx < outputsCount; outputNdx++) |
| for (int y = 0; y < (int)m_height; y++) |
| for (int x = 0; x < (int)m_width; x++) |
| { |
| Vec4 color = accesses[outputNdx].getPixel(x, y); |
| if (isSRGBFormat) |
| color = tcu::sRGBToLinear(color); |
| |
| const Vec4 diff(tcu::abs(color - refColor)); |
| |
| if (isValueAboveThreshold(diff, threshold)) |
| { |
| isOk = false; |
| errorMask.getAccess().setPixel(errorColor, x, y, outputNdx); |
| break; |
| } |
| else |
| errorMask.getAccess().setPixel(okColor, x, y, outputNdx); |
| } |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| { |
| const UVec4 refColor(0, 48, 144, 189); |
| UVec4 threshold(1, 1, 1, 1); |
| |
| if (m_format == VK_FORMAT_A2B10G10R10_UINT_PACK32) |
| threshold[3] = 200; |
| |
| typedef bool(*ValueAboveThresholdFn)(const UVec4&, const UVec4&); |
| ValueAboveThresholdFn componentToFnMap[4] = |
| { |
| isValueAboveThreshold1<UVec4>, |
| isValueAboveThreshold2<UVec4>, |
| isValueAboveThreshold3<UVec4>, |
| isValueAboveThreshold4<UVec4> |
| }; |
| ValueAboveThresholdFn isValueAboveThreshold = componentToFnMap[componentCount - 1]; |
| |
| for (int outputNdx = 0; outputNdx < outputsCount; outputNdx++) |
| for (int y = 0; y < (int)m_height; y++) |
| for (int x = 0; x < (int)m_width; x++) |
| { |
| const UVec4 color (accesses[outputNdx].getPixelUint(x, y)); |
| const UVec4 diff (std::abs(int(color.x()) - int(refColor.x())), |
| std::abs(int(color.y()) - int(refColor.y())), |
| std::abs(int(color.z()) - int(refColor.z())), |
| std::abs(int(color.w()) - int(refColor.w()))); |
| |
| if (isValueAboveThreshold(diff, threshold)) |
| { |
| isOk = false; |
| errorMask.getAccess().setPixel(errorColor, x, y, outputNdx); |
| break; |
| } |
| else |
| errorMask.getAccess().setPixel(okColor, x, y, outputNdx); |
| } |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| { |
| const IVec4 refColor (0, 24, 75, 93); |
| const IVec4 threshold (1, 1, 1, 1); |
| |
| typedef bool(*ValueAboveThresholdFn)(const IVec4&, const IVec4&); |
| ValueAboveThresholdFn componentToFnMap[4] = |
| { |
| isValueAboveThreshold1<IVec4>, |
| isValueAboveThreshold2<IVec4>, |
| isValueAboveThreshold3<IVec4>, |
| isValueAboveThreshold4<IVec4> |
| }; |
| ValueAboveThresholdFn isValueAboveThreshold = componentToFnMap[componentCount - 1]; |
| |
| for (int outputNdx = 0; outputNdx < outputsCount; outputNdx++) |
| for (int y = 0; y < (int)m_height; y++) |
| for (int x = 0; x < (int)m_width; x++) |
| { |
| const IVec4 color (accesses[outputNdx].getPixelInt(x, y)); |
| const IVec4 diff (std::abs(color.x() - refColor.x()), |
| std::abs(color.y() - refColor.y()), |
| std::abs(color.z() - refColor.z()), |
| std::abs(color.w() - refColor.w())); |
| |
| if (isValueAboveThreshold(diff, threshold)) |
| { |
| isOk = false; |
| errorMask.getAccess().setPixel(errorColor, x, y, outputNdx); |
| break; |
| } |
| else |
| errorMask.getAccess().setPixel(okColor, x, y, outputNdx); |
| } |
| break; |
| } |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| |
| if (!isOk) |
| { |
| const std::string sectionName ("MaxAttachmentsVerify"); |
| const tcu::ScopedLogSection section (log, sectionName, sectionName); |
| |
| logImage("ErrorMask", errorMask.getAccess()); |
| m_resultCollector.fail("Fail"); |
| } |
| } |
| |
| tcu::TestStatus MaxAttachmenstsRenderPassTestInstance::iterate(void) |
| { |
| submitSwitch(m_renderingType); |
| verify(); |
| |
| return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); |
| } |
| |
| Move<VkDescriptorSetLayout> MaxAttachmenstsRenderPassTestInstance::createDescriptorSetLayout() |
| { |
| const VkDescriptorSetLayoutBinding bindingTemplate = |
| { |
| 0, // binding |
| VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // descriptorType |
| 1u, // descriptorCount |
| VK_SHADER_STAGE_FRAGMENT_BIT, // stageFlags |
| DE_NULL // pImmutableSamplers |
| }; |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings(m_attachmentsCount, bindingTemplate); |
| for (deUint32 idx = 0; idx < m_attachmentsCount; ++idx) |
| bindings[idx].binding = idx; |
| |
| const VkDescriptorSetLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType |
| DE_NULL, // pNext |
| 0u, // flags |
| m_attachmentsCount, // bindingCount |
| &bindings[0] // pBindings |
| }; |
| |
| return ::createDescriptorSetLayout(m_context.getDeviceInterface(), m_context.getDevice(), &createInfo); |
| } |
| |
| Move<VkDescriptorPool> MaxAttachmenstsRenderPassTestInstance::createDescriptorPool() |
| { |
| const VkDescriptorPoolSize size = |
| { |
| VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // type |
| m_attachmentsCount // descriptorCount |
| }; |
| |
| const VkDescriptorPoolCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // sType |
| DE_NULL, // pNext |
| VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // flags |
| 1u, // maxSets |
| 1u, // poolSizeCount |
| &size // pPoolSizes |
| }; |
| |
| return ::createDescriptorPool(m_context.getDeviceInterface(), m_context.getDevice(), &createInfo); |
| } |
| |
| Move<VkDescriptorSet> MaxAttachmenstsRenderPassTestInstance::createDescriptorSet() |
| { |
| const VkDescriptorSetAllocateInfo allocateInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType |
| DE_NULL, // pNext |
| *m_descriptorPool, // descriptorPool |
| 1u, // descriptorSetCount |
| &*m_descriptorSetLayout // pSetLayouts |
| }; |
| |
| const vk::DeviceInterface& vkd = m_context.getDeviceInterface(); |
| vk::VkDevice device = m_context.getDevice(); |
| Move<VkDescriptorSet> descriptorSet = allocateDescriptorSet(vkd, device, &allocateInfo); |
| vector<VkDescriptorImageInfo> descriptorImageInfo (m_attachmentsCount); |
| vector<VkWriteDescriptorSet> descriptorWrites (m_attachmentsCount); |
| |
| for (deUint32 idx = 0; idx < m_attachmentsCount; ++idx) |
| { |
| const VkDescriptorImageInfo imageInfo = |
| { |
| DE_NULL, // VkSampler sampler |
| **m_singlesampleImageViews[idx], // VkImageView imageView |
| VK_IMAGE_LAYOUT_GENERAL // VkImageLayout imageLayout |
| }; |
| descriptorImageInfo[idx] = imageInfo; |
| |
| const VkWriteDescriptorSet write = |
| { |
| VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| *descriptorSet, // VkDescriptorSet dstSet |
| (deUint32)idx, // uint32_t dstBinding |
| 0u, // uint32_t dstArrayElement |
| 1u, // uint32_t descriptorCount |
| VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // VkDescriptorType descriptorType |
| &descriptorImageInfo[idx], // const VkDescriptorImageInfo* pImageInfo |
| DE_NULL, // const VkDescriptorBufferInfo* pBufferInfo |
| DE_NULL // const VkBufferView* pTexelBufferView |
| }; |
| |
| descriptorWrites[idx] = write; |
| } |
| |
| vkd.updateDescriptorSets(device, (deUint32)descriptorWrites.size(), &descriptorWrites[0], 0u, DE_NULL); |
| return descriptorSet; |
| } |
| |
| template<typename RenderPassTrait> |
| Move<VkRenderPass> MaxAttachmenstsRenderPassTestInstance::createRenderPass(void) |
| { |
| // make name for RenderPass1Trait or RenderPass2Trait shorter |
| typedef RenderPassTrait RPT; |
| |
| typedef RenderPassTrait RPT; |
| typedef typename RPT::AttDesc AttDesc; |
| typedef typename RPT::AttRef AttRef; |
| typedef typename RPT::SubpassDep SubpassDep; |
| typedef typename RPT::SubpassDesc SubpassDesc; |
| typedef typename RPT::RenderPassCreateInfo RenderPassCreateInfo; |
| |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| std::vector<AttDesc> attachments; |
| std::vector<AttRef> sp0colorAttachmentRefs; |
| std::vector<AttRef> sp0resolveAttachmentRefs; |
| std::vector<AttRef> sp1inAttachmentRefs; |
| std::vector<AttRef> sp1colorAttachmentRefs; |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++) |
| { |
| // define first subpass outputs |
| { |
| const AttDesc multisampleAttachment |
| ( |
| DE_NULL, // pNext |
| 0u, // flags |
| m_format, // format |
| m_sampleCount, // samples |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // loadOp |
| VK_ATTACHMENT_STORE_OP_STORE, // storeOp |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp |
| VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // finalLayout |
| ); |
| const AttRef attachmentRef |
| ( |
| DE_NULL, |
| (deUint32)attachments.size(), // attachment |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // layout |
| 0u // aspectMask |
| ); |
| sp0colorAttachmentRefs.push_back(attachmentRef); |
| attachments.push_back(multisampleAttachment); |
| } |
| // define first subpass resolve attachments |
| { |
| const AttDesc singlesampleAttachment |
| ( |
| DE_NULL, // pNext |
| 0u, // flags |
| m_format, // format |
| VK_SAMPLE_COUNT_1_BIT, // samples |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // loadOp |
| VK_ATTACHMENT_STORE_OP_STORE, // storeOp |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp |
| VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout |
| VK_IMAGE_LAYOUT_GENERAL // finalLayout |
| ); |
| const AttRef attachmentRef |
| ( |
| DE_NULL, // pNext |
| (deUint32)attachments.size(), // attachment |
| VK_IMAGE_LAYOUT_GENERAL, // layout |
| 0u // aspectMask |
| ); |
| sp0resolveAttachmentRefs.push_back(attachmentRef); |
| attachments.push_back(singlesampleAttachment); |
| } |
| // define second subpass inputs |
| { |
| const AttRef attachmentRef |
| ( |
| DE_NULL, // pNext |
| (deUint32)attachments.size() - 1, // attachment |
| VK_IMAGE_LAYOUT_GENERAL, // layout |
| VK_IMAGE_ASPECT_COLOR_BIT // aspectMask |
| ); |
| sp1inAttachmentRefs.push_back(attachmentRef); |
| } |
| // define second subpass outputs - it merges pairs of |
| // results that were produced by the first subpass |
| if (attachmentNdx < (m_attachmentsCount / 2)) |
| { |
| const AttRef colorAttachmentRef |
| ( |
| DE_NULL, // pNext |
| (deUint32)attachments.size() - 1, // attachment |
| VK_IMAGE_LAYOUT_GENERAL, // layout |
| 0u // aspectMask |
| ); |
| sp1colorAttachmentRefs.push_back(colorAttachmentRef); |
| } |
| } |
| |
| DE_ASSERT(sp0colorAttachmentRefs.size() == sp0resolveAttachmentRefs.size()); |
| DE_ASSERT(attachments.size() == sp0colorAttachmentRefs.size() + sp0resolveAttachmentRefs.size()); |
| |
| { |
| const SubpassDesc subpass0 |
| ( |
| // sType |
| DE_NULL, // pNext |
| (VkSubpassDescriptionFlags)0, // flags |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint |
| 0u, // viewMask |
| 0u, // inputAttachmentCount |
| DE_NULL, // pInputAttachments |
| (deUint32)sp0colorAttachmentRefs.size(), // colorAttachmentCount |
| &sp0colorAttachmentRefs[0], // pColorAttachments |
| &sp0resolveAttachmentRefs[0], // pResolveAttachments |
| DE_NULL, // pDepthStencilAttachment |
| 0u, // preserveAttachmentCount |
| DE_NULL // pPreserveAttachments |
| ); |
| const SubpassDesc subpass1 |
| ( |
| // sType |
| DE_NULL, // pNext |
| (VkSubpassDescriptionFlags)0, // flags |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint |
| 0u, // viewMask |
| (deUint32)sp1inAttachmentRefs.size(), // inputAttachmentCount |
| &sp1inAttachmentRefs[0], // pInputAttachments |
| (deUint32)sp1colorAttachmentRefs.size(), // colorAttachmentCount |
| &sp1colorAttachmentRefs[0], // pColorAttachments |
| DE_NULL, // pResolveAttachments |
| DE_NULL, // pDepthStencilAttachment |
| 0u, // preserveAttachmentCount |
| DE_NULL // pPreserveAttachments |
| ); |
| SubpassDesc subpasses[] = |
| { |
| subpass0, |
| subpass1 |
| }; |
| const SubpassDep subpassDependency |
| ( |
| DE_NULL, // pNext |
| 0u, // srcSubpass |
| 1u, // dstSubpass |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // dstStageMask |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask |
| VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // dstAccessMask |
| 0u, // dependencyFlags |
| 0u // viewOffset |
| ); |
| const RenderPassCreateInfo renderPassCreator |
| ( |
| // sType |
| DE_NULL, // pNext |
| (VkRenderPassCreateFlags)0u, // flags |
| (deUint32)attachments.size(), // attachmentCount |
| &attachments[0], // pAttachments |
| 2u, // subpassCount |
| subpasses, // pSubpasses |
| 1u, // dependencyCount |
| &subpassDependency, // pDependencies |
| 0u, // correlatedViewMaskCount |
| DE_NULL // pCorrelatedViewMasks |
| ); |
| |
| return renderPassCreator.createRenderPass(vkd, device); |
| } |
| } |
| |
| Move<VkRenderPass> MaxAttachmenstsRenderPassTestInstance::createRenderPassSwitch(const RenderingType renderingType) |
| { |
| switch (renderingType) |
| { |
| case RENDERING_TYPE_RENDERPASS_LEGACY: |
| return createRenderPass<RenderPass1Trait>(); |
| case RENDERING_TYPE_RENDERPASS2: |
| return createRenderPass<RenderPass2Trait>(); |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| Move<VkPipelineLayout> MaxAttachmenstsRenderPassTestInstance::createRenderPipelineLayout(bool secondSubpass) |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| |
| const VkPipelineLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| DE_NULL, |
| (vk::VkPipelineLayoutCreateFlags)0, |
| |
| secondSubpass ? 1u : 0u, |
| secondSubpass ? &*m_descriptorSetLayout : DE_NULL, |
| |
| 0u, |
| DE_NULL |
| }; |
| |
| return createPipelineLayout(vkd, device, &createInfo); |
| } |
| |
| Move<VkPipeline> MaxAttachmenstsRenderPassTestInstance::createRenderPipeline(bool secondSubpass) |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| VkDevice device = m_context.getDevice(); |
| const vk::BinaryCollection& binaryCollection = m_context.getBinaryCollection(); |
| VkSampleCountFlagBits sampleCount = sampleCountBitFromSampleCount(m_sampleCount); |
| deUint32 blendStatesCount = m_attachmentsCount; |
| std::string fragShaderNameBase = "quad-frag-sp0-"; |
| |
| if (secondSubpass) |
| { |
| sampleCount = VK_SAMPLE_COUNT_1_BIT; |
| blendStatesCount /= 2; |
| fragShaderNameBase = "quad-frag-sp1-"; |
| } |
| |
| std::string fragShaderName = fragShaderNameBase + de::toString(m_attachmentsCount); |
| const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u)); |
| const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get(fragShaderName), 0u)); |
| const Move<VkShaderModule> geometryShaderModule (m_layerCount == 1 ? Move<VkShaderModule>() : createShaderModule(vkd, device, binaryCollection.get("geom"), 0u)); |
| |
| // Disable blending |
| const VkPipelineColorBlendAttachmentState attachmentBlendState = |
| { |
| VK_FALSE, |
| VK_BLEND_FACTOR_SRC_ALPHA, |
| VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, |
| VK_BLEND_OP_ADD, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_OP_ADD, |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT |
| }; |
| std::vector<VkPipelineColorBlendAttachmentState> attachmentBlendStates(blendStatesCount, attachmentBlendState); |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineVertexInputStateCreateFlags)0u, |
| |
| 0u, |
| DE_NULL, |
| |
| 0u, |
| DE_NULL |
| }; |
| const tcu::UVec2 renderArea (m_width, m_height); |
| const std::vector<VkViewport> viewports (1, makeViewport(renderArea)); |
| const std::vector<VkRect2D> scissors (1, makeRect2D(renderArea)); |
| |
| const VkPipelineMultisampleStateCreateInfo multisampleState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineMultisampleStateCreateFlags)0u, |
| |
| sampleCount, |
| VK_FALSE, |
| 0.0f, |
| DE_NULL, |
| VK_FALSE, |
| VK_FALSE, |
| }; |
| const VkPipelineDepthStencilStateCreateInfo depthStencilState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineDepthStencilStateCreateFlags)0u, |
| |
| VK_FALSE, |
| VK_TRUE, |
| VK_COMPARE_OP_ALWAYS, |
| VK_FALSE, |
| VK_TRUE, |
| { |
| VK_STENCIL_OP_KEEP, |
| VK_STENCIL_OP_INCREMENT_AND_WRAP, |
| VK_STENCIL_OP_KEEP, |
| VK_COMPARE_OP_ALWAYS, |
| ~0u, |
| ~0u, |
| 0xFFu / (m_sampleCount + 1) |
| }, |
| { |
| VK_STENCIL_OP_KEEP, |
| VK_STENCIL_OP_INCREMENT_AND_WRAP, |
| VK_STENCIL_OP_KEEP, |
| VK_COMPARE_OP_ALWAYS, |
| ~0u, |
| ~0u, |
| 0xFFu / (m_sampleCount + 1) |
| }, |
| |
| 0.0f, |
| 1.0f |
| }; |
| const VkPipelineColorBlendStateCreateInfo blendState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineColorBlendStateCreateFlags)0u, |
| |
| VK_FALSE, |
| VK_LOGIC_OP_COPY, |
| deUint32(attachmentBlendStates.size()), |
| &attachmentBlendStates[0], |
| { 0.0f, 0.0f, 0.0f, 0.0f } |
| }; |
| |
| return makeGraphicsPipeline(vkd, // vk |
| device, // device |
| secondSubpass ? *m_pipelineLayoutPass1 : *m_pipelineLayoutPass0, // pipelineLayout |
| *vertexShaderModule, // vertexShaderModule |
| DE_NULL, // tessellationControlShaderModule |
| DE_NULL, // tessellationEvalShaderModule |
| m_layerCount != 1 ? *geometryShaderModule : DE_NULL, // geometryShaderModule |
| *fragmentShaderModule, // fragmentShaderModule |
| *m_renderPass, // renderPass |
| viewports, // viewports |
| scissors, // scissors |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // topology |
| secondSubpass, // subpass |
| 0u, // patchControlPoints |
| &vertexInputState, // vertexInputStateCreateInfo |
| DE_NULL, // rasterizationStateCreateInfo |
| &multisampleState, // multisampleStateCreateInfo |
| &depthStencilState, // depthStencilStateCreateInfo |
| &blendState); // colorBlendStateCreateInfo |
| } |
| |
| class MultisampleRenderPassResolveLevelTestInstance : public MultisampleRenderPassTestInstance |
| { |
| public: |
| MultisampleRenderPassResolveLevelTestInstance (Context& context, TestConfig2 config); |
| ~MultisampleRenderPassResolveLevelTestInstance (void) = default; |
| }; |
| |
| MultisampleRenderPassResolveLevelTestInstance::MultisampleRenderPassResolveLevelTestInstance (Context& context, TestConfig2 config) |
| : MultisampleRenderPassTestInstance(context, config, config.resolveLevel) |
| { |
| } |
| |
| struct Programs |
| { |
| void init(vk::SourceCollections& dst, TestConfig config) const |
| { |
| const tcu::TextureFormat format (mapVkFormat(config.format)); |
| const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); |
| |
| dst.glslSources.add("quad-vert") << glu::VertexSource( |
| "#version 450\n" |
| "out gl_PerVertex {\n" |
| "\tvec4 gl_Position;\n" |
| "};\n" |
| "highp float;\n" |
| "void main (void) {\n" |
| "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" |
| "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" |
| "}\n"); |
| |
| if (config.layerCount > 1) |
| { |
| std::ostringstream src; |
| |
| src << "#version 450\n" |
| << "highp float;\n" |
| << "\n" |
| << "layout(triangles) in;\n" |
| << "layout(triangle_strip, max_vertices = " << 3 * 2 * config.layerCount << ") out;\n" |
| << "\n" |
| << "in gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << "} gl_in[];\n" |
| << "\n" |
| << "out gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << "};\n" |
| << "\n" |
| << "void main (void) {\n" |
| << " for (int layerNdx = 0; layerNdx < " << config.layerCount << "; ++layerNdx) {\n" |
| << " for(int vertexNdx = 0; vertexNdx < gl_in.length(); vertexNdx++) {\n" |
| << " gl_Position = gl_in[vertexNdx].gl_Position;\n" |
| << " gl_Layer = layerNdx;\n" |
| << " EmitVertex();\n" |
| << " };\n" |
| << " EndPrimitive();\n" |
| << " };\n" |
| << "}\n"; |
| |
| dst.glslSources.add("geom") << glu::GeometrySource(src.str()); |
| } |
| |
| const tcu::StringTemplate genericLayoutTemplate("layout(location = ${INDEX}) out ${TYPE_PREFIX}vec4 o_color${INDEX};\n"); |
| const tcu::StringTemplate genericBodyTemplate("\to_color${INDEX} = ${TYPE_PREFIX}vec4(${COLOR_VAL});\n"); |
| |
| if (config.testType == RESOLVE || config.testType == COMPATIBILITY) |
| { |
| const tcu::StringTemplate fragTemplate("#version 450\n" |
| "layout(push_constant) uniform PushConstant {\n" |
| "\thighp uint sampleMask;\n" |
| "} pushConstants;\n" |
| "${LAYOUT}" |
| "void main (void)\n" |
| "{\n" |
| "${BODY}" |
| "}\n"); |
| |
| std::map<std::string, std::string> parameters; |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| parameters["TYPE_PREFIX"] = "u"; |
| parameters["COLOR_VAL"] = "255"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| parameters["TYPE_PREFIX"] = "i"; |
| parameters["COLOR_VAL"] = "127"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| parameters["TYPE_PREFIX"] = ""; |
| parameters["COLOR_VAL"] = "1.0"; |
| break; |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| |
| std::string layoutDefinitions = ""; |
| std::string shaderBody = "\tgl_SampleMask[0] = int(pushConstants.sampleMask);\n"; |
| |
| for (deUint32 attIdx = 0; attIdx < config.attachmentCount; ++attIdx) |
| { |
| parameters["INDEX"] = de::toString(attIdx); |
| layoutDefinitions += genericLayoutTemplate.specialize(parameters); |
| shaderBody += genericBodyTemplate.specialize(parameters); |
| } |
| |
| parameters["LAYOUT"] = layoutDefinitions; |
| parameters["BODY"] = shaderBody; |
| dst.glslSources.add("quad-frag") << glu::FragmentSource(fragTemplate.specialize(parameters)); |
| } |
| else // MAX_ATTACMENTS |
| { |
| const tcu::StringTemplate fragTemplate("#version 450\n" |
| "${LAYOUT}" |
| "void main (void)\n" |
| "{\n" |
| "${BODY}" |
| "}\n"); |
| |
| std::map<std::string, std::string> parameters; |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| parameters["TYPE_PREFIX"] = "u"; |
| parameters["COLOR_VAL"] = "0, 64, 192, 252"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| parameters["TYPE_PREFIX"] = "i"; |
| parameters["COLOR_VAL"] = "0, 32, 100, 124"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| parameters["TYPE_PREFIX"] = ""; |
| parameters["COLOR_VAL"] = "0.0, 0.4, 0.8, 1.0"; |
| break; |
| |
| default: |
| DE_FATAL("Unknown channel class"); |
| } |
| |
| // parts of fragment shader for second subpass - Vulkan introduced a new uniform type and syntax to glsl for input attachments |
| const tcu::StringTemplate subpassLayoutTemplate("layout (input_attachment_index = ${INDEX}, set = 0, binding = ${INDEX}) uniform ${TYPE_PREFIX}subpassInput i_color${INDEX};\n"); |
| const tcu::StringTemplate subpassFBodyTemplate("\to_color${INDEX} = subpassLoad(i_color${INDEX})*0.5 + subpassLoad(i_color${MIX_INDEX})*0.25;\n"); |
| const tcu::StringTemplate subpassIBodyTemplate("\to_color${INDEX} = subpassLoad(i_color${INDEX}) / 2 + subpassLoad(i_color${MIX_INDEX}) / 4;\n"); |
| |
| bool selectIBody = isIntFormat(config.format) || isUintFormat(config.format); |
| const tcu::StringTemplate& subpassBodyTemplate = selectIBody ? subpassIBodyTemplate : subpassFBodyTemplate; |
| |
| std::string sp0layoutDefinitions = ""; |
| std::string sp0shaderBody = ""; |
| std::string sp1inLayoutDefinitions = ""; |
| std::string sp1outLayoutDefinitions = ""; |
| std::string sp1shaderBody = ""; |
| |
| deUint32 halfAttachments = config.attachmentCount / 2; |
| for (deUint32 attIdx = 0; attIdx < config.attachmentCount; ++attIdx) |
| { |
| parameters["INDEX"] = de::toString(attIdx); |
| |
| sp0layoutDefinitions += genericLayoutTemplate.specialize(parameters); |
| sp0shaderBody += genericBodyTemplate.specialize(parameters); |
| |
| sp1inLayoutDefinitions += subpassLayoutTemplate.specialize(parameters); |
| if (attIdx < halfAttachments) |
| { |
| // we are combining pairs of input attachments to produce half the number of outputs |
| parameters["MIX_INDEX"] = de::toString(halfAttachments + attIdx); |
| sp1outLayoutDefinitions += genericLayoutTemplate.specialize(parameters); |
| sp1shaderBody += subpassBodyTemplate.specialize(parameters); |
| } |
| } |
| |
| // construct fragment shaders for subpass1 and subpass2; note that there |
| // is different shader definition depending on number of attachments |
| std::string nameBase = "quad-frag-sp"; |
| std::string namePostfix = de::toString(config.attachmentCount); |
| parameters["LAYOUT"] = sp0layoutDefinitions; |
| parameters["BODY"] = sp0shaderBody; |
| dst.glslSources.add(nameBase + "0-" + namePostfix) << glu::FragmentSource(fragTemplate.specialize(parameters)); |
| parameters["LAYOUT"] = sp1inLayoutDefinitions + sp1outLayoutDefinitions; |
| parameters["BODY"] = sp1shaderBody; |
| dst.glslSources.add(nameBase + "1-" + namePostfix) << glu::FragmentSource(fragTemplate.specialize(parameters)); |
| } |
| } |
| }; |
| |
| template<class TestConfigType> |
| void checkSupport(Context& context, TestConfigType config) |
| { |
| if (config.layerCount > 1) |
| context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); |
| |
| if (config.renderingType == RENDERING_TYPE_RENDERPASS2) |
| context.requireDeviceFunctionality("VK_KHR_create_renderpass2"); |
| |
| if (config.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) |
| context.requireDeviceFunctionality("VK_KHR_dynamic_rendering"); |
| |
| if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && |
| !context.getPortabilitySubsetFeatures().multisampleArrayImage && |
| (config.sampleCount != VK_SAMPLE_COUNT_1_BIT) && (config.layerCount != 1)) |
| { |
| TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support image array with multiple samples per texel"); |
| } |
| |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); |
| const vk::VkPhysicalDeviceProperties properties = vk::getPhysicalDeviceProperties(vki, physicalDevice); |
| |
| if (config.attachmentCount > properties.limits.maxColorAttachments) |
| TCU_THROW(NotSupportedError, "Required number of color attachments not supported."); |
| } |
| |
| std::string formatToName (VkFormat format) |
| { |
| const std::string formatStr = de::toString(format); |
| const std::string prefix = "VK_FORMAT_"; |
| |
| DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix); |
| |
| return de::toLower(formatStr.substr(prefix.length())); |
| } |
| |
| void initTests (tcu::TestCaseGroup* group, RenderingType renderingType) |
| { |
| static const VkFormat formats[] = |
| { |
| VK_FORMAT_R5G6B5_UNORM_PACK16, |
| VK_FORMAT_R8_UNORM, |
| VK_FORMAT_R8_SNORM, |
| VK_FORMAT_R8_UINT, |
| VK
|