blob: aa4dc56f33ec91494d58cdb80202b6960bc57669 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2017 The Khronos Group Inc.
* Copyright (c) 2017 Samsung Electronics Co., 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 Protected Memory image validator helper
*//*--------------------------------------------------------------------*/
#include "vktProtectedMemImageValidator.hpp"
#include "tcuTestLog.hpp"
#include "tcuStringTemplate.hpp"
#include "vkBuilderUtil.hpp"
#include "vkPrograms.hpp"
#include "vkTypeUtil.hpp"
#include "vkImageUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestGroupUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vktProtectedMemUtils.hpp"
#include "vktProtectedMemContext.hpp"
namespace vkt
{
namespace ProtectedMem
{
void ImageValidator::initPrograms (vk::SourceCollections& programCollection) const
{
// Layout:
// set = 0, location = 0 -> uniform *sampler2D u_protectedImage
// set = 0, location = 1 -> buffer ProtectedHelper (2 * uint)
// set = 0, location = 2 -> uniform Data (2 * vec2 + 4 * vec4)
const char* validatorShader = "#version 450\n"
"layout(local_size_x = 1) in;\n"
"\n"
"layout(set=0, binding=0) uniform ${SAMPLER_TYPE} u_protectedImage;\n"
"\n"
"layout(set=0, binding=1) buffer ProtectedHelper\n"
"{\n"
" highp uint zero; // set to 0\n"
" highp uint dummyOut;\n"
"} helper;\n"
"\n"
"layout(set=0, binding=2) uniform Data\n"
"{\n"
" highp vec2 protectedImageCoord[4];\n"
" highp vec4 protectedImageRef[4];\n"
"};\n"
"\n"
"void error ()\n"
"{\n"
" for (uint x = 0; x < 10; x += helper.zero)\n"
" atomicAdd(helper.dummyOut, 1u);\n"
"}\n"
"\n"
"bool compare (vec4 a, vec4 b, float threshold)\n"
"{\n"
" return all(lessThanEqual(abs(a - b), vec4(threshold)));\n"
"}\n"
"\n"
"void main (void)\n"
"{\n"
" float threshold = 0.1;\n"
" for (uint i = 0; i < 4; i++)\n"
" {\n"
" if (!compare(texture(u_protectedImage, protectedImageCoord[i]), protectedImageRef[i], threshold))\n"
" error();\n"
" }\n"
"}\n";
const char* resetSSBOShader = "#version 450\n"
"layout(local_size_x = 1) in;\n"
"\n"
"layout(set=0, binding=1) buffer ProtectedHelper\n"
"{\n"
" highp uint zero; // set to 0\n"
" highp uint dummyOut;\n"
"} helper;\n"
"\n"
"void main (void)\n"
"{\n"
" helper.zero = 0;\n"
"}\n";
programCollection.glslSources.add("ResetSSBO") << glu::ComputeSource(resetSSBOShader);
std::map<std::string, std::string> validationParams;
validationParams["SAMPLER_TYPE"] = isIntFormat(m_imageFormat) ? "isampler2D" :
isUintFormat(m_imageFormat) ? "usampler2D" : "sampler2D";
programCollection.glslSources.add("ImageValidator") << glu::ComputeSource(tcu::StringTemplate(validatorShader).specialize(validationParams));
}
bool ImageValidator::validateImage (ProtectedContext& ctx, const ValidationData& refData,
const vk::VkImage image, const vk::VkFormat imageFormat, const vk::VkImageLayout imageLayout) const
{
// Log out a few reference info
{
ctx.getTestContext().getLog()
<< tcu::TestLog::Message << "Reference coordinates: \n"
<< "1: " << refData.coords[0] << "\n"
<< "2: " << refData.coords[1] << "\n"
<< "3: " << refData.coords[2] << "\n"
<< "4: " << refData.coords[3] << "\n"
<< tcu::TestLog::EndMessage
<< tcu::TestLog::Message << "Reference color values: \n"
<< "1: " << refData.values[0] << "\n"
<< "2: " << refData.values[1] << "\n"
<< "3: " << refData.values[2] << "\n"
<< "4: " << refData.values[3] << "\n"
<< tcu::TestLog::EndMessage;
}
const deUint64 oneSec = 1000 * 1000 * 1000;
const vk::DeviceInterface& vk = ctx.getDeviceInterface();
const vk::VkDevice device = ctx.getDevice();
const vk::VkQueue queue = ctx.getQueue();
const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
const deUint32 refUniformSize = sizeof(refData);
de::UniquePtr<vk::BufferWithMemory> refUniform (makeBuffer(ctx,
PROTECTION_DISABLED,
queueFamilyIndex,
refUniformSize,
vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
vk::MemoryRequirement::HostVisible));
// Set the reference uniform data
{
deMemcpy(refUniform->getAllocation().getHostPtr(), &refData, refUniformSize);
vk::flushMappedMemoryRange(vk, device, refUniform->getAllocation().getMemory(), refUniform->getAllocation().getOffset(), refUniformSize);
}
const deUint32 helperBufferSize = (deUint32)(2 * sizeof(deUint32));
de::MovePtr<vk::BufferWithMemory> helperBuffer (makeBuffer(ctx,
PROTECTION_ENABLED,
queueFamilyIndex,
helperBufferSize,
vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
vk::MemoryRequirement::Protected));
vk::Unique<vk::VkShaderModule> resetSSBOShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ResetSSBO"), 0));
vk::Unique<vk::VkShaderModule> validatorShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ImageValidator"), 0));
vk::Unique<vk::VkSampler> sampler (makeSampler(vk, device));
const vk::VkImageViewCreateInfo viewParams =
{
vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
DE_NULL, // pNext
0u, // flags
image, // image
vk::VK_IMAGE_VIEW_TYPE_2D, // viewType
imageFormat, // format
vk::makeComponentMappingRGBA(), // components
{
vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
0u, // baseMipLevel
1u, // mipLeves
0u, // baseArraySlice
1u, // arraySize
} // subresourceRange
};
vk::Unique<vk::VkImageView> imageView (vk::createImageView(vk, device, &viewParams));
// Create descriptors
vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
.addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_SHADER_STAGE_COMPUTE_BIT, DE_NULL)
.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
.build(vk, device));
vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder()
.addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u)
.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
// Update descriptor set infirmation
{
vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refUniformSize);
vk::VkDescriptorBufferInfo descBuffer = makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize);
vk::VkDescriptorImageInfo descSampledImg = makeDescriptorImageInfo(*sampler, *imageView, imageLayout);
vk::DescriptorSetUpdateBuilder()
.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descSampledImg)
.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBuffer)
.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
.update(vk, device);
}
// Build pipeline
vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
// Reset helper SSBO
{
const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
vk::Unique<vk::VkPipeline> resetSSBOPipeline (makeComputePipeline(vk, device, *pipelineLayout, *resetSSBOShader, DE_NULL));
vk::Unique<vk::VkCommandBuffer> resetCmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
beginCommandBuffer(vk, *resetCmdBuffer);
vk.cmdBindPipeline(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *resetSSBOPipeline);
vk.cmdBindDescriptorSets(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
vk.cmdDispatch(*resetCmdBuffer, 1u, 1u, 1u);
endCommandBuffer(vk, *resetCmdBuffer);
VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *resetCmdBuffer, *fence, ~0ull));
}
// Create validation compute commands & submit
vk::VkResult queueSubmitResult;
{
const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
vk::Unique<vk::VkPipeline> validationPipeline (makeComputePipeline(vk, device, *pipelineLayout, *validatorShader, DE_NULL));
vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
beginCommandBuffer(vk, *cmdBuffer);
vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *validationPipeline);
vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
endCommandBuffer(vk, *cmdBuffer);
queueSubmitResult = queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, oneSec);
}
// \todo do we need to check the fence status?
if (queueSubmitResult == vk::VK_TIMEOUT)
return false;
// at this point the submit result should be VK_TRUE
VK_CHECK(queueSubmitResult);
return true;
}
} // ProtectedMem
} // vkt