blob: 4b7081687e8c044a043bd35a2b85447f0dd93f1d [file] [log] [blame]
// Copyright 2015 The Shaderc Authors. All rights reserved.
//
// 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 "shaderc.hpp"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include <thread>
#include "SPIRV/spirv.h"
namespace {
using testing::Each;
using testing::HasSubstr;
TEST(CppInterface, MultipleCalls) {
shaderc::Compiler compiler1, compiler2, compiler3;
EXPECT_TRUE(compiler1.IsValid());
EXPECT_TRUE(compiler2.IsValid());
EXPECT_TRUE(compiler3.IsValid());
}
TEST(CppInterface, MultipleThreadsInitializing) {
std::unique_ptr<shaderc::Compiler> compiler1;
std::unique_ptr<shaderc::Compiler> compiler2;
std::unique_ptr<shaderc::Compiler> compiler3;
std::thread t1([&compiler1]() {
compiler1 = std::unique_ptr<shaderc::Compiler>(new shaderc::Compiler());
});
std::thread t2([&compiler2]() {
compiler2 = std::unique_ptr<shaderc::Compiler>(new shaderc::Compiler());
});
std::thread t3([&compiler3]() {
compiler3 = std::unique_ptr<shaderc::Compiler>(new shaderc::Compiler());
});
t1.join();
t2.join();
t3.join();
EXPECT_TRUE(compiler1->IsValid());
EXPECT_TRUE(compiler2->IsValid());
EXPECT_TRUE(compiler3->IsValid());
}
// Compiles a shader and returns true on success, false on failure.
bool CompilationSuccess(const shaderc::Compiler& compiler,
const std::string& shader, shaderc_shader_kind kind) {
return compiler.CompileGlslToSpv(shader.c_str(), shader.length(), kind)
.GetSuccess();
}
// Compiles a shader and returns true if the result is valid SPIR-V.
bool CompilesToValidSpv(const shaderc::Compiler& compiler,
const std::string& shader, shaderc_shader_kind kind) {
shaderc::SpvModule result = compiler.CompileGlslToSpv(shader, kind);
if (!result.GetSuccess()) return false;
size_t length = result.GetLength();
if (length < 20) return false;
const uint32_t* bytes =
static_cast<const uint32_t*>(static_cast<const void*>(result.GetData()));
return bytes[0] == spv::MagicNumber;
}
TEST(CppInterface, CompilerMoves) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
shaderc::Compiler compiler2(std::move(compiler));
ASSERT_FALSE(compiler.IsValid());
ASSERT_TRUE(compiler2.IsValid());
}
TEST(CppInterface, EmptyString) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
EXPECT_TRUE(CompilationSuccess(compiler, "", shaderc_glsl_vertex_shader));
EXPECT_TRUE(CompilationSuccess(compiler, "", shaderc_glsl_fragment_shader));
}
TEST(CppInterface, ModuleMoves) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
shaderc::SpvModule result =
compiler.CompileGlslToSpv("", shaderc_glsl_vertex_shader);
EXPECT_TRUE(result.GetSuccess());
shaderc::SpvModule result2(std::move(result));
EXPECT_FALSE(result.GetSuccess());
EXPECT_TRUE(result2.GetSuccess());
}
TEST(CppInterface, GarbageString) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
EXPECT_FALSE(
CompilationSuccess(compiler, "jfalkds", shaderc_glsl_vertex_shader));
EXPECT_FALSE(
CompilationSuccess(compiler, "jfalkds", shaderc_glsl_fragment_shader));
}
TEST(CppInterface, MinimalShader) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
const std::string kMinimalShader = "void main(){}";
EXPECT_TRUE(
CompilesToValidSpv(compiler, kMinimalShader, shaderc_glsl_vertex_shader));
EXPECT_TRUE(CompilesToValidSpv(compiler, kMinimalShader,
shaderc_glsl_fragment_shader));
}
TEST(CppInterface, StdAndCString) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
const char* kMinimalShader = "void main(){}";
shaderc::SpvModule result1 = compiler.CompileGlslToSpv(
kMinimalShader, strlen(kMinimalShader), shaderc_glsl_fragment_shader);
shaderc::SpvModule result2 = compiler.CompileGlslToSpv(
std::string(kMinimalShader), shaderc_glsl_fragment_shader);
EXPECT_TRUE(result1.GetSuccess());
EXPECT_TRUE(result2.GetSuccess());
EXPECT_EQ(result1.GetLength(), result2.GetLength());
EXPECT_EQ(std::vector<char>(result1.GetData(),
result1.GetData() + result1.GetLength()),
std::vector<char>(result2.GetData(),
result2.GetData() + result2.GetLength()));
}
TEST(CppInterface, ErrorsReported) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
shaderc::SpvModule result = compiler.CompileGlslToSpv(
"int f(){return wrongname;}", shaderc_glsl_vertex_shader);
ASSERT_FALSE(result.GetSuccess());
EXPECT_THAT(result.GetErrorMessage(), HasSubstr("wrongname"));
}
TEST(CppInterface, MultipleThreadsCalling) {
shaderc::Compiler compiler;
ASSERT_TRUE(compiler.IsValid());
bool results[10];
std::vector<std::thread> threads;
for (auto& r : results) {
threads.emplace_back([&compiler, &r]() {
r = CompilationSuccess(compiler, "void main(){}",
shaderc_glsl_vertex_shader);
});
}
for (auto& t : threads) {
t.join();
}
EXPECT_THAT(results, Each(true));
}
TEST(CppInterface, AccessorsOnNullModule) {
shaderc::SpvModule result(nullptr);
EXPECT_FALSE(result.GetSuccess());
EXPECT_EQ(std::string(), result.GetErrorMessage());
EXPECT_EQ(std::string(), result.GetData());
EXPECT_EQ(0u, result.GetLength());
}
} // anonymous namespace