Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
99 lines (85 sloc)
5.05 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Copyright (c) 2019 Hans-Kristian Arntzen | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining | |
| * a copy of this software and associated documentation files (the | |
| * "Software"), to deal in the Software without restriction, including | |
| * without limitation the rights to use, copy, modify, merge, publish, | |
| * distribute, sublicense, and/or sell copies of the Software, and to | |
| * permit persons to whom the Software is furnished to do so, subject to | |
| * the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be | |
| * included in all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| */ | |
| #include "vulkan.hpp" | |
| #include "device.hpp" | |
| #include "util.hpp" | |
| // For simplicity sake, we have used glslc (shaderc project) to compile GLSL to SPIR-V, expressed as a | |
| // nice little uint32_t C array. | |
| // Granite has shader manager which is far more sophisticated than this, but it is built on top of the basic shader | |
| // creation API in Granite, and is not really important from a Vulkan API design point of view. | |
| static const uint32_t simple_vert[] = | |
| #include "shaders/simple.vert.inc" | |
| ; | |
| static const uint32_t simple_frag[] = | |
| #include "shaders/simple.frag.inc" | |
| ; | |
| int main() | |
| { | |
| // See sample 01. | |
| if (!Vulkan::Context::init_loader(nullptr)) | |
| { | |
| LOGE("Failed to create loader!\n"); | |
| return 1; | |
| } | |
| Vulkan::Context context; | |
| if (!context.init_instance_and_device(nullptr, 0, nullptr, 0)) | |
| { | |
| LOGE("Failed to create VkInstance and VkDevice.\n"); | |
| return 1; | |
| } | |
| Vulkan::Device device; | |
| device.set_context(context); | |
| //// | |
| // Shaders and programs are considered to be persistent objects in Granite. Once a Shader handle has been requested | |
| // it is permanent. Vulkan::Device owns the handle, and therefore Vulkan::Shader and Vulkan::Program are simply pointers to some internally allocated data structure. | |
| // This is where we start to see a common theme in Granite, where we hash input data and translate that to a persistent data structure. | |
| // In Vulkan, a pipeline will require all shader stages to be combined into one pipeline. | |
| // Descriptor set layouts and pipeline layouts also require shader stages to be together. | |
| // When a new shader is found, a Vulkan::Shader object is created. | |
| // At this point, we also perform reflection with SPIRV-Cross. | |
| // For each shader, we need to know which binding points and locations are active in the shader, | |
| // as well as how many bytes of push constants are in use. | |
| // In theory, if SPIR-V modules are built offline and shipped as-is, we could also provide the reflection info as side-band data | |
| // without having to bundle a reflection library, but I never felt the need to this plumbing exercise yet. | |
| // An important thing to note is that we do *not* reflect any names, only semantically important decorations | |
| // like bindings, locations and descriptor sets. | |
| // The binding model is fully index based, no GL-style "glGetUniformLocation" shenanigans. | |
| Vulkan::Shader *vert = device.request_shader(simple_vert, sizeof(simple_vert)); | |
| Vulkan::Shader *frag = device.request_shader(simple_frag, sizeof(simple_frag)); | |
| // There is no real work done here, except that once we know all shader stages, we finally know | |
| // an appropriate pipeline layout. We essentially take the union of all resources used in the two graphics stages here. | |
| // At this point, we create look at all active descriptor sets and create new Vulkan::DescriptorSetAllocator objects internally. | |
| // These internal objects are of course hashed. A Vulkan::DescriptorSetAllocator internally can be represented as: | |
| // - The VkDescriptorSetLayout. | |
| // - The resource binding signature for the set. | |
| // - A recycling allocator which is designed to allocate and recycle VkDescriptorSets of this particular VkDescriptorSetLayout. | |
| // The recycling allocator design is kinda cool, and is explored in later samples. | |
| // Automatically deducing pipeline layouts is one of the biggest convenience features of Granite. | |
| // There is very little gain from hand-crafting pipeline layouts - and as you will know if you have done it - | |
| // it is ridiculously tedious (and error prone!) to hand-write these structures. | |
| // Once we have a list of VkDescriptorSetLayouts and push constant layouts, we now have our Vulkan::PipelineLayout. | |
| // This is of course, hashed as well based on the hash of descriptor set layouts and push constant ranges. | |
| Vulkan::Program *program = device.request_program(vert, frag); | |
| // We are not at the point where we can translate Program to a Pipeline. For that we will need to add lot more | |
| // state as you will be familiar with if you wrote some Vulkan code before. | |
| // This is for later samples. | |
| } |