551 lines
20 KiB
C++
551 lines
20 KiB
C++
// Copyright 2018 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
|
|
//
|
|
// 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.
|
|
|
|
#include "src/shader_compiler.h"
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "src/sampler.h"
|
|
#include "src/shader_data.h"
|
|
#if AMBER_ENABLE_SHADERC
|
|
#include "shaderc/shaderc.hpp"
|
|
#endif
|
|
|
|
namespace amber {
|
|
namespace {
|
|
|
|
const char kHexShader[] =
|
|
R"(0x03 0x02 0x23 0x07 0x00 0x00 0x01 0x00 0x07 0x00 0x08 0x00
|
|
0x15 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x11 0x00 0x02 0x00
|
|
0x01 0x00 0x00 0x00 0x0b 0x00 0x06 0x00 0x01 0x00 0x00 0x00
|
|
0x47 0x4c 0x53 0x4c 0x2e 0x73 0x74 0x64 0x2e 0x34 0x35 0x30
|
|
0x00 0x00 0x00 0x00 0x0e 0x00 0x03 0x00 0x00 0x00 0x00 0x00
|
|
0x01 0x00 0x00 0x00 0x0f 0x00 0x07 0x00 0x00 0x00 0x00 0x00
|
|
0x04 0x00 0x00 0x00 0x6d 0x61 0x69 0x6e 0x00 0x00 0x00 0x00
|
|
0x0d 0x00 0x00 0x00 0x11 0x00 0x00 0x00 0x03 0x00 0x03 0x00
|
|
0x02 0x00 0x00 0x00 0xae 0x01 0x00 0x00 0x05 0x00 0x04 0x00
|
|
0x04 0x00 0x00 0x00 0x6d 0x61 0x69 0x6e 0x00 0x00 0x00 0x00
|
|
0x05 0x00 0x06 0x00 0x0b 0x00 0x00 0x00 0x67 0x6c 0x5f 0x50
|
|
0x65 0x72 0x56 0x65 0x72 0x74 0x65 0x78 0x00 0x00 0x00 0x00
|
|
0x06 0x00 0x06 0x00 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x67 0x6c 0x5f 0x50 0x6f 0x73 0x69 0x74 0x69 0x6f 0x6e 0x00
|
|
0x06 0x00 0x07 0x00 0x0b 0x00 0x00 0x00 0x01 0x00 0x00 0x00
|
|
0x67 0x6c 0x5f 0x50 0x6f 0x69 0x6e 0x74 0x53 0x69 0x7a 0x65
|
|
0x00 0x00 0x00 0x00 0x06 0x00 0x07 0x00 0x0b 0x00 0x00 0x00
|
|
0x02 0x00 0x00 0x00 0x67 0x6c 0x5f 0x43 0x6c 0x69 0x70 0x44
|
|
0x69 0x73 0x74 0x61 0x6e 0x63 0x65 0x00 0x05 0x00 0x03 0x00
|
|
0x0d 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x05 0x00 0x05 0x00
|
|
0x11 0x00 0x00 0x00 0x70 0x6f 0x73 0x69 0x74 0x69 0x6f 0x6e
|
|
0x00 0x00 0x00 0x00 0x48 0x00 0x05 0x00 0x0b 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x48 0x00 0x05 0x00 0x0b 0x00 0x00 0x00 0x01 0x00 0x00 0x00
|
|
0x0b 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x48 0x00 0x05 0x00
|
|
0x0b 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x0b 0x00 0x00 0x00
|
|
0x03 0x00 0x00 0x00 0x47 0x00 0x03 0x00 0x0b 0x00 0x00 0x00
|
|
0x02 0x00 0x00 0x00 0x47 0x00 0x04 0x00 0x11 0x00 0x00 0x00
|
|
0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x13 0x00 0x02 0x00
|
|
0x02 0x00 0x00 0x00 0x21 0x00 0x03 0x00 0x03 0x00 0x00 0x00
|
|
0x02 0x00 0x00 0x00 0x16 0x00 0x03 0x00 0x06 0x00 0x00 0x00
|
|
0x20 0x00 0x00 0x00 0x17 0x00 0x04 0x00 0x07 0x00 0x00 0x00
|
|
0x06 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x15 0x00 0x04 0x00
|
|
0x08 0x00 0x00 0x00 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x2b 0x00 0x04 0x00 0x08 0x00 0x00 0x00 0x09 0x00 0x00 0x00
|
|
0x01 0x00 0x00 0x00 0x1c 0x00 0x04 0x00 0x0a 0x00 0x00 0x00
|
|
0x06 0x00 0x00 0x00 0x09 0x00 0x00 0x00 0x1e 0x00 0x05 0x00
|
|
0x0b 0x00 0x00 0x00 0x07 0x00 0x00 0x00 0x06 0x00 0x00 0x00
|
|
0x0a 0x00 0x00 0x00 0x20 0x00 0x04 0x00 0x0c 0x00 0x00 0x00
|
|
0x03 0x00 0x00 0x00 0x0b 0x00 0x00 0x00 0x3b 0x00 0x04 0x00
|
|
0x0c 0x00 0x00 0x00 0x0d 0x00 0x00 0x00 0x03 0x00 0x00 0x00
|
|
0x15 0x00 0x04 0x00 0x0e 0x00 0x00 0x00 0x20 0x00 0x00 0x00
|
|
0x01 0x00 0x00 0x00 0x2b 0x00 0x04 0x00 0x0e 0x00 0x00 0x00
|
|
0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x00 0x04 0x00
|
|
0x10 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x07 0x00 0x00 0x00
|
|
0x3b 0x00 0x04 0x00 0x10 0x00 0x00 0x00 0x11 0x00 0x00 0x00
|
|
0x01 0x00 0x00 0x00 0x20 0x00 0x04 0x00 0x13 0x00 0x00 0x00
|
|
0x03 0x00 0x00 0x00 0x07 0x00 0x00 0x00 0x36 0x00 0x05 0x00
|
|
0x02 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x03 0x00 0x00 0x00 0xf8 0x00 0x02 0x00 0x05 0x00 0x00 0x00
|
|
0x3d 0x00 0x04 0x00 0x07 0x00 0x00 0x00 0x12 0x00 0x00 0x00
|
|
0x11 0x00 0x00 0x00 0x41 0x00 0x05 0x00 0x13 0x00 0x00 0x00
|
|
0x14 0x00 0x00 0x00 0x0d 0x00 0x00 0x00 0x0f 0x00 0x00 0x00
|
|
0x3e 0x00 0x03 0x00 0x14 0x00 0x00 0x00 0x12 0x00 0x00 0x00
|
|
0xfd 0x00 0x01 0x00 0x38 0x00 0x01 0x00)";
|
|
|
|
} // namespace
|
|
|
|
using ShaderCompilerTest = testing::Test;
|
|
|
|
#if AMBER_ENABLE_SHADERC
|
|
TEST_F(ShaderCompilerTest, CompilesGlsl) {
|
|
std::string contents = R"(
|
|
#version 420
|
|
layout(location = 0) in vec4 position;
|
|
|
|
void main() {
|
|
gl_Position = position;
|
|
})";
|
|
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatGlsl);
|
|
shader.SetData(contents);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess()) << r.Error();
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
}
|
|
#endif // AMBER_ENABLE_SHADERC
|
|
|
|
#if AMBER_ENABLE_SPIRV_TOOLS
|
|
TEST_F(ShaderCompilerTest, CompilesSpirvAsm) {
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatSpirvAsm);
|
|
shader.SetData(kPassThroughShader);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, InvalidSpirvHex) {
|
|
std::string contents = kHexShader;
|
|
contents[3] = '0';
|
|
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName("BadTestShader");
|
|
shader.SetFormat(kShaderFormatSpirvHex);
|
|
shader.SetData(contents);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_FALSE(r.IsSuccess());
|
|
EXPECT_EQ("Invalid shader: error: line 0: Invalid SPIR-V magic number.\n",
|
|
r.Error());
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, InvalidHex) {
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName("BadTestShader");
|
|
shader.SetFormat(kShaderFormatSpirvHex);
|
|
shader.SetData("aaaaaaaaaa");
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_FALSE(r.IsSuccess());
|
|
EXPECT_EQ("Invalid shader: error: line 0: Invalid SPIR-V magic number.\n",
|
|
r.Error());
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, OptimizeShader) {
|
|
const std::string spirv = R"(
|
|
OpCapability Shader
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpDecorate %block Block
|
|
OpMemberDecorate %block 0 Offset 0
|
|
OpDecorate %in DescriptorSet 0
|
|
OpDecorate %in Binding 0
|
|
OpDecorate %out DescriptorSet 0
|
|
OpDecorate %out Binding 1
|
|
%void = OpTypeVoid
|
|
%int = OpTypeInt 32 0
|
|
%int_0 = OpConstant %int 0
|
|
%block = OpTypeStruct %int
|
|
%ptr_ssbo_block = OpTypePointer StorageBuffer %block
|
|
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
|
%in = OpVariable %ptr_ssbo_block StorageBuffer
|
|
%out = OpVariable %ptr_ssbo_block StorageBuffer
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
%in_gep = OpAccessChain %ptr_ssbo_int %in %int_0
|
|
%ld = OpLoad %int %in_gep
|
|
%dead = OpIAdd %int %ld %int_0
|
|
%out_gep = OpAccessChain %ptr_ssbo_int %out %int_0
|
|
OpStore %out_gep %ld
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
Shader shader(kShaderTypeCompute);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatSpirvAsm);
|
|
shader.SetData(spirv);
|
|
|
|
Pipeline::ShaderInfo unoptimized(&shader, kShaderTypeCompute);
|
|
Pipeline::ShaderInfo optimized(&shader, kShaderTypeCompute);
|
|
optimized.SetShaderOptimizations({"--eliminate-dead-code-aggressive"});
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> unopt_binary;
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, unopt_binary) = sc.Compile(&pipeline, &unoptimized, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
|
|
std::vector<uint32_t> opt_binary;
|
|
std::tie(r, opt_binary) = sc.Compile(&pipeline, &optimized, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_NE(opt_binary.size(), unopt_binary.size());
|
|
}
|
|
#endif // AMBER_ENABLE_SPIRV_TOOLS
|
|
|
|
TEST_F(ShaderCompilerTest, CompilesSpirvHex) {
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatSpirvHex);
|
|
shader.SetData(kHexShader);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, FailsOnInvalidShader) {
|
|
std::string contents = "Just Random\nText()\nThat doesn't work.";
|
|
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName("BadTestShader");
|
|
shader.SetFormat(kShaderFormatGlsl);
|
|
shader.SetData(contents);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_FALSE(r.IsSuccess());
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, ReturnsCachedShader) {
|
|
// This shader would normally fail, but because we pull it from the cache,
|
|
// we don't compile this so the test will pass.
|
|
std::string contents = "Just Random\nText()\nThat doesn't work.";
|
|
|
|
static const char kShaderName[] = "CachedShader";
|
|
static const char kShaderNameWithPipeline[] = "pipeline-CachedShader";
|
|
Shader shader(kShaderTypeVertex);
|
|
shader.SetName(kShaderName);
|
|
shader.SetFormat(kShaderFormatGlsl);
|
|
shader.SetData(contents);
|
|
|
|
std::vector<uint32_t> src_bytes = {1, 2, 3, 4, 5};
|
|
|
|
ShaderMap map;
|
|
map[kShaderNameWithPipeline] = src_bytes;
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
pipeline.SetName("pipeline");
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, map);
|
|
ASSERT_TRUE(r.IsSuccess()) << r.Error();
|
|
|
|
ASSERT_EQ(binary.size(), src_bytes.size());
|
|
for (size_t i = 0; i < src_bytes.size(); ++i) {
|
|
EXPECT_EQ(src_bytes[i], binary[i]);
|
|
}
|
|
}
|
|
|
|
#if AMBER_ENABLE_CLSPV
|
|
TEST_F(ShaderCompilerTest, ClspvCompile) {
|
|
Shader shader(kShaderTypeCompute);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatOpenCLC);
|
|
shader.SetData(R"(
|
|
kernel void TestShader(global int* in, global int* out) {
|
|
*out = *in;
|
|
}
|
|
)");
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, ClspvDisallowCaching) {
|
|
Shader shader(kShaderTypeCompute);
|
|
std::string name = "TestShader";
|
|
shader.SetName(name);
|
|
shader.SetFormat(kShaderFormatOpenCLC);
|
|
shader.SetData(R"(
|
|
kernel void TestShader(global int* in, global int* out) {
|
|
*out = *in;
|
|
}
|
|
)");
|
|
|
|
std::vector<uint32_t> src_bytes = {1, 2, 3, 4, 5};
|
|
|
|
ShaderMap map;
|
|
map[name] = src_bytes;
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info, map);
|
|
ASSERT_FALSE(r.IsSuccess());
|
|
EXPECT_TRUE(binary.empty());
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, ClspvCompileOptions) {
|
|
std::string data = R"(
|
|
kernel void TestShader(global int* in, global int* out, int m, int b) {
|
|
*out = *in * m + b;
|
|
}
|
|
)";
|
|
Shader shader(kShaderTypeCompute);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatOpenCLC);
|
|
shader.SetData(data);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info1(&shader, kShaderTypeCompute);
|
|
shader_info1.SetCompileOptions({"-cluster-pod-kernel-args=0"});
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info1, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
auto iter = shader_info1.GetDescriptorMap().find("TestShader");
|
|
ASSERT_NE(iter, shader_info1.GetDescriptorMap().end());
|
|
uint32_t max_binding = 0;
|
|
bool has_pod_ubo = 0;
|
|
for (const auto& entry : iter->second) {
|
|
max_binding = std::max(max_binding, entry.binding);
|
|
has_pod_ubo =
|
|
entry.kind == Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_UBO;
|
|
}
|
|
EXPECT_EQ(3U, max_binding);
|
|
EXPECT_TRUE(has_pod_ubo);
|
|
|
|
binary.clear();
|
|
Pipeline::ShaderInfo shader_info2(&shader, kShaderTypeCompute);
|
|
shader_info2.SetCompileOptions({"-cluster-pod-kernel-args", "-pod-ubo"});
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info2, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
iter = shader_info2.GetDescriptorMap().find("TestShader");
|
|
ASSERT_NE(iter, shader_info2.GetDescriptorMap().end());
|
|
max_binding = 0;
|
|
has_pod_ubo = 0;
|
|
for (const auto& entry : iter->second) {
|
|
max_binding = std::max(max_binding, entry.binding);
|
|
has_pod_ubo =
|
|
entry.kind == Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD_UBO;
|
|
}
|
|
EXPECT_EQ(2U, max_binding);
|
|
EXPECT_TRUE(has_pod_ubo);
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, ClspvImagesAndSamplers) {
|
|
std::string data = R"(
|
|
kernel void TestShader(read_only image2d_t ro_image, write_only image2d_t wo_image, sampler_t sampler) {
|
|
int2 coord = (int2)(0, 0);
|
|
float4 texel = read_imagef(ro_image, sampler, coord);
|
|
write_imagef(wo_image, coord, texel);
|
|
}
|
|
)";
|
|
|
|
Shader shader(kShaderTypeCompute);
|
|
shader.SetName("TestShader");
|
|
shader.SetFormat(kShaderFormatOpenCLC);
|
|
shader.SetData(data);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info1(&shader, kShaderTypeCompute);
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info1, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
auto iter = shader_info1.GetDescriptorMap().find("TestShader");
|
|
for (const auto& entry : iter->second) {
|
|
if (entry.binding == 0) {
|
|
EXPECT_EQ(entry.kind,
|
|
Pipeline::ShaderInfo::DescriptorMapEntry::Kind::RO_IMAGE);
|
|
} else if (entry.binding == 1) {
|
|
EXPECT_EQ(entry.kind,
|
|
Pipeline::ShaderInfo::DescriptorMapEntry::Kind::WO_IMAGE);
|
|
} else if (entry.binding == 2) {
|
|
EXPECT_EQ(entry.kind,
|
|
Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SAMPLER);
|
|
} else {
|
|
ASSERT_TRUE(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(ShaderCompilerTest, ClspvLiteralSamplers) {
|
|
std::string data = R"(
|
|
const sampler_t s1 = CLK_ADDRESS_NONE | CLK_FILTER_NEAREST | CLK_NORMALIZED_COORDS_FALSE;
|
|
const sampler_t s2 = CLK_ADDRESS_MIRRORED_REPEAT | CLK_FILTER_LINEAR | CLK_NORMALIZED_COORDS_TRUE;
|
|
|
|
kernel void foo(read_only image2d_t im, global float4* out) {
|
|
out[0] = read_imagef(im, s1, (int2)(0));
|
|
out[1] = read_imagef(im, s2, (int2)(0));
|
|
}
|
|
)";
|
|
|
|
Pipeline pipeline(PipelineType::kCompute);
|
|
pipeline.SetName("pipe");
|
|
Shader shader(kShaderTypeCompute);
|
|
shader.SetName("foo");
|
|
shader.SetFormat(kShaderFormatOpenCLC);
|
|
shader.SetData(data);
|
|
|
|
ShaderCompiler sc;
|
|
Result r;
|
|
std::vector<uint32_t> binary;
|
|
Pipeline::ShaderInfo shader_info1(&shader, kShaderTypeCompute);
|
|
std::tie(r, binary) = sc.Compile(&pipeline, &shader_info1, ShaderMap());
|
|
ASSERT_TRUE(r.IsSuccess());
|
|
EXPECT_FALSE(binary.empty());
|
|
EXPECT_EQ(0x07230203u, binary[0]); // Verify SPIR-V header present.
|
|
bool found_s1 = false;
|
|
bool found_s2 = false;
|
|
EXPECT_EQ(0, pipeline.GetSamplers()[0].descriptor_set);
|
|
EXPECT_EQ(0, pipeline.GetSamplers()[1].descriptor_set);
|
|
EXPECT_NE(pipeline.GetSamplers()[0].binding,
|
|
pipeline.GetSamplers()[1].binding);
|
|
if (pipeline.GetSamplers()[0].mask == 0x10 ||
|
|
pipeline.GetSamplers()[1].mask == 0x10) {
|
|
found_s1 = true;
|
|
}
|
|
if (pipeline.GetSamplers()[0].mask == (0x1 | 0x8 | 0x20) ||
|
|
pipeline.GetSamplers()[1].mask == (0x1 | 0x8 | 0x20)) {
|
|
found_s2 = true;
|
|
}
|
|
EXPECT_EQ(true, found_s1);
|
|
EXPECT_EQ(true, found_s2);
|
|
}
|
|
#endif // AMBER_ENABLE_CLSPV
|
|
|
|
struct ParseSpvEnvCase {
|
|
std::string env_str;
|
|
bool ok;
|
|
uint32_t target_env;
|
|
uint32_t env_version;
|
|
uint32_t spirv_version;
|
|
};
|
|
|
|
using ParseSpvEnvTest = ::testing::TestWithParam<ParseSpvEnvCase>;
|
|
|
|
TEST_P(ParseSpvEnvTest, Samples) {
|
|
uint32_t target_env = 42u;
|
|
uint32_t env_version = 43u;
|
|
uint32_t spirv_version = 44u;
|
|
auto r = amber::ParseSpvEnv(GetParam().env_str, &target_env, &env_version,
|
|
&spirv_version);
|
|
if (GetParam().ok) {
|
|
EXPECT_TRUE(r.IsSuccess());
|
|
EXPECT_EQ(GetParam().target_env, target_env) << GetParam().env_str;
|
|
EXPECT_EQ(GetParam().env_version, env_version) << GetParam().env_str;
|
|
EXPECT_EQ(GetParam().spirv_version, spirv_version) << GetParam().env_str;
|
|
} else {
|
|
EXPECT_FALSE(r.IsSuccess());
|
|
}
|
|
}
|
|
|
|
// See also shaderc/env.h
|
|
const uint32_t vulkan = 0;
|
|
const uint32_t vulkan_1_0 = ((uint32_t(1) << 22));
|
|
const uint32_t vulkan_1_1 = ((uint32_t(1) << 22) | (1 << 12));
|
|
const uint32_t vulkan_1_2 = ((uint32_t(1) << 22) | (2 << 12));
|
|
const uint32_t spv_1_0 = uint32_t(0x10000);
|
|
const uint32_t spv_1_1 = uint32_t(0x10100);
|
|
const uint32_t spv_1_2 = uint32_t(0x10200);
|
|
const uint32_t spv_1_3 = uint32_t(0x10300);
|
|
const uint32_t spv_1_4 = uint32_t(0x10400);
|
|
const uint32_t spv_1_5 = uint32_t(0x10500);
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ParseSpvEnvFailures,
|
|
ParseSpvEnvTest,
|
|
::testing::ValuesIn(std::vector<ParseSpvEnvCase>{
|
|
{"foobar", false, 0u, 0u, 0u},
|
|
{"spv99", false, 0u, 0u, 0u},
|
|
{"spv99.9", false, 0u, 0u, 0u},
|
|
{"spv1.0.1", false, 0u, 0u, 0u},
|
|
{"spv1.0.1", false, 0u, 0u, 0u},
|
|
{"spv1.9", false, 0u, 0u, 0u},
|
|
{"vulkan99", false, 0u, 0u, 0u},
|
|
{"vulkan99.9", false, 0u, 0u, 0u},
|
|
}));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ParseSpvEnvSuccesses,
|
|
ParseSpvEnvTest,
|
|
::testing::ValuesIn(std::vector<ParseSpvEnvCase>{
|
|
{"", true, vulkan, vulkan_1_0, spv_1_0},
|
|
{"spv1.0", true, vulkan, vulkan_1_0, spv_1_0},
|
|
{"spv1.1", true, vulkan, vulkan_1_1, spv_1_1},
|
|
{"spv1.2", true, vulkan, vulkan_1_1, spv_1_2},
|
|
{"spv1.3", true, vulkan, vulkan_1_1, spv_1_3},
|
|
{"spv1.4", true, vulkan, vulkan_1_2, spv_1_4},
|
|
{"spv1.5", true, vulkan, vulkan_1_2, spv_1_5},
|
|
{"vulkan1.0", true, vulkan, vulkan_1_0, spv_1_0},
|
|
{"vulkan1.1", true, vulkan, vulkan_1_1, spv_1_3},
|
|
{"vulkan1.1spv1.4", true, vulkan, vulkan_1_1,
|
|
spv_1_4},
|
|
{"vulkan1.2", true, vulkan, vulkan_1_2, spv_1_5},
|
|
}));
|
|
|
|
} // namespace amber
|