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.
582 lines
18 KiB
582 lines
18 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
|
|
*/
|
|
|
|
|
|
#include "shadermodulemanager_vk.hpp"
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#include <nvh/fileoperations.hpp>
|
|
#include <nvh/nvprint.hpp>
|
|
|
|
#if NVP_SUPPORTS_SHADERC
|
|
#include <shaderc/shaderc.hpp>
|
|
#endif
|
|
|
|
#define NV_LINE_MARKERS 1
|
|
|
|
|
|
namespace nvvk {
|
|
|
|
const VkShaderModule ShaderModuleManager::PREPROCESS_ONLY_MODULE = (VkShaderModule)~0;
|
|
|
|
#if NVP_SUPPORTS_SHADERC
|
|
// Shared shaderc compiler, and reference count + mutex protecting it.
|
|
shaderc_compiler_t ShaderModuleManager::s_shadercCompiler = nullptr;
|
|
uint32_t ShaderModuleManager::s_shadercCompilerUsers{0};
|
|
std::mutex ShaderModuleManager::s_shadercCompilerMutex;
|
|
|
|
// Adapts the include file loader of nvh::ShaderFileManager to what shaderc expects.
|
|
class ShadercIncludeBridge : public shaderc::CompileOptions::IncluderInterface
|
|
{
|
|
// Borrowed pointer to our include file loader.
|
|
nvvk::ShaderModuleManager* m_pShaderFileManager;
|
|
|
|
// Inputs/outputs reused for manualInclude.
|
|
std::string m_filenameFound;
|
|
const std::string m_emptyString;
|
|
|
|
// Subtype of shaderc_include_result that holds the include data
|
|
// we found; MUST be static_cast to this type before delete-ing as
|
|
// shaderc_include_result lacks virtual destructor.
|
|
class Result : public shaderc_include_result
|
|
{
|
|
// Containers for actual data; shaderc_include_result pointers
|
|
// point to data held within.
|
|
const std::string m_content;
|
|
const std::string m_filenameFound;
|
|
|
|
public:
|
|
Result(std::string content, std::string filenameFound)
|
|
: m_content(std::move(content))
|
|
, m_filenameFound(std::move(filenameFound))
|
|
{
|
|
this->source_name = m_filenameFound.data();
|
|
this->source_name_length = m_filenameFound.size();
|
|
this->content = m_content.data();
|
|
this->content_length = m_content.size();
|
|
this->user_data = nullptr;
|
|
}
|
|
};
|
|
|
|
public:
|
|
ShadercIncludeBridge(nvvk::ShaderModuleManager* pShaderFileManager) { m_pShaderFileManager = pShaderFileManager; }
|
|
|
|
// Handles shaderc_include_resolver_fn callbacks.
|
|
virtual shaderc_include_result* GetInclude(const char* requested_source,
|
|
shaderc_include_type type,
|
|
const char* requesting_source,
|
|
size_t /*include_depth*/) override
|
|
{
|
|
std::string filename = requested_source;
|
|
std::string includeFileText;
|
|
bool versionFound = false; // Trying to match glslc behavior: it doesn't allow #version directives in include files.
|
|
if(type == shaderc_include_type_relative) // "header.h"
|
|
{
|
|
includeFileText = m_pShaderFileManager->getContentWithRequestingSourceDirectory(filename, m_filenameFound, requesting_source);
|
|
}
|
|
else // shaderc_include_type_standard <header.h>
|
|
{
|
|
includeFileText = m_pShaderFileManager->getContent(filename, m_filenameFound);
|
|
}
|
|
std::string content = m_pShaderFileManager->manualIncludeText(includeFileText, m_filenameFound, m_emptyString, versionFound);
|
|
return new Result(std::move(content), std::move(m_filenameFound));
|
|
}
|
|
|
|
// Handles shaderc_include_result_release_fn callbacks.
|
|
virtual void ReleaseInclude(shaderc_include_result* data) override { delete static_cast<Result*>(data); }
|
|
|
|
// Set as the includer for the given shaderc_compile_options_t.
|
|
// This ShadercIncludeBridge MUST not be destroyed while in-use by a
|
|
// shaderc compiler using these options.
|
|
void setAsIncluder(shaderc_compile_options_t options)
|
|
{
|
|
shaderc_compile_options_set_include_callbacks(
|
|
options,
|
|
[](void* pvShadercIncludeBridge, const char* requestedSource, int type, const char* requestingSource, size_t includeDepth) {
|
|
return static_cast<ShadercIncludeBridge*>(pvShadercIncludeBridge)
|
|
->GetInclude(requestedSource, (shaderc_include_type)type, requestingSource, includeDepth);
|
|
},
|
|
[](void* pvShadercIncludeBridge, shaderc_include_result* includeResult) {
|
|
return static_cast<ShadercIncludeBridge*>(pvShadercIncludeBridge)->ReleaseInclude(includeResult);
|
|
},
|
|
this);
|
|
}
|
|
};
|
|
#endif /* NVP_SUPPORTS_SHADERC */
|
|
|
|
std::string ShaderModuleManager::DefaultInterface::getTypeDefine(uint32_t type) const
|
|
{
|
|
switch(type)
|
|
{
|
|
case VK_SHADER_STAGE_VERTEX_BIT:
|
|
return "#define _VERTEX_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_FRAGMENT_BIT:
|
|
return "#define _FRAGMENT_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_COMPUTE_BIT:
|
|
return "#define _COMPUTE_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_GEOMETRY_BIT:
|
|
return "#define _GEOMETRY_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
|
|
return "#define _TESS_CONTROL_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
|
|
return "#define _TESS_EVALUATION_SHADER_ 1\n";
|
|
#if VK_NV_mesh_shader
|
|
case VK_SHADER_STAGE_MESH_BIT_NV:
|
|
return "#define _MESH_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_TASK_BIT_NV:
|
|
return "#define _TASK_SHADER_ 1\n";
|
|
#endif
|
|
#if VK_NV_ray_tracing
|
|
case VK_SHADER_STAGE_RAYGEN_BIT_NV:
|
|
return "#define _RAY_GENERATION_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
|
|
return "#define _RAY_ANY_HIT_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
|
|
return "#define _RAY_CLOSEST_HIT_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_MISS_BIT_NV:
|
|
return "#define _RAY_MISS_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
|
|
return "#define _RAY_INTERSECTION_SHADER_ 1\n";
|
|
case VK_SHADER_STAGE_CALLABLE_BIT_NV:
|
|
return "#define _RAY_CALLABLE_BIT_SHADER_ 1\n";
|
|
#endif
|
|
}
|
|
|
|
return std::string();
|
|
}
|
|
|
|
uint32_t ShaderModuleManager::DefaultInterface::getTypeShadercKind(uint32_t type) const
|
|
{
|
|
#if NVP_SUPPORTS_SHADERC
|
|
switch(type)
|
|
{
|
|
case VK_SHADER_STAGE_VERTEX_BIT:
|
|
return shaderc_glsl_vertex_shader;
|
|
case VK_SHADER_STAGE_FRAGMENT_BIT:
|
|
return shaderc_glsl_fragment_shader;
|
|
case VK_SHADER_STAGE_COMPUTE_BIT:
|
|
return shaderc_glsl_compute_shader;
|
|
case VK_SHADER_STAGE_GEOMETRY_BIT:
|
|
return shaderc_glsl_geometry_shader;
|
|
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
|
|
return shaderc_glsl_tess_control_shader;
|
|
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
|
|
return shaderc_glsl_tess_evaluation_shader;
|
|
|
|
#if VK_NV_mesh_shader
|
|
case VK_SHADER_STAGE_MESH_BIT_NV:
|
|
return shaderc_glsl_mesh_shader;
|
|
case VK_SHADER_STAGE_TASK_BIT_NV:
|
|
return shaderc_glsl_task_shader;
|
|
#endif
|
|
#if VK_NV_ray_tracing
|
|
case VK_SHADER_STAGE_RAYGEN_BIT_NV:
|
|
return shaderc_glsl_raygen_shader;
|
|
case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
|
|
return shaderc_glsl_anyhit_shader;
|
|
case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
|
|
return shaderc_glsl_closesthit_shader;
|
|
case VK_SHADER_STAGE_MISS_BIT_NV:
|
|
return shaderc_glsl_miss_shader;
|
|
case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
|
|
return shaderc_glsl_intersection_shader;
|
|
case VK_SHADER_STAGE_CALLABLE_BIT_NV:
|
|
return shaderc_glsl_callable_shader;
|
|
#endif
|
|
}
|
|
|
|
return shaderc_glsl_infer_from_source;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
bool ShaderModuleManager::setupShaderModule(ShaderModule& module)
|
|
{
|
|
Definition& definition = module.definition;
|
|
|
|
module.module = VK_NULL_HANDLE;
|
|
if(definition.filetype == FILETYPE_DEFAULT)
|
|
{
|
|
definition.filetype = m_filetype;
|
|
}
|
|
|
|
std::string combinedPrepend = m_prepend;
|
|
std::string combinedFilenames;
|
|
combinedPrepend += definition.prepend;
|
|
combinedFilenames += definition.filename;
|
|
|
|
if(definition.filetype == FILETYPE_SPIRV)
|
|
{
|
|
std::string filenameFound;
|
|
definition.content = nvh::loadFile(definition.filename, true, m_directories, filenameFound);
|
|
}
|
|
else
|
|
{
|
|
std::string prepend = m_usedSetupIF->getTypeDefine(definition.type);
|
|
|
|
definition.content =
|
|
manualInclude(definition.filename, definition.filenameFound, prepend + m_prepend + definition.prepend, false);
|
|
}
|
|
|
|
if(definition.content.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(m_preprocessOnly)
|
|
{
|
|
module.module = PREPROCESS_ONLY_MODULE;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
VkResult vkresult = VK_ERROR_INVALID_SHADER_NV;
|
|
VkShaderModuleCreateInfo shaderModuleInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
|
|
|
#if NVP_SUPPORTS_SHADERC
|
|
shaderc_compilation_result_t result = nullptr;
|
|
if(definition.filetype == FILETYPE_GLSL)
|
|
{
|
|
std::lock_guard<std::mutex> guard(s_shadercCompilerMutex);
|
|
shaderc_shader_kind shaderkind = (shaderc_shader_kind)m_usedSetupIF->getTypeShadercKind(definition.type);
|
|
shaderc_compile_options_t options = (shaderc_compile_options_t)m_usedSetupIF->getShadercCompileOption(s_shadercCompiler);
|
|
if(!options)
|
|
{
|
|
if(m_apiMajor == 1 && m_apiMinor == 0)
|
|
{
|
|
shaderc_compile_options_set_target_env(m_shadercOptions, shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_0);
|
|
}
|
|
else if(m_apiMajor == 1 && m_apiMinor == 1)
|
|
{
|
|
shaderc_compile_options_set_target_env(m_shadercOptions, shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1);
|
|
}
|
|
else if(m_apiMajor == 1 && m_apiMinor == 2)
|
|
{
|
|
shaderc_compile_options_set_target_env(m_shadercOptions, shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2);
|
|
}
|
|
else if(m_apiMajor == 1 && m_apiMinor == 3)
|
|
{
|
|
shaderc_compile_options_set_target_env(m_shadercOptions, shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3);
|
|
}
|
|
else
|
|
{
|
|
LOGE("nvvk::ShaderModuleManager: Unsupported Vulkan version: %i.%i\n", int(m_apiMajor), int(m_apiMinor));
|
|
assert(0);
|
|
}
|
|
|
|
shaderc_compile_options_set_optimization_level(m_shadercOptions, m_shadercOptimizationLevel);
|
|
|
|
// Keep debug info, doesn't cost shader execution perf, only compile-time and memory size.
|
|
// Improves usage for debugging tools, not recommended for shipping application,
|
|
// but good for developmenent builds.
|
|
shaderc_compile_options_set_generate_debug_info(m_shadercOptions);
|
|
|
|
options = m_shadercOptions;
|
|
}
|
|
|
|
// Tell shaderc to use this class (really our base class, nvh::ShaderFileManager) to load include files.
|
|
ShadercIncludeBridge shadercIncludeBridge(this);
|
|
shadercIncludeBridge.setAsIncluder(options);
|
|
|
|
// Note: need filenameFound, not filename, so that relative includes work.
|
|
result = shaderc_compile_into_spv(s_shadercCompiler, definition.content.c_str(), definition.content.size(),
|
|
shaderkind, definition.filenameFound.c_str(), "main", options);
|
|
|
|
if(!result)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(shaderc_result_get_compilation_status(result) != shaderc_compilation_status_success)
|
|
{
|
|
bool failedToOptimize = strstr(shaderc_result_get_error_message(result), "failed to optimize");
|
|
int level = failedToOptimize ? LOGLEVEL_WARNING : LOGLEVEL_ERROR;
|
|
nvprintfLevel(level, "%s: optimization_level_performance\n", definition.filename.c_str());
|
|
nvprintfLevel(level, " %s\n", definition.prepend.c_str());
|
|
nvprintfLevel(level, " %s\n", shaderc_result_get_error_message(result));
|
|
shaderc_result_release(result);
|
|
|
|
if(!failedToOptimize || options != m_shadercOptions)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// try again without optimization
|
|
shaderc_compile_options_set_optimization_level(m_shadercOptions, shaderc_optimization_level_zero);
|
|
|
|
result = shaderc_compile_into_spv(s_shadercCompiler, definition.content.c_str(), definition.content.size(),
|
|
shaderkind, definition.filename.c_str(), "main", options);
|
|
}
|
|
|
|
if(shaderc_result_get_compilation_status(result) != shaderc_compilation_status_success)
|
|
{
|
|
LOGE("%s: optimization_level_zero\n", definition.filename.c_str());
|
|
LOGE(" %s\n", definition.prepend.c_str());
|
|
LOGE(" %s\n", shaderc_result_get_error_message(result));
|
|
shaderc_result_release(result);
|
|
return false;
|
|
}
|
|
|
|
shaderModuleInfo.codeSize = shaderc_result_get_length(result);
|
|
shaderModuleInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result);
|
|
}
|
|
else
|
|
#else
|
|
if(definition.filetype == FILETYPE_GLSL)
|
|
{
|
|
LOGW("No direct GLSL support\n");
|
|
return false;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
shaderModuleInfo.codeSize = definition.content.size();
|
|
shaderModuleInfo.pCode = (const uint32_t*)definition.content.c_str();
|
|
}
|
|
|
|
vkresult = ::vkCreateShaderModule(m_device, &shaderModuleInfo, nullptr, &module.module);
|
|
|
|
if(vkresult == VK_SUCCESS && m_keepModuleSPIRV)
|
|
{
|
|
module.moduleSPIRV = std::string((const char*)shaderModuleInfo.pCode, shaderModuleInfo.codeSize);
|
|
}
|
|
|
|
#if NVP_SUPPORTS_SHADERC
|
|
if(result)
|
|
{
|
|
shaderc_result_release(result);
|
|
}
|
|
#endif
|
|
|
|
return vkresult == VK_SUCCESS;
|
|
}
|
|
}
|
|
|
|
void ShaderModuleManager::init(VkDevice device, int apiMajor, int apiMinor)
|
|
{
|
|
assert(!m_device);
|
|
m_device = device;
|
|
m_apiMajor = apiMajor;
|
|
m_apiMinor = apiMinor;
|
|
|
|
#if NVP_SUPPORTS_SHADERC
|
|
// First user initializes compiler.
|
|
std::lock_guard<std::mutex> lock(s_shadercCompilerMutex);
|
|
s_shadercCompilerUsers++;
|
|
if(!s_shadercCompiler)
|
|
{
|
|
s_shadercCompiler = shaderc_compiler_initialize();
|
|
}
|
|
m_shadercOptions = shaderc_compile_options_initialize();
|
|
#endif
|
|
}
|
|
|
|
void ShaderModuleManager::deinit()
|
|
{
|
|
if(m_device)
|
|
{
|
|
#if NVP_SUPPORTS_SHADERC
|
|
// Last user de-inits compiler.
|
|
std::lock_guard<std::mutex> lock(s_shadercCompilerMutex);
|
|
s_shadercCompilerUsers--;
|
|
if(s_shadercCompiler && s_shadercCompilerUsers == 0)
|
|
{
|
|
shaderc_compiler_release(s_shadercCompiler);
|
|
s_shadercCompiler = nullptr;
|
|
}
|
|
if(m_shadercOptions)
|
|
{
|
|
shaderc_compile_options_release(m_shadercOptions);
|
|
}
|
|
#endif
|
|
}
|
|
deleteShaderModules();
|
|
m_device = nullptr;
|
|
}
|
|
|
|
ShaderModuleID ShaderModuleManager::createShaderModule(const Definition& definition)
|
|
{
|
|
ShaderModule module;
|
|
module.definition = definition;
|
|
|
|
setupShaderModule(module);
|
|
|
|
// find unused
|
|
for(size_t i = 0; i < m_shadermodules.size(); i++)
|
|
{
|
|
if(m_shadermodules[i].definition.type == 0)
|
|
{
|
|
m_shadermodules[i] = module;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
m_shadermodules.push_back(module);
|
|
return m_shadermodules.size() - 1;
|
|
}
|
|
|
|
ShaderModuleID ShaderModuleManager::createShaderModule(uint32_t type,
|
|
std::string const& filename,
|
|
std::string const& prepend,
|
|
FileType fileType /*= FILETYPE_DEFAULT*/,
|
|
std::string const& entryname /*= "main"*/)
|
|
{
|
|
Definition def;
|
|
def.type = type;
|
|
def.filename = filename;
|
|
def.prepend = prepend;
|
|
def.filetype = fileType;
|
|
def.entry = entryname;
|
|
return createShaderModule(def);
|
|
}
|
|
|
|
bool ShaderModuleManager::areShaderModulesValid()
|
|
{
|
|
bool valid = true;
|
|
for(size_t i = 0; i < m_shadermodules.size(); i++)
|
|
{
|
|
valid = valid && isValid(i);
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
void ShaderModuleManager::deleteShaderModules()
|
|
{
|
|
for(size_t i = 0; i < m_shadermodules.size(); i++)
|
|
{
|
|
destroyShaderModule((ShaderModuleID)i);
|
|
}
|
|
m_shadermodules.clear();
|
|
}
|
|
|
|
void ShaderModuleManager::reloadModule(ShaderModuleID idx)
|
|
{
|
|
if(!isValid(idx))
|
|
return;
|
|
|
|
ShaderModule& module = getShaderModule(idx);
|
|
|
|
bool old = m_preprocessOnly;
|
|
m_preprocessOnly = module.module == PREPROCESS_ONLY_MODULE;
|
|
if(module.module && module.module != PREPROCESS_ONLY_MODULE)
|
|
{
|
|
vkDestroyShaderModule(m_device, module.module, nullptr);
|
|
module.module = nullptr;
|
|
}
|
|
if(module.definition.type != 0)
|
|
{
|
|
setupShaderModule(module);
|
|
}
|
|
|
|
m_preprocessOnly = old;
|
|
}
|
|
|
|
void ShaderModuleManager::reloadShaderModules()
|
|
{
|
|
LOGI("Reloading programs...\n");
|
|
|
|
for(size_t i = 0; i < m_shadermodules.size(); i++)
|
|
{
|
|
reloadModule((ShaderModuleID)i);
|
|
}
|
|
|
|
LOGI("done\n");
|
|
}
|
|
|
|
bool ShaderModuleManager::isValid(ShaderModuleID idx) const
|
|
{
|
|
return idx.isValid()
|
|
&& ((m_shadermodules[idx].definition.type && m_shadermodules[idx].module != 0)
|
|
|| !m_shadermodules[idx].definition.type);
|
|
}
|
|
|
|
VkShaderModule ShaderModuleManager::get(ShaderModuleID idx) const
|
|
{
|
|
return m_shadermodules[idx].module;
|
|
}
|
|
|
|
ShaderModuleManager::ShaderModule& ShaderModuleManager::getShaderModule(ShaderModuleID idx)
|
|
{
|
|
return m_shadermodules[idx];
|
|
}
|
|
|
|
const ShaderModuleManager::ShaderModule& ShaderModuleManager::getShaderModule(ShaderModuleID idx) const
|
|
{
|
|
return m_shadermodules[idx];
|
|
}
|
|
|
|
void ShaderModuleManager::destroyShaderModule(ShaderModuleID idx)
|
|
{
|
|
if(!isValid(idx))
|
|
return;
|
|
|
|
ShaderModule& module = getShaderModule(idx);
|
|
|
|
if(module.module && module.module != PREPROCESS_ONLY_MODULE)
|
|
{
|
|
vkDestroyShaderModule(m_device, module.module, nullptr);
|
|
module.module = 0;
|
|
}
|
|
module.definition = Definition();
|
|
}
|
|
|
|
const char* ShaderModuleManager::getCode(ShaderModuleID idx, size_t* len) const
|
|
{
|
|
return m_shadermodules[idx].definition.content.c_str();
|
|
}
|
|
const size_t ShaderModuleManager::getCodeLen(ShaderModuleID idx) const
|
|
{
|
|
return m_shadermodules[idx].definition.content.size();
|
|
}
|
|
|
|
|
|
bool ShaderModuleManager::dumpSPIRV(ShaderModuleID idx, const char* filename) const
|
|
{
|
|
if(m_shadermodules[idx].moduleSPIRV.empty())
|
|
return false;
|
|
|
|
FILE* f = fopen(filename, "wb");
|
|
if(f)
|
|
{
|
|
fwrite(m_shadermodules[idx].moduleSPIRV.data(), m_shadermodules[idx].moduleSPIRV.size(), 1, f);
|
|
fclose(f);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ShaderModuleManager::getSPIRV(ShaderModuleID idx, size_t* pLen, const uint32_t** pCode) const
|
|
{
|
|
if(m_shadermodules[idx].moduleSPIRV.empty())
|
|
return false;
|
|
|
|
*pLen = m_shadermodules[idx].moduleSPIRV.size();
|
|
*pCode = reinterpret_cast<const uint32_t*>(m_shadermodules[idx].moduleSPIRV.data());
|
|
return true;
|
|
}
|
|
|
|
} // namespace nvvk
|
|
|