blob: 84ce8d7b7e04c69c5be85c2645c292fd566196a5 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Imagination Technologies Ltd.
*
* 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 Image sampling case
*//*--------------------------------------------------------------------*/
#include "vktPipelineImageSamplingInstance.hpp"
#include "vktPipelineClearUtil.hpp"
#include "vktPipelineReferenceRenderer.hpp"
#include "vkBuilderUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkPrograms.hpp"
#include "vkQueryUtil.hpp"
#include "vkRefUtil.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuTestLog.hpp"
#include "deSTLUtil.hpp"
namespace vkt
{
namespace pipeline
{
using namespace vk;
using de::MovePtr;
using de::UniquePtr;
namespace
{
de::MovePtr<Allocation> allocateBuffer (const InstanceInterface& vki,
const DeviceInterface& vkd,
const VkPhysicalDevice& physDevice,
const VkDevice device,
const VkBuffer& buffer,
const MemoryRequirement requirement,
Allocator& allocator,
AllocationKind allocationKind)
{
switch (allocationKind)
{
case ALLOCATION_KIND_SUBALLOCATED:
{
const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vkd, device, buffer);
return allocator.allocate(memoryRequirements, requirement);
}
case ALLOCATION_KIND_DEDICATED:
{
return allocateDedicated(vki, vkd, physDevice, device, buffer, requirement);
}
default:
{
TCU_THROW(InternalError, "Invalid allocation kind");
}
}
}
de::MovePtr<Allocation> allocateImage (const InstanceInterface& vki,
const DeviceInterface& vkd,
const VkPhysicalDevice& physDevice,
const VkDevice device,
const VkImage& image,
const MemoryRequirement requirement,
Allocator& allocator,
AllocationKind allocationKind)
{
switch (allocationKind)
{
case ALLOCATION_KIND_SUBALLOCATED:
{
const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vkd, device, image);
return allocator.allocate(memoryRequirements, requirement);
}
case ALLOCATION_KIND_DEDICATED:
{
return allocateDedicated(vki, vkd, physDevice, device, image, requirement);
}
default:
{
TCU_THROW(InternalError, "Invalid allocation kind");
}
}
}
static VkImageType getCompatibleImageType (VkImageViewType viewType)
{
switch (viewType)
{
case VK_IMAGE_VIEW_TYPE_1D: return VK_IMAGE_TYPE_1D;
case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return VK_IMAGE_TYPE_1D;
case VK_IMAGE_VIEW_TYPE_2D: return VK_IMAGE_TYPE_2D;
case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return VK_IMAGE_TYPE_2D;
case VK_IMAGE_VIEW_TYPE_3D: return VK_IMAGE_TYPE_3D;
case VK_IMAGE_VIEW_TYPE_CUBE: return VK_IMAGE_TYPE_2D;
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return VK_IMAGE_TYPE_2D;
default:
break;
}
DE_ASSERT(false);
return VK_IMAGE_TYPE_1D;
}
template<typename TcuFormatType>
static MovePtr<TestTexture> createTestTexture (const TcuFormatType format, VkImageViewType viewType, const tcu::IVec3& size, int layerCount)
{
MovePtr<TestTexture> texture;
const VkImageType imageType = getCompatibleImageType(viewType);
switch (imageType)
{
case VK_IMAGE_TYPE_1D:
if (layerCount == 1)
texture = MovePtr<TestTexture>(new TestTexture1D(format, size.x()));
else
texture = MovePtr<TestTexture>(new TestTexture1DArray(format, size.x(), layerCount));
break;
case VK_IMAGE_TYPE_2D:
if (layerCount == 1)
{
texture = MovePtr<TestTexture>(new TestTexture2D(format, size.x(), size.y()));
}
else
{
if (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
{
if (layerCount == tcu::CUBEFACE_LAST && viewType == VK_IMAGE_VIEW_TYPE_CUBE)
{
texture = MovePtr<TestTexture>(new TestTextureCube(format, size.x()));
}
else
{
DE_ASSERT(layerCount % tcu::CUBEFACE_LAST == 0);
texture = MovePtr<TestTexture>(new TestTextureCubeArray(format, size.x(), layerCount));
}
}
else
{
texture = MovePtr<TestTexture>(new TestTexture2DArray(format, size.x(), size.y(), layerCount));
}
}
break;
case VK_IMAGE_TYPE_3D:
texture = MovePtr<TestTexture>(new TestTexture3D(format, size.x(), size.y(), size.z()));
break;
default:
DE_ASSERT(false);
}
return texture;
}
} // anonymous
ImageSamplingInstance::ImageSamplingInstance (Context& context,
const tcu::UVec2& renderSize,
VkImageViewType imageViewType,
VkFormat imageFormat,
const tcu::IVec3& imageSize,
int layerCount,
const VkComponentMapping& componentMapping,
const VkImageSubresourceRange& subresourceRange,
const VkSamplerCreateInfo& samplerParams,
float samplerLod,
const std::vector<Vertex4Tex4>& vertices,
VkDescriptorType samplingType,
int imageCount,
AllocationKind allocationKind)
: vkt::TestInstance (context)
, m_allocationKind (allocationKind)
, m_samplingType (samplingType)
, m_imageViewType (imageViewType)
, m_imageFormat (imageFormat)
, m_imageSize (imageSize)
, m_layerCount (layerCount)
, m_imageCount (imageCount)
, m_componentMapping (componentMapping)
, m_subresourceRange (subresourceRange)
, m_samplerParams (samplerParams)
, m_samplerLod (samplerLod)
, m_renderSize (renderSize)
, m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
, m_vertices (vertices)
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice physDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const VkQueue queue = context.getUniversalQueue();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
if (!isSupportedSamplableFormat(context.getInstanceInterface(), context.getPhysicalDevice(), imageFormat))
throw tcu::NotSupportedError(std::string("Unsupported format for sampling: ") + getFormatName(imageFormat));
if ((deUint32)imageCount > context.getDeviceProperties().limits.maxColorAttachments)
throw tcu::NotSupportedError(std::string("Unsupported render target count: ") + de::toString(imageCount));
if ((samplerParams.minFilter == VK_FILTER_LINEAR ||
samplerParams.magFilter == VK_FILTER_LINEAR ||
samplerParams.mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR) &&
!isLinearFilteringSupported(context.getInstanceInterface(), context.getPhysicalDevice(), imageFormat, VK_IMAGE_TILING_OPTIMAL))
throw tcu::NotSupportedError(std::string("Unsupported format for linear filtering: ") + getFormatName(imageFormat));
if ((samplerParams.addressModeU == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
samplerParams.addressModeV == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
samplerParams.addressModeW == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) &&
!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_sampler_mirror_clamp_to_edge"))
TCU_THROW(NotSupportedError, "VK_KHR_sampler_mirror_clamp_to_edge not supported");
if (isCompressedFormat(imageFormat) && imageViewType == VK_IMAGE_VIEW_TYPE_3D)
{
// \todo [2016-01-22 pyry] Mandate VK_ERROR_FORMAT_NOT_SUPPORTED
try
{
const VkImageFormatProperties formatProperties = getPhysicalDeviceImageFormatProperties(context.getInstanceInterface(),
context.getPhysicalDevice(),
imageFormat,
VK_IMAGE_TYPE_3D,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_SAMPLED_BIT,
(VkImageCreateFlags)0);
if (formatProperties.maxExtent.width == 0 &&
formatProperties.maxExtent.height == 0 &&
formatProperties.maxExtent.depth == 0)
TCU_THROW(NotSupportedError, "3D compressed format not supported");
}
catch (const Error&)
{
TCU_THROW(NotSupportedError, "3D compressed format not supported");
}
}
if (imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && !context.getDeviceFeatures().imageCubeArray)
TCU_THROW(NotSupportedError, "imageCubeArray feature is not supported");
if (m_allocationKind == ALLOCATION_KIND_DEDICATED)
{
const std::string extensionName("VK_KHR_dedicated_allocation");
if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName))
TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str());
}
// Create texture images, views and samplers
{
VkImageCreateFlags imageFlags = 0u;
if (m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE || m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
imageFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
// Initialize texture data
if (isCompressedFormat(imageFormat))
m_texture = createTestTexture(mapVkCompressedFormat(imageFormat), imageViewType, imageSize, layerCount);
else
m_texture = createTestTexture(mapVkFormat(imageFormat), imageViewType, imageSize, layerCount);
const VkImageCreateInfo imageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
imageFlags, // VkImageCreateFlags flags;
getCompatibleImageType(m_imageViewType), // VkImageType imageType;
imageFormat, // VkFormat format;
{ // VkExtent3D extent;
(deUint32)m_imageSize.x(),
(deUint32)m_imageSize.y(),
(deUint32)m_imageSize.z()
},
(deUint32)m_texture->getNumLevels(), // deUint32 mipLevels;
(deUint32)m_layerCount, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_images.resize(m_imageCount);
m_imageAllocs.resize(m_imageCount);
m_imageViews.resize(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
m_images[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &imageParams)));
m_imageAllocs[imgNdx] = SharedAllocPtr(new UniqueAlloc(allocateImage(vki, vk, physDevice, vkDevice, **m_images[imgNdx], MemoryRequirement::Any, memAlloc, m_allocationKind)));
VK_CHECK(vk.bindImageMemory(vkDevice, **m_images[imgNdx], (*m_imageAllocs[imgNdx])->getMemory(), (*m_imageAllocs[imgNdx])->getOffset()));
// Upload texture data
uploadTestTexture(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_texture, **m_images[imgNdx]);
// Create image view and sampler
const VkImageViewCreateInfo imageViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
**m_images[imgNdx], // VkImage image;
m_imageViewType, // VkImageViewType viewType;
imageFormat, // VkFormat format;
m_componentMapping, // VkComponentMapping components;
m_subresourceRange, // VkImageSubresourceRange subresourceRange;
};
m_imageViews[imgNdx] = SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &imageViewParams)));
}
m_sampler = createSampler(vk, vkDevice, &m_samplerParams);
}
// Create descriptor set for image and sampler
{
DescriptorPoolBuilder descriptorPoolBuilder;
if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER, 1u);
descriptorPoolBuilder.addType(m_samplingType, m_imageCount);
m_descriptorPool = descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? m_imageCount + 1u : m_imageCount);
DescriptorSetLayoutBuilder setLayoutBuilder;
if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
setLayoutBuilder.addArrayBinding(m_samplingType, m_imageCount, VK_SHADER_STAGE_FRAGMENT_BIT);
m_descriptorSetLayout = setLayoutBuilder.build(vk, vkDevice);
const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_descriptorPool, // VkDescriptorPool descriptorPool;
1u, // deUint32 setLayoutCount;
&m_descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts;
};
m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocateInfo);
const VkSampler sampler = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? DE_NULL : *m_sampler;
std::vector<VkDescriptorImageInfo> descriptorImageInfo(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
descriptorImageInfo[imgNdx].sampler = sampler; // VkSampler sampler;
descriptorImageInfo[imgNdx].imageView = **m_imageViews[imgNdx]; // VkImageView imageView;
descriptorImageInfo[imgNdx].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // VkImageLayout imageLayout;
}
DescriptorSetUpdateBuilder setUpdateBuilder;
if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
{
const VkDescriptorImageInfo descriptorSamplerInfo =
{
*m_sampler, // VkSampler sampler;
DE_NULL, // VkImageView imageView;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout;
};
setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_SAMPLER, &descriptorSamplerInfo);
}
const deUint32 binding = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? 1u : 0u;
setUpdateBuilder.writeArray(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(binding), m_samplingType, m_imageCount, descriptorImageInfo.data());
setUpdateBuilder.update(vk, vkDevice);
}
// Create color images and views
{
const VkImageCreateInfo colorImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_colorFormat, // VkFormat format;
{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_colorImages.resize(m_imageCount);
m_colorImageAllocs.resize(m_imageCount);
m_colorAttachmentViews.resize(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
m_colorImages[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &colorImageParams)));
m_colorImageAllocs[imgNdx] = SharedAllocPtr(new UniqueAlloc(allocateImage(vki, vk, physDevice, vkDevice, **m_colorImages[imgNdx], MemoryRequirement::Any, memAlloc, m_allocationKind)));
VK_CHECK(vk.bindImageMemory(vkDevice, **m_colorImages[imgNdx], (*m_colorImageAllocs[imgNdx])->getMemory(), (*m_colorImageAllocs[imgNdx])->getOffset()));
const VkImageViewCreateInfo colorAttachmentViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
**m_colorImages[imgNdx], // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_colorFormat, // VkFormat format;
componentMappingRGBA, // VkComponentMapping components;
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
};
m_colorAttachmentViews[imgNdx] = SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &colorAttachmentViewParams)));
}
}
// Create render pass
{
std::vector<VkAttachmentDescription> colorAttachmentDescriptions(m_imageCount);
std::vector<VkAttachmentReference> colorAttachmentReferences(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
colorAttachmentDescriptions[imgNdx].flags = 0u; // VkAttachmentDescriptionFlags flags;
colorAttachmentDescriptions[imgNdx].format = m_colorFormat; // VkFormat format;
colorAttachmentDescriptions[imgNdx].samples = VK_SAMPLE_COUNT_1_BIT; // VkSampleCountFlagBits samples;
colorAttachmentDescriptions[imgNdx].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // VkAttachmentLoadOp loadOp;
colorAttachmentDescriptions[imgNdx].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // VkAttachmentStoreOp storeOp;
colorAttachmentDescriptions[imgNdx].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // VkAttachmentLoadOp stencilLoadOp;
colorAttachmentDescriptions[imgNdx].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // VkAttachmentStoreOp stencilStoreOp;
colorAttachmentDescriptions[imgNdx].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout initialLayout;
colorAttachmentDescriptions[imgNdx].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout finalLayout;
colorAttachmentReferences[imgNdx].attachment = (deUint32)imgNdx; // deUint32 attachment;
colorAttachmentReferences[imgNdx].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout layout;
}
const VkSubpassDescription subpassDescription =
{
0u, // VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // deUint32 inputAttachmentCount;
DE_NULL, // const VkAttachmentReference* pInputAttachments;
(deUint32)m_imageCount, // deUint32 colorAttachmentCount;
&colorAttachmentReferences[0], // const VkAttachmentReference* pColorAttachments;
DE_NULL, // const VkAttachmentReference* pResolveAttachments;
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
0u, // deUint32 preserveAttachmentCount;
DE_NULL // const VkAttachmentReference* pPreserveAttachments;
};
const VkRenderPassCreateInfo renderPassParams =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkRenderPassCreateFlags flags;
(deUint32)m_imageCount, // deUint32 attachmentCount;
&colorAttachmentDescriptions[0], // const VkAttachmentDescription* pAttachments;
1u, // deUint32 subpassCount;
&subpassDescription, // const VkSubpassDescription* pSubpasses;
0u, // deUint32 dependencyCount;
DE_NULL // const VkSubpassDependency* pDependencies;
};
m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
}
// Create framebuffer
{
std::vector<VkImageView> pAttachments(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
pAttachments[imgNdx] = m_colorAttachmentViews[imgNdx]->get();
const VkFramebufferCreateInfo framebufferParams =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkFramebufferCreateFlags flags;
*m_renderPass, // VkRenderPass renderPass;
(deUint32)m_imageCount, // deUint32 attachmentCount;
&pAttachments[0], // const VkImageView* pAttachments;
(deUint32)m_renderSize.x(), // deUint32 width;
(deUint32)m_renderSize.y(), // deUint32 height;
1u // deUint32 layers;
};
m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
}
// Create pipeline layout
{
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineLayoutCreateFlags flags;
1u, // deUint32 setLayoutCount;
&m_descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
}
m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tex_vert"), 0);
m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tex_frag"), 0);
// Create pipeline
{
const VkPipelineShaderStageCreateInfo shaderStages[2] =
{
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
*m_vertexShaderModule, // VkShaderModule module;
"main", // const char* pName;
DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
},
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
*m_fragmentShaderModule, // VkShaderModule module;
"main", // const char* pName;
DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
}
};
const VkVertexInputBindingDescription vertexInputBindingDescription =
{
0u, // deUint32 binding;
sizeof(Vertex4Tex4), // deUint32 strideInBytes;
VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
};
const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
{
{
0u, // deUint32 location;
0u, // deUint32 binding;
VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
0u // deUint32 offset;
},
{
1u, // deUint32 location;
0u, // deUint32 binding;
VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
DE_OFFSET_OF(Vertex4Tex4, texCoord), // deUint32 offset;
}
};
const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineVertexInputStateCreateFlags flags;
1u, // deUint32 vertexBindingDescriptionCount;
&vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2u, // deUint32 vertexAttributeDescriptionCount;
vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
};
const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineInputAssemblyStateCreateFlags flags;
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
false // VkBool32 primitiveRestartEnable;
};
const VkViewport viewport =
{
0.0f, // float x;
0.0f, // float y;
(float)m_renderSize.x(), // float width;
(float)m_renderSize.y(), // float height;
0.0f, // float minDepth;
1.0f // float maxDepth;
};
const VkRect2D scissor = { { 0, 0 }, { (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() } };
const VkPipelineViewportStateCreateInfo viewportStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineViewportStateCreateFlags flags;
1u, // deUint32 viewportCount;
&viewport, // const VkViewport* pViewports;
1u, // deUint32 scissorCount;
&scissor // const VkRect2D* pScissors;
};
const VkPipelineRasterizationStateCreateInfo rasterStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineRasterizationStateCreateFlags flags;
false, // VkBool32 depthClampEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
false, // VkBool32 depthBiasEnable;
0.0f, // float depthBiasConstantFactor;
0.0f, // float depthBiasClamp;
0.0f, // float depthBiasSlopeFactor;
1.0f // float lineWidth;
};
std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
colorBlendAttachmentStates[imgNdx].blendEnable = false; // VkBool32 blendEnable;
colorBlendAttachmentStates[imgNdx].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // VkBlendFactor srcColorBlendFactor;
colorBlendAttachmentStates[imgNdx].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // VkBlendFactor dstColorBlendFactor;
colorBlendAttachmentStates[imgNdx].colorBlendOp = VK_BLEND_OP_ADD; // VkBlendOp colorBlendOp;
colorBlendAttachmentStates[imgNdx].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // VkBlendFactor srcAlphaBlendFactor;
colorBlendAttachmentStates[imgNdx].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // VkBlendFactor dstAlphaBlendFactor;
colorBlendAttachmentStates[imgNdx].alphaBlendOp = VK_BLEND_OP_ADD; // VkBlendOp alphaBlendOp;
colorBlendAttachmentStates[imgNdx].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
}
const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineColorBlendStateCreateFlags flags;
false, // VkBool32 logicOpEnable;
VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
(deUint32)m_imageCount, // deUint32 attachmentCount;
&colorBlendAttachmentStates[0], // const VkPipelineColorBlendAttachmentState* pAttachments;
{ 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4];
};
const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineMultisampleStateCreateFlags flags;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
false, // VkBool32 sampleShadingEnable;
0.0f, // float minSampleShading;
DE_NULL, // const VkSampleMask* pSampleMask;
false, // VkBool32 alphaToCoverageEnable;
false // VkBool32 alphaToOneEnable;
};
VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineDepthStencilStateCreateFlags flags;
false, // VkBool32 depthTestEnable;
false, // VkBool32 depthWriteEnable;
VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
false, // VkBool32 depthBoundsTestEnable;
false, // VkBool32 stencilTestEnable;
{ // VkStencilOpState front;
VK_STENCIL_OP_ZERO, // VkStencilOp failOp;
VK_STENCIL_OP_ZERO, // VkStencilOp passOp;
VK_STENCIL_OP_ZERO, // VkStencilOp depthFailOp;
VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
0u, // deUint32 compareMask;
0u, // deUint32 writeMask;
0u // deUint32 reference;
},
{ // VkStencilOpState back;
VK_STENCIL_OP_ZERO, // VkStencilOp failOp;
VK_STENCIL_OP_ZERO, // VkStencilOp passOp;
VK_STENCIL_OP_ZERO, // VkStencilOp depthFailOp;
VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
0u, // deUint32 compareMask;
0u, // deUint32 writeMask;
0u // deUint32 reference;
},
0.0f, // float minDepthBounds;
1.0f // float maxDepthBounds;
};
const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineCreateFlags flags;
2u, // deUint32 stageCount;
shaderStages, // const VkPipelineShaderStageCreateInfo* pStages;
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
&inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState;
&rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
&multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
&depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
(const VkPipelineDynamicStateCreateInfo*)DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
*m_pipelineLayout, // VkPipelineLayout layout;
*m_renderPass, // VkRenderPass renderPass;
0u, // deUint32 subpass;
0u, // VkPipeline basePipelineHandle;
0u // deInt32 basePipelineIndex;
};
m_graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
}
// Create vertex buffer
{
const VkDeviceSize vertexBufferSize = (VkDeviceSize)(m_vertices.size() * sizeof(Vertex4Tex4));
const VkBufferCreateInfo vertexBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
vertexBufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
DE_ASSERT(vertexBufferSize > 0);
m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
m_vertexBufferAlloc = allocateBuffer(vki, vk, physDevice, vkDevice, *m_vertexBuffer, MemoryRequirement::HostVisible, memAlloc, m_allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
// Load vertices into vertex buffer
deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], (size_t)vertexBufferSize);
flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
}
// Create command pool
m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
// Create command buffer
{
const VkCommandBufferBeginInfo cmdBufferBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkCommandBufferUsageFlags flags;
(const VkCommandBufferInheritanceInfo*)DE_NULL,
};
const std::vector<VkClearValue> attachmentClearValues (m_imageCount, defaultClearValue(m_colorFormat));
const VkRenderPassBeginInfo renderPassBeginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_renderPass, // VkRenderPass renderPass;
*m_framebuffer, // VkFramebuffer framebuffer;
{
{ 0, 0 },
{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
}, // VkRect2D renderArea;
static_cast<deUint32>(attachmentClearValues.size()), // deUint32 clearValueCount;
&attachmentClearValues[0] // const VkClearValue* pClearValues;
};
std::vector<VkImageMemoryBarrier> preAttachmentBarriers(m_imageCount);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
preAttachmentBarriers[imgNdx].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; // VkStructureType sType;
preAttachmentBarriers[imgNdx].pNext = DE_NULL; // const void* pNext;
preAttachmentBarriers[imgNdx].srcAccessMask = 0u; // VkAccessFlags srcAccessMask;
preAttachmentBarriers[imgNdx].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; // VkAccessFlags dstAccessMask;
preAttachmentBarriers[imgNdx].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; // VkImageLayout oldLayout;
preAttachmentBarriers[imgNdx].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout newLayout;
preAttachmentBarriers[imgNdx].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // deUint32 srcQueueFamilyIndex;
preAttachmentBarriers[imgNdx].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // deUint32 dstQueueFamilyIndex;
preAttachmentBarriers[imgNdx].image = **m_colorImages[imgNdx]; // VkImage image;
preAttachmentBarriers[imgNdx].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // VkImageSubresourceRange subresourceRange;
preAttachmentBarriers[imgNdx].subresourceRange.baseMipLevel = 0u;
preAttachmentBarriers[imgNdx].subresourceRange.levelCount = 1u;
preAttachmentBarriers[imgNdx].subresourceRange.baseArrayLayer = 0u;
preAttachmentBarriers[imgNdx].subresourceRange.layerCount = 1u;
}
m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (VkDependencyFlags)0,
0u, DE_NULL, 0u, DE_NULL, (deUint32)m_imageCount, &preAttachmentBarriers[0]);
vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
const VkDeviceSize vertexBufferOffset = 0;
vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
vk.cmdEndRenderPass(*m_cmdBuffer);
VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
}
// Create fence
m_fence = createFence(vk, vkDevice);
}
ImageSamplingInstance::~ImageSamplingInstance (void)
{
}
tcu::TestStatus ImageSamplingInstance::iterate (void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // deUint32 waitSemaphoreCount;
DE_NULL, // const VkSemaphore* pWaitSemaphores;
DE_NULL,
1u, // deUint32 commandBufferCount;
&m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
0u, // deUint32 signalSemaphoreCount;
DE_NULL // const VkSemaphore* pSignalSemaphores;
};
VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
return verifyImage();
}
namespace
{
bool isLookupResultValid (const tcu::Texture1DView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, coords.x(), lodBounds, result);
}
bool isLookupResultValid (const tcu::Texture1DArrayView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1), lodBounds, result);
}
bool isLookupResultValid (const tcu::Texture2DView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1), lodBounds, result);
}
bool isLookupResultValid (const tcu::Texture2DArrayView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
}
bool isLookupResultValid (const tcu::TextureCubeView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
}
bool isLookupResultValid (const tcu::TextureCubeArrayView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, tcu::IVec4(precision.coordBits.x()), coords, lodBounds, result);
}
bool isLookupResultValid(const tcu::Texture3DView& texture,
const tcu::Sampler& sampler,
const tcu::LookupPrecision& precision,
const tcu::Vec4& coords,
const tcu::Vec2& lodBounds,
const tcu::Vec4& result)
{
return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
}
template<typename TextureViewType>
bool validateResultImage (const TextureViewType& texture,
const tcu::Sampler& sampler,
const tcu::ConstPixelBufferAccess& texCoords,
const tcu::Vec2& lodBounds,
const tcu::LookupPrecision& lookupPrecision,
const tcu::Vec4& lookupScale,
const tcu::Vec4& lookupBias,
const tcu::ConstPixelBufferAccess& result,
const tcu::PixelBufferAccess& errorMask)
{
const int w = result.getWidth();
const int h = result.getHeight();
bool allOk = true;
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const tcu::Vec4 resultPixel = result.getPixel(x, y);
const tcu::Vec4 resultColor = (resultPixel - lookupBias) / lookupScale;
const tcu::Vec4 texCoord = texCoords.getPixel(x, y);
const bool pixelOk = isLookupResultValid(texture, sampler, lookupPrecision, texCoord, lodBounds, resultColor);
errorMask.setPixel(tcu::Vec4(pixelOk?0.0f:1.0f, pixelOk?1.0f:0.0f, 0.0f, 1.0f), x, y);
if (!pixelOk)
allOk = false;
}
}
return allOk;
}
template<typename ScalarType>
ScalarType getSwizzledComp (const tcu::Vector<ScalarType, 4>& vec, vk::VkComponentSwizzle comp, int identityNdx)
{
if (comp == vk::VK_COMPONENT_SWIZZLE_IDENTITY)
return vec[identityNdx];
else if (comp == vk::VK_COMPONENT_SWIZZLE_ZERO)
return ScalarType(0);
else if (comp == vk::VK_COMPONENT_SWIZZLE_ONE)
return ScalarType(1);
else
return vec[comp - vk::VK_COMPONENT_SWIZZLE_R];
}
template<typename ScalarType>
tcu::Vector<ScalarType, 4> swizzle (const tcu::Vector<ScalarType, 4>& vec, const vk::VkComponentMapping& swz)
{
return tcu::Vector<ScalarType, 4>(getSwizzledComp(vec, swz.r, 0),
getSwizzledComp(vec, swz.g, 1),
getSwizzledComp(vec, swz.b, 2),
getSwizzledComp(vec, swz.a, 3));
}
tcu::Vec4 swizzleScaleBias (const tcu::Vec4& vec, const vk::VkComponentMapping& swz)
{
const float channelValues[] =
{
1.0f, // -1
1.0f, // 0
1.0f,
vec.x(),
vec.y(),
vec.z(),
vec.w()
};
return tcu::Vec4(channelValues[swz.r], channelValues[swz.g], channelValues[swz.b], channelValues[swz.a]);
}
template<typename ScalarType>
void swizzleT (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
{
for (int z = 0; z < dst.getDepth(); ++z)
for (int y = 0; y < dst.getHeight(); ++y)
for (int x = 0; x < dst.getWidth(); ++x)
dst.setPixel(swizzle(src.getPixelT<ScalarType>(x, y, z), swz), x, y, z);
}
void swizzleFromSRGB (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
{
for (int z = 0; z < dst.getDepth(); ++z)
for (int y = 0; y < dst.getHeight(); ++y)
for (int x = 0; x < dst.getWidth(); ++x)
dst.setPixel(swizzle(tcu::sRGBToLinear(src.getPixelT<float>(x, y, z)), swz), x, y, z);
}
void swizzle (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
{
const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(dst.getFormat().type);
DE_ASSERT(src.getWidth() == dst.getWidth() &&
src.getHeight() == dst.getHeight() &&
src.getDepth() == dst.getDepth());
if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
swizzleT<deInt32>(src, dst, swz);
else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
swizzleT<deUint32>(src, dst, swz);
else if (tcu::isSRGB(src.getFormat()) && !tcu::isSRGB(dst.getFormat()))
swizzleFromSRGB(src, dst, swz);
else
swizzleT<float>(src, dst, swz);
}
bool isIdentitySwizzle (const vk::VkComponentMapping& swz)
{
return (swz.r == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.r == vk::VK_COMPONENT_SWIZZLE_R) &&
(swz.g == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.g == vk::VK_COMPONENT_SWIZZLE_G) &&
(swz.b == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.b == vk::VK_COMPONENT_SWIZZLE_B) &&
(swz.a == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.a == vk::VK_COMPONENT_SWIZZLE_A);
}
template<typename TextureViewType> struct TexViewTraits;
template<> struct TexViewTraits<tcu::Texture1DView> { typedef tcu::Texture1D TextureType; };
template<> struct TexViewTraits<tcu::Texture1DArrayView> { typedef tcu::Texture1DArray TextureType; };
template<> struct TexViewTraits<tcu::Texture2DView> { typedef tcu::Texture2D TextureType; };
template<> struct TexViewTraits<tcu::Texture2DArrayView> { typedef tcu::Texture2DArray TextureType; };
template<> struct TexViewTraits<tcu::TextureCubeView> { typedef tcu::TextureCube TextureType; };
template<> struct TexViewTraits<tcu::TextureCubeArrayView> { typedef tcu::TextureCubeArray TextureType; };
template<> struct TexViewTraits<tcu::Texture3DView> { typedef tcu::Texture3D TextureType; };
template<typename TextureViewType>
typename TexViewTraits<TextureViewType>::TextureType* createSkeletonClone (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0);
tcu::TextureFormat getSwizzleTargetFormat (tcu::TextureFormat format)
{
// Swizzled texture needs to hold all four channels
// \todo [2016-09-21 pyry] We could save some memory by using smaller formats
// when possible (for example U8).
const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(format.type);
if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
else
return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
}
template<>
tcu::Texture1D* createSkeletonClone<tcu::Texture1DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
{
return new tcu::Texture1D(format, level0.getWidth());
}
template<>
tcu::Texture1DArray* createSkeletonClone<tcu::Texture1DArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
{
return new tcu::Texture1DArray(format, level0.getWidth(), level0.getHeight());
}
template<>
tcu::Texture2D* createSkeletonClone<tcu::Texture2DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
{
return new tcu::Texture2D(format, level0.getWidth(), level0.getHeight());
}
template<>
tcu::Texture2DArray* createSkeletonClone<tcu::Texture2DArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
{
return new tcu::Texture2DArray(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
}
template<>
tcu::Texture3D* createSkeletonClone<tcu::Texture3DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
{
return new tcu::Texture3D(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
}
template<>
tcu::TextureCubeArray* createSkeletonClone<tcu::TextureCubeArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
{
return new tcu::TextureCubeArray(format, level0.getWidth(), level0.getDepth());
}
template<typename TextureViewType>
MovePtr<typename TexViewTraits<TextureViewType>::TextureType> createSwizzledCopy (const TextureViewType& texture, const vk::VkComponentMapping& swz)
{
MovePtr<typename TexViewTraits<TextureViewType>::TextureType> copy (createSkeletonClone<TextureViewType>(getSwizzleTargetFormat(texture.getLevel(0).getFormat()), texture.getLevel(0)));
for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
{
copy->allocLevel(levelNdx);
swizzle(texture.getLevel(levelNdx), copy->getLevel(levelNdx), swz);
}
return copy;
}
template<>
MovePtr<tcu::TextureCube> createSwizzledCopy (const tcu::TextureCubeView& texture, const vk::VkComponentMapping& swz)
{
MovePtr<tcu::TextureCube> copy (new tcu::TextureCube(getSwizzleTargetFormat(texture.getLevelFace(0, tcu::CUBEFACE_NEGATIVE_X).getFormat()), texture.getSize()));
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
{
for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
{
copy->allocLevel((tcu::CubeFace)faceNdx, levelNdx);
swizzle(texture.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), copy->getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), swz);
}
}
return copy;
}
template<typename TextureViewType>
bool validateResultImage (const TextureViewType& texture,
const tcu::Sampler& sampler,
const vk::VkComponentMapping& swz,
const tcu::ConstPixelBufferAccess& texCoords,
const tcu::Vec2& lodBounds,
const tcu::LookupPrecision& lookupPrecision,
const tcu::Vec4& lookupScale,
const tcu::Vec4& lookupBias,
const tcu::ConstPixelBufferAccess& result,
const tcu::PixelBufferAccess& errorMask)
{
if (isIdentitySwizzle(swz))
return validateResultImage(texture, sampler, texCoords, lodBounds, lookupPrecision, lookupScale, lookupBias, result, errorMask);
else
{
// There is (currently) no way to handle swizzling inside validation loop
// and thus we need to pre-swizzle the texture.
UniquePtr<typename TexViewTraits<TextureViewType>::TextureType> swizzledTex (createSwizzledCopy(texture, swz));
return validateResultImage(*swizzledTex, sampler, texCoords, lodBounds, lookupPrecision, swizzleScaleBias(lookupScale, swz), swizzleScaleBias(lookupBias, swz), result, errorMask);
}
}
vk::VkImageSubresourceRange resolveSubresourceRange (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource)
{
vk::VkImageSubresourceRange resolved = subresource;
if (subresource.levelCount == VK_REMAINING_MIP_LEVELS)
resolved.levelCount = testTexture.getNumLevels()-subresource.baseMipLevel;
if (subresource.layerCount == VK_REMAINING_ARRAY_LAYERS)
resolved.layerCount = testTexture.getArraySize()-subresource.baseArrayLayer;
return resolved;
}
MovePtr<tcu::Texture1DView> getTexture1DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
DE_ASSERT(subresource.layerCount == 1);
levels.resize(subresource.levelCount);
for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
{
const tcu::ConstPixelBufferAccess& srcLevel = testTexture.getLevel((int)subresource.baseMipLevel+levelNdx, subresource.baseArrayLayer);
levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, 0, srcLevel.getWidth(), 1, 1);
}
return MovePtr<tcu::Texture1DView>(new tcu::Texture1DView((int)levels.size(), &levels[0]));
}
MovePtr<tcu::Texture1DArrayView> getTexture1DArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
const TestTexture1D* tex1D = dynamic_cast<const TestTexture1D*>(&testTexture);
const TestTexture1DArray* tex1DArray = dynamic_cast<const TestTexture1DArray*>(&testTexture);
DE_ASSERT(!!tex1D != !!tex1DArray);
DE_ASSERT(tex1DArray || subresource.baseArrayLayer == 0);
levels.resize(subresource.levelCount);
for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
{
const tcu::ConstPixelBufferAccess& srcLevel = tex1D ? tex1D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
: tex1DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
levels[levelNdx] = tcu::getSubregion(srcLevel, 0, (int)subresource.baseArrayLayer, 0, srcLevel.getWidth(), (int)subresource.layerCount, 1);
}
return MovePtr<tcu::Texture1DArrayView>(new tcu::Texture1DArrayView((int)levels.size(), &levels[0]));
}
MovePtr<tcu::Texture2DView> getTexture2DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
const TestTexture2D* tex2D = dynamic_cast<const TestTexture2D*>(&testTexture);
const TestTexture2DArray* tex2DArray = dynamic_cast<const TestTexture2DArray*>(&testTexture);
DE_ASSERT(subresource.layerCount == 1);
DE_ASSERT(!!tex2D != !!tex2DArray);
DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
levels.resize(subresource.levelCount);
for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
{
const tcu::ConstPixelBufferAccess& srcLevel = tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
: tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), 1);
}
return MovePtr<tcu::Texture2DView>(new tcu::Texture2DView((int)levels.size(), &levels[0]));
}
MovePtr<tcu::Texture2DArrayView> getTexture2DArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
const TestTexture2D* tex2D = dynamic_cast<const TestTexture2D*>(&testTexture);
const TestTexture2DArray* tex2DArray = dynamic_cast<const TestTexture2DArray*>(&testTexture);
DE_ASSERT(!!tex2D != !!tex2DArray);
DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
levels.resize(subresource.levelCount);
for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
{
const tcu::ConstPixelBufferAccess& srcLevel = tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
: tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), (int)subresource.layerCount);
}
return MovePtr<tcu::Texture2DArrayView>(new tcu::Texture2DArrayView((int)levels.size(), &levels[0]));
}
MovePtr<tcu::TextureCubeView> getTextureCubeView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
const static tcu::CubeFace s_faceMap[tcu::CUBEFACE_LAST] =
{
tcu::CUBEFACE_POSITIVE_X,
tcu::CUBEFACE_NEGATIVE_X,
tcu::CUBEFACE_POSITIVE_Y,
tcu::CUBEFACE_NEGATIVE_Y,
tcu::CUBEFACE_POSITIVE_Z,
tcu::CUBEFACE_NEGATIVE_Z
};
const TestTextureCube* texCube = dynamic_cast<const TestTextureCube*>(&testTexture);
const TestTextureCubeArray* texCubeArray = dynamic_cast<const TestTextureCubeArray*>(&testTexture);
DE_ASSERT(!!texCube != !!texCubeArray);
DE_ASSERT(subresource.layerCount == 6);
DE_ASSERT(texCubeArray || subresource.baseArrayLayer == 0);
levels.resize(subresource.levelCount*tcu::CUBEFACE_LAST);
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
{
for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
{
const tcu::ConstPixelBufferAccess& srcLevel = texCubeArray ? texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
: texCube->getTexture().getLevelFace(levelNdx, s_faceMap[faceNdx]);
levels[faceNdx*subresource.levelCount + levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer + (texCubeArray ? faceNdx : 0), srcLevel.getWidth(), srcLevel.getHeight(), 1);
}
}
{
const tcu::ConstPixelBufferAccess* reordered[tcu::CUBEFACE_LAST];
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
reordered[s_faceMap[faceNdx]] = &levels[faceNdx*subresource.levelCount];
return MovePtr<tcu::TextureCubeView>(new tcu::TextureCubeView((int)subresource.levelCount, reordered));
}
}
MovePtr<tcu::TextureCubeArrayView> getTextureCubeArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
const TestTextureCubeArray* texCubeArray = dynamic_cast<const TestTextureCubeArray*>(&testTexture);
DE_ASSERT(texCubeArray);
DE_ASSERT(subresource.layerCount%6 == 0);
levels.resize(subresource.levelCount);
for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
{
const tcu::ConstPixelBufferAccess& srcLevel = texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), (int)subresource.layerCount);
}
return MovePtr<tcu::TextureCubeArrayView>(new tcu::TextureCubeArrayView((int)levels.size(), &levels[0]));
}
MovePtr<tcu::Texture3DView> getTexture3DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
{
DE_ASSERT(subresource.baseArrayLayer == 0 && subresource.layerCount == 1);
levels.resize(subresource.levelCount);
for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
levels[levelNdx] = testTexture.getLevel((int)subresource.baseMipLevel+levelNdx, subresource.baseArrayLayer);
return MovePtr<tcu::Texture3DView>(new tcu::Texture3DView((int)levels.size(), &levels[0]));
}
bool validateResultImage (const TestTexture& texture,
const VkImageViewType imageViewType,
const VkImageSubresourceRange& subresource,
const tcu::Sampler& sampler,
const vk::VkComponentMapping& componentMapping,
const tcu::ConstPixelBufferAccess& coordAccess,
const tcu::Vec2& lodBounds,
const tcu::LookupPrecision& lookupPrecision,
const tcu::Vec4& lookupScale,
const tcu::Vec4& lookupBias,
const tcu::ConstPixelBufferAccess& resultAccess,
const tcu::PixelBufferAccess& errorAccess)
{
std::vector<tcu::ConstPixelBufferAccess> levels;
switch (imageViewType)
{
case VK_IMAGE_VIEW_TYPE_1D:
{
UniquePtr<tcu::Texture1DView> texView(getTexture1DView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
}
case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
{
UniquePtr<tcu::Texture1DArrayView> texView(getTexture1DArrayView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
}
case VK_IMAGE_VIEW_TYPE_2D:
{
UniquePtr<tcu::Texture2DView> texView(getTexture2DView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
}
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
{
UniquePtr<tcu::Texture2DArrayView> texView(getTexture2DArrayView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
}
case VK_IMAGE_VIEW_TYPE_CUBE:
{
UniquePtr<tcu::TextureCubeView> texView(getTextureCubeView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
}
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
{
UniquePtr<tcu::TextureCubeArrayView> texView(getTextureCubeArrayView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
break;
}
case VK_IMAGE_VIEW_TYPE_3D:
{
UniquePtr<tcu::Texture3DView> texView(getTexture3DView(texture, subresource, levels));
return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
}
default:
DE_ASSERT(false);
return false;
}
}
} // anonymous
tcu::TestStatus ImageSamplingInstance::verifyImage (void)
{
const VkPhysicalDeviceLimits& limits = m_context.getDeviceProperties().limits;
// \note Color buffer is used to capture coordinates - not sampled texture values
const tcu::TextureFormat colorFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
const tcu::TextureFormat depthStencilFormat; // Undefined depth/stencil format.
const CoordinateCaptureProgram coordCaptureProgram;
const rr::Program rrProgram = coordCaptureProgram.getReferenceProgram();
ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, colorFormat, depthStencilFormat, &rrProgram);
bool compareOkAll = true;
bool anyWarnings = false;
tcu::Vec4 lookupScale (1.0f);
tcu::Vec4 lookupBias (0.0f);
getLookupScaleBias(m_imageFormat, lookupScale, lookupBias);
// Render out coordinates
{
const rr::RenderState renderState(refRenderer.getViewportState());
refRenderer.draw(renderState, rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
}
// Verify results
{
const tcu::Sampler sampler = mapVkSampler(m_samplerParams);
const float referenceLod = de::clamp(m_samplerParams.mipLodBias + m_samplerLod, m_samplerParams.minLod, m_samplerParams.maxLod);
const float lodError = 1.0f / static_cast<float>((1u << limits.mipmapPrecisionBits) - 1u);
const tcu::Vec2 lodBounds (referenceLod - lodError, referenceLod + lodError);
const vk::VkImageSubresourceRange subresource = resolveSubresourceRange(*m_texture, m_subresourceRange);
const tcu::ConstPixelBufferAccess coordAccess = refRenderer.getAccess();
tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), (int)m_renderSize.x(), (int)m_renderSize.y());
const tcu::PixelBufferAccess errorAccess = errorMask.getAccess();
const bool allowSnorm8Bug = m_texture->getTextureFormat().type == tcu::TextureFormat::SNORM_INT8 &&
(m_samplerParams.minFilter == VK_FILTER_LINEAR || m_samplerParams.magFilter == VK_FILTER_LINEAR);
tcu::LookupPrecision lookupPrecision;
// Set precision requirements - very low for these tests as
// the point of the test is not to validate accuracy.
lookupPrecision.coordBits = tcu::IVec3(17, 17, 17);
lookupPrecision.uvwBits = tcu::IVec3(5, 5, 5);
lookupPrecision.colorMask = tcu::BVec4(true);
lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(tcu::IVec4(8, 8, 8, 8)) / swizzleScaleBias(lookupScale, m_componentMapping);
if (tcu::isSRGB(m_texture->getTextureFormat()))
lookupPrecision.colorThreshold += tcu::Vec4(4.f / 255.f);
for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
{
// Read back result image
UniquePtr<tcu::TextureLevel> result (readColorAttachment(m_context.getDeviceInterface(),
m_context.getDevice(),
m_context.getUniversalQueue(),
m_context.getUniversalQueueFamilyIndex(),
m_context.getDefaultAllocator(),
**m_colorImages[imgNdx],
m_colorFormat,
m_renderSize));
const tcu::ConstPixelBufferAccess resultAccess = result->getAccess();
bool compareOk = validateResultImage(*m_texture,
m_imageViewType,
subresource,
sampler,
m_componentMapping,
coordAccess,
lodBounds,
lookupPrecision,
lookupScale,
lookupBias,
resultAccess,
errorAccess);
if (!compareOk && allowSnorm8Bug)
{
// HW waiver (VK-GL-CTS issue: 229)
//
// Due to an error in bit replication of the fixed point SNORM values, linear filtered
// negative SNORM values will differ slightly from ideal precision in the last bit, moving
// the values towards 0.
//
// This occurs on all members of the PowerVR Rogue family of GPUs
tcu::LookupPrecision relaxedPrecision;
relaxedPrecision.colorThreshold += tcu::Vec4(4.f / 255.f);
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Warning: Strict validation failed, re-trying with lower precision for SNORM8 format"
<< tcu::TestLog::EndMessage;
anyWarnings = true;
compareOk = validateResultImage(*m_texture,
m_imageViewType,
subresource,
sampler,
m_componentMapping,
coordAccess,
lodBounds,
relaxedPrecision,
lookupScale,
lookupBias,
resultAccess,
errorAccess);
}
if (!compareOk)
m_context.getTestContext().getLog()
<< tcu::TestLog::Image("Result", "Result Image", resultAccess)
<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorAccess);
compareOkAll = compareOkAll && compareOk;
}
}
if (compareOkAll)
{
if (anyWarnings)
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Inaccurate filtering results");
else
return tcu::TestStatus::pass("Result image matches reference");
}
else
return tcu::TestStatus::fail("Image mismatch");
}
} // pipeline
} // vkt