This example shows how a Vulkan based renderer can call the code generated by the "GLSL" backend for compiled materials to evaluate sub-expressions of multiple materials. This example mostly explains how to configure the "GLSL" backend for Vulkan. Loading textures and the texture access functions are not covered here. For an introduction and a more in depth explanation of the "GLSL" backend and how to work with textures in please refer to the Example for Execution of Compiled MDL Materials (GLSL) section.
To compile the source code, you require a recent version of the Vulkan SDK and GLFW. For detailed instructions, please refer to the Getting Started section.
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <cstring>
#include "example_shared.h"
#include "example_vulkan_shared.h"
#include <vulkan/vulkan.h>
#include <GLFW/glfw3.h>
struct Options
{
bool no_window = false;
std::string outputfile = "output.png";
uint32_t res_x = 1024;
uint32_t res_y = 768;
uint32_t num_images = 3;
bool enable_validation_layers = false;
uint32_t material_pattern = 7;
};
struct Vulkan_texture
{
VkImage image = nullptr;
VkImageView image_view = nullptr;
VkDeviceMemory device_memory = nullptr;
};
struct Vulkan_buffer
{
VkBuffer buffer = nullptr;
VkDeviceMemory device_memory = nullptr;
};
static const char* g_vertex_shader_filename = "example_execution_glsl_vk.vert";
static const char* g_fragment_shader_filename = "example_execution_glsl_vk.frag";
static const uint32_t g_material_textures_descriptor_binding = 0;
static const uint32_t g_ro_data_descriptor_set = 0;
static const uint32_t g_ro_data_descriptor_binding = 1;
{
std::string src =
"#version 450\n"
"struct State {\n"
" vec3 normal;\n"
" vec3 geom_normal;\n"
" vec3 position;\n"
" float animation_time;\n"
" vec3[1] text_coords;\n"
" vec3[1] tangent_u;\n"
" vec3[1] tangent_v;\n"
" int ro_data_segment_offset;\n"
" mat4 world_to_object;\n"
" mat4 object_to_world;\n"
" int object_id;\n"
" float meters_per_scene_unit;\n"
" int arg_block_offset;\n"
"};\n"
"\n"
"uint get_mdl_num_mat_subexprs() { return " +
"u; }\n"
"\n";
std::string switch_func =
"vec3 mdl_mat_subexpr(uint id, State state) {\n"
" switch(id) {\n";
i < num_target_codes;
++i)
{
i, mi::neuraylib::ITarget_code::SL_GLSL);
src += '\n';
switch_func +=
" case " + std::to_string(i) + "u: return " + func_name + "(state);\n";
}
switch_func +=
" default: return vec3(0);\n"
" }\n"
"}\n";
return src + "\n" + switch_func;
}
VkShaderModule create_fragment_shader_module(
{
std::stringstream main_source;
main_source << "#version 450\n";
main_source << "#define NUM_TEXTURES "
main_source << mi::examples::io::read_text_file(
mi::examples::io::get_executable_folder() + "/" + g_fragment_shader_filename);
#ifdef DUMP_GLSL
std::cout << "Dumping main GLSL code:\n\n" << main_source.str() << std::endl;
#endif
std::string generated_target_source(target_code->
get_code());
#ifdef REMAP_NOISE_FUNCTIONS
generated_target_source.append(mi::examples::io::read_text_file(
mi::examples::io::get_executable_folder() + "/" + "noise_no_lut.glsl"));
#endif
#ifdef DUMP_GLSL
std::cout << "Dumping GLSL target code:\n\n" << generated_target_source << std::endl;
#endif
std::string glsl_switch_func_source = generate_glsl_switch_func(target_code);
#ifdef DUMP_GLSL
std::cout << "Dumping GLSL code for the \"mdl_mat_subexpr\" switch function:\n\n"
<< glsl_switch_func_source << std::endl;
#endif
mi::examples::vk::Glsl_compiler glsl_compiler(EShLangFragment, "main");
glsl_compiler.add_shader(main_source.str());
glsl_compiler.add_shader(generated_target_source);
glsl_compiler.add_shader(glsl_switch_func_source);
std::vector<unsigned int> compiled_shader = glsl_compiler.link_program();
VkShaderModuleCreateInfo shader_module_create_info = {};
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_create_info.pCode = compiled_shader.data();
shader_module_create_info.codeSize = compiled_shader.size() * sizeof(unsigned int);
VkShaderModule shader_module;
VK_CHECK(vkCreateShaderModule(
device, &shader_module_create_info, nullptr, &shader_module));
return shader_module;
}
VkShaderModule create_vertex_shader_module(VkDevice device)
{
std::string shader_source = mi::examples::io::read_text_file(
mi::examples::io::get_executable_folder() + "/" + g_vertex_shader_filename);
mi::examples::vk::Glsl_compiler glsl_compiler(EShLangVertex, "main");
glsl_compiler.add_shader(shader_source);
std::vector<unsigned int> compiled_shader = glsl_compiler.link_program();
VkShaderModuleCreateInfo shader_module_create_info = {};
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_create_info.pCode = compiled_shader.data();
shader_module_create_info.codeSize = compiled_shader.size() * sizeof(unsigned int);
VkShaderModule shader_module;
VK_CHECK(vkCreateShaderModule(device,
&shader_module_create_info, nullptr, &shader_module));
return shader_module;
}
const std::vector<std::string>& material_db_names,
const std::vector<std::string>& expression_paths,
const std::vector<std::string>& function_names)
{
check_success(be_glsl->set_option("num_texture_spaces", "1") == 0);
check_success(be_glsl->set_option("glsl_version", "450") == 0);
check_success(be_glsl->set_option("glsl_max_const_data", "0") == 0);
check_success(be_glsl->set_option("glsl_place_uniforms_into_ssbo", "on") == 0);
check_success(be_glsl->set_option("glsl_uniform_ssbo_binding",
std::to_string(g_ro_data_descriptor_binding).c_str()) == 0);
check_success(be_glsl->set_option("glsl_uniform_ssbo_set",
std::to_string(g_ro_data_descriptor_set).c_str()) == 0);
#ifdef REMAP_NOISE_FUNCTIONS
check_success(be_glsl->set_option("glsl_remap_functions",
"_ZN4base12perlin_noiseEu6float4=noise_float4"
",_ZN4base12worley_noiseEu6float3fi=noise_worley"
",_ZN4base8mi_noiseEu6float3=noise_mi_float3"
",_ZN4base8mi_noiseEu4int3=noise_mi_int3") == 0);
#endif
be_glsl->create_link_unit(transaction, context));
for (size_t i = 0; i < material_db_names.size(); ++i)
{
if (!material_definition)
exit_failure("Failed to access material definition '%s'.", material_db_names[i].c_str());
material_definition->create_function_call(nullptr, &result));
if (result != 0)
exit_failure("Failed to instantiate material '%s'.", material_db_names[i].c_str());
material_instance2->create_compiled_material(compile_flags, context));
check_success(print_messages(context));
const char* path = expression_paths[i].c_str();
const char* fname = function_names[i].c_str();
link_unit->add_material_expression(compiled_material.get(), path, fname, context);
check_success(print_messages(context));
}
be_glsl->translate_link_unit(link_unit.get(), context));
check_success(print_messages(context));
check_success(target_code);
return target_code.get();
}
Vulkan_buffer create_ro_data_buffer(
VkDevice device,
VkPhysicalDevice physical_device,
VkQueue queue,
VkCommandPool command_pool,
{
Vulkan_buffer ro_data_buffer;
if (num_segments == 0)
return ro_data_buffer;
if (num_segments > 1)
{
std::cerr << "Multiple uniforms are defined for read-only data."
<< " This should not be the case if a storage buffer is used.\n";
terminate();
}
{
VkBufferCreateInfo buffer_create_info = {};
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_create_info.usage
= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VK_CHECK(vkCreateBuffer(
device, &buffer_create_info, nullptr, &ro_data_buffer.buffer));
ro_data_buffer.device_memory = mi::examples::vk::allocate_and_bind_buffer_memory(
device, physical_device, ro_data_buffer.buffer,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
{
mi::examples::vk::Staging_buffer staging_buffer(device, physical_device,
void* mapped_data = staging_buffer.map_memory();
staging_buffer.unmap_memory();
mi::examples::vk::Temporary_command_buffer command_buffer(device, command_pool);
command_buffer.begin();
VkBufferCopy copy_region = {};
vkCmdCopyBuffer(command_buffer.get(),
staging_buffer.get(), ro_data_buffer.buffer, 1, ©_region);
command_buffer.end_and_submit(queue);
}
return ro_data_buffer;
}
Vulkan_texture create_material_texture(
VkDevice device,
VkPhysicalDevice physical_device,
VkQueue queue,
VkCommandPool command_pool,
{
mi::Uint32 tex_width = canvas->get_resolution_x();
mi::Uint32 tex_height = canvas->get_resolution_y();
mi::Uint32 tex_layers = canvas->get_layers_size();
char const* image_type = image->get_type(0, 0);
if (image->is_uvtile() || image->is_animated())
{
std::cerr << "The example does not support uvtile and/or animated textures!" << std::endl;
terminate();
}
if (tex_layers != 1)
{
std::cerr << "The example doesn't support layered images!" << std::endl;
terminate();
}
{
std::cerr << "The example only supports 2D textures!" << std::endl;
terminate();
}
if (texture->get_effective_gamma(0, 0) != 1.0f)
{
image_api->
convert(canvas.get(),
"Color"));
gamma_canvas->set_gamma(texture->get_effective_gamma(0, 0));
canvas = gamma_canvas;
}
else if (strcmp(image_type, "Color") != 0 && strcmp(image_type, "Float32<4>") != 0)
{
canvas = image_api->
convert(canvas.get(),
"Color");
}
Vulkan_texture material_texture;
VkImageCreateInfo image_create_info = {};
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R32G32B32A32_SFLOAT;
image_create_info.extent.width = tex_width;
image_create_info.extent.height = tex_height;
image_create_info.extent.depth = 1;
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK(vkCreateImage(device, &image_create_info, nullptr, &material_texture.image));
material_texture.device_memory = mi::examples::vk::allocate_and_bind_image_memory(
device, physical_device, material_texture.image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
{
size_t staging_buffer_size = tex_width * tex_height * sizeof(float) * 4;
mi::examples::vk::Staging_buffer staging_buffer(device, physical_device,
staging_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
void* mapped_data = staging_buffer.map_memory();
std::memcpy(mapped_data, tile->get_data(), staging_buffer_size);
staging_buffer.unmap_memory();
mi::examples::vk::Temporary_command_buffer command_buffer(device, command_pool);
command_buffer.begin();
{
VkImageMemoryBarrier image_memory_barrier = {};
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = material_texture.image;
image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer.get(),
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
1, &image_memory_barrier);
}
VkBufferImageCopy copy_region = {};
copy_region.bufferOffset = 0;
copy_region.bufferRowLength = 0;
copy_region.bufferImageHeight = 0;
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.imageSubresource.mipLevel = 0;
copy_region.imageSubresource.baseArrayLayer = 0;
copy_region.imageSubresource.layerCount = 1;
copy_region.imageOffset = { 0, 0, 0 };
copy_region.imageExtent = { tex_width, tex_height, 1 };
vkCmdCopyBufferToImage(command_buffer.get(), staging_buffer.get(),
material_texture.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
{
VkImageMemoryBarrier image_memory_barrier = {};
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = material_texture.image;
image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer.get(),
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &image_memory_barrier);
}
command_buffer.end_and_submit(queue);
}
VkImageViewCreateInfo image_view_create_info = {};
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
image_view_create_info.image = material_texture.image;
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_create_info.format = VK_FORMAT_R32G32B32A32_SFLOAT;
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_view_create_info.subresourceRange.baseMipLevel = 0;
image_view_create_info.subresourceRange.levelCount = 1;
image_view_create_info.subresourceRange.baseArrayLayer = 0;
image_view_create_info.subresourceRange.layerCount = 1;
VK_CHECK(vkCreateImageView(
device, &image_view_create_info, nullptr, &material_texture.image_view));
return material_texture;
}
class Example_app : public mi::examples::vk::Vulkan_example_app
{
public:
Example_app(
const Options& options)
: Vulkan_example_app(mdl_impexp_api.get(), image_api.get())
, m_transaction(transaction)
, m_target_code(target_code)
, m_options(options)
{
m_user_data.animation_time = 0.0f;
m_user_data.material_pattern = options.material_pattern;
}
virtual void init_resources() override;
virtual void cleanup_resources() override;
virtual void recreate_size_dependent_resources() override;
virtual void update(float elapsed_seconds, uint32_t frame_index) override;
virtual void render(VkCommandBuffer command_buffer, uint32_t frame_index, uint32_t image_index) override;
virtual void key_callback(int key, int action) override;
private:
void create_descriptor_set_layout();
void create_graphics_pipeline_layout();
void create_graphics_pipeline();
void create_descriptor_pool_and_set();
void populate_descriptor_set();
private:
Vulkan_buffer m_ro_data_buffer;
std::vector<Vulkan_texture> m_material_textures;
VkPipelineLayout m_pipeline_layout = nullptr;
VkPipeline m_graphics_pipeline = nullptr;
VkDescriptorSetLayout m_descriptor_set_layout = nullptr;
VkDescriptorPool m_descriptor_pool = nullptr;
VkDescriptorSet m_descriptor_set = nullptr;
VkSampler m_linear_sampler = nullptr;
struct User_data
{
uint32_t material_pattern;
float animation_time;
} m_user_data;
Options m_options;
uint32_t m_last_image_index = 0;
};
void Example_app::init_resources()
{
glslang::InitializeProcess();
m_ro_data_buffer = create_ro_data_buffer(
m_device, m_physical_device, m_graphics_queue, m_command_pool, m_target_code.get());
for (
mi::Size tex_index = 1; tex_index < m_target_code->get_texture_count(); tex_index++)
{
Vulkan_texture texture = create_material_texture(
m_device, m_physical_device, m_graphics_queue,
m_command_pool, m_transaction.get(), m_image_api.get(), m_target_code.get(),
tex_index);
m_material_textures.push_back(texture);
}
create_descriptor_set_layout();
create_descriptor_pool_and_set();
create_graphics_pipeline_layout();
create_graphics_pipeline();
m_linear_sampler = mi::examples::vk::create_linear_sampler(m_device);
populate_descriptor_set();
}
void Example_app::cleanup_resources()
{
if (m_options.no_window)
save_screenshot(m_last_image_index, m_options.outputfile.c_str());
for (Vulkan_texture& texture : m_material_textures)
{
vkDestroyImageView(m_device, texture.image_view, nullptr);
vkDestroyImage(m_device, texture.image, nullptr);
vkFreeMemory(m_device, texture.device_memory, nullptr);
}
vkDestroyBuffer(m_device, m_ro_data_buffer.buffer, nullptr);
vkFreeMemory(m_device, m_ro_data_buffer.device_memory, nullptr);
vkDestroySampler(m_device, m_linear_sampler, nullptr);
vkDestroyDescriptorPool(m_device, m_descriptor_pool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr);
vkDestroyPipelineLayout(m_device, m_pipeline_layout, nullptr);
vkDestroyPipeline(m_device, m_graphics_pipeline, nullptr);
glslang::FinalizeProcess();
}
void Example_app::recreate_size_dependent_resources()
{
vkDestroyPipeline(m_device, m_graphics_pipeline, nullptr);
create_graphics_pipeline();
}
void Example_app::update(float elapsed_seconds, uint32_t frame_index)
{
m_user_data.animation_time += elapsed_seconds;
}
void Example_app::render(VkCommandBuffer command_buffer, uint32_t frame_index, uint32_t image_index)
{
m_last_image_index = image_index;
VkRenderPassBeginInfo render_pass_begin_info = {};
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin_info.renderPass = m_main_render_pass;
render_pass_begin_info.framebuffer = m_framebuffers[image_index];
render_pass_begin_info.renderArea = { {0, 0}, {m_image_width, m_image_height} };
VkClearValue clear_values[2];
clear_values[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clear_values[1].depthStencil = { 1.0f, 0 };
render_pass_begin_info.clearValueCount = std::size(clear_values);
render_pass_begin_info.pClearValues = clear_values;
vkCmdBeginRenderPass(
command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(
command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphics_pipeline);
vkCmdPushConstants(command_buffer, m_pipeline_layout,
VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(User_data), &m_user_data);
vkCmdBindDescriptorSets(
command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout,
0, 1, &m_descriptor_set, 0, nullptr);
vkCmdDraw(command_buffer, 3, 1, 0, 0);
vkCmdEndRenderPass(command_buffer);
}
void Example_app::key_callback(int key, int action)
{
if (action != GLFW_PRESS)
return;
if (GLFW_KEY_KP_0 <= key && key <= GLFW_KEY_KP_9)
key += GLFW_KEY_0 - GLFW_KEY_KP_0;
switch (key)
{
case GLFW_KEY_1:
case GLFW_KEY_2:
case GLFW_KEY_3:
case GLFW_KEY_4:
case GLFW_KEY_5:
case GLFW_KEY_6:
case GLFW_KEY_7:
m_user_data.material_pattern = key - GLFW_KEY_0;
break;
case GLFW_KEY_ENTER:
request_screenshot();
break;
}
}
void Example_app::create_descriptor_set_layout()
{
VkDescriptorSetLayoutBinding material_textures_layout_binding = {};
material_textures_layout_binding.binding = g_material_textures_descriptor_binding;
material_textures_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
material_textures_layout_binding.descriptorCount
= static_cast<uint32_t>(m_material_textures.size());
material_textures_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutBinding ro_data_buffer_layout_binding = {};
ro_data_buffer_layout_binding.binding = g_ro_data_descriptor_binding;
ro_data_buffer_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
ro_data_buffer_layout_binding.descriptorCount = 1;
ro_data_buffer_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
const VkDescriptorSetLayoutBinding descriptor_set_layout_bindings[] = {
material_textures_layout_binding,
ro_data_buffer_layout_binding
};
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info = {};
descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptor_set_layout_create_info.bindingCount = std::size(descriptor_set_layout_bindings);
descriptor_set_layout_create_info.pBindings = descriptor_set_layout_bindings;
VK_CHECK(vkCreateDescriptorSetLayout(
m_device, &descriptor_set_layout_create_info,
nullptr, &m_descriptor_set_layout));
}
void Example_app::create_graphics_pipeline_layout()
{
VkPushConstantRange push_constant_range;
push_constant_range.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
push_constant_range.offset = 0;
push_constant_range.size = sizeof(User_data);
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_create_info.setLayoutCount = 1;
pipeline_layout_create_info.pSetLayouts = &m_descriptor_set_layout;
pipeline_layout_create_info.pushConstantRangeCount = 1;
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
VK_CHECK(vkCreatePipelineLayout(
m_device, &pipeline_layout_create_info, nullptr, &m_pipeline_layout));
}
void Example_app::create_graphics_pipeline()
{
VkShaderModule vertex_shader = create_vertex_shader_module(m_device);
VkShaderModule fragment_shader
= create_fragment_shader_module(m_device, m_target_code.get());
VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {};
vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertex_shader_stage_info.module = vertex_shader;
vertex_shader_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {};
fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragment_shader_stage_info.module = fragment_shader;
fragment_shader_stage_info.pName = "main";
const VkPipelineShaderStageCreateInfo shader_stages[] = {
vertex_shader_stage_info,
fragment_shader_stage_info
};
VkPipelineVertexInputStateCreateInfo vertex_input_state = {};
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {};
input_assembly_state.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
input_assembly_state.primitiveRestartEnable = false;
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(m_image_width);
viewport.height = static_cast<float>(m_image_height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor_rect;
scissor_rect.offset.x = 0;
scissor_rect.offset.y = 0;
scissor_rect.extent.width = m_image_width;
scissor_rect.extent.height = m_image_height;
VkPipelineViewportStateCreateInfo viewport_state = {};
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state.viewportCount = 1;
viewport_state.pViewports = &viewport;
viewport_state.scissorCount = 1;
viewport_state.pScissors = &scissor_rect;
VkPipelineRasterizationStateCreateInfo rasterization_state = {};
rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterization_state.depthClampEnable = false;
rasterization_state.rasterizerDiscardEnable = false;
rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;
rasterization_state.cullMode = VK_CULL_MODE_BACK_BIT;
rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterization_state.depthBiasEnable = false;
rasterization_state.lineWidth = 1.0f;
VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {};
depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depth_stencil_state.depthTestEnable = false;
depth_stencil_state.depthWriteEnable = false;
depth_stencil_state.depthBoundsTestEnable = false;
depth_stencil_state.stencilTestEnable = false;
VkPipelineMultisampleStateCreateInfo multisample_state = {};
multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
color_blend_attachment.blendEnable = false;
color_blend_attachment.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo color_blend_state = {};
color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blend_state.logicOpEnable = false;
color_blend_state.attachmentCount = 1;
color_blend_state.pAttachments = &color_blend_attachment;
VkGraphicsPipelineCreateInfo pipeline_create_info = {};
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_create_info.stageCount = std::size(shader_stages);
pipeline_create_info.pStages = shader_stages;
pipeline_create_info.pVertexInputState = &vertex_input_state;
pipeline_create_info.pInputAssemblyState = &input_assembly_state;
pipeline_create_info.pViewportState = &viewport_state;
pipeline_create_info.pRasterizationState = &rasterization_state;
pipeline_create_info.pDepthStencilState = &depth_stencil_state;
pipeline_create_info.pMultisampleState = &multisample_state;
pipeline_create_info.pColorBlendState = &color_blend_state;
pipeline_create_info.layout = m_pipeline_layout;
pipeline_create_info.renderPass = m_main_render_pass;
pipeline_create_info.subpass = 0;
VK_CHECK(vkCreateGraphicsPipelines(
m_device, nullptr, 1, &pipeline_create_info, nullptr, &m_graphics_pipeline));
vkDestroyShaderModule(m_device, vertex_shader, nullptr);
vkDestroyShaderModule(m_device, fragment_shader, nullptr);
}
void Example_app::create_descriptor_pool_and_set()
{
VkDescriptorPoolSize texture_pool_size;
texture_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
texture_pool_size.descriptorCount = static_cast<uint32_t>(m_material_textures.size());
VkDescriptorPoolSize storage_buffer_pool_size;
storage_buffer_pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
storage_buffer_pool_size.descriptorCount = 1;
const VkDescriptorPoolSize pool_sizes[] = {
texture_pool_size,
storage_buffer_pool_size
};
VkDescriptorPoolCreateInfo descriptor_pool_create_info = {};
descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptor_pool_create_info.maxSets = 1;
descriptor_pool_create_info.poolSizeCount = std::size(pool_sizes);
descriptor_pool_create_info.pPoolSizes = pool_sizes;
VK_CHECK(vkCreateDescriptorPool(
m_device, &descriptor_pool_create_info, nullptr, &m_descriptor_pool));
VkDescriptorSetAllocateInfo descriptor_set_alloc_info = {};
descriptor_set_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptor_set_alloc_info.descriptorPool = m_descriptor_pool;
descriptor_set_alloc_info.descriptorSetCount = 1;
descriptor_set_alloc_info.pSetLayouts = &m_descriptor_set_layout;
VK_CHECK(vkAllocateDescriptorSets(
m_device, &descriptor_set_alloc_info, &m_descriptor_set));
}
void Example_app::populate_descriptor_set()
{
std::vector<VkDescriptorImageInfo> descriptor_image_infos(m_material_textures.size());
for (size_t i = 0; i < m_material_textures.size(); i++)
{
descriptor_image_infos[i].sampler = m_linear_sampler;
descriptor_image_infos[i].imageView = m_material_textures[i].image_view;
descriptor_image_infos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
VkWriteDescriptorSet textures_descriptor_write = {};
textures_descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
textures_descriptor_write.dstSet = m_descriptor_set;
textures_descriptor_write.dstBinding = g_material_textures_descriptor_binding;
textures_descriptor_write.dstArrayElement = 0;
textures_descriptor_write.descriptorCount
= static_cast<uint32_t>(descriptor_image_infos.size());
textures_descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
textures_descriptor_write.pImageInfo = descriptor_image_infos.data();
VkDescriptorBufferInfo descriptor_ro_data_info;
descriptor_ro_data_info.buffer = m_ro_data_buffer.buffer;
descriptor_ro_data_info.offset = 0;
descriptor_ro_data_info.range = VK_WHOLE_SIZE;
VkWriteDescriptorSet ro_data_descriptor_write = {};
ro_data_descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
ro_data_descriptor_write.dstSet = m_descriptor_set;
ro_data_descriptor_write.dstBinding = g_ro_data_descriptor_binding;
ro_data_descriptor_write.dstArrayElement = 0;
ro_data_descriptor_write.descriptorCount = 1;
ro_data_descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
ro_data_descriptor_write.pBufferInfo = &descriptor_ro_data_info;
std::vector<VkWriteDescriptorSet> descriptor_writes;
descriptor_writes.push_back(textures_descriptor_write);
if (m_ro_data_buffer.buffer)
descriptor_writes.push_back(ro_data_descriptor_write);
vkUpdateDescriptorSets(
m_device, descriptor_writes.size(), descriptor_writes.data(), 0, nullptr);
}
void usage(char const* prog_name)
{
std::cout
<< "Usage: " << prog_name << " [options] [<material_pattern>]\n"
<< "Options:\n"
<< " --nowin don't show interactive display\n"
<< " --res <x> <y> resolution (default: 1024x768)\n"
<< " --numimg <n> swapchain image count (default: 3)\n"
<< " -o <outputfile> image file to write result in nowin mode (default: output.png)\n"
<< " --vkdebug enable the Vulkan validation layers\n"
<< " <material_pattern> a number from 1 to 7 choosing which material combination to use"
<< std::endl;
exit_failure();
}
Options parse_command_line(int argc, char* argv[])
{
Options options;
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
if (arg[0] == '-')
{
if (arg == "--nowin")
options.no_window = true;
else if (arg == "-o" && i < argc - 1)
options.outputfile = argv[++i];
else if (arg == "--res" && i < argc - 2)
{
options.res_x = std::max(std::atoi(argv[++i]), 1);
options.res_y = std::max(std::atoi(argv[++i]), 1);
}
else if (arg == "--numimg" && i < argc - 1)
options.num_images = std::max(std::atoi(argv[++i]), 2);
else if (arg == "--vkdebug")
options.enable_validation_layers = true;
else
usage(argv[0]);
}
else
{
options.material_pattern = static_cast<uint32_t>(std::atoi(argv[i]));
if (options.material_pattern < 1 || options.material_pattern > 7)
{
std::cerr << "Invalid material_pattern parameter." << std::endl;
usage(argv[0]);
}
}
}
return options;
}
int MAIN_UTF8(int argc, char* argv[])
{
Options options = parse_command_line(argc, argv);
mi::examples::mdl::load_and_get_ineuray());
if (!neuray.is_valid_interface())
exit_failure("Failed to load the SDK.");
mi::examples::mdl::Configure_options configure_options;
if (!mi::examples::mdl::configure(neuray.get(), configure_options))
exit_failure("Failed to initialize the SDK.");
if (result != 0)
exit_failure("Failed to initialize the SDK. Result code: %d", result);
{
mdl_factory->create_execution_context());
std::string module_name = "::nvidia::sdk_examples::tutorials";
mdl_impexp_api->load_module(transaction.get(), module_name.c_str(), context.get());
if (!print_messages(context.get()))
exit_failure("Loading module '%s' failed.", module_name.c_str());
mdl_factory->get_db_definition_name(module_name.c_str()));
if (!module)
exit_failure("Failed to access the loaded module.");
std::vector<std::string> material_simple_names;
material_simple_names.push_back("example_execution1");
material_simple_names.push_back("example_execution2");
material_simple_names.push_back("example_execution3");
std::vector<std::string> material_db_names(material_simple_names.size());
for (size_t i = 0; i < material_db_names.size(); ++i)
{
material_db_names[i]
= std::string(module_db_name->get_c_str()) + "::" + material_simple_names[i];
material_db_names[i] = mi::examples::mdl::add_missing_material_signature(
module.get(), material_db_names[i]);
if (material_db_names[i].empty())
{
exit_failure("Failed to find the material %s in the module %s.",
material_simple_names[i].c_str(), module_name.c_str());
}
}
module.reset();
std::vector<std::string> expression_paths;
expression_paths.push_back("surface.scattering.tint");
expression_paths.push_back("surface.scattering.tint");
expression_paths.push_back("surface.scattering.tint");
std::vector<std::string> function_names;
function_names.push_back("tint");
function_names.push_back("tint_2");
function_names.push_back("tint_3");
generate_glsl_code( mdl_backend_api.get(), transaction.get(), context.get(),
material_db_names, expression_paths, function_names));
{
mi::examples::vk::Vulkan_example_app::Config app_config;
app_config.window_title = "MDL SDK GLSL Vulkan Execution Example - Switch pattern with keys 1 - 7";
app_config.image_width = options.res_x;
app_config.image_height = options.res_y;
app_config.image_count = options.num_images;
app_config.headless = options.no_window;
app_config.enable_validation_layers = options.enable_validation_layers;
Example_app app(
transaction, mdl_impexp_api, image_api, target_code, options);
app.run(app_config);
}
}
if (neuray->shutdown() != 0)
exit_failure("Failed to shutdown the SDK.");
neuray = nullptr;
if (!mi::examples::mdl::unload())
exit_failure("Failed to unload the SDK.");
exit_success();
}
COMMANDLINE_TO_UTF8
This interface is used to interact with the distributed database.
Definition: idatabase.h:289
This interface represents a function definition.
Definition: ifunction_definition.h:44
This interface provides various utilities related to canvases and buffers.
Definition: iimage_api.h:72
virtual ITile * convert(const ITile *tile, const char *pixel_type) const =0
Converts a tile to a different pixel type.
virtual void adjust_gamma(ITile *tile, Float32 old_gamma, Float32 new_gamma) const =0
Sets the gamma value of a tile and adjusts the pixel data accordingly.
This interface represents a pixel image file.
Definition: iimage.h:66
This interface represents a material instance.
Definition: imaterial_instance.h:34
@ DEFAULT_OPTIONS
Default compilation options (e.g., instance compilation).
Definition: imaterial_instance.h:40
This interface can be used to obtain the MDL backends.
Definition: imdl_backend_api.h:56
virtual IMdl_backend * get_backend(Mdl_backend_kind kind)=0
Returns an MDL backend generator.
The execution context can be used to query status information like error and warning messages concern...
Definition: imdl_execution_context.h:131
Factory for various MDL interfaces and functions.
Definition: imdl_factory.h:53
API component for MDL related import and export operations.
Definition: imdl_impexp_api.h:43
This interface represents an MDL module.
Definition: imodule.h:634
Represents target code of an MDL backend.
Definition: imdl_backend.h:783
Textures add image processing options to images.
Definition: itexture.h:68
A transaction provides a consistent view on the database.
Definition: itransaction.h:82
virtual const base::IInterface * access(const char *name)=0
Retrieves an element from the database.
virtual Sint32 commit()=0
Commits the transaction.
virtual Uint32 retain() const =0
Increments the reference count.
unsigned int Uint32
32-bit unsigned integer.
Definition: types.h:49
Uint64 Size
Unsigned integral type that is large enough to hold the size of all types.
Definition: types.h:112
signed int Sint32
32-bit signed integer.
Definition: types.h:46
virtual const char * get_code() const =0
Returns the represented target code in ASCII representation.
virtual const char * get_texture(Size index) const =0
Returns the name of a texture resource used by the target code.
virtual Texture_shape get_texture_shape(Size index) const =0
Returns the texture shape of a given texture resource used by the target code.
virtual Size get_ro_data_segment_count() const =0
Returns the number of constant data initializers.
virtual const char * get_callable_function_prototype(Size index, Prototype_language lang) const =0
Returns the prototype of a callable function in the target code.
virtual Size get_ro_data_segment_size(Size index) const =0
Returns the size of the constant data segment at the given index.
virtual const char * get_ro_data_segment_data(Size index) const =0
Returns the data of the constant data segment at the given index.
virtual Size get_callable_function_count() const =0
Returns the number of callable functions in the target code.
virtual Size get_texture_count() const =0
Returns the number of texture resources used by the target code.
virtual const char * get_callable_function(Size index) const =0
Returns the name of a callable function in the target code.
Texture_shape
Definition: imdl_backend.h:811
@ Texture_shape_2d
Two-dimensional texture.
Definition: imdl_backend.h:813