blob: 400a42de1ed53c00419fb59acae8bb9883afb945 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 The Khronos Group Inc.
* Copyright (c) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Memory qualifiers tests
*//*--------------------------------------------------------------------*/
#include "vktImageQualifiersTests.hpp"
#include "vktImageLoadStoreTests.hpp"
#include "vktImageTestsUtil.hpp"
#include "vkDefs.hpp"
#include "vkImageUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "deDefs.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorType.hpp"
using namespace vk;
namespace vkt
{
namespace image
{
namespace
{
static const tcu::UVec3 g_localWorkGroupSizeBase = tcu::UVec3(8, 8, 2);
static const deInt32 g_ShaderReadOffsetsX[4] = { 1, 4, 7, 10 };
static const deInt32 g_ShaderReadOffsetsY[4] = { 2, 5, 8, 11 };
static const deInt32 g_ShaderReadOffsetsZ[4] = { 3, 6, 9, 12 };
static const char* const g_ShaderReadOffsetsXStr = "int[]( 1, 4, 7, 10 )";
static const char* const g_ShaderReadOffsetsYStr = "int[]( 2, 5, 8, 11 )";
static const char* const g_ShaderReadOffsetsZStr = "int[]( 3, 6, 9, 12 )";
const tcu::UVec3 getLocalWorkGroupSize (const ImageType imageType, const tcu::UVec3& imageSize)
{
const tcu::UVec3 computeGridSize = getShaderGridSize(imageType, imageSize);
const tcu::UVec3 localWorkGroupSize = tcu::UVec3(de::min(g_localWorkGroupSizeBase.x(), computeGridSize.x()),
de::min(g_localWorkGroupSizeBase.y(), computeGridSize.y()),
de::min(g_localWorkGroupSizeBase.z(), computeGridSize.z()));
return localWorkGroupSize;
}
const tcu::UVec3 getNumWorkGroups (const ImageType imageType, const tcu::UVec3& imageSize)
{
const tcu::UVec3 computeGridSize = getShaderGridSize(imageType, imageSize);
const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(imageType, imageSize);
return computeGridSize / localWorkGroupSize;
}
tcu::ConstPixelBufferAccess getLayerOrSlice (const ImageType imageType,
const tcu::ConstPixelBufferAccess& access,
const deUint32 layer)
{
switch (imageType)
{
case IMAGE_TYPE_1D:
case IMAGE_TYPE_2D:
case IMAGE_TYPE_BUFFER:
DE_ASSERT(layer == 0);
return access;
case IMAGE_TYPE_1D_ARRAY:
return tcu::getSubregion(access, 0, layer, access.getWidth(), 1);
case IMAGE_TYPE_2D_ARRAY:
case IMAGE_TYPE_3D:
case IMAGE_TYPE_CUBE:
case IMAGE_TYPE_CUBE_ARRAY:
return tcu::getSubregion(access, 0, 0, layer, access.getWidth(), access.getHeight(), 1);
default:
DE_FATAL("Unknown image type");
return tcu::ConstPixelBufferAccess();
}
}
bool comparePixelBuffers (tcu::TestContext& testCtx,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format,
const tcu::ConstPixelBufferAccess& reference,
const tcu::ConstPixelBufferAccess& result)
{
DE_ASSERT(reference.getFormat() == result.getFormat());
DE_ASSERT(reference.getSize() == result.getSize());
const bool intFormat = isIntFormat(mapTextureFormat(format)) || isUintFormat(mapTextureFormat(format));
deUint32 passedLayers = 0;
for (deUint32 layerNdx = 0; layerNdx < getNumLayers(imageType, imageSize); ++layerNdx)
{
const std::string comparisonName = "Comparison" + de::toString(layerNdx);
std::string comparisonDesc = "Image Comparison, ";
switch (imageType)
{
case IMAGE_TYPE_3D:
comparisonDesc = comparisonDesc + "slice " + de::toString(layerNdx);
break;
case IMAGE_TYPE_CUBE:
case IMAGE_TYPE_CUBE_ARRAY:
comparisonDesc = comparisonDesc + "face " + de::toString(layerNdx % 6) + ", cube " + de::toString(layerNdx / 6);
break;
default:
comparisonDesc = comparisonDesc + "layer " + de::toString(layerNdx);
break;
}
const tcu::ConstPixelBufferAccess refLayer = getLayerOrSlice(imageType, reference, layerNdx);
const tcu::ConstPixelBufferAccess resultLayer = getLayerOrSlice(imageType, result, layerNdx);
bool ok = false;
if (intFormat)
ok = tcu::intThresholdCompare(testCtx.getLog(), comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::UVec4(0), tcu::COMPARE_LOG_RESULT);
else
ok = tcu::floatThresholdCompare(testCtx.getLog(), comparisonName.c_str(), comparisonDesc.c_str(), refLayer, resultLayer, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
if (ok)
++passedLayers;
}
return passedLayers == getNumLayers(imageType, imageSize);
}
const std::string getCoordStr (const ImageType imageType,
const std::string& x,
const std::string& y,
const std::string& z)
{
switch (imageType)
{
case IMAGE_TYPE_1D:
case IMAGE_TYPE_BUFFER:
return x;
case IMAGE_TYPE_1D_ARRAY:
case IMAGE_TYPE_2D:
return "ivec2(" + x + "," + y + ")";
case IMAGE_TYPE_2D_ARRAY:
case IMAGE_TYPE_3D:
case IMAGE_TYPE_CUBE:
case IMAGE_TYPE_CUBE_ARRAY:
return "ivec3(" + x + "," + y + "," + z + ")";
default:
DE_ASSERT(false);
return "";
}
}
class MemoryQualifierTestCase : public vkt::TestCase
{
public:
enum Qualifier
{
QUALIFIER_COHERENT = 0,
QUALIFIER_VOLATILE,
QUALIFIER_RESTRICT,
QUALIFIER_LAST
};
MemoryQualifierTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const Qualifier qualifier,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format,
const glu::GLSLVersion glslVersion);
virtual ~MemoryQualifierTestCase (void) {}
virtual void initPrograms (SourceCollections& programCollection) const;
virtual TestInstance* createInstance (Context& context) const;
protected:
const Qualifier m_qualifier;
const ImageType m_imageType;
const tcu::UVec3 m_imageSize;
const tcu::TextureFormat m_format;
const glu::GLSLVersion m_glslVersion;
};
MemoryQualifierTestCase::MemoryQualifierTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const Qualifier qualifier,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format,
const glu::GLSLVersion glslVersion)
: vkt::TestCase(testCtx, name, description)
, m_qualifier(qualifier)
, m_imageType(imageType)
, m_imageSize(imageSize)
, m_format(format)
, m_glslVersion(glslVersion)
{
}
void MemoryQualifierTestCase::initPrograms (SourceCollections& programCollection) const
{
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
const char* const qualifierName = m_qualifier == QUALIFIER_COHERENT ? "coherent"
: m_qualifier == QUALIFIER_VOLATILE ? "volatile"
: DE_NULL;
const bool uintFormat = isUintFormat(mapTextureFormat(m_format));
const bool intFormat = isIntFormat(mapTextureFormat(m_format));
const std::string colorVecTypeName = std::string(uintFormat ? "u" : intFormat ? "i" : "") + "vec4";
const std::string colorScalarTypeName = std::string(uintFormat ? "uint" : intFormat ? "int" : "float");
const std::string invocationCoord = getCoordStr(m_imageType, "gx", "gy", "gz");
const std::string shaderImageFormat = getShaderImageFormatQualifier(m_format);
const std::string shaderImageType = getShaderImageType(m_format, m_imageType);
const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(m_imageType, m_imageSize);
const std::string localSizeX = de::toString(localWorkGroupSize.x());
const std::string localSizeY = de::toString(localWorkGroupSize.y());
const std::string localSizeZ = de::toString(localWorkGroupSize.z());
std::ostringstream programBuffer;
programBuffer
<< versionDecl << "\n"
<< "\n"
<< "precision highp " << shaderImageType << ";\n"
<< "\n"
<< "layout (local_size_x = " << localSizeX << ", local_size_y = " << localSizeY << ", local_size_z = " + localSizeZ << ") in;\n"
<< "layout (" << shaderImageFormat << ", binding=0) " << qualifierName << " uniform " << shaderImageType << " u_image;\n"
<< "void main (void)\n"
<< "{\n"
<< " int gx = int(gl_GlobalInvocationID.x);\n"
<< " int gy = int(gl_GlobalInvocationID.y);\n"
<< " int gz = int(gl_GlobalInvocationID.z);\n"
<< " imageStore(u_image, " << invocationCoord << ", " << colorVecTypeName << "(gx^gy^gz));\n"
<< "\n"
<< " memoryBarrier();\n"
<< " barrier();\n"
<< "\n"
<< " " << colorScalarTypeName << " sum = " << colorScalarTypeName << "(0);\n"
<< " int groupBaseX = gx/" << localSizeX << "*" << localSizeX << ";\n"
<< " int groupBaseY = gy/" << localSizeY << "*" << localSizeY << ";\n"
<< " int groupBaseZ = gz/" << localSizeZ << "*" << localSizeZ << ";\n"
<< " int xOffsets[] = " << g_ShaderReadOffsetsXStr << ";\n"
<< " int yOffsets[] = " << g_ShaderReadOffsetsYStr << ";\n"
<< " int zOffsets[] = " << g_ShaderReadOffsetsZStr << ";\n"
<< " for (int i = 0; i < " << de::toString(DE_LENGTH_OF_ARRAY(g_ShaderReadOffsetsX)) << "; i++)\n"
<< " {\n"
<< " int readX = groupBaseX + (gx + xOffsets[i]) % " + localSizeX + ";\n"
<< " int readY = groupBaseY + (gy + yOffsets[i]) % " + localSizeY + ";\n"
<< " int readZ = groupBaseZ + (gz + zOffsets[i]) % " + localSizeZ + ";\n"
<< " sum += imageLoad(u_image, " << getCoordStr(m_imageType, "readX", "readY", "readZ") << ").x;\n"
<< " }\n"
<< "\n"
<< " memoryBarrier();\n"
<< " barrier();\n"
<< "\n"
<< " imageStore(u_image, " + invocationCoord + ", " + colorVecTypeName + "(sum));\n"
<< "}\n";
programCollection.glslSources.add(m_name) << glu::ComputeSource(programBuffer.str());
}
class MemoryQualifierInstanceBase : public vkt::TestInstance
{
public:
MemoryQualifierInstanceBase (Context& context,
const std::string& name,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format);
virtual ~MemoryQualifierInstanceBase (void) {};
virtual tcu::TestStatus iterate (void);
virtual void prepareResources (const VkDeviceSize bufferSizeInBytes) = 0;
virtual void prepareDescriptors (void) = 0;
virtual void commandsBeforeCompute (const VkCommandBuffer cmdBuffer,
const VkDeviceSize bufferSizeInBytes) const = 0;
virtual void commandsAfterCompute (const VkCommandBuffer cmdBuffer,
const VkDeviceSize bufferSizeInBytes) const = 0;
protected:
tcu::TextureLevel generateReferenceImage (void) const;
const std::string m_name;
const ImageType m_imageType;
const tcu::UVec3 m_imageSize;
const tcu::TextureFormat m_format;
de::MovePtr<Buffer> m_buffer;
Move<VkDescriptorPool> m_descriptorPool;
Move<VkDescriptorSetLayout> m_descriptorSetLayout;
Move<VkDescriptorSet> m_descriptorSet;
};
MemoryQualifierInstanceBase::MemoryQualifierInstanceBase (Context& context,
const std::string& name,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format)
: vkt::TestInstance(context)
, m_name(name)
, m_imageType(imageType)
, m_imageSize(imageSize)
, m_format(format)
{
}
tcu::TestStatus MemoryQualifierInstanceBase::iterate (void)
{
const VkDevice device = m_context.getDevice();
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const VkDeviceSize bufferSizeInBytes = getNumPixels(m_imageType, m_imageSize) * tcu::getPixelSize(m_format);
// Prepare resources for the test
prepareResources(bufferSizeInBytes);
// Prepare descriptor sets
prepareDescriptors();
// Create compute shader
const vk::Unique<VkShaderModule> shaderModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get(m_name), 0u));
// Create compute pipeline
const vk::Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, device, *m_descriptorSetLayout));
const vk::Unique<VkPipeline> pipeline(makeComputePipeline(deviceInterface, device, *pipelineLayout, *shaderModule));
// Create command buffer
const Unique<VkCommandPool> cmdPool(createCommandPool(deviceInterface, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(deviceInterface, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
// Start recording commands
beginCommandBuffer(deviceInterface, *cmdBuffer);
deviceInterface.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
deviceInterface.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
commandsBeforeCompute(*cmdBuffer, bufferSizeInBytes);
const tcu::UVec3 numGroups = getNumWorkGroups(m_imageType, m_imageSize);
deviceInterface.cmdDispatch(*cmdBuffer, numGroups.x(), numGroups.y(), numGroups.z());
commandsAfterCompute(*cmdBuffer, bufferSizeInBytes);
endCommandBuffer(deviceInterface, *cmdBuffer);
// Submit and wait for completion
submitCommandsAndWait(deviceInterface, device, queue, *cmdBuffer);
// Retrieve data from buffer to host memory
const Allocation& allocation = m_buffer->getAllocation();
invalidateMappedMemoryRange(deviceInterface, device, allocation.getMemory(), allocation.getOffset(), bufferSizeInBytes);
const tcu::UVec3 computeGridSize = getShaderGridSize(m_imageType, m_imageSize);
tcu::ConstPixelBufferAccess resultPixelBuffer(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z(), allocation.getHostPtr());
// Create a reference image
tcu::TextureLevel referenceImage = generateReferenceImage();
tcu::ConstPixelBufferAccess referencePixelBuffer = referenceImage.getAccess();
// Validate the result
if (comparePixelBuffers(m_context.getTestContext(), m_imageType, m_imageSize, m_format, referencePixelBuffer, resultPixelBuffer))
return tcu::TestStatus::pass("Passed");
else
return tcu::TestStatus::fail("Image comparison failed");
}
tcu::TextureLevel MemoryQualifierInstanceBase::generateReferenceImage (void) const
{
// Generate a reference image data using the storage format
const tcu::UVec3 computeGridSize = getShaderGridSize(m_imageType, m_imageSize);
tcu::TextureLevel base(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z());
tcu::PixelBufferAccess baseAccess = base.getAccess();
tcu::TextureLevel reference(m_format, computeGridSize.x(), computeGridSize.y(), computeGridSize.z());
tcu::PixelBufferAccess referenceAccess = reference.getAccess();
for (deInt32 z = 0; z < baseAccess.getDepth(); ++z)
for (deInt32 y = 0; y < baseAccess.getHeight(); ++y)
for (deInt32 x = 0; x < baseAccess.getWidth(); ++x)
{
baseAccess.setPixel(tcu::IVec4(x^y^z), x, y, z);
}
const tcu::UVec3 localWorkGroupSize = getLocalWorkGroupSize(m_imageType, m_imageSize);
for (deInt32 z = 0; z < referenceAccess.getDepth(); ++z)
for (deInt32 y = 0; y < referenceAccess.getHeight(); ++y)
for (deInt32 x = 0; x < referenceAccess.getWidth(); ++x)
{
const deInt32 groupBaseX = x / localWorkGroupSize.x() * localWorkGroupSize.x();
const deInt32 groupBaseY = y / localWorkGroupSize.y() * localWorkGroupSize.y();
const deInt32 groupBaseZ = z / localWorkGroupSize.z() * localWorkGroupSize.z();
deInt32 sum = 0;
for (deInt32 i = 0; i < DE_LENGTH_OF_ARRAY(g_ShaderReadOffsetsX); i++)
{
sum += baseAccess.getPixelInt(
groupBaseX + (x + g_ShaderReadOffsetsX[i]) % localWorkGroupSize.x(),
groupBaseY + (y + g_ShaderReadOffsetsY[i]) % localWorkGroupSize.y(),
groupBaseZ + (z + g_ShaderReadOffsetsZ[i]) % localWorkGroupSize.z()).x();
}
referenceAccess.setPixel(tcu::IVec4(sum), x, y, z);
}
return reference;
}
class MemoryQualifierInstanceImage : public MemoryQualifierInstanceBase
{
public:
MemoryQualifierInstanceImage (Context& context,
const std::string& name,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format)
: MemoryQualifierInstanceBase(context, name, imageType, imageSize, format) {}
virtual ~MemoryQualifierInstanceImage (void) {};
virtual void prepareResources (const VkDeviceSize bufferSizeInBytes);
virtual void prepareDescriptors (void);
virtual void commandsBeforeCompute (const VkCommandBuffer cmdBuffer,
const VkDeviceSize bufferSizeInBytes) const;
virtual void commandsAfterCompute (const VkCommandBuffer cmdBuffer,
const VkDeviceSize bufferSizeInBytes) const;
protected:
de::MovePtr<Image> m_image;
Move<VkImageView> m_imageView;
};
void MemoryQualifierInstanceImage::prepareResources (const VkDeviceSize bufferSizeInBytes)
{
const VkDevice device = m_context.getDevice();
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
Allocator& allocator = m_context.getDefaultAllocator();
// Create image
const VkImageCreateInfo imageCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
m_imageType == IMAGE_TYPE_CUBE ||
m_imageType == IMAGE_TYPE_CUBE_ARRAY
? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u, // VkImageCreateFlags flags;
mapImageType(m_imageType), // VkImageType imageType;
mapTextureFormat(m_format), // VkFormat format;
makeExtent3D(getLayerSize(m_imageType, m_imageSize)), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getNumLayers(m_imageType, m_imageSize), // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
0u, // deUint32 queueFamilyIndexCount;
DE_NULL, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_image = de::MovePtr<Image>(new Image(deviceInterface, device, allocator, imageCreateInfo, MemoryRequirement::Any));
// Create imageView
const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
m_imageView = makeImageView(deviceInterface, device, m_image->get(), mapImageViewType(m_imageType), mapTextureFormat(m_format), subresourceRange);
// Create a buffer to store shader output (copied from image data)
const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
}
void MemoryQualifierInstanceImage::prepareDescriptors (void)
{
const VkDevice device = m_context.getDevice();
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
// Create descriptor pool
m_descriptorPool =
DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
.build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
// Create descriptor set layout
m_descriptorSetLayout =
DescriptorSetLayoutBuilder()
.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
.build(deviceInterface, device);
// Allocate descriptor set
m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *m_descriptorSetLayout);
// Set the bindings
const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL);
DescriptorSetUpdateBuilder()
.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
.update(deviceInterface, device);
}
void MemoryQualifierInstanceImage::commandsBeforeCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const
{
DE_UNREF(bufferSizeInBytes);
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
const VkImageMemoryBarrier imageLayoutBarrier
= makeImageMemoryBarrier(0u,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
m_image->get(),
subresourceRange);
deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutBarrier);
}
void MemoryQualifierInstanceImage::commandsAfterCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const
{
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
const VkImageMemoryBarrier imagePreCopyBarrier
= makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
m_image->get(),
subresourceRange);
deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imagePreCopyBarrier);
const VkBufferImageCopy copyParams = makeBufferImageCopy(makeExtent3D(getLayerSize(m_imageType, m_imageSize)), getNumLayers(m_imageType, m_imageSize));
deviceInterface.cmdCopyImageToBuffer(cmdBuffer, m_image->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer->get(), 1u, &copyParams);
const VkBufferMemoryBarrier bufferPostCopyBarrier
= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_HOST_READ_BIT,
m_buffer->get(),
0ull,
bufferSizeInBytes);
deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferPostCopyBarrier, 0u, DE_NULL);
}
class MemoryQualifierInstanceBuffer : public MemoryQualifierInstanceBase
{
public:
MemoryQualifierInstanceBuffer (Context& context,
const std::string& name,
const ImageType imageType,
const tcu::UVec3& imageSize,
const tcu::TextureFormat& format)
: MemoryQualifierInstanceBase(context, name, imageType, imageSize, format) {}
virtual ~MemoryQualifierInstanceBuffer (void) {};
virtual void prepareResources (const VkDeviceSize bufferSizeInBytes);
virtual void prepareDescriptors (void);
virtual void commandsBeforeCompute (const VkCommandBuffer,
const VkDeviceSize) const {}
virtual void commandsAfterCompute (const VkCommandBuffer cmdBuffer,
const VkDeviceSize bufferSizeInBytes) const;
protected:
Move<VkBufferView> m_bufferView;
};
void MemoryQualifierInstanceBuffer::prepareResources (const VkDeviceSize bufferSizeInBytes)
{
const VkDevice device = m_context.getDevice();
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
Allocator& allocator = m_context.getDefaultAllocator();
// Create a buffer to store shader output
const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSizeInBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
m_bufferView = makeBufferView(deviceInterface, device, m_buffer->get(), mapTextureFormat(m_format), 0ull, bufferSizeInBytes);
}
void MemoryQualifierInstanceBuffer::prepareDescriptors (void)
{
const VkDevice device = m_context.getDevice();
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
// Create descriptor pool
m_descriptorPool =
DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
.build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
// Create descriptor set layout
m_descriptorSetLayout =
DescriptorSetLayoutBuilder()
.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
.build(deviceInterface, device);
// Allocate descriptor set
m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *m_descriptorSetLayout);
// Set the bindings
DescriptorSetUpdateBuilder()
.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
.update(deviceInterface, device);
}
void MemoryQualifierInstanceBuffer::commandsAfterCompute (const VkCommandBuffer cmdBuffer, const VkDeviceSize bufferSizeInBytes) const
{
const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
const VkBufferMemoryBarrier shaderWriteBarrier
= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_HOST_READ_BIT,
m_buffer->get(),
0ull,
bufferSizeInBytes);
deviceInterface.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
}
TestInstance* MemoryQualifierTestCase::createInstance (Context& context) const
{
if ( m_imageType == IMAGE_TYPE_BUFFER )
return new MemoryQualifierInstanceBuffer(context, m_name, m_imageType, m_imageSize, m_format);
else
return new MemoryQualifierInstanceImage(context, m_name, m_imageType, m_imageSize, m_format);
}
} // anonymous ns
tcu::TestCaseGroup* createImageQualifiersTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> imageQualifiersTests(new tcu::TestCaseGroup(testCtx, "qualifiers", "Coherent, volatile and restrict"));
struct ImageParams
{
ImageParams(const ImageType imageType, const tcu::UVec3& imageSize)
: m_imageType (imageType)
, m_imageSize (imageSize)
{
}
ImageType m_imageType;
tcu::UVec3 m_imageSize;
};
static const ImageParams imageParamsArray[] =
{
ImageParams(IMAGE_TYPE_1D, tcu::UVec3(64u, 1u, 1u)),
ImageParams(IMAGE_TYPE_1D_ARRAY, tcu::UVec3(64u, 1u, 8u)),
ImageParams(IMAGE_TYPE_2D, tcu::UVec3(64u, 64u, 1u)),
ImageParams(IMAGE_TYPE_2D_ARRAY, tcu::UVec3(64u, 64u, 8u)),
ImageParams(IMAGE_TYPE_3D, tcu::UVec3(64u, 64u, 8u)),
ImageParams(IMAGE_TYPE_CUBE, tcu::UVec3(64u, 64u, 1u)),
ImageParams(IMAGE_TYPE_CUBE_ARRAY, tcu::UVec3(64u, 64u, 2u)),
ImageParams(IMAGE_TYPE_BUFFER, tcu::UVec3(64u, 1u, 1u))
};
static const tcu::TextureFormat formats[] =
{
tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT),
tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT32),
tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::SIGNED_INT32),
};
for (deUint32 qualifierI = 0; qualifierI < MemoryQualifierTestCase::QUALIFIER_LAST; ++qualifierI)
{
const MemoryQualifierTestCase::Qualifier memoryQualifier = (MemoryQualifierTestCase::Qualifier)qualifierI;
const char* const memoryQualifierName =
memoryQualifier == MemoryQualifierTestCase::QUALIFIER_COHERENT ? "coherent" :
memoryQualifier == MemoryQualifierTestCase::QUALIFIER_VOLATILE ? "volatile" :
memoryQualifier == MemoryQualifierTestCase::QUALIFIER_RESTRICT ? "restrict" :
DE_NULL;
de::MovePtr<tcu::TestCaseGroup> qualifierGroup(new tcu::TestCaseGroup(testCtx, memoryQualifierName, ""));
for (deInt32 imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(imageParamsArray); imageTypeNdx++)
{
const ImageType imageType = imageParamsArray[imageTypeNdx].m_imageType;
const tcu::UVec3 imageSize = imageParamsArray[imageTypeNdx].m_imageSize;
if (memoryQualifier == MemoryQualifierTestCase::QUALIFIER_RESTRICT)
{
de::MovePtr<TestCase> restrictCase = createImageQualifierRestrictCase(testCtx, imageType, getImageTypeName(imageType));
qualifierGroup->addChild(restrictCase.release());
}
else
{
de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
for (deInt32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
{
const tcu::TextureFormat& format = formats[formatNdx];
const std::string formatName = getShaderImageFormatQualifier(formats[formatNdx]);
imageTypeGroup->addChild(
new MemoryQualifierTestCase(testCtx, formatName, "", memoryQualifier, imageType, imageSize, format, glu::GLSL_VERSION_440));
}
qualifierGroup->addChild(imageTypeGroup.release());
}
}
imageQualifiersTests->addChild(qualifierGroup.release());
}
return imageQualifiersTests.release();
}
} // image
} // vkt