blob: 4b13667e9599630f9f3780bd21a5d439eee0df85 [file] [log] [blame]
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/vulkan/vulkan_shader_module.h"
#include <memory>
#include <shaderc/shaderc.h>
#include <sstream>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "gpu/vulkan/vulkan_device_queue.h"
namespace {
class ShaderCCompiler {
public:
class CompilationResult {
public:
explicit CompilationResult(shaderc_compilation_result_t compilation_result)
: compilation_result_(compilation_result) {}
~CompilationResult() { shaderc_result_release(compilation_result_); }
bool IsValid() const {
return shaderc_compilation_status_success ==
shaderc_result_get_compilation_status(compilation_result_);
}
std::string GetErrors() const {
return shaderc_result_get_error_message(compilation_result_);
}
std::string GetResult() const {
return std::string(shaderc_result_get_bytes(compilation_result_),
shaderc_result_get_length(compilation_result_));
}
private:
shaderc_compilation_result_t compilation_result_;
};
ShaderCCompiler()
: compiler_(shaderc_compiler_initialize()),
compiler_options_(shaderc_compile_options_initialize()) {}
~ShaderCCompiler() { shaderc_compiler_release(compiler_); }
void AddMacroDef(const std::string& name, const std::string& value) {
shaderc_compile_options_add_macro_definition(compiler_options_,
name.c_str(), name.length(),
value.c_str(), value.length());
}
std::unique_ptr<ShaderCCompiler::CompilationResult> CompileShaderModule(
gpu::VulkanShaderModule::ShaderType shader_type,
const std::string& name,
const std::string& entry_point,
const std::string& source) {
return base::MakeUnique<ShaderCCompiler::CompilationResult>(
shaderc_compile_into_spv(
compiler_, source.c_str(), source.length(),
(shader_type == gpu::VulkanShaderModule::ShaderType::VERTEX
? shaderc_glsl_vertex_shader
: shaderc_glsl_fragment_shader),
name.c_str(), entry_point.c_str(), compiler_options_));
}
private:
shaderc_compiler_t compiler_;
shaderc_compile_options_t compiler_options_;
};
} // namespace
namespace gpu {
VulkanShaderModule::VulkanShaderModule(VulkanDeviceQueue* device_queue)
: device_queue_(device_queue) {
DCHECK(device_queue_);
}
VulkanShaderModule::~VulkanShaderModule() {
DCHECK_EQ(static_cast<VkShaderModule>(VK_NULL_HANDLE), handle_);
}
bool VulkanShaderModule::InitializeGLSL(ShaderType type,
std::string name,
std::string entry_point,
std::string source) {
ShaderCCompiler shaderc_compiler;
std::unique_ptr<ShaderCCompiler::CompilationResult> compilation_result(
shaderc_compiler.CompileShaderModule(type, name, entry_point, source));
if (!compilation_result->IsValid()) {
error_messages_ = compilation_result->GetErrors();
return false;
}
return InitializeSPIRV(type, std::move(name), std::move(entry_point),
compilation_result->GetResult());
}
bool VulkanShaderModule::InitializeSPIRV(ShaderType type,
std::string name,
std::string entry_point,
std::string source) {
DCHECK_EQ(static_cast<VkShaderModule>(VK_NULL_HANDLE), handle_);
shader_type_ = type;
name_ = std::move(name);
entry_point_ = std::move(entry_point);
// Make sure source is a multiple of 4.
const int padding = 4 - (source.length() % 4);
if (padding < 4) {
for (int i = 0; i < padding; ++i) {
source += ' ';
}
}
VkShaderModuleCreateInfo shader_module_create_info = {};
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_create_info.pCode =
reinterpret_cast<const uint32_t*>(source.c_str());
shader_module_create_info.codeSize = source.length() / 4;
VkShaderModule shader_module = VK_NULL_HANDLE;
VkResult result =
vkCreateShaderModule(device_queue_->GetVulkanDevice(),
&shader_module_create_info, nullptr, &shader_module);
if (VK_SUCCESS != result) {
std::stringstream ss;
ss << "vkCreateShaderModule() failed: " << result;
error_messages_ = ss.str();
DLOG(ERROR) << error_messages_;
return false;
}
handle_ = shader_module;
return true;
}
void VulkanShaderModule::Destroy() {
if (handle_ != VK_NULL_HANDLE) {
vkDestroyShaderModule(device_queue_->GetVulkanDevice(), handle_, nullptr);
handle_ = VK_NULL_HANDLE;
}
entry_point_.clear();
error_messages_.clear();
}
} // namespace gpu