blob: e3eaf4a1c4cdcefa694a4a56014563d7bcfca2c0 [file] [log] [blame]
#ifndef _VKTPROTECTEDMEMBUFFERVALIDATOR_HPP
#define _VKTPROTECTEDMEMBUFFERVALIDATOR_HPP
/*------------------------------------------------------------------------
* 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 content buffer validator helper
*//*--------------------------------------------------------------------*/
#include "tcuVector.hpp"
#include "vkDefs.hpp"
#include "vktTestCase.hpp"
#include "tcuVector.hpp"
#include "tcuTestLog.hpp"
#include "vkBuilderUtil.hpp"
#include "vkPrograms.hpp"
#include "vkTypeUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestGroupUtil.hpp"
#include "tcuStringTemplate.hpp"
#include "vktProtectedMemUtils.hpp"
#include "vktProtectedMemContext.hpp"
namespace vkt
{
namespace ProtectedMem
{
class ProtectedContext;
template<typename T>
struct ValidationData {
const tcu::IVec4 positions[4];
const T values[4];
};
template<typename T>
struct ValidationDataStorage {
T values;
};
typedef ValidationData<tcu::UVec4> ValidationDataUVec4;
typedef ValidationData<tcu::IVec4> ValidationDataIVec4;
typedef ValidationData<tcu::Vec4> ValidationDataVec4;
enum TestType {
TYPE_UINT,
TYPE_INT,
TYPE_FLOAT,
};
enum BufferType {
SAMPLER_BUFFER,
STORAGE_BUFFER,
};
void initBufferValidatorPrograms (vk::SourceCollections& programCollection, TestType testType, BufferType bufferType);
vk::VkDescriptorType getDescriptorType (BufferType bufferType);
template<typename T>
class BufferValidator
{
public:
BufferValidator (const ValidationData<T> data)
: m_refData (data)
, m_refDataStorage (*reinterpret_cast<ValidationDataStorage<T>*>( &std::vector<char>(sizeof(ValidationDataStorage<T>), '\0').front()))
, m_bufferType (SAMPLER_BUFFER)
{
}
BufferValidator (const ValidationDataStorage<T> data)
: m_refData (*reinterpret_cast<ValidationData<T>*>( &std::vector<char>(sizeof(ValidationData<T>), '\0').front()))
, m_refDataStorage (data)
, m_bufferType (STORAGE_BUFFER)
{
}
~BufferValidator () {}
void initPrograms (vk::SourceCollections& programCollection) const;
bool validateBuffer (ProtectedContext& ctx,
const vk::VkBuffer buffer) const;
private:
deUint32 getReferenceDataSize () const;
const void * getReferenceDataSrc () const;
void printReferenceInfo (ProtectedContext& ctx) const;
const ValidationData<T> m_refData;
const ValidationDataStorage<T> m_refDataStorage;
BufferType m_bufferType;
};
template<>
inline void BufferValidator<tcu::UVec4>::initPrograms (vk::SourceCollections& programCollection) const
{
initBufferValidatorPrograms(programCollection, TYPE_UINT, m_bufferType);
}
template<>
inline void BufferValidator<tcu::IVec4>::initPrograms (vk::SourceCollections& programCollection) const
{
initBufferValidatorPrograms(programCollection, TYPE_INT, m_bufferType);
}
template<>
inline void BufferValidator<tcu::Vec4>::initPrograms (vk::SourceCollections& programCollection) const
{
initBufferValidatorPrograms(programCollection, TYPE_FLOAT, m_bufferType);
}
template<typename T>
deUint32 BufferValidator<T>::getReferenceDataSize () const
{
return m_bufferType == SAMPLER_BUFFER ? (deUint32)sizeof(m_refData) : (deUint32)sizeof(m_refDataStorage);
}
template<typename T>
const void * BufferValidator<T>::getReferenceDataSrc () const
{
return m_bufferType == SAMPLER_BUFFER ? (void*)&m_refData : (void*)&m_refDataStorage;
}
template<typename T>
void BufferValidator<T>::printReferenceInfo (ProtectedContext& ctx) const
{
if (m_bufferType == SAMPLER_BUFFER)
{
ctx.getTestContext().getLog()
<< tcu::TestLog::Message << "Reference positions: \n"
<< "1: " << m_refData.positions[0] << "\n"
<< "2: " << m_refData.positions[1] << "\n"
<< "3: " << m_refData.positions[2] << "\n"
<< "4: " << m_refData.positions[3] << "\n"
<< tcu::TestLog::EndMessage
<< tcu::TestLog::Message << "Reference fill values: \n"
<< "1: " << m_refData.values[0] << "\n"
<< "2: " << m_refData.values[1] << "\n"
<< "3: " << m_refData.values[2] << "\n"
<< "4: " << m_refData.values[3] << "\n"
<< tcu::TestLog::EndMessage;
} else if (m_bufferType == STORAGE_BUFFER)
{
ctx.getTestContext().getLog()
<< tcu::TestLog::Message << "Reference values: \n"
<< "1: " << m_refDataStorage.values << "\n"
<< tcu::TestLog::EndMessage;
}
}
template<typename T>
bool BufferValidator<T>::validateBuffer (ProtectedContext& ctx,
const vk::VkBuffer buffer) const
{
// Log out a few reference info
printReferenceInfo(ctx);
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();
vk::Move<vk::VkBufferView> bufferView;
const deUint32 refDataSize = getReferenceDataSize();
de::UniquePtr<vk::BufferWithMemory> refUniform (makeBuffer(ctx,
PROTECTION_DISABLED,
queueFamilyIndex,
refDataSize,
vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
vk::MemoryRequirement::HostVisible));
// Set the reference uniform data
{
deMemcpy(refUniform->getAllocation().getHostPtr(), getReferenceDataSrc(), refDataSize);
vk::flushMappedMemoryRange(vk, device, refUniform->getAllocation().getMemory(), refUniform->getAllocation().getOffset(), refDataSize);
}
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("BufferValidator"), 0));
// Create descriptors
vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout (vk::DescriptorSetLayoutBuilder()
.addSingleBinding(getDescriptorType(m_bufferType), vk::VK_SHADER_STAGE_COMPUTE_BIT)
.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(getDescriptorType(m_bufferType), 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 information
{
vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refDataSize);
vk::VkDescriptorBufferInfo descBuffer = makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize);
vk::DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
switch (m_bufferType)
{
case SAMPLER_BUFFER:
{
const vk::VkBufferViewCreateInfo viewParams =
{
vk::VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkBufferViewCreateFlags flags
buffer, // VkBuffer buffer
vk::VK_FORMAT_R32G32B32A32_UINT, // VkFormat format
0u, // VkDeviceSize offset
VK_WHOLE_SIZE // VkDeviceSize range
};
bufferView = vk::Move<vk::VkBufferView> (vk::createBufferView(vk, device, &viewParams));
descriptorSetUpdateBuilder
.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, &bufferView.get());
break;
}
case STORAGE_BUFFER:
{
const deUint32 testBufferSize = (deUint32)(sizeof(ValidationDataStorage<T>));
vk::VkDescriptorBufferInfo descTestBuffer = makeDescriptorBufferInfo(buffer, 0, testBufferSize);
descriptorSetUpdateBuilder
.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer);
break;
}
}
descriptorSetUpdateBuilder
.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
#endif // _VKTPROTECTEDMEMBUFFERVALIDATOR_HPP