blob: 090dbeca7b05e98bf9002945a2956ed21bd5a180 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2019 The Khronos Group 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 SPIR-V Assembly Tests for indexing with access chain operations.
*//*--------------------------------------------------------------------*/
#include "vktSpvAsmFromHlslTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkPrograms.hpp"
#include "vkObjUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkCmdUtil.hpp"
namespace vkt
{
namespace SpirVAssembly
{
namespace
{
using namespace vk;
enum TestType
{
TT_CBUFFER_PACKING = 0,
};
struct TestConfig
{
TestType type;
};
struct Programs
{
void init (vk::SourceCollections& dst, TestConfig config) const
{
if (config.type == TT_CBUFFER_PACKING)
{
// HLSL shaders has a packing corner case that GLSL shaders cannot exhibit.
// Below shader, foo has an ArrayStride of 16, which leaves bar effectively
// 'within' the end of the foo array. This is entirely valid for HLSL and
// with the VK_EXT_scalar_block_layout extension.
std::string source(
"cbuffer cbIn\n"
"{\n"
" int foo[2] : packoffset(c0);\n"
" int bar : packoffset(c1.y);\n"
"};\n"
"RWStructuredBuffer<int> result : register(u1);\n"
"[numthreads(1, 1, 1)]\n"
"void main(uint3 dispatchThreadID : SV_DispatchThreadID)\n"
"{\n"
" result[0] = bar;\n"
"}\n");
dst.hlslSources.add("comp") << glu::ComputeSource(source)
<< vk::ShaderBuildOptions(dst.usedVulkanVersion, vk::SPIRV_VERSION_1_0, vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS);
}
}
};
class HlslTest : public TestInstance
{
public:
HlslTest (Context& context, TestConfig config);
virtual ~HlslTest (void) = default;
tcu::TestStatus iterate (void);
};
HlslTest::HlslTest(Context& context, TestConfig config)
: TestInstance(context)
{
DE_UNREF(config);
}
tcu::TestStatus HlslTest::iterate(void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice device = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
Allocator& allocator = m_context.getDefaultAllocator();
const int testValue = 5;
// Create an input buffer
const VkBufferUsageFlags inBufferUsageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
const VkDeviceSize inBufferSizeBytes = 32; // 2 element array with 16B stride
VkBufferCreateInfo inBufferCreateInfo = makeBufferCreateInfo(inBufferSizeBytes, inBufferUsageFlags);
vk::Move<vk::VkBuffer> inBuffer = createBuffer(vk, device, &inBufferCreateInfo);
de::MovePtr<vk::Allocation> inAllocation = allocator.allocate(getBufferMemoryRequirements(vk, device, *inBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(device, *inBuffer, inAllocation->getMemory(), inAllocation->getOffset()));
// Fill the input structure with data - first attribute is array that has 16B stride,
// this means that second attribute has to start at offset 20B (4B + 16B)
{
int* bufferPtr = static_cast<int*>(inAllocation->getHostPtr());
memset(bufferPtr, 0, inBufferSizeBytes);
bufferPtr[5] = testValue;
flushAlloc(vk, device, *inAllocation);
}
// Create an output buffer
const VkBufferUsageFlags outBufferUsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
const VkDeviceSize outBufferSizeBytes = sizeof(int);
VkBufferCreateInfo outBufferCreateInfo = makeBufferCreateInfo(outBufferSizeBytes, outBufferUsageFlags);
vk::Move<vk::VkBuffer> outBuffer = createBuffer(vk, device, &outBufferCreateInfo);
de::MovePtr<vk::Allocation> outAllocation = allocator.allocate(getBufferMemoryRequirements(vk, device, *outBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(device, *outBuffer, outAllocation->getMemory(), outAllocation->getOffset()));
// Create descriptor set
const VkDescriptorType uniBufDesc = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
const VkDescriptorType storBufDesc = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
const Unique<VkDescriptorSetLayout> descriptorSetLayout(
DescriptorSetLayoutBuilder()
.addSingleBinding(uniBufDesc, VK_SHADER_STAGE_COMPUTE_BIT)
.addSingleBinding(storBufDesc, VK_SHADER_STAGE_COMPUTE_BIT)
.build(vk, device));
const Unique<VkDescriptorPool> descriptorPool(
DescriptorPoolBuilder()
.addType(uniBufDesc)
.addType(storBufDesc)
.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
const VkDescriptorBufferInfo inputBufferDescriptorInfo = makeDescriptorBufferInfo(*inBuffer, 0ull, inBufferSizeBytes);
const VkDescriptorBufferInfo outputBufferDescriptorInfo = makeDescriptorBufferInfo(*outBuffer, 0ull, outBufferSizeBytes);
DescriptorSetUpdateBuilder()
.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), uniBufDesc, &inputBufferDescriptorInfo)
.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), storBufDesc, &outputBufferDescriptorInfo)
.update(vk, device);
// Perform the computation
const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
const VkPipelineShaderStageCreateInfo pipelineShaderStageParams =
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
static_cast<VkPipelineShaderStageCreateFlags>(0u),
VK_SHADER_STAGE_COMPUTE_BIT,
*shaderModule,
"main",
DE_NULL,
};
const VkComputePipelineCreateInfo pipelineCreateInfo =
{
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
DE_NULL,
static_cast<VkPipelineCreateFlags>(0u),
pipelineShaderStageParams,
*pipelineLayout,
DE_NULL,
0,
};
Unique<VkPipeline> pipeline(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
const VkBufferMemoryBarrier hostWriteBarrier = makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, *inBuffer, 0ull, inBufferSizeBytes);
const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *outBuffer, 0ull, outBufferSizeBytes);
const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
// Start recording commands
beginCommandBuffer(vk, *cmdBuffer);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &shaderWriteBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
endCommandBuffer(vk, *cmdBuffer);
// Wait for completion
submitCommandsAndWait(vk, device, queue, *cmdBuffer);
// Validate the results
invalidateAlloc(vk, device, *outAllocation);
const int* bufferPtr = static_cast<int*>(outAllocation->getHostPtr());
if (*bufferPtr != testValue)
return tcu::TestStatus::fail("Fail");
return tcu::TestStatus::pass("Pass");
}
} // anonymous
tcu::TestCaseGroup* createHlslComputeGroup (tcu::TestContext& testCtx)
{
typedef InstanceFactory1<HlslTest, TestConfig, Programs> HlslTestInstance;
de::MovePtr<tcu::TestCaseGroup> hlslCasesGroup(new tcu::TestCaseGroup(testCtx, "hlsl_cases", ""));
TestConfig testConfig = { TT_CBUFFER_PACKING };
hlslCasesGroup->addChild(new HlslTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, "cbuffer_packing", "", testConfig));
return hlslCasesGroup.release();
}
} // SpirVAssembly
} // vkt