Implicit surface rendering via ray tracing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

246 lines
7.2 KiB

/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. 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.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NV_SHADERMODULEMANAGER_INCLUDED
#define NV_SHADERMODULEMANAGER_INCLUDED
#include <mutex>
#include <stdio.h>
#include <string>
#include <vector>
#include <vulkan/vulkan_core.h>
#if NVP_SUPPORTS_SHADERC
#define NV_EXTENSIONS
#include <shaderc/shaderc.h>
#undef NV_EXTENSIONS
#endif
#include <nvh/shaderfilemanager.hpp>
namespace nvvk {
//////////////////////////////////////////////////////////////////////////
/**
\class nvvk::ShaderModuleManager
The nvvk::ShaderModuleManager manages VkShaderModules stored in files (SPIR-V or GLSL)
Using ShaderFileManager it will find the files and resolve #include for GLSL.
You must add include directories to the base-class for this.
It also comes with some convenience functions to reload shaders etc.
That is why we pass out the ShaderModuleID rather than a VkShaderModule directly.
To change the compilation behavior manipulate the public member variables
prior createShaderModule.
m_filetype is crucial for this. You can pass raw spir-v files or GLSL.
If GLSL is used, shaderc must be used as well (which must be added via
_add_package_ShaderC() in CMake of the project)
Example:
\code{.cpp}
ShaderModuleManager mgr(myDevice);
// derived from ShaderFileManager
mgr.addDirectory("spv/");
// all shaders get this injected after #version statement
mgr.m_prepend = "#define USE_NOISE 1\n";
vid = mgr.createShaderModule(VK_SHADER_STAGE_VERTEX_BIT, "object.vert.glsl");
fid = mgr.createShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, "object.frag.glsl");
// ... later use module
info.module = mgr.get(vid);
\endcode
*/
class ShaderModuleID
{
public:
size_t m_value;
ShaderModuleID()
: m_value(size_t(~0))
{
}
ShaderModuleID(size_t b)
: m_value(b)
{
}
ShaderModuleID& operator=(size_t b)
{
m_value = b;
return *this;
}
bool isValid() const { return m_value != size_t(~0); }
operator bool() const { return isValid(); }
operator size_t() const { return m_value; }
friend bool operator==(const ShaderModuleID& lhs, const ShaderModuleID& rhs) { return rhs.m_value == lhs.m_value; }
};
class ShaderModuleManager : public nvh::ShaderFileManager
{
public:
struct ShaderModule
{
ShaderModule()
: module(0)
{
}
VkShaderModule module;
std::string moduleSPIRV;
Definition definition;
};
void init(VkDevice device, int apiMajor = 1, int apiMinor = 1);
// also calls deleteShaderModules
void deinit();
ShaderModuleID createShaderModule(uint32_t type,
std::string const& filename,
std::string const& prepend = "",
FileType fileType = FILETYPE_DEFAULT,
std::string const& entryname = "main");
void destroyShaderModule(ShaderModuleID idx);
void reloadModule(ShaderModuleID idx);
void reloadShaderModules();
void deleteShaderModules();
bool areShaderModulesValid();
#if NVP_SUPPORTS_SHADERC
void setOptimizationLevel(shaderc_optimization_level level) { m_shadercOptimizationLevel = level; }
#endif
bool isValid(ShaderModuleID idx) const;
VkShaderModule get(ShaderModuleID idx) const;
ShaderModule& getShaderModule(ShaderModuleID idx);
const ShaderModule& getShaderModule(ShaderModuleID idx) const;
const char* getCode(ShaderModuleID idx, size_t* len = NULL) const;
const size_t getCodeLen(ShaderModuleID idx) const;
bool dumpSPIRV(ShaderModuleID idx, const char* filename) const;
bool getSPIRV(ShaderModuleID idx, size_t* pLen, const uint32_t** pCode) const;
// state will affect the next created shader module
// also keep m_filetype in mind!
bool m_preprocessOnly = false;
bool m_keepModuleSPIRV = false;
//////////////////////////////////////////////////////////////////////////
//
// for internal development, useful when we have new shader types that
// are not covered by public VulkanSDK
struct SetupInterface
{
// This class is to aid using a shaderc library version that is not
// provided by the Vulkan SDK, but custom. Therefore it allows custom settings etc.
// Useful for driver development of new shader stages, otherwise can be pretty much ignored.
virtual std::string getTypeDefine(uint32_t type) const = 0;
virtual uint32_t getTypeShadercKind(uint32_t type) const = 0;
virtual void* getShadercCompileOption(void* shadercCompiler) { return nullptr; }
};
void setSetupIF(SetupInterface* setupIF);
ShaderModuleManager(ShaderModuleManager const&) = delete;
ShaderModuleManager& operator=(ShaderModuleManager const&) = delete;
// Constructors reference-count the shared shaderc compiler, and
// disable ShaderFileManager's homemade #include mechanism iff we're
// using shaderc.
#if NVP_SUPPORTS_SHADERC
static constexpr bool s_handleIncludePasting = false;
#else
static constexpr bool s_handleIncludePasting = true;
#endif
ShaderModuleManager(VkDevice device = nullptr)
: ShaderFileManager(s_handleIncludePasting)
{
m_usedSetupIF = &m_defaultSetupIF;
m_supportsExtendedInclude = true;
if(device)
init(device);
}
~ShaderModuleManager()
{
deinit();
}
// Shaderc has its own interface for handling include files that I
// have to subclass; this needs access to protected
// ShaderFileManager functions.
friend class ShadercIncludeBridge;
private:
ShaderModuleID createShaderModule(const Definition& def);
bool setupShaderModule(ShaderModule& prog);
struct DefaultInterface : public SetupInterface
{
std::string getTypeDefine(uint32_t type) const override;
uint32_t getTypeShadercKind(uint32_t type) const override;
};
static const VkShaderModule PREPROCESS_ONLY_MODULE;
VkDevice m_device = nullptr;
DefaultInterface m_defaultSetupIF;
SetupInterface* m_usedSetupIF = nullptr;
int m_apiMajor = 1;
int m_apiMinor = 1;
#if NVP_SUPPORTS_SHADERC
static uint32_t s_shadercCompilerUsers;
static shaderc_compiler_t s_shadercCompiler; // Lock mutex below while using.
static std::mutex s_shadercCompilerMutex;
shaderc_compile_options_t m_shadercOptions = nullptr;
shaderc_optimization_level m_shadercOptimizationLevel = shaderc_optimization_level_performance;
#endif
std::vector<ShaderModule> m_shadermodules;
};
} // namespace nvvk
#endif //NV_PROGRAM_INCLUDED