--- /dev/null
+#!amber
+# Copyright 2020 The Amber Authors.
+#
+# 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
+#
+# https://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.
+
+DEVICE_EXTENSION VK_KHR_variable_pointers
+DEVICE_EXTENSION VK_KHR_storage_buffer_storage_class
+DEVICE_FEATURE VariablePointerFeatures.variablePointers
+DEVICE_FEATURE VariablePointerFeatures.variablePointersStorageBuffer
+
+# Based on the following GLSL shader pseudocode:
+#
+#SHADER compute compute_shader GLSL
+##version 430
+#
+#layout(set = 0, binding = 0) buffer InputData
+#{
+# int data[10];
+#} input0[2];
+#
+#layout(set = 0, binding = 1) buffer InputData
+#{
+# int data[10];
+#} input1[2];
+#
+#layout(set = 0, binding = 2) buffer Result
+#{
+# int result;
+#};
+#
+#layout(push_constant) uniform Indices
+#{
+# int idx0;
+# int idx1;
+# int idx2;
+#};
+#
+#
+#void main()
+#{
+# InputData input[]* = (idx0 == 0) ? &input0 : &input1;
+# result = input[idx1].data[idx2];
+#}
+#END
+
+SHADER compute compute_shader SPIRV-ASM
+ OpCapability Shader
+ OpCapability VariablePointers
+ OpExtension "SPV_KHR_variable_pointers"
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 430
+ OpMemberDecorate %Indices 0 Offset 0
+ OpMemberDecorate %Indices 1 Offset 4
+ OpMemberDecorate %Indices 2 Offset 8
+ OpDecorate %Indices Block
+ OpMemberDecorate %Result 0 Offset 0
+ OpDecorate %Result Block
+ OpDecorate %result DescriptorSet 0
+ OpDecorate %result Binding 2
+ OpDecorate %_arr_int_int_10 ArrayStride 16
+ OpMemberDecorate %InputData 0 Offset 0
+ OpDecorate %InputData Block
+ OpDecorate %input0 DescriptorSet 0
+ OpDecorate %input0 Binding 0
+ OpDecorate %input1 DescriptorSet 0
+ OpDecorate %input1 Binding 1
+ %void = OpTypeVoid
+ %bool = OpTypeBool
+ %int = OpTypeInt 32 1
+ %void_func = OpTypeFunction %void
+ %Indices = OpTypeStruct %int %int %int
+%_ptr_PushConstant_Indices = OpTypePointer PushConstant %Indices
+ %indices = OpVariable %_ptr_PushConstant_Indices PushConstant
+ %int_0 = OpConstant %int 0
+ %int_1 = OpConstant %int 1
+ %int_2 = OpConstant %int 2
+ %int_10 = OpConstant %int 10
+%_ptr_PushConstant_int = OpTypePointer PushConstant %int
+ %Result = OpTypeStruct %int
+%_ptr_StorageBuffer_Result = OpTypePointer StorageBuffer %Result
+ %result = OpVariable %_ptr_StorageBuffer_Result StorageBuffer
+%_arr_int_int_10 = OpTypeArray %int %int_10
+ %InputData = OpTypeStruct %_arr_int_int_10
+%_arr_InputData_int_2 = OpTypeArray %InputData %int_2
+%_ptr_StorageBuffer__arr_InputData_int_2 = OpTypePointer StorageBuffer %_arr_InputData_int_2
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+ %input0 = OpVariable %_ptr_StorageBuffer__arr_InputData_int_2 StorageBuffer
+ %input1 = OpVariable %_ptr_StorageBuffer__arr_InputData_int_2 StorageBuffer
+ %main = OpFunction %void None %void_func
+ %label = OpLabel
+ %idx0_ptr = OpAccessChain %_ptr_PushConstant_int %indices %int_0
+ %idx0 = OpLoad %int %idx0_ptr
+ %idx1_ptr = OpAccessChain %_ptr_PushConstant_int %indices %int_1
+ %idx1 = OpLoad %int %idx1_ptr
+ %idx2_ptr = OpAccessChain %_ptr_PushConstant_int %indices %int_2
+ %idx2 = OpLoad %int %idx2_ptr
+ %idx0_zero = OpIEqual %bool %idx0 %int_0
+%variable_ptr = OpSelect %_ptr_StorageBuffer__arr_InputData_int_2 %idx0_zero %input0 %input1
+%input_data_ptr = OpAccessChain %_ptr_StorageBuffer_int %variable_ptr %idx1 %int_0 %idx2
+ %input_data = OpLoad %int %input_data_ptr
+%result_data_ptr = OpAccessChain %_ptr_StorageBuffer_int %result %int_0
+ OpStore %result_data_ptr %input_data
+ OpReturn
+ OpFunctionEnd
+END
+
+BUFFER buf0 DATA_TYPE int32 SIZE 1024 SERIES_FROM 0 INC_BY 1
+BUFFER buf1 DATA_TYPE int32 SIZE 1024 SERIES_FROM 1 INC_BY 1
+BUFFER buf2 DATA_TYPE int32 SIZE 1024 SERIES_FROM 2 INC_BY 1
+BUFFER buf3 DATA_TYPE int32 SIZE 1024 SERIES_FROM 3 INC_BY 1
+BUFFER indices0 DATA_TYPE int32 DATA
+0 1 2
+END
+BUFFER indices1 DATA_TYPE int32 DATA
+1 1 2
+END
+BUFFER result DATA_TYPE int32 DATA
+0
+END
+
+# This pipeline will select input from buf1 which has a dynamic offset of 256 bytes.
+# The sequence in that buffer starts from 1, and the array stride in the shader is
+# 16 bytes. The shader reads an array element number 2. Thus the expected value is:
+# 256/4 + 1 + 2 * 4 = 73.
+PIPELINE compute pipeline0
+ ATTACH compute_shader
+
+ BIND BUFFER_ARRAY buf0 buf1 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 0 OFFSET 0 256
+ BIND BUFFER_ARRAY buf2 buf3 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 1 OFFSET 512 768
+ BIND BUFFER indices0 AS push_constant
+ BIND BUFFER result AS storage DESCRIPTOR_SET 0 BINDING 2
+END
+
+RUN pipeline0 1 1 1
+
+EXPECT result IDX 0 EQ 73
+
+# This pipeline will select input from buf3 which has a dynamic offset of 768 bytes.
+# The sequence in that buffer starts from 3, and the array stride in the shader is
+# 16 bytes. The shader reads an array element number 2. Thus the expected value is:
+# 768/4 + 3 + 2 * 4 = 203.
+PIPELINE compute pipeline1
+ ATTACH compute_shader
+
+ BIND BUFFER_ARRAY buf0 buf1 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 0 OFFSET 0 256
+ BIND BUFFER_ARRAY buf2 buf3 AS storage_dynamic DESCRIPTOR_SET 0 BINDING 1 OFFSET 512 768
+ BIND BUFFER indices1 AS push_constant
+ BIND BUFFER result AS storage DESCRIPTOR_SET 0 BINDING 2
+END
+
+RUN pipeline1 1 1 1
+
+EXPECT result IDX 0 EQ 203
#include "vktSpvAsmVariablePointersTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
+#include "vktAmberTestCase.hpp"
#include <limits>
#include <map>
}
}
+void addDynamicOffsetComputeGroup (tcu::TestCaseGroup* group)
+{
+ tcu::TestContext &testCtx = group->getTestContext();
+
+ static const char dataDir[] = "spirv_assembly/instruction/compute/variable_pointer/dynamic_offset";
+
+ struct Case
+ {
+ string name;
+ string desc;
+ };
+
+ static const Case cases[] =
+ {
+ { "select_descriptor_array", "Test accessing a descriptor array using a variable pointer from OpSelect" },
+ };
+
+ for (const auto& testCase : cases)
+ {
+ const string fileName = testCase.name + ".amber";
+
+ group->addChild(cts_amber::createAmberTestCase(testCtx, testCase.name.c_str(), testCase.desc.c_str(), dataDir, fileName, {"VK_KHR_variable_pointers", "VK_KHR_storage_buffer_storage_class", "VariablePointerFeatures.variablePointers", "VariablePointerFeatures.variablePointersStorageBuffer"}));
+ }
+}
+
void addVariablePointersGraphicsGroup (tcu::TestCaseGroup* testGroup)
{
tcu::TestContext& testCtx = testGroup->getTestContext();
"nullptr_compute",
"Test the usage of nullptr using the variable pointers extension in a compute shader",
addNullptrVariablePointersComputeGroup);
+ addTestGroup(group.get(), "dynamic_offset",
+ "Testing variable pointers referring to descriptors using dynamic offset",
+ addDynamicOffsetComputeGroup);
return group.release();
}