/*------------------------------------------------------------------------- * 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 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 inBuffer = createBuffer(vk, device, &inBufferCreateInfo); de::MovePtr 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(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 outBuffer = createBuffer(vk, device, &outBufferCreateInfo); de::MovePtr 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 descriptorSetLayout( DescriptorSetLayoutBuilder() .addSingleBinding(uniBufDesc, VK_SHADER_STAGE_COMPUTE_BIT) .addSingleBinding(storBufDesc, VK_SHADER_STAGE_COMPUTE_BIT) .build(vk, device)); const Unique descriptorPool( DescriptorPoolBuilder() .addType(uniBufDesc) .addType(storBufDesc) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); const Unique 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 shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u)); const Unique pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout)); const VkPipelineShaderStageCreateInfo pipelineShaderStageParams = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, static_cast(0u), VK_SHADER_STAGE_COMPUTE_BIT, *shaderModule, "main", DE_NULL, }; const VkComputePipelineCreateInfo pipelineCreateInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, DE_NULL, static_cast(0u), pipelineShaderStageParams, *pipelineLayout, DE_NULL, 0, }; Unique 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 cmdPool(makeCommandPool(vk, device, queueFamilyIndex)); const Unique 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(outAllocation->getHostPtr()); if (*bufferPtr != testValue) return tcu::TestStatus::fail("Fail"); return tcu::TestStatus::pass("Pass"); } void checkSupport(Context& context) { context.requireDeviceFunctionality("VK_EXT_scalar_block_layout"); } } // anonymous tcu::TestCaseGroup* createHlslComputeGroup (tcu::TestContext& testCtx) { typedef InstanceFactory1WithSupport HlslTestInstance; de::MovePtr hlslCasesGroup(new tcu::TestCaseGroup(testCtx, "hlsl_cases", "")); TestConfig testConfig = { TT_CBUFFER_PACKING }; hlslCasesGroup->addChild(new HlslTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, "cbuffer_packing", "", testConfig, checkSupport)); return hlslCasesGroup.release(); } } // SpirVAssembly } // vkt