blob: 23654634a68597a2ef429b42eaf76ca9c00d9cfe [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2019 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 OpImageQuery & YCbCr Tests
*//*--------------------------------------------------------------------*/
#include "vktYCbCrImageQueryTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktShaderExecutor.hpp"
#include "vktYCbCrUtil.hpp"
#include "vktDrawUtil.hpp"
#include "vkStrUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "deStringUtil.hpp"
#include "deSharedPtr.hpp"
#include "deUniquePtr.hpp"
#include "deRandom.hpp"
#include "deSTLUtil.hpp"
namespace vkt
{
namespace ycbcr
{
namespace
{
using namespace vk;
using namespace shaderexecutor;
using tcu::UVec2;
using tcu::Vec2;
using tcu::Vec4;
using tcu::TestLog;
using de::MovePtr;
using de::UniquePtr;
using std::vector;
using std::string;
typedef de::SharedPtr<Allocation> AllocationSp;
typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp;
enum QueryType
{
QUERY_TYPE_IMAGE_SIZE_LOD, // OpImageQuerySizeLod
QUERY_TYPE_IMAGE_LOD, // OpImageQueryLod
QUERY_TYPE_IMAGE_LEVELS, // OpImageQueryLevels
QUERY_TYPE_LAST
};
struct TestParameters
{
QueryType query;
VkFormat format;
VkImageCreateFlags flags;
glu::ShaderType shaderType;
TestParameters (QueryType query_, VkFormat format_, VkImageCreateFlags flags_, glu::ShaderType shaderType_)
: query (query_)
, format (format_)
, flags (flags_)
, shaderType(shaderType_)
{
}
TestParameters (void)
: query (QUERY_TYPE_LAST)
, format (VK_FORMAT_UNDEFINED)
, flags (0u)
, shaderType(glu::SHADERTYPE_LAST)
{
}
};
ShaderSpec getShaderSpec (const TestParameters& params)
{
ShaderSpec spec;
const char* expr = DE_NULL;
glu::DataType resultType = glu::TYPE_LAST;
switch (params.query)
{
case QUERY_TYPE_IMAGE_SIZE_LOD:
expr = "textureSize(u_image, lod)";
resultType = glu::TYPE_INT_VEC2;
break;
case QUERY_TYPE_IMAGE_LEVELS:
expr = "textureQueryLevels(u_image)";
resultType = glu::TYPE_INT;
break;
default:
DE_FATAL("Unknown query");
}
spec.glslVersion = glu::GLSL_VERSION_450;
spec.inputs.push_back(Symbol("lod", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
spec.outputs.push_back(Symbol("result", glu::VarType(resultType, glu::PRECISION_HIGHP)));
spec.globalDeclarations =
"layout(binding = 0, set = 1) uniform highp sampler2D u_image;\n";
spec.source =
string("result = ") + expr + ";\n";
return spec;
}
Move<VkImage> createTestImage (const DeviceInterface& vkd,
VkDevice device,
VkFormat format,
const UVec2& size,
VkImageCreateFlags createFlags)
{
const VkImageCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
DE_NULL,
createFlags,
VK_IMAGE_TYPE_2D,
format,
makeExtent3D(size.x(), size.y(), 1u),
1u, // mipLevels
1u, // arrayLayers
VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT,
VK_SHARING_MODE_EXCLUSIVE,
0u,
(const deUint32*)DE_NULL,
VK_IMAGE_LAYOUT_UNDEFINED,
};
return createImage(vkd, device, &createInfo);
}
Move<VkImageView> createImageView (const DeviceInterface& vkd,
VkDevice device,
VkImage image,
VkFormat format,
VkSamplerYcbcrConversion conversion)
{
const VkSamplerYcbcrConversionInfo samplerConversionInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
DE_NULL,
conversion
};
const VkImageViewCreateInfo viewInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
(conversion != DE_NULL) ? &samplerConversionInfo : DE_NULL,
(VkImageViewCreateFlags)0,
image,
VK_IMAGE_VIEW_TYPE_2D,
format,
{
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
},
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
};
return createImageView(vkd, device, &viewInfo);
}
class TestImage
{
public:
TestImage (const Context& context,
const DeviceInterface& vkd,
VkDevice device,
Allocator& allocator,
VkFormat format,
const UVec2& size,
const VkImageCreateFlags createFlags,
VkSamplerYcbcrConversion conversion);
const UVec2& getSize (void) const { return m_size; }
VkImageView getImageView (void) const { return *m_imageView; }
private:
const UVec2 m_size;
const Unique<VkImage> m_image;
const vector<AllocationSp> m_allocations;
const Unique<VkImageView> m_imageView;
};
TestImage::TestImage (const Context& context,
const DeviceInterface& vkd,
VkDevice device,
Allocator& allocator,
VkFormat format,
const UVec2& size,
const VkImageCreateFlags createFlags,
VkSamplerYcbcrConversion conversion)
: m_size (size)
, m_image (createTestImage(vkd, device, format, size, createFlags))
, m_allocations (allocateAndBindImageMemory(vkd, device, allocator, *m_image, format, createFlags))
, m_imageView (createImageView(vkd, device, *m_image, format, conversion))
{
// Transition image layout
{
Move<VkCommandPool> cmdPool;
Move<VkCommandBuffer> cmdBuffer;
const VkQueue queue = context.getUniversalQueue();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
cmdPool = createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
beginCommandBuffer(vkd, *cmdBuffer);
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u };
const VkImageMemoryBarrier imageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, *m_image, subresourceRange);
vkd.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
endCommandBuffer(vkd, *cmdBuffer);
submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
}
}
typedef de::SharedPtr<TestImage> TestImageSp;
Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler sampler)
{
const VkDescriptorSetLayoutBinding binding =
{
0u, // binding
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1u, // descriptorCount
VK_SHADER_STAGE_ALL,
&sampler
};
const VkDescriptorSetLayoutCreateInfo layoutInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
DE_NULL,
(VkDescriptorSetLayoutCreateFlags)0u,
1u,
&binding,
};
return createDescriptorSetLayout(vkd, device, &layoutInfo);
}
Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device)
{
const VkDescriptorPoolSize poolSizes[] =
{
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u },
};
const VkDescriptorPoolCreateInfo poolInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
DE_NULL,
(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
1u, // maxSets
DE_LENGTH_OF_ARRAY(poolSizes),
poolSizes,
};
return createDescriptorPool(vkd, device, & poolInfo);
}
Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkd,
VkDevice device,
VkDescriptorPool descPool,
VkDescriptorSetLayout descLayout)
{
const VkDescriptorSetAllocateInfo allocInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
descPool,
1u,
&descLayout,
};
return allocateDescriptorSet(vkd, device, &allocInfo);
}
void bindImage (const DeviceInterface& vkd,
VkDevice device,
VkDescriptorSet descriptorSet,
VkImageView imageView,
VkSampler sampler)
{
const VkDescriptorImageInfo imageInfo =
{
sampler,
imageView,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
};
const VkWriteDescriptorSet descriptorWrite =
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
DE_NULL,
descriptorSet,
0u, // dstBinding
0u, // dstArrayElement
1u, // descriptorCount
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
&imageInfo,
(const VkDescriptorBufferInfo*)DE_NULL,
(const VkBufferView*)DE_NULL,
};
vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
}
UVec2 getMaxPlaneDivisor (const PlanarFormatDescription& formatDesc)
{
UVec2 maxDivisor (1u, 1u);
for (deUint32 ndx = 0; ndx < formatDesc.numPlanes; ++ndx)
{
maxDivisor.x() = de::max<deUint32>(maxDivisor.x(), formatDesc.planes[ndx].widthDivisor);
maxDivisor.y() = de::max<deUint32>(maxDivisor.y(), formatDesc.planes[ndx].heightDivisor);
}
return maxDivisor;
}
tcu::TestStatus testImageQuery (Context& context, TestParameters params)
{
const bool isYCbCrImage = isYCbCrFormat(params.format);
const DeviceInterface& vkd = context.getDeviceInterface();
const VkDevice device = context.getDevice();
const VkSamplerYcbcrConversionCreateInfo conversionInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
DE_NULL,
params.format,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
{
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
},
VK_CHROMA_LOCATION_MIDPOINT,
VK_CHROMA_LOCATION_MIDPOINT,
VK_FILTER_NEAREST,
VK_FALSE, // forceExplicitReconstruction
};
const Unique<VkSamplerYcbcrConversion> conversion (isYCbCrImage
? createSamplerYcbcrConversion(vkd, device, &conversionInfo)
: Move<VkSamplerYcbcrConversion>());
const VkSamplerYcbcrConversionInfo samplerConversionInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
DE_NULL,
*conversion,
};
const VkSamplerCreateInfo samplerInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
isYCbCrImage ? &samplerConversionInfo : DE_NULL,
0u,
VK_FILTER_NEAREST, // magFilter
VK_FILTER_NEAREST, // minFilter
VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
0.0f, // mipLodBias
VK_FALSE, // anisotropyEnable
1.0f, // maxAnisotropy
VK_FALSE, // compareEnable
VK_COMPARE_OP_ALWAYS, // compareOp
0.0f, // minLod
0.0f, // maxLod
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
VK_FALSE, // unnormalizedCoords
};
const Unique<VkSampler> sampler (createSampler(vkd, device, &samplerInfo));
const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *sampler));
const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device));
const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout));
vector<TestImageSp> testImages;
if (params.query == QUERY_TYPE_IMAGE_SIZE_LOD)
{
const PlanarFormatDescription& formatDesc = getPlanarFormatDescription(params.format);
const UVec2 maxDivisor = getMaxPlaneDivisor(formatDesc);
vector<UVec2> testSizes;
testSizes.push_back(maxDivisor);
testSizes.push_back(maxDivisor * UVec2(2u, 1u));
testSizes.push_back(maxDivisor * UVec2(1u, 2u));
testSizes.push_back(maxDivisor * UVec2(63u, 79u));
testSizes.push_back(maxDivisor * UVec2(99u, 1u));
testSizes.push_back(maxDivisor * UVec2(421u, 1117u));
testImages.resize(testSizes.size());
for (size_t ndx = 0; ndx < testSizes.size(); ++ndx)
testImages[ndx] = TestImageSp(new TestImage(context, vkd, device, context.getDefaultAllocator(), params.format, testSizes[ndx], params.flags, *conversion));
}
else
testImages.push_back(TestImageSp(new TestImage(context, vkd, device, context.getDefaultAllocator(), params.format, UVec2(16, 18), params.flags, *conversion)));
{
UniquePtr<ShaderExecutor> executor (createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
bool allOk = true;
for (size_t imageNdx = 0; imageNdx < testImages.size(); ++imageNdx)
{
const deUint32 lod = 0u;
UVec2 result (~0u, ~0u);
const void* inputs[] = { &lod };
void* outputs[] = { result.getPtr() };
bindImage(vkd, device, *descSet, testImages[imageNdx]->getImageView(), *sampler);
executor->execute(1, inputs, outputs, *descSet);
switch (params.query)
{
case QUERY_TYPE_IMAGE_SIZE_LOD:
{
const UVec2 reference = testImages[imageNdx]->getSize();
if (result != reference)
{
context.getTestContext().getLog()
<< TestLog::Message << "ERROR: Image " << imageNdx
<< ": got " << result
<< ", expected " << reference
<< TestLog::EndMessage;
allOk = false;
}
break;
}
case QUERY_TYPE_IMAGE_LEVELS:
{
if (result.x() != 1u)
{
context.getTestContext().getLog()
<< TestLog::Message << "ERROR: Image " << imageNdx
<< ": got " << result.x()
<< ", expected " << 1
<< TestLog::EndMessage;
allOk = false;
}
break;
}
default:
DE_FATAL("Invalid query type");
}
}
if (allOk)
return tcu::TestStatus::pass("Queries passed");
else
return tcu::TestStatus::fail("Got invalid results");
}
}
void checkSupport (Context& context, TestParameters params)
{
const bool isYCbCrImage = isYCbCrFormat(params.format);
if (isYCbCrImage)
checkImageSupport(context, params.format, params.flags);
}
tcu::TestStatus testImageQueryLod (Context& context, TestParameters params)
{
const bool isYCbCrImage = isYCbCrFormat(params.format);
const DeviceInterface& vkd = context.getDeviceInterface();
const VkDevice device = context.getDevice();
const VkSamplerYcbcrConversionCreateInfo conversionInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
DE_NULL,
params.format,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
{
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
},
VK_CHROMA_LOCATION_MIDPOINT,
VK_CHROMA_LOCATION_MIDPOINT,
VK_FILTER_NEAREST,
VK_FALSE, // forceExplicitReconstruction
};
const Unique<VkSamplerYcbcrConversion> conversion (isYCbCrImage
? createSamplerYcbcrConversion(vkd, device, &conversionInfo)
: Move<VkSamplerYcbcrConversion>());
const VkSamplerYcbcrConversionInfo samplerConversionInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
DE_NULL,
*conversion,
};
const VkSamplerCreateInfo samplerInfo =
{
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
isYCbCrImage ? &samplerConversionInfo : DE_NULL,
0u,
VK_FILTER_NEAREST, // magFilter
VK_FILTER_NEAREST, // minFilter
VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
0.0f, // mipLodBias
VK_FALSE, // anisotropyEnable
1.0f, // maxAnisotropy
VK_FALSE, // compareEnable
VK_COMPARE_OP_ALWAYS, // compareOp
0.0f, // minLod
0.0f, // maxLod
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
VK_FALSE, // unnormalizedCoords
};
const Unique<VkSampler> sampler (createSampler(vkd, device, &samplerInfo));
const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *sampler));
const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device));
const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout));
vector<TestImageSp> testImages;
DE_ASSERT(params.query == QUERY_TYPE_IMAGE_LOD);
DE_ASSERT(params.shaderType == glu::SHADERTYPE_FRAGMENT);
{
const PlanarFormatDescription& formatDesc = getPlanarFormatDescription(params.format);
const UVec2 maxDivisor = getMaxPlaneDivisor(formatDesc);
vector<UVec2> testSizes;
testSizes.push_back(maxDivisor);
testSizes.push_back(maxDivisor * UVec2(2u, 1u));
testSizes.push_back(maxDivisor * UVec2(1u, 2u));
testSizes.push_back(maxDivisor * UVec2(4u, 123u));
testSizes.push_back(maxDivisor * UVec2(312u, 13u));
testSizes.push_back(maxDivisor * UVec2(841u, 917u));
testImages.resize(testSizes.size());
for (size_t ndx = 0; ndx < testSizes.size(); ++ndx)
testImages[ndx] = TestImageSp(new TestImage(context, vkd, device, context.getDefaultAllocator(), params.format, testSizes[ndx], params.flags, *conversion));
}
{
using namespace drawutil;
struct LocalUtil
{
static DrawState getDrawState (UVec2 renderSize, const int subpixelBits)
{
DrawState state(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, renderSize.x(), renderSize.y(), subpixelBits);
state.colorFormat = VK_FORMAT_R32G32_SFLOAT;
return state;
}
static vector<Vec4> getVertices (void)
{
vector<Vec4> vertices;
vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
vertices.push_back(Vec4(+1.0f, -1.0f, 0.0f, 1.0f));
vertices.push_back(Vec4(-1.0f, +1.0f, 0.0f, 1.0f));
vertices.push_back(Vec4(+1.0f, -1.0f, 0.0f, 1.0f));
vertices.push_back(Vec4(-1.0f, +1.0f, 0.0f, 1.0f));
vertices.push_back(Vec4(+1.0f, +1.0f, 0.0f, 1.0f));
return vertices;
}
static VulkanProgram getProgram (Context& ctx, VkDescriptorSetLayout descriptorLayout, VkDescriptorSet descriptorSet)
{
VulkanProgram prog;
prog.shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, ctx.getBinaryCollection().get("vert")));
prog.shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, ctx.getBinaryCollection().get("frag")));
prog.descriptorSet = descriptorSet;
prog.descriptorSetLayout = descriptorLayout;
return prog;
}
};
const UVec2 renderSize (128, 256);
const vector<Vec4> vertices (LocalUtil::getVertices());
const DrawState drawState (LocalUtil::getDrawState(renderSize, context.getDeviceProperties().limits.subPixelPrecisionBits));
const DrawCallData drawCallData(vertices);
const VulkanProgram program (LocalUtil::getProgram(context, *descLayout, *descSet));
bool allOk = true;
context.getTestContext().getLog()
<< TestLog::Message << "Rendering " << renderSize << " quad" << TestLog::EndMessage;
for (size_t imageNdx = 0; imageNdx < testImages.size(); ++imageNdx)
{
context.getTestContext().getLog()
<< TestLog::Message << "Testing image size " << testImages[imageNdx]->getSize() << TestLog::EndMessage;
bindImage(vkd, device, *descSet, testImages[imageNdx]->getImageView(), *sampler);
VulkanDrawContext renderer (context, drawState, drawCallData, program);
renderer.draw();
{
// Only du/dx and dv/dy are non-zero
const Vec2 dtdp = testImages[imageNdx]->getSize().cast<float>() / renderSize.cast<float>();
const tcu::LodPrecision lodPrec (16, 4); // Pretty lax since we are not verifying LOD precision
const Vec2 lodBounds (tcu::computeLodBoundsFromDerivates(dtdp.x(), 0.0f, 0.0f, dtdp.y(), lodPrec));
tcu::ConstPixelBufferAccess resultImg (renderer.getColorPixels());
const int maxErrors = 5;
int numErrors = 0;
for (int y = 0; y < resultImg.getHeight(); ++y)
for (int x = 0; x < resultImg.getWidth(); ++x)
{
const Vec2 result = resultImg.getPixel(x, y).swizzle(0,1);
const bool levelOk = result.x() == 0.0f;
const bool lodOk = de::inRange(result.y(), lodBounds.x(), lodBounds.y());
if (!levelOk || !lodOk)
{
if (numErrors < maxErrors)
{
context.getTestContext().getLog()
<< TestLog::Message << "ERROR: At (" << x << ", " << y << ")"
<< ": got " << result
<< ", expected (0, [" << lodBounds.x() << ", " << lodBounds.y() << "])"
<< TestLog::EndMessage;
}
else if (numErrors == maxErrors)
context.getTestContext().getLog() << TestLog::Message << "..." << TestLog::EndMessage;
numErrors += 1;
}
}
allOk = allOk && (numErrors == 0);
}
}
if (allOk)
return tcu::TestStatus::pass("Queries passed");
else
return tcu::TestStatus::fail("Got invalid results");
}
}
void initImageQueryPrograms (SourceCollections& dst, TestParameters params)
{
const ShaderSpec spec = getShaderSpec(params);
generateSources(params.shaderType, spec, dst);
}
void initImageQueryLodPrograms (SourceCollections& dst, TestParameters)
{
dst.glslSources.add("vert")
<< glu::VertexSource("#version 450\n"
"layout(location = 0) in highp vec4 a_position;\n"
"layout(location = 0) out highp vec2 v_texCoord;\n"
"\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
" v_texCoord = a_position.xy * 0.5 - 0.5;\n"
"}\n");
dst.glslSources.add("frag")
<< glu::FragmentSource("#version 450\n"
"layout(binding = 0, set = 0) uniform highp sampler2D u_image;\n"
"layout(location = 0) in highp vec2 v_texCoord;\n"
"layout(location = 0) out highp vec2 o_lod;\n"
"\n"
"void main (void)\n"
"{\n"
" o_lod = textureQueryLod(u_image, v_texCoord);\n"
"}\n");
}
void addImageQueryCase (tcu::TestCaseGroup* group, const TestParameters& params)
{
std::string name = de::toLower(de::toString(params.format).substr(10));
const bool isLod = params.query == QUERY_TYPE_IMAGE_LOD;
if ((params.flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
name += "_disjoint";
addFunctionCaseWithPrograms(group,
name,
"",
checkSupport,
isLod ? initImageQueryLodPrograms : initImageQueryPrograms,
isLod ? testImageQueryLod : testImageQuery,
params);
}
struct QueryGroupParams
{
QueryType query;
glu::ShaderType shaderType;
QueryGroupParams (QueryType query_, glu::ShaderType shaderType_)
: query (query_)
, shaderType(shaderType_)
{}
QueryGroupParams (void)
: query (QUERY_TYPE_LAST)
, shaderType(glu::SHADERTYPE_LAST)
{}
};
void populateQueryInShaderGroup (tcu::TestCaseGroup* group, QueryGroupParams params)
{
// "Reference" formats for testing
addImageQueryCase(group, TestParameters(params.query, VK_FORMAT_R8G8B8A8_UNORM, 0u, params.shaderType));
for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
{
const VkFormat format = (VkFormat)formatNdx;
addImageQueryCase(group, TestParameters(params.query, format, 0u, params.shaderType));
if (getPlaneCount(format) > 1)
addImageQueryCase(group, TestParameters(params.query, format, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT, params.shaderType));
}
}
void populateQueryGroup (tcu::TestCaseGroup* group, QueryType query)
{
for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; ++shaderTypeNdx)
{
const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeNdx;
if (query == QUERY_TYPE_IMAGE_LOD && shaderType != glu::SHADERTYPE_FRAGMENT)
continue;
if (!executorSupported(shaderType))
continue;
addTestGroup(group, glu::getShaderTypeName(shaderType), "", populateQueryInShaderGroup, QueryGroupParams(query, shaderType));
}
}
void populateImageQueryGroup (tcu::TestCaseGroup* group)
{
addTestGroup(group, "size_lod", "OpImageQuerySizeLod", populateQueryGroup, QUERY_TYPE_IMAGE_SIZE_LOD);
addTestGroup(group, "lod", "OpImageQueryLod", populateQueryGroup, QUERY_TYPE_IMAGE_LOD);
addTestGroup(group, "levels", "OpImageQueryLevels", populateQueryGroup, QUERY_TYPE_IMAGE_LEVELS);
}
} // namespace
tcu::TestCaseGroup* createImageQueryTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "query", "Image Query Tests", populateImageQueryGroup);
}
} // ycbcr
} // vkt