void CVulkanShader::VKCreateShaderModule(const std::vector<char>& code, VkShaderModule& shaderModule) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); createInfo.pCode = (uint32_t*)code.data(); if (vkCreateShaderModule(m_pVkDevice->getDevice(), &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { g_pDebug->printError("failed to create shader module!"); } }
void VkApp::createShaderModule(const std::vector<char>& code, VDeleter<VkShaderModule>& shaderModule) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); createInfo.pCode = (uint32_t*) code.data(); if( vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS ){ throw std::runtime_error("failed to create shader module!"); } }
VkResult ShaderModule::init_try(const Device &dev, const VkShaderModuleCreateInfo &info) { VkShaderModule mod; VkResult err = vkCreateShaderModule(dev.handle(), &info, NULL, &mod); if (err == VK_SUCCESS) NonDispHandle::init(dev.handle(), mod); return err; }
bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule) { VkShaderModuleCreateInfo sm{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; sm.pCode = spirv.data(); sm.codeSize = spirv.size() * sizeof(uint32_t); sm.flags = 0; VkResult result = vkCreateShaderModule(device_, &sm, nullptr, shaderModule); if (result != VK_SUCCESS) { return false; } else { return true; } }
VkShaderModule createShaderModule(const std::vector<char>& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data()); VkShaderModule shaderModule; if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } return shaderModule; }
VkShaderModule create_shader_module(const char * filename) { auto load_code = [](const char * filename, size_t& psize) -> void * { long int size; size_t retval; void * shader_code; FILE *fp = fopen(filename, "rb"); if (!fp) return NULL; fseek(fp, 0L, SEEK_END); size = ftell(fp); fseek(fp, 0L, SEEK_SET); shader_code = malloc(size); retval = fread(shader_code, size, 1, fp); assert(retval == 1); psize = size; fclose(fp); return shader_code; }; VkShaderModule vert_shader_module; { size_t size; void * vert_shader_code = load_code(filename, size); VkShaderModuleCreateInfo module_create_info; VkResult err; module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; module_create_info.pNext = NULL; module_create_info.codeSize = size; module_create_info.pCode = (uint32_t *)vert_shader_code; module_create_info.flags = 0; err = vkCreateShaderModule(_vulkan_device, &module_create_info, NULL, &vert_shader_module); assert(!err); free(vert_shader_code); } return vert_shader_module; }
void GpuProgramManager::createResources(const GpuProgramRefArray& p_Refs) { for (uint32_t i = 0u; i < p_Refs.size(); ++i) { GpuProgramRef ref = p_Refs[i]; const SpirvBuffer& spirvBuffer = _spirvBuffer(ref); // No spirv buffer? Retrieve it from the cache or compile the shader if (spirvBuffer.empty()) { compileShader(ref, false, false); if (spirvBuffer.empty()) { continue; } } VkShaderModule& module = _vkShaderModule(ref); // Shader module { VkShaderModuleCreateInfo creationInfo; creationInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; creationInfo.pNext = nullptr; creationInfo.flags = 0; creationInfo.codeSize = spirvBuffer.size() * sizeof(uint32_t); creationInfo.pCode = spirvBuffer.data(); _INTR_ASSERT(module == VK_NULL_HANDLE); VkResult result = vkCreateShaderModule(RenderSystem::_vkDevice, &creationInfo, nullptr, &module); _INTR_VK_CHECK_RESULT(result); } // Pipeline state { VkPipelineShaderStageCreateInfo& pipelineCreateInfo = _vkPipelineShaderStageCreateInfo(ref); pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; pipelineCreateInfo.pNext = nullptr; pipelineCreateInfo.pSpecializationInfo = nullptr; pipelineCreateInfo.flags = 0u; pipelineCreateInfo.stage = Helper::mapGpuProgramTypeToVkShaderStage( (GpuProgramType::Enum)_descGpuProgramType(ref)); pipelineCreateInfo.pName = _descEntryPoint(ref).c_str(); pipelineCreateInfo.module = module; } } }
int VulkanRenderer::LoadFragmentShader( const void* data, size_t size ) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = size; createInfo.pCode = static_cast<const uint32_t*>(data); if ( vkCreateShaderModule( mInstance->device(), &createInfo, nullptr, &mFragmentShader ) != VK_SUCCESS ) { throw std::runtime_error("failed to create shader module!"); } mReady = false; return 0; }
VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count) { VkShaderModuleCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; info.codeSize = spv_word_count * sizeof(u32); info.pCode = spv; VkShaderModule module; VkResult res = vkCreateShaderModule(g_vulkan_context->GetDevice(), &info, nullptr, &module); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateShaderModule failed: "); return VK_NULL_HANDLE; } return module; }
VkShaderModule loadShaderModule(VkDevice device, const char *pPath) { vector<uint32_t> buffer; if (FAILED(OS::getAssetManager().readBinaryFile(&buffer, pPath))) { LOGE("Failed to read SPIR-V file: %s.\n", pPath); return VK_NULL_HANDLE; } VkShaderModuleCreateInfo moduleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; moduleInfo.codeSize = buffer.size() * sizeof(uint32_t); moduleInfo.pCode = buffer.data(); VkShaderModule shaderModule; VK_CHECK(vkCreateShaderModule(device, &moduleInfo, nullptr, &shaderModule)); return shaderModule; }
VkShaderModule load(const char *fileName, VkDevice device) { size_t size = 0; const char *shaderCode = readBinaryFile(fileName, &size); assert(size > 0); VkShaderModule shaderModule; VkShaderModuleCreateInfo moduleCreateInfo; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.codeSize = size; moduleCreateInfo.pCode = (uint32_t*)shaderCode; moduleCreateInfo.flags = 0; VkResult err = vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule); assert(!err); return shaderModule; }
int Shader::loadSPV(const void* spvBegin, const void* spvEnd) { VkShaderModuleCreateInfo VkInit(smci); smci.codeSize = reinterpret_cast<const char*>(spvEnd) - reinterpret_cast<const char*>(spvBegin); if (smci.codeSize % 4 != 0) { fprintf(stderr, "LoadSPV(%p, %p) size %zu is invalid\n", spvBegin, spvEnd, smci.codeSize); return 1; } smci.pCode = reinterpret_cast<const uint32_t*>(spvBegin); VkResult r = vkCreateShaderModule(vkdev, &smci, nullptr, &vk); if (r != VK_SUCCESS) { fprintf(stderr, "loadSPV(%p, %p) vkCreateShaderModule returned %d (%s)\n", spvBegin, spvEnd, r, string_VkResult(r)); return 1; } return 0; }
bool ShaderStage::fromSPIRVSource(VkDevice device, const char* src, uint32_t len, VkShaderStageFlagBits shaderStageType, const char* entryFunc) { clear(device); if (len <= 4) return false; VkShaderModuleCreateInfo shaderModuleCreateInfo{}; shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shaderModuleCreateInfo.codeSize = len; shaderModuleCreateInfo.pCode = reinterpret_cast<const uint32_t*>(src); VkResult result = vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &m_shaderModule); m_entryFunction = entryFunc; m_shaderType = shaderStageType; return result == VK_SUCCESS; }
void VKVertexProgram::Compile() { fs::create_path(fs::get_config_dir() + "/shaderlog"); fs::file(fs::get_config_dir() + "shaderlog/VertexProgram" + std::to_string(id) + ".spirv", fs::rewrite).write(shader); std::vector<u32> spir_v; if (!vk::compile_glsl_to_spv(shader, glsl::glsl_vertex_program, spir_v)) fmt::throw_exception("Failed to compile vertex shader" HERE); VkShaderModuleCreateInfo vs_info; vs_info.codeSize = spir_v.size() * sizeof(u32); vs_info.pNext = nullptr; vs_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vs_info.pCode = (uint32_t*)spir_v.data(); vs_info.flags = 0; VkDevice dev = (VkDevice)*vk::get_current_renderer(); vkCreateShaderModule(dev, &vs_info, nullptr, &handle); }
coResult coVulkanShader::OnInit(const coObject::InitConfig& _config) { coTRY(Super::OnInit(_config), nullptr); const InitConfig& config = static_cast<const InitConfig&>(_config); coTRY(config.code.count > 0, nullptr); coTRY(config.code.count % 4 == 0, nullptr); VkShaderModuleCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = config.code.count; createInfo.pCode = reinterpret_cast<const uint32_t*>(config.code.data); const VkDevice& device_vk = GetVkDevice(); coTRY(device_vk != VK_NULL_HANDLE, nullptr); coASSERT(shaderModule_vk == VK_NULL_HANDLE); coVULKAN_TRY(vkCreateShaderModule(device_vk, &createInfo, nullptr, &shaderModule_vk), "Failed to create Vulkan shader module."); return true; }
void VKVertexProgram::Compile() { fs::file(fs::get_config_dir() + "VertexProgram.vert", fs::rewrite).write(shader); std::vector<u32> spir_v; if (!vk::compile_glsl_to_spv(shader, vk::glsl::glsl_vertex_program, spir_v)) throw EXCEPTION("Failed to compile vertex shader"); VkShaderModuleCreateInfo vs_info; vs_info.codeSize = spir_v.size() * sizeof(u32); vs_info.pNext = nullptr; vs_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vs_info.pCode = (uint32_t*)spir_v.data(); vs_info.flags = 0; VkDevice dev = (VkDevice)*vk::get_current_renderer(); vkCreateShaderModule(dev, &vs_info, nullptr, &handle); id = (u32)((u64)handle); }
IShaderModuleSP VKTS_APIENTRY shaderModuleCreate(const VkDevice device, const VkShaderModuleCreateFlags flags, const size_t codeSize, const uint32_t* code) { if (!device) { return IShaderModuleSP(); } VkResult result; VkShaderModuleCreateInfo shaderModuleCreateInfo; memset(&shaderModuleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo)); shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shaderModuleCreateInfo.flags = flags; shaderModuleCreateInfo.codeSize = codeSize; shaderModuleCreateInfo.pCode = code; VkShaderModule shaderModule; result = vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &shaderModule); if (result != VK_SUCCESS) { logPrint(VKTS_LOG_ERROR, "Shader: Could not create shader module."); return IShaderModuleSP(); } auto newInstance = new ShaderModule(device, flags, codeSize, code, shaderModule); if (!newInstance) { vkDestroyShaderModule(device, shaderModule, nullptr); return IShaderModuleSP(); } return IShaderModuleSP(newInstance); }
void VKFragmentProgram::Compile() { fs::create_path(fs::get_config_dir() + "/shaderlog"); fs::file(fs::get_config_dir() + "shaderlog/FragmentProgram.spirv", fs::rewrite).write(shader); std::vector<u32> spir_v; if (!vk::compile_glsl_to_spv(shader, vk::glsl::glsl_fragment_program, spir_v)) fmt::throw_exception("Failed to compile fragment shader" HERE); //Create the object and compile VkShaderModuleCreateInfo fs_info; fs_info.codeSize = spir_v.size() * sizeof(u32); fs_info.pNext = nullptr; fs_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; fs_info.pCode = (uint32_t*)spir_v.data(); fs_info.flags = 0; VkDevice dev = (VkDevice)*vk::get_current_renderer(); vkCreateShaderModule(dev, &fs_info, nullptr, &handle); id = (u32)((u64)handle); }
Tools::AutoDeleter<VkShaderModule, PFN_vkDestroyShaderModule> Tutorial03::CreateShaderModule( const char* filename ) { const std::vector<char> code = Tools::GetBinaryFileContents( filename ); if( code.size() == 0 ) { return Tools::AutoDeleter<VkShaderModule, PFN_vkDestroyShaderModule>(); } VkShaderModuleCreateInfo shader_module_create_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType nullptr, // const void *pNext 0, // VkShaderModuleCreateFlags flags code.size(), // size_t codeSize reinterpret_cast<const uint32_t*>(&code[0]) // const uint32_t *pCode }; VkShaderModule shader_module; if( vkCreateShaderModule( GetDevice(), &shader_module_create_info, nullptr, &shader_module ) != VK_SUCCESS ) { std::cout << "Could not create shader module from a \"" << filename << "\" file!" << std::endl; return Tools::AutoDeleter<VkShaderModule, PFN_vkDestroyShaderModule>(); } return Tools::AutoDeleter<VkShaderModule, PFN_vkDestroyShaderModule>( shader_module, vkDestroyShaderModule, GetDevice() ); }
VkBool32 Example::buildShader() { auto vertexShaderBinary = vkts::fileLoadBinary(VKTS_VERTEX_SHADER_NAME); if (!vertexShaderBinary.get()) { vkts::logPrint(VKTS_LOG_ERROR, "Example: Could not load vertex shader: '%s'", VKTS_VERTEX_SHADER_NAME); return VK_FALSE; } auto fragmentShaderBinary = vkts::fileLoadBinary(VKTS_FRAGMENT_SHADER_NAME); if (!fragmentShaderBinary.get()) { vkts::logPrint(VKTS_LOG_ERROR, "Example: Could not load fragment shader: '%s'", VKTS_FRAGMENT_SHADER_NAME); return VK_FALSE; } // VkResult result; VkShaderModuleCreateInfo shaderModuleCreateInfo; memset(&shaderModuleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo)); shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shaderModuleCreateInfo.flags = 0; shaderModuleCreateInfo.codeSize = vertexShaderBinary->getSize(); shaderModuleCreateInfo.pCode = (const uint32_t*)vertexShaderBinary->getData(); result = vkCreateShaderModule(device->getDevice(), &shaderModuleCreateInfo, nullptr, &vertexShaderModule); if (result != VK_SUCCESS) { vkts::logPrint(VKTS_LOG_ERROR, "Example: Could not create vertex shader module."); return VK_FALSE; } memset(&shaderModuleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo)); shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shaderModuleCreateInfo.flags = 0; shaderModuleCreateInfo.codeSize = fragmentShaderBinary->getSize(); shaderModuleCreateInfo.pCode = (const uint32_t*)fragmentShaderBinary->getData(); result = vkCreateShaderModule(device->getDevice(), &shaderModuleCreateInfo, nullptr, &fragmentShaderModule); if (result != VK_SUCCESS) { vkts::logPrint(VKTS_LOG_ERROR, "Example: Could not create fragment shader module."); return VK_FALSE; } return VK_TRUE; }
bool ShaderProgram::compile(const char *name) { EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); glslang::TProgram program; const char *stageNames[StageCount] = {"Vertex", "TessControl", "TessEvaluation", "Geometry", "Fragment", "Compute"}; const char *extensions[StageCount] = { "vert", "tesc", "tese", "geom", "frag", "comp" }; glslang::TShader tShaders[EShLangCount] = { glslang::TShader(EShLangVertex), glslang::TShader(EShLangTessControl), glslang::TShader(EShLangTessEvaluation), glslang::TShader(EShLangGeometry), glslang::TShader(EShLangFragment), glslang::TShader(EShLangCompute) }; //#define glslangValidator "C:\\VulkanSDK\\1.0.21.1\\Bin\\glslangValidator.exe" #ifdef glslangValidator char szCommand[1024]; sprintf(szCommand, glslangValidator " -V"); #endif const char *psz = NULL; for (int i = 0; i < EShLangCount; i++) { if (stages[i].glsl.empty()) continue; #ifdef glslangValidator VK::Path pGLSL = VK::Path::Shader().add("temp.%s", extensions[i]); strcat(szCommand, " "); strcat(szCommand, pGLSL.basename().c_str()); std::ofstream os(pGLSL, std::ios::binary); os << stages[i].glsl; os.close(); #endif psz = stages[i].glsl.c_str(); tShaders[i].setStrings(&psz, 1); if (!stages[i].entry.empty()) tShaders[i].setEntryPoint(stages[i].entry.c_str()); VKLogDebug("%s stage for program: %s\n%s", stageNames[i], name, stages[i].glsl.c_str()); if (!tShaders[i].parse(&DefaultTBuiltInResource, 110, false, messages)) { psz = tShaders[i].getInfoLog(); if (psz && *psz) VKLogError("%s", psz); return false; } psz = tShaders[i].getInfoLog(); if (psz && *psz) VKLogInfo("%s stage parsing info for program: %s\n%s", stageNames[i], name, psz); psz = tShaders[i].getInfoDebugLog(); if (psz && *psz) VKLogDebug("%s stage debug info for program: %s\n%s", stageNames[i], name, psz); program.addShader(&tShaders[i]); } if (!program.link(messages)) { psz = program.getInfoLog(); if (psz && *psz) VKLogError("Link failed for program: %s\n%s", name, psz); return false; } #ifdef glslangValidator LaunchAndWait(szCommand, VK::Path::Shader(), 0, 0, SW_HIDE); #endif for (int i = 0; i < EShLangCount; i++) { stages[i].spirv.clear(); if (stages[i].module) { vkDestroyShaderModule(vk, stages[i].module, NULL); stages[i].module = NULL; } glslang::TIntermediate *intermediate = program.getIntermediate((EShLanguage)i); if (intermediate) { glslang::GlslangToSpv(*intermediate, stages[i].spirv); #ifdef glslangValidator VK::Path p = VK::Path::Shader().add("%s.spv", extensions[i]); std::string str = p.read(); std::vector<uint32_t> spirv; spirv.resize(str.size() / 4); memcpy(&spirv[0], str.c_str(), str.size()); if (spirv.size() != stages[i].spirv.size() || memcmp(&spirv[0], &stages[i].spirv[0], spirv.size() * 4) != 0) VKLogWarning("glslangValidator mismatch!"); #endif std::ostringstream ostr; spv::Disassemble(ostr, stages[i].spirv); VKLogDebug("%s stage dissassembly for program: %s\n%s", stageNames[i], name, ostr.str().c_str()); ShaderModuleCreateInfo shader(stages[i].spirv); OBJ_CHECK(vkCreateShaderModule(vk, &shader, nullptr, &stages[i].module)); } } return true; }
int sample_main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "SPIR-V Specialization"; const bool depthPresent = true; process_command_line_args(info, argc, argv); init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 500, 500); init_connection(info); init_window(info); init_swapchain_extension(info); init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info); init_depth_buffer(info); init_texture(info); init_uniform_buffer(info); init_descriptor_and_pipeline_layouts(info, true); init_renderpass(info, depthPresent); /* VULKAN_KEY_START */ // Pass in nullptr for fragment shader so we can setup specialization init_shaders(info, vertShaderText, nullptr); // This structure maps constant ids to data locations. // NOTE: Padding bool to 32-bits for simplicity const VkSpecializationMapEntry entries[] = // id, offset, size {{5, 0, sizeof(uint32_t)}, {7, 1 * sizeof(uint32_t), sizeof(uint32_t)}, {8, 2 * sizeof(uint32_t), sizeof(uint32_t)}, {9, 3 * sizeof(uint32_t), sizeof(uint32_t)}}; // Initialize the values we want our mini-ubershader to use const bool drawUserColor = true; const float userColor[] = {0.0f, 0.0f, 1.0f}; // Populate our data entry uint32_t data[4] = {}; data[0] = drawUserColor ? 1 : 0; ((float *)data)[1] = userColor[0]; ((float *)data)[2] = userColor[1]; ((float *)data)[3] = userColor[2]; // Set up the info describing our spec map and data const VkSpecializationInfo specInfo = { 4, // mapEntryCount entries, // pMapEntries 4 * sizeof(float), // dataSize data, // pData }; // Provide the specialization data to fragment stage info.shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; info.shaderStages[1].pNext = NULL; info.shaderStages[1].pSpecializationInfo = &specInfo; info.shaderStages[1].flags = 0; info.shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; info.shaderStages[1].pName = "main"; VkShaderModuleCreateInfo moduleCreateInfo; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.flags = 0; if (use_SPIRV_asm) { // Use the hand edited SPIR-V assembly spv_context spvContext = spvContextCreate(SPV_ENV_VULKAN_1_0); spv_binary fragmentBinary = {}; spv_diagnostic fragmentDiag = {}; spv_result_t fragmentResult = spvTextToBinary(spvContext, fragmentSPIRV_specialized.c_str(), fragmentSPIRV_specialized.length(), &fragmentBinary, &fragmentDiag); if (fragmentDiag) { printf("Diagnostic info from fragment shader:\n"); spvDiagnosticPrint(fragmentDiag); } assert(fragmentResult == SPV_SUCCESS); moduleCreateInfo.codeSize = fragmentBinary->wordCount * sizeof(unsigned int); moduleCreateInfo.pCode = fragmentBinary->code; spvDiagnosticDestroy(fragmentDiag); spvContextDestroy(spvContext); } else { // Convert GLSL to SPIR-V init_glslang(); std::vector<unsigned int> fragSpv; bool U_ASSERT_ONLY retVal = GLSLtoSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fragShaderText, fragSpv); assert(retVal); finalize_glslang(); moduleCreateInfo.codeSize = fragSpv.size() * sizeof(unsigned int); moduleCreateInfo.pCode = fragSpv.data(); } res = vkCreateShaderModule(info.device, &moduleCreateInfo, NULL, &info.shaderStages[1].module); assert(res == VK_SUCCESS); /* VULKAN_KEY_END */ init_framebuffers(info, depthPresent); init_vertex_buffer(info, g_vb_texture_Data, sizeof(g_vb_texture_Data), sizeof(g_vb_texture_Data[0]), true); init_descriptor_pool(info, true); init_descriptor_set(info, true); init_pipeline_cache(info); init_pipeline(info, depthPresent); init_presentable_image(info); VkClearValue clear_values[2]; init_clear_color_and_depth(info, clear_values); VkRenderPassBeginInfo rp_begin; init_render_pass_begin_info(info, rp_begin); rp_begin.clearValueCount = 2; rp_begin.pClearValues = clear_values; vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); init_viewports(info); init_scissors(info); vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); vkCmdEndRenderPass(info.cmd); res = vkEndCommandBuffer(info.cmd); assert(res == VK_SUCCESS); VkFence drawFence = {}; init_fence(info, drawFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submit_info = {}; init_submit_info(info, submit_info, pipe_stage_flags); /* Queue the command buffer for execution */ res = vkQueueSubmit(info.graphics_queue, 1, &submit_info, drawFence); assert(res == VK_SUCCESS); /* Now present the image in the window */ VkPresentInfoKHR present = {}; init_present_info(info, present); /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.present_queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); if (info.save_images) write_ppm(info, "spirv_specialization"); vkDestroyFence(info.device, drawFence, NULL); vkDestroySemaphore(info.device, info.imageAcquiredSemaphore, NULL); destroy_pipeline(info); destroy_pipeline_cache(info); destroy_textures(info); destroy_descriptor_pool(info); destroy_vertex_buffer(info); destroy_framebuffers(info); destroy_shaders(info); destroy_renderpass(info); destroy_descriptor_and_pipeline_layouts(info); destroy_uniform_buffer(info); destroy_depth_buffer(info); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
int main(void) { VkInstance instance; { const char debug_ext[] = "VK_EXT_debug_report"; const char* extensions[] = {debug_ext,}; const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation"; const char* layers[] = {validation_layer,}; VkInstanceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, .flags = 0, .pApplicationInfo = NULL, .enabledLayerCount = NELEMS(layers), .ppEnabledLayerNames = layers, .enabledExtensionCount = NELEMS(extensions), .ppEnabledExtensionNames = extensions, }; assert(vkCreateInstance(&create_info, NULL, &instance) == VK_SUCCESS); } VkDebugReportCallbackEXT debug_callback; { VkDebugReportCallbackCreateInfoEXT create_info = { .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, .pNext = NULL, .flags = (VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT), .pfnCallback = &debugReportCallback, .pUserData = NULL, }; PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); assert(createDebugReportCallback); assert(createDebugReportCallback(instance, &create_info, NULL, &debug_callback) == VK_SUCCESS); } VkPhysicalDevice phy_device; { uint32_t num_devices; assert(vkEnumeratePhysicalDevices(instance, &num_devices, NULL) == VK_SUCCESS); assert(num_devices >= 1); VkPhysicalDevice * phy_devices = malloc(sizeof(*phy_devices) * num_devices); assert(vkEnumeratePhysicalDevices(instance, &num_devices, phy_devices) == VK_SUCCESS); phy_device = phy_devices[0]; free(phy_devices); } VkPhysicalDeviceMemoryProperties memory_properties; vkGetPhysicalDeviceMemoryProperties(phy_device, &memory_properties); VkDevice device; { float queue_priorities[] = {1.0}; const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation"; const char* layers[] = {validation_layer,}; uint32_t nqueues; matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, NULL); assert(nqueues > 0); uint32_t * queue_family_idxs = malloc(sizeof(*queue_family_idxs) * nqueues); matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, queue_family_idxs); VkDeviceQueueCreateInfo queue_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .pNext = NULL, .flags = 0, .queueFamilyIndex = queue_family_idxs[0], .queueCount = 1, .pQueuePriorities = queue_priorities, }; free(queue_family_idxs); VkPhysicalDeviceFeatures features = { .geometryShader = VK_TRUE, .fillModeNonSolid = VK_TRUE, }; VkDeviceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = NULL, .flags = 0, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_info, .enabledLayerCount = NELEMS(layers), .ppEnabledLayerNames = layers, .enabledExtensionCount = 0, .ppEnabledExtensionNames = NULL, .pEnabledFeatures = &features, }; assert(vkCreateDevice(phy_device, &create_info, NULL, &device) == VK_SUCCESS); } VkQueue queue; vkGetDeviceQueue(device, 0, 0, &queue); VkCommandPool cmd_pool; { VkCommandPoolCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = NULL, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = 0, }; assert(vkCreateCommandPool(device, &create_info, NULL, &cmd_pool) == VK_SUCCESS); } VkRenderPass render_pass; { VkAttachmentDescription attachments[] = {{ .flags = 0, .format = VK_FORMAT_R8G8B8A8_UNORM, .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }, { .flags = 0, .format = VK_FORMAT_D16_UNORM, .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, { .flags = 0, .format = VK_FORMAT_R8G8B8A8_UNORM, .samples = VK_SAMPLE_COUNT_1_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, }}; VkAttachmentReference attachment_refs[NELEMS(attachments)] = {{ .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }, { .attachment = 1, .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, { .attachment = 2, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }}; VkSubpassDescription subpasses[1] = {{ .flags = 0, .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .inputAttachmentCount = 0, .pInputAttachments = NULL, .colorAttachmentCount = 1, .pColorAttachments = &attachment_refs[0], .pResolveAttachments = &attachment_refs[2], .pDepthStencilAttachment = &attachment_refs[1], .preserveAttachmentCount = 0, .pPreserveAttachments = NULL, }}; VkSubpassDependency dependencies[] = {{ .srcSubpass = 0, .dstSubpass = VK_SUBPASS_EXTERNAL, .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .dependencyFlags = 0, }}; VkRenderPassCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, .pNext = NULL, .flags = 0, .attachmentCount = NELEMS(attachments), .pAttachments = attachments, .subpassCount = NELEMS(subpasses), .pSubpasses = subpasses, .dependencyCount = NELEMS(dependencies), .pDependencies = dependencies, }; assert(vkCreateRenderPass(device, &create_info, NULL, &render_pass) == VK_SUCCESS); } VkImage images[3]; VkDeviceMemory image_memories[NELEMS(images)]; VkImageView views[NELEMS(images)]; createFrameImage(memory_properties, device, render_size, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &images[0], &image_memories[0], &views[0]); createFrameImage(memory_properties, device, render_size, VK_FORMAT_D16_UNORM, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_ASPECT_DEPTH_BIT, &images[1], &image_memories[1], &views[1]); createFrameImage(memory_properties, device, render_size, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &images[2], &image_memories[2], &views[2]); VkBuffer verts_buffer; VkDeviceMemory verts_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, sizeof(verts), verts, &verts_buffer, &verts_memory); VkBuffer index_buffer; VkDeviceMemory index_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, sizeof(indices), indices, &index_buffer, &index_memory); VkBuffer image_buffer; VkDeviceMemory image_buffer_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_TRANSFER_DST_BIT, render_size.height * render_size.width * 4, NULL, &image_buffer, &image_buffer_memory); VkFramebuffer framebuffer; createFramebuffer(device, render_size, 3, views, render_pass, &framebuffer); VkShaderModule shaders[5]; { char* filenames[NELEMS(shaders)] = {"cube.vert.spv", "cube.geom.spv", "cube.frag.spv", "wireframe.geom.spv", "color.frag.spv"}; for (size_t i = 0; i < NELEMS(shaders); i++){ size_t code_size; uint32_t * code; assert((code_size = loadModule(filenames[i], &code)) != 0); VkShaderModuleCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .pNext = NULL, .flags = 0, .codeSize = code_size, .pCode = code, }; assert(vkCreateShaderModule(device, &create_info, NULL, &shaders[i]) == VK_SUCCESS); free(code); } } VkPipelineLayout pipeline_layout; { VkPushConstantRange push_range = { .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .offset = 0, .size = 4, }; VkPipelineLayoutCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = NULL, .flags = 0, .setLayoutCount = 0, .pSetLayouts = NULL, .pushConstantRangeCount = 1, .pPushConstantRanges = &push_range, }; assert(vkCreatePipelineLayout(device, &create_info, NULL, &pipeline_layout) == VK_SUCCESS); } VkPipeline pipelines[2]; { VkPipelineShaderStageCreateInfo stages[3] = {{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_VERTEX_BIT, .module = shaders[0], .pName = "main", .pSpecializationInfo = NULL, },{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_GEOMETRY_BIT, .module = shaders[1], .pName = "main", .pSpecializationInfo = NULL, },{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, .module = shaders[2], .pName = "main", .pSpecializationInfo = NULL, }}; VkVertexInputBindingDescription vtx_binding = { .binding = 0, .stride = sizeof(struct Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, }; VkVertexInputAttributeDescription vtx_attr = { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(struct Vertex, pos), }; VkPipelineVertexInputStateCreateInfo vtx_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &vtx_binding, .vertexAttributeDescriptionCount = 1, .pVertexAttributeDescriptions = &vtx_attr, }; VkPipelineInputAssemblyStateCreateInfo ia_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, .primitiveRestartEnable = VK_TRUE, }; VkViewport viewport = { .x = 0, .y = 0, .width = render_size.width, .height = render_size.height, .minDepth = 0.0, .maxDepth = 1.0, }; VkRect2D scissor= { .offset = {.x = 0, .y = 0,}, .extent = render_size, }; VkPipelineViewportStateCreateInfo viewport_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .viewportCount = 1, .pViewports = &viewport, .scissorCount = 1, .pScissors = &scissor, }; VkPipelineRasterizationStateCreateInfo rasterization_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, .cullMode = VK_CULL_MODE_NONE, .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = VK_FALSE, .lineWidth = 1.0, }; VkPipelineMultisampleStateCreateInfo multisample_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .rasterizationSamples = VK_SAMPLE_COUNT_8_BIT, .sampleShadingEnable = VK_FALSE, .minSampleShading = 0.0, .pSampleMask = NULL, .alphaToCoverageEnable = VK_FALSE, .alphaToOneEnable = VK_FALSE, }; VkPipelineDepthStencilStateCreateInfo depth_stencil_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .depthTestEnable = VK_TRUE, .depthWriteEnable = VK_TRUE, .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL, .depthBoundsTestEnable = VK_FALSE, .stencilTestEnable = VK_FALSE, .front = {}, .back = {}, .minDepthBounds = 0.0, .maxDepthBounds = 1.0, }; VkPipelineColorBlendAttachmentState color_blend_attachment = { .blendEnable = VK_FALSE, .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 = { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .logicOpEnable = VK_FALSE, //.logicOp = 0, .attachmentCount = 1, .pAttachments = &color_blend_attachment, .blendConstants = {}, }; VkGraphicsPipelineCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = NULL, .flags = 0, .stageCount = NELEMS(stages), .pStages = stages, .pVertexInputState = &vtx_state, .pInputAssemblyState = &ia_state, .pTessellationState = NULL, .pViewportState = &viewport_state, .pRasterizationState = &rasterization_state, .pMultisampleState = &multisample_state, .pDepthStencilState = &depth_stencil_state, .pColorBlendState = &color_blend_state, .pDynamicState = NULL, .layout = pipeline_layout, .renderPass = render_pass, .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, }; assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[0]) == VK_SUCCESS); stages[1].module = shaders[3]; stages[2].module = shaders[4]; rasterization_state.polygonMode = VK_POLYGON_MODE_LINE; assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[1]) == VK_SUCCESS); } VkCommandBuffer draw_buffers[2]; { VkCommandBufferAllocateInfo allocate_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = NULL, .commandPool = cmd_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = NELEMS(draw_buffers), }; assert(vkAllocateCommandBuffers(device, &allocate_info, draw_buffers) == VK_SUCCESS); } { VkCommandBufferBeginInfo begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .pNext = NULL, .flags = 0, .pInheritanceInfo = NULL, }; VkClearValue clear_values[] = {{ .color.float32 = {0.0, 0.0, 0.0, 1.0}, }, { .depthStencil = {.depth = 1.0}, }}; VkRenderPassBeginInfo renderpass_begin_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = NULL, .renderPass = render_pass, .framebuffer = framebuffer, .renderArea = { .offset = {.x = 0, .y = 0}, .extent = render_size, }, .clearValueCount = NELEMS(clear_values), .pClearValues = clear_values, }; for (size_t i = 0; i < NELEMS(draw_buffers); i++){ assert(vkBeginCommandBuffer(draw_buffers[i], &begin_info) == VK_SUCCESS); uint32_t persp = i == 0; vkCmdPushConstants(draw_buffers[i], pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(persp), &persp); vkCmdBeginRenderPass(draw_buffers[i], &renderpass_begin_info, VK_SUBPASS_CONTENTS_INLINE); VkDeviceSize offset = 0; vkCmdBindVertexBuffers(draw_buffers[i], 0, 1, &verts_buffer, &offset); vkCmdBindIndexBuffer(draw_buffers[i], index_buffer, 0, VK_INDEX_TYPE_UINT32); for (size_t j = 0; j < NELEMS(pipelines); j++) { vkCmdBindPipeline(draw_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[j]); vkCmdDrawIndexed(draw_buffers[i], 20, 27, 0, 0, 0); } vkCmdEndRenderPass(draw_buffers[i]); } VkBufferImageCopy copy = { .bufferOffset = 0, .bufferRowLength = 0, // Tightly packed .bufferImageHeight = 0, // Tightly packed .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, .imageOffset = {0, 0, 0}, .imageExtent = {.width = render_size.width, .height = render_size.height, .depth = 1}, }; VkBufferMemoryBarrier transfer_barrier = { .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .pNext = 0, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = VK_ACCESS_HOST_READ_BIT, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .buffer = image_buffer, .offset = 0, .size = VK_WHOLE_SIZE, }; for (size_t i = 0; i < NELEMS(draw_buffers); i++){ vkCmdCopyImageToBuffer(draw_buffers[i], images[2], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image_buffer, 1, ©); vkCmdPipelineBarrier(draw_buffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &transfer_barrier, 0, NULL); assert(vkEndCommandBuffer(draw_buffers[i]) == VK_SUCCESS); } } VkFence fence; { VkFenceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = 0, }; assert(vkCreateFence(device, &create_info, NULL, &fence) == VK_SUCCESS); } { char * filenames[] = {"cube_persp.tif", "cube_ortho.tif"}; char * image_data; assert(vkMapMemory(device, image_buffer_memory, 0, VK_WHOLE_SIZE, 0, (void **) &image_data) == VK_SUCCESS); VkMappedMemoryRange image_flush = { .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .pNext = NULL, .memory = image_buffer_memory, .offset = 0, .size = VK_WHOLE_SIZE, }; VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = NULL, .waitSemaphoreCount = 0, .pWaitSemaphores = NULL, .pWaitDstStageMask = NULL, .commandBufferCount = 1, .pCommandBuffers = NULL, .signalSemaphoreCount = 0, .pSignalSemaphores = NULL, }; for (size_t i = 0; i < NELEMS(filenames); i++){ submit_info.pCommandBuffers = &draw_buffers[i]; assert(vkResetFences(device, 1, &fence) == VK_SUCCESS); assert(vkQueueSubmit(queue, 1, &submit_info, fence) == VK_SUCCESS); assert(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX) == VK_SUCCESS); assert(vkInvalidateMappedMemoryRanges(device, 1, &image_flush) == VK_SUCCESS); assert(writeTiff(filenames[i], image_data, render_size, nchannels) == 0); } vkUnmapMemory(device, image_buffer_memory); } assert(vkQueueWaitIdle(queue) == VK_SUCCESS); vkDestroyFence(device, fence, NULL); vkDestroyFramebuffer(device, framebuffer, NULL); for (size_t i = 0; i < NELEMS(images); i++){ vkDestroyImage(device, images[i], NULL); vkDestroyImageView(device, views[i], NULL); vkFreeMemory(device, image_memories[i], NULL); } vkDestroyBuffer(device, image_buffer, NULL); vkFreeMemory(device, image_buffer_memory, NULL); vkDestroyBuffer(device, verts_buffer, NULL); vkFreeMemory(device, verts_memory, NULL); vkDestroyBuffer(device, index_buffer, NULL); vkFreeMemory(device, index_memory, NULL); for (size_t i = 0; i < NELEMS(pipelines); i++){ vkDestroyPipeline(device, pipelines[i], NULL); } vkDestroyPipelineLayout(device, pipeline_layout, NULL); for(size_t i = 0; i < NELEMS(shaders); i++) vkDestroyShaderModule(device, shaders[i], NULL); vkDestroyRenderPass(device, render_pass, NULL); vkFreeCommandBuffers(device, cmd_pool, NELEMS(draw_buffers), draw_buffers); vkDestroyCommandPool(device, cmd_pool, NULL); vkDestroyDevice(device, NULL); { PFN_vkDestroyDebugReportCallbackEXT destroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); assert(destroyDebugReportCallback); destroyDebugReportCallback(instance, debug_callback, NULL); } vkDestroyInstance(instance, NULL); return 0; }
void BaseImage::ValidateContent(RandomNumberGenerator& rand) { /* dstBuf has following layout: For each of texels to be sampled, [0..valueCount): struct { in uint32_t pixelX; in uint32_t pixelY; out uint32_t pixelColor; } */ const uint32_t valueCount = 128; VkBufferCreateInfo dstBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; dstBufCreateInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; dstBufCreateInfo.size = valueCount * sizeof(uint32_t) * 3; VmaAllocationCreateInfo dstBufAllocCreateInfo = {}; dstBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; dstBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU; VkBuffer dstBuf = nullptr; VmaAllocation dstBufAlloc = nullptr; VmaAllocationInfo dstBufAllocInfo = {}; TEST( vmaCreateBuffer(g_hAllocator, &dstBufCreateInfo, &dstBufAllocCreateInfo, &dstBuf, &dstBufAlloc, &dstBufAllocInfo) == VK_SUCCESS ); // Fill dstBuf input data. { uint32_t* dstBufContent = (uint32_t*)dstBufAllocInfo.pMappedData; for(uint32_t i = 0; i < valueCount; ++i) { const uint32_t x = rand.Generate() % m_CreateInfo.extent.width; const uint32_t y = rand.Generate() % m_CreateInfo.extent.height; dstBufContent[i * 3 ] = x; dstBufContent[i * 3 + 1] = y; dstBufContent[i * 3 + 2] = 0; } } VkSamplerCreateInfo samplerCreateInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samplerCreateInfo.magFilter = VK_FILTER_NEAREST; samplerCreateInfo.minFilter = VK_FILTER_NEAREST; samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerCreateInfo.unnormalizedCoordinates = VK_TRUE; VkSampler sampler = nullptr; TEST( vkCreateSampler( g_hDevice, &samplerCreateInfo, nullptr, &sampler) == VK_SUCCESS ); VkDescriptorSetLayoutBinding bindings[2] = {}; bindings[0].binding = 0; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bindings[0].descriptorCount = 1; bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; bindings[0].pImmutableSamplers = &sampler; bindings[1].binding = 1; bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bindings[1].descriptorCount = 1; bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; VkDescriptorSetLayoutCreateInfo descSetLayoutCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; descSetLayoutCreateInfo.bindingCount = 2; descSetLayoutCreateInfo.pBindings = bindings; VkDescriptorSetLayout descSetLayout = nullptr; TEST( vkCreateDescriptorSetLayout(g_hDevice, &descSetLayoutCreateInfo, nullptr, &descSetLayout) == VK_SUCCESS ); VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pipelineLayoutCreateInfo.setLayoutCount = 1; pipelineLayoutCreateInfo.pSetLayouts = &descSetLayout; VkPipelineLayout pipelineLayout = nullptr; TEST( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout) == VK_SUCCESS ); std::vector<char> shaderCode; LoadShader(shaderCode, "SparseBindingTest.comp.spv"); VkShaderModuleCreateInfo shaderModuleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; shaderModuleCreateInfo.codeSize = shaderCode.size(); shaderModuleCreateInfo.pCode = (const uint32_t*)shaderCode.data(); VkShaderModule shaderModule = nullptr; TEST( vkCreateShaderModule(g_hDevice, &shaderModuleCreateInfo, nullptr, &shaderModule) == VK_SUCCESS ); VkComputePipelineCreateInfo pipelineCreateInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; pipelineCreateInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; pipelineCreateInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; pipelineCreateInfo.stage.module = shaderModule; pipelineCreateInfo.stage.pName = "main"; pipelineCreateInfo.layout = pipelineLayout; VkPipeline pipeline = nullptr; TEST( vkCreateComputePipelines(g_hDevice, nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline) == VK_SUCCESS ); VkDescriptorPoolSize poolSizes[2] = {}; poolSizes[0].type = bindings[0].descriptorType; poolSizes[0].descriptorCount = bindings[0].descriptorCount; poolSizes[1].type = bindings[1].descriptorType; poolSizes[1].descriptorCount = bindings[1].descriptorCount; VkDescriptorPoolCreateInfo descPoolCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; descPoolCreateInfo.maxSets = 1; descPoolCreateInfo.poolSizeCount = 2; descPoolCreateInfo.pPoolSizes = poolSizes; VkDescriptorPool descPool = nullptr; TEST( vkCreateDescriptorPool(g_hDevice, &descPoolCreateInfo, nullptr, &descPool) == VK_SUCCESS ); VkDescriptorSetAllocateInfo descSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; descSetAllocInfo.descriptorPool = descPool; descSetAllocInfo.descriptorSetCount = 1; descSetAllocInfo.pSetLayouts = &descSetLayout; VkDescriptorSet descSet = nullptr; TEST( vkAllocateDescriptorSets(g_hDevice, &descSetAllocInfo, &descSet) == VK_SUCCESS ); VkImageViewCreateInfo imageViewCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; imageViewCreateInfo.image = m_Image; imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.format = m_CreateInfo.format; imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageViewCreateInfo.subresourceRange.layerCount = 1; imageViewCreateInfo.subresourceRange.levelCount = 1; VkImageView imageView = nullptr; TEST( vkCreateImageView(g_hDevice, &imageViewCreateInfo, nullptr, &imageView) == VK_SUCCESS ); VkDescriptorImageInfo descImageInfo = {}; descImageInfo.imageView = imageView; descImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkDescriptorBufferInfo descBufferInfo = {}; descBufferInfo.buffer = dstBuf; descBufferInfo.offset = 0; descBufferInfo.range = VK_WHOLE_SIZE; VkWriteDescriptorSet descWrites[2] = {}; descWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descWrites[0].dstSet = descSet; descWrites[0].dstBinding = bindings[0].binding; descWrites[0].dstArrayElement = 0; descWrites[0].descriptorCount = 1; descWrites[0].descriptorType = bindings[0].descriptorType; descWrites[0].pImageInfo = &descImageInfo; descWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descWrites[1].dstSet = descSet; descWrites[1].dstBinding = bindings[1].binding; descWrites[1].dstArrayElement = 0; descWrites[1].descriptorCount = 1; descWrites[1].descriptorType = bindings[1].descriptorType; descWrites[1].pBufferInfo = &descBufferInfo; vkUpdateDescriptorSets(g_hDevice, 2, descWrites, 0, nullptr); BeginSingleTimeCommands(); vkCmdBindPipeline(g_hTemporaryCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); vkCmdBindDescriptorSets(g_hTemporaryCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, &descSet, 0, nullptr); vkCmdDispatch(g_hTemporaryCommandBuffer, valueCount, 1, 1); EndSingleTimeCommands(); // Validate dstBuf output data. { const uint32_t* dstBufContent = (const uint32_t*)dstBufAllocInfo.pMappedData; for(uint32_t i = 0; i < valueCount; ++i) { const uint32_t x = dstBufContent[i * 3 ]; const uint32_t y = dstBufContent[i * 3 + 1]; const uint32_t color = dstBufContent[i * 3 + 2]; const uint8_t a = (uint8_t)(color >> 24); const uint8_t b = (uint8_t)(color >> 16); const uint8_t g = (uint8_t)(color >> 8); const uint8_t r = (uint8_t)color; TEST(r == (uint8_t)x && g == (uint8_t)y && b == 13 && a == 25); } } vkDestroyImageView(g_hDevice, imageView, nullptr); vkDestroyDescriptorPool(g_hDevice, descPool, nullptr); vmaDestroyBuffer(g_hAllocator, dstBuf, dstBufAlloc); vkDestroyPipeline(g_hDevice, pipeline, nullptr); vkDestroyShaderModule(g_hDevice, shaderModule, nullptr); vkDestroyPipelineLayout(g_hDevice, pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(g_hDevice, descSetLayout, nullptr); vkDestroySampler(g_hDevice, sampler, nullptr); }
void Renderer::_InitGraphicsPipeline() { { // Create Vertex Shader Module std::vector<char> vert_shader_code = readFile(VERT_PATH); VkShaderModuleCreateInfo shader_module_create_info{}; shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_create_info.codeSize = vert_shader_code.size(); shader_module_create_info.pCode = (uint32_t *)vert_shader_code.data(); ErrorCheck(vkCreateShaderModule(_device, &shader_module_create_info, nullptr, &_vert_module)); } { // Create Fragment Shader Module std::vector<char> frag_shader_code = readFile(FRAG_PATH); VkShaderModuleCreateInfo shader_module_create_info{}; shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_create_info.codeSize = frag_shader_code.size(); shader_module_create_info.pCode = (uint32_t *)frag_shader_code.data(); ErrorCheck(vkCreateShaderModule(_device, &shader_module_create_info, nullptr, &_frag_module)); } VkPipelineShaderStageCreateInfo vert_shader_stage_create_info{}; vert_shader_stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vert_shader_stage_create_info.stage = VK_SHADER_STAGE_VERTEX_BIT; vert_shader_stage_create_info.module = _vert_module; vert_shader_stage_create_info.pName = "main"; VkPipelineShaderStageCreateInfo frag_shader_stage_create_info{}; frag_shader_stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; frag_shader_stage_create_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; frag_shader_stage_create_info.module = _frag_module; frag_shader_stage_create_info.pName = "main"; VkPipelineShaderStageCreateInfo shader_stages[] = { vert_shader_stage_create_info, frag_shader_stage_create_info }; VkVertexInputBindingDescription binding_description = Vertex::getBindingDescription(); std::array<VkVertexInputAttributeDescription, 3> attribute_descriptions = Vertex::getAttributeDescriptions(); VkPipelineVertexInputStateCreateInfo vertex_input_info_create_info{}; vertex_input_info_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_input_info_create_info.vertexBindingDescriptionCount = 1; vertex_input_info_create_info.pVertexBindingDescriptions = &binding_description; vertex_input_info_create_info.vertexAttributeDescriptionCount = (uint32_t)attribute_descriptions.size(); vertex_input_info_create_info.pVertexAttributeDescriptions = attribute_descriptions.data(); VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info{}; pipeline_input_assembly_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; pipeline_input_assembly_state_create_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; pipeline_input_assembly_state_create_info.primitiveRestartEnable = VK_FALSE; VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = (float)(_window->getWidth()); viewport.height = (float)(_window->getHeight()); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor{}; scissor.offset = { 0, 0 }; scissor.extent.width = _window->getWidth(); scissor.extent.height = _window->getHeight(); VkPipelineViewportStateCreateInfo pipeline_viewport_state_create_info{}; pipeline_viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; pipeline_viewport_state_create_info.viewportCount = 1; pipeline_viewport_state_create_info.pViewports = &viewport; pipeline_viewport_state_create_info.scissorCount = 1; pipeline_viewport_state_create_info.pScissors = &scissor; VkPipelineRasterizationStateCreateInfo rasterization_state_create_info{}; rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterization_state_create_info.depthClampEnable = VK_FALSE; rasterization_state_create_info.rasterizerDiscardEnable = VK_FALSE; rasterization_state_create_info.polygonMode = VK_POLYGON_MODE_FILL; rasterization_state_create_info.lineWidth = 1.0f; rasterization_state_create_info.cullMode = VK_CULL_MODE_BACK_BIT; rasterization_state_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterization_state_create_info.depthBiasEnable = VK_FALSE; rasterization_state_create_info.depthBiasConstantFactor = 0.0f; rasterization_state_create_info.depthBiasClamp = 0.0f; rasterization_state_create_info.depthBiasSlopeFactor = 0.0f; VkPipelineMultisampleStateCreateInfo pipeline_multisample_state_create_info{}; // Anti-Aliasing pipeline_multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; pipeline_multisample_state_create_info.sampleShadingEnable = VK_FALSE; pipeline_multisample_state_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; pipeline_multisample_state_create_info.minSampleShading = 1.0f; pipeline_multisample_state_create_info.pSampleMask = nullptr; pipeline_multisample_state_create_info.alphaToCoverageEnable = VK_FALSE; pipeline_multisample_state_create_info.alphaToOneEnable = VK_FALSE; VkPipelineColorBlendAttachmentState pipeline_color_blend_attachment_state{}; pipeline_color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; pipeline_color_blend_attachment_state.blendEnable = VK_FALSE; pipeline_color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; pipeline_color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; pipeline_color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; pipeline_color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; pipeline_color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; pipeline_color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; VkPipelineColorBlendStateCreateInfo pipeline_color_blend_state_create_info{}; pipeline_color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; pipeline_color_blend_state_create_info.logicOpEnable = VK_FALSE; pipeline_color_blend_state_create_info.logicOp = VK_LOGIC_OP_COPY; pipeline_color_blend_state_create_info.attachmentCount = 1; pipeline_color_blend_state_create_info.pAttachments = &pipeline_color_blend_attachment_state; pipeline_color_blend_state_create_info.blendConstants[0] = 0.0f; pipeline_color_blend_state_create_info.blendConstants[1] = 0.0f; pipeline_color_blend_state_create_info.blendConstants[2] = 0.0f; pipeline_color_blend_state_create_info.blendConstants[3] = 0.0f; VkPipelineDepthStencilStateCreateInfo depth_stencil{}; depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depth_stencil.depthTestEnable = VK_TRUE; depth_stencil.depthWriteEnable = VK_TRUE; depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; depth_stencil.depthBoundsTestEnable = VK_FALSE; depth_stencil.minDepthBounds = 0.0f; depth_stencil.maxDepthBounds = 1.0f; depth_stencil.stencilTestEnable = VK_FALSE; depth_stencil.front = {}; depth_stencil.back = {}; VkDescriptorSetLayout descriptor_set_layouts[] = { _descriptor_set_layout }; 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 = descriptor_set_layouts; pipeline_layout_create_info.pushConstantRangeCount = 0; pipeline_layout_create_info.pPushConstantRanges = 0; ErrorCheck(vkCreatePipelineLayout(_device, &pipeline_layout_create_info, nullptr, &_pipeline_layout)); VkGraphicsPipelineCreateInfo graphics_pipeline_create_info {}; graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; graphics_pipeline_create_info.stageCount = 2; // Shader stages graphics_pipeline_create_info.pStages = shader_stages; graphics_pipeline_create_info.pVertexInputState = &vertex_input_info_create_info; graphics_pipeline_create_info.pInputAssemblyState = &pipeline_input_assembly_state_create_info; graphics_pipeline_create_info.pViewportState = &pipeline_viewport_state_create_info; graphics_pipeline_create_info.pRasterizationState = &rasterization_state_create_info; graphics_pipeline_create_info.pMultisampleState = &pipeline_multisample_state_create_info; graphics_pipeline_create_info.pDepthStencilState = &depth_stencil; graphics_pipeline_create_info.pColorBlendState = &pipeline_color_blend_state_create_info; graphics_pipeline_create_info.pDynamicState = nullptr; graphics_pipeline_create_info.layout = _pipeline_layout; graphics_pipeline_create_info.renderPass = _render_pass; graphics_pipeline_create_info.subpass = 0; graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; graphics_pipeline_create_info.basePipelineIndex = -1; ErrorCheck(vkCreateGraphicsPipelines(_device, VK_NULL_HANDLE, 1, &graphics_pipeline_create_info, nullptr, &_graphics_pipeline)); }
bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() { VkResult err; VkShaderModule vert_module; VkShaderModule frag_module; // Create The Shader Modules: { VkShaderModuleCreateInfo vert_info = {}; vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vert_info.codeSize = __glsl_shader_vert_spv_len; vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module); ImGui_ImplGlfwVulkan_VkResult(err); VkShaderModuleCreateInfo frag_info = {}; frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; frag_info.codeSize = __glsl_shader_frag_spv_len; frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); ImGui_ImplGlfwVulkan_VkResult(err); } if (!g_FontSampler) { VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = VK_FILTER_LINEAR; info.minFilter = VK_FILTER_LINEAR; info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.minLod = -1000; info.maxLod = 1000; err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler); ImGui_ImplGlfwVulkan_VkResult(err); } if (!g_DescriptorSetLayout) { VkSampler sampler[1] = {g_FontSampler}; VkDescriptorSetLayoutBinding binding[1] = {}; binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; binding[0].descriptorCount = 1; binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; binding[0].pImmutableSamplers = sampler; VkDescriptorSetLayoutCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; info.bindingCount = 1; info.pBindings = binding; err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout); ImGui_ImplGlfwVulkan_VkResult(err); } // Create Descriptor Set: { VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorPool = g_DescriptorPool; alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &g_DescriptorSetLayout; err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet); ImGui_ImplGlfwVulkan_VkResult(err); } if (!g_PipelineLayout) { VkPushConstantRange push_constants[1] = {}; push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].offset = sizeof(float) * 0; push_constants[0].size = sizeof(float) * 4; VkDescriptorSetLayout set_layout[1] = {g_DescriptorSetLayout}; VkPipelineLayoutCreateInfo layout_info = {}; layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layout_info.setLayoutCount = 1; layout_info.pSetLayouts = set_layout; layout_info.pushConstantRangeCount = 1; layout_info.pPushConstantRanges = push_constants; err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout); ImGui_ImplGlfwVulkan_VkResult(err); } VkPipelineShaderStageCreateInfo stage[2] = {}; stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; stage[0].module = vert_module; stage[0].pName = "main"; stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; stage[1].module = frag_module; stage[1].pName = "main"; VkVertexInputBindingDescription binding_desc[1] = {}; binding_desc[0].stride = sizeof(ImDrawVert); binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkVertexInputAttributeDescription attribute_desc[3] = {}; attribute_desc[0].location = 0; attribute_desc[0].binding = binding_desc[0].binding; attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; attribute_desc[0].offset = (size_t)(&((ImDrawVert*)0)->pos); attribute_desc[1].location = 1; attribute_desc[1].binding = binding_desc[0].binding; attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; attribute_desc[1].offset = (size_t)(&((ImDrawVert*)0)->uv); attribute_desc[2].location = 2; attribute_desc[2].binding = binding_desc[0].binding; attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; attribute_desc[2].offset = (size_t)(&((ImDrawVert*)0)->col); VkPipelineVertexInputStateCreateInfo vertex_info = {}; vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_info.vertexBindingDescriptionCount = 1; vertex_info.pVertexBindingDescriptions = binding_desc; vertex_info.vertexAttributeDescriptionCount = 3; vertex_info.pVertexAttributeDescriptions = attribute_desc; VkPipelineInputAssemblyStateCreateInfo ia_info = {}; ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPipelineViewportStateCreateInfo viewport_info = {}; viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_info.viewportCount = 1; viewport_info.scissorCount = 1; VkPipelineRasterizationStateCreateInfo raster_info = {}; raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; raster_info.polygonMode = VK_POLYGON_MODE_FILL; raster_info.cullMode = VK_CULL_MODE_NONE; raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; raster_info.lineWidth = 1.0f; VkPipelineMultisampleStateCreateInfo ms_info = {}; ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_attachment[1] = {}; color_attachment[0].blendEnable = VK_TRUE; color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineDepthStencilStateCreateInfo depth_info = {}; depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; VkPipelineColorBlendStateCreateInfo blend_info = {}; blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; blend_info.attachmentCount = 1; blend_info.pAttachments = color_attachment; VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_state.dynamicStateCount = 2; dynamic_state.pDynamicStates = dynamic_states; VkGraphicsPipelineCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; info.flags = g_PipelineCreateFlags; info.stageCount = 2; info.pStages = stage; info.pVertexInputState = &vertex_info; info.pInputAssemblyState = &ia_info; info.pViewportState = &viewport_info; info.pRasterizationState = &raster_info; info.pMultisampleState = &ms_info; info.pDepthStencilState = &depth_info; info.pColorBlendState = &blend_info; info.pDynamicState = &dynamic_state; info.layout = g_PipelineLayout; info.renderPass = g_RenderPass; err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline); ImGui_ImplGlfwVulkan_VkResult(err); vkDestroyShaderModule(g_Device, vert_module, g_Allocator); vkDestroyShaderModule(g_Device, frag_module, g_Allocator); return true; }
// clang-format on int main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "SPIR-V Assembly"; const bool depthPresent = true; process_command_line_args(info, argc, argv); init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 500, 500); init_connection(info); init_window(info); init_swapchain_extension(info); init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info); init_depth_buffer(info); init_texture(info); init_uniform_buffer(info); init_descriptor_and_pipeline_layouts(info, true); init_renderpass(info, depthPresent); /* VULKAN_KEY_START */ // Init the assembler context spv_context spvContext = spvContextCreate(); // Convert the vertex assembly into binary format spv_binary vertexBinary = {}; spv_diagnostic vertexDiag = {}; spv_result_t vertexResult = spvTextToBinary(spvContext, vertexSPIRV.c_str(), vertexSPIRV.length(), &vertexBinary, &vertexDiag); if (vertexDiag) { printf("Diagnostic info from vertex shader:\n"); spvDiagnosticPrint(vertexDiag); } assert(vertexResult == SPV_SUCCESS); // Convert the fragment assembly into binary format spv_binary fragmentBinary = {}; spv_diagnostic fragmentDiag = {}; spv_result_t fragmentResult = spvTextToBinary(spvContext, fragmentSPIRV.c_str(), fragmentSPIRV.length(), &fragmentBinary, &fragmentDiag); if (fragmentDiag) { printf("Diagnostic info from fragment shader:\n"); spvDiagnosticPrint(fragmentDiag); } assert(fragmentResult == SPV_SUCCESS); info.shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; info.shaderStages[0].pNext = NULL; info.shaderStages[0].pSpecializationInfo = NULL; info.shaderStages[0].flags = 0; info.shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; info.shaderStages[0].pName = "main"; VkShaderModuleCreateInfo moduleCreateInfo; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.flags = 0; // Use wordCount and code pointers from the spv_binary moduleCreateInfo.codeSize = vertexBinary->wordCount * sizeof(unsigned int); moduleCreateInfo.pCode = vertexBinary->code; res = vkCreateShaderModule(info.device, &moduleCreateInfo, NULL, &info.shaderStages[0].module); assert(res == VK_SUCCESS); info.shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; info.shaderStages[1].pNext = NULL; info.shaderStages[1].pSpecializationInfo = NULL; info.shaderStages[1].flags = 0; info.shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; info.shaderStages[1].pName = "main"; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.flags = 0; // Use wordCount and code pointers from the spv_binary moduleCreateInfo.codeSize = fragmentBinary->wordCount * sizeof(unsigned int); moduleCreateInfo.pCode = fragmentBinary->code; res = vkCreateShaderModule(info.device, &moduleCreateInfo, NULL, &info.shaderStages[1].module); assert(res == VK_SUCCESS); // Clean up the diagnostics spvDiagnosticDestroy(vertexDiag); spvDiagnosticDestroy(fragmentDiag); // Clean up the assembler context spvContextDestroy(spvContext); /* VULKAN_KEY_END */ init_framebuffers(info, depthPresent); init_vertex_buffer(info, g_vb_texture_Data, sizeof(g_vb_texture_Data), sizeof(g_vb_texture_Data[0]), true); init_descriptor_pool(info, true); init_descriptor_set(info, true); init_pipeline_cache(info); init_pipeline(info, depthPresent); init_presentable_image(info); VkClearValue clear_values[2]; init_clear_color_and_depth(info, clear_values); VkRenderPassBeginInfo rp_begin; init_render_pass_begin_info(info, rp_begin); rp_begin.clearValueCount = 2; rp_begin.pClearValues = clear_values; vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); init_viewports(info); init_scissors(info); vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); vkCmdEndRenderPass(info.cmd); execute_pre_present_barrier(info); res = vkEndCommandBuffer(info.cmd); assert(res == VK_SUCCESS); VkFence drawFence = {}; init_fence(info, drawFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkSubmitInfo submit_info = {}; init_submit_info(info, submit_info, pipe_stage_flags); /* Queue the command buffer for execution */ res = vkQueueSubmit(info.queue, 1, &submit_info, drawFence); assert(res == VK_SUCCESS); /* Now present the image in the window */ VkPresentInfoKHR present = {}; init_present_info(info, present); /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); if (info.save_images) write_ppm(info, "spirv_assembly"); vkDestroyFence(info.device, drawFence, NULL); vkDestroySemaphore(info.device, info.presentCompleteSemaphore, NULL); destroy_pipeline(info); destroy_pipeline_cache(info); destroy_textures(info); destroy_descriptor_pool(info); destroy_vertex_buffer(info); destroy_framebuffers(info); destroy_shaders(info); destroy_renderpass(info); destroy_descriptor_and_pipeline_layouts(info); destroy_uniform_buffer(info); destroy_depth_buffer(info); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
int main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "Pipeline Derivative"; const bool depthPresent = true; process_command_line_args(info, argc, argv); init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 500, 500); init_connection(info); init_window(info); init_swapchain_extension(info); init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info); init_depth_buffer(info); init_texture(info); init_uniform_buffer(info); init_descriptor_and_pipeline_layouts(info, true); init_renderpass(info, depthPresent); init_shaders(info, vertShaderText, fragShaderText); init_framebuffers(info, depthPresent); init_vertex_buffer(info, g_vb_texture_Data, sizeof(g_vb_texture_Data), sizeof(g_vb_texture_Data[0]), true); init_descriptor_pool(info, true); init_descriptor_set(info, true); init_pipeline_cache(info); /* VULKAN_KEY_START */ // // Create two pipelines. // // First pipeline is the same as that generated by init_pipeline(), // but with VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT set. // // Second pipeline has a modified fragment shader and sets the // VK_PIPELINE_CREATE_DERIVATIVE_BIT flag. // bool include_depth = true; bool include_vi = true; VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE]; VkPipelineDynamicStateCreateInfo dynamicState = {}; memset(dynamicStateEnables, 0, sizeof dynamicStateEnables); dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.pNext = NULL; dynamicState.pDynamicStates = dynamicStateEnables; dynamicState.dynamicStateCount = 0; VkPipelineVertexInputStateCreateInfo vi; vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vi.pNext = NULL; vi.flags = 0; vi.vertexBindingDescriptionCount = 1; vi.pVertexBindingDescriptions = &info.vi_binding; vi.vertexAttributeDescriptionCount = 2; vi.pVertexAttributeDescriptions = info.vi_attribs; VkPipelineInputAssemblyStateCreateInfo ia; ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; ia.pNext = NULL; ia.flags = 0; ia.primitiveRestartEnable = VK_FALSE; ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPipelineRasterizationStateCreateInfo rs; rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs.pNext = NULL; rs.flags = 0; rs.polygonMode = VK_POLYGON_MODE_FILL; rs.cullMode = VK_CULL_MODE_BACK_BIT; rs.frontFace = VK_FRONT_FACE_CLOCKWISE; rs.depthClampEnable = include_depth; rs.rasterizerDiscardEnable = VK_FALSE; rs.depthBiasEnable = VK_FALSE; rs.depthBiasConstantFactor = 0; rs.depthBiasClamp = 0; rs.depthBiasSlopeFactor = 0; rs.lineWidth = 0; VkPipelineColorBlendStateCreateInfo cb; cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; cb.flags = 0; cb.pNext = NULL; VkPipelineColorBlendAttachmentState att_state[1]; att_state[0].colorWriteMask = 0xf; att_state[0].blendEnable = VK_FALSE; att_state[0].alphaBlendOp = VK_BLEND_OP_ADD; att_state[0].colorBlendOp = VK_BLEND_OP_ADD; att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; att_state[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; cb.attachmentCount = 1; cb.pAttachments = att_state; cb.logicOpEnable = VK_FALSE; cb.logicOp = VK_LOGIC_OP_NO_OP; cb.blendConstants[0] = 1.0f; cb.blendConstants[1] = 1.0f; cb.blendConstants[2] = 1.0f; cb.blendConstants[3] = 1.0f; VkPipelineViewportStateCreateInfo vp = {}; vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vp.pNext = NULL; vp.flags = 0; vp.viewportCount = NUM_VIEWPORTS; dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; vp.scissorCount = NUM_SCISSORS; dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; vp.pScissors = NULL; vp.pViewports = NULL; VkPipelineDepthStencilStateCreateInfo ds; ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; ds.pNext = NULL; ds.flags = 0; ds.depthTestEnable = include_depth; ds.depthWriteEnable = include_depth; ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; ds.depthBoundsTestEnable = VK_FALSE; ds.stencilTestEnable = VK_FALSE; ds.back.failOp = VK_STENCIL_OP_KEEP; ds.back.passOp = VK_STENCIL_OP_KEEP; ds.back.compareOp = VK_COMPARE_OP_ALWAYS; ds.back.compareMask = 0; ds.back.reference = 0; ds.back.depthFailOp = VK_STENCIL_OP_KEEP; ds.back.writeMask = 0; ds.minDepthBounds = 0; ds.maxDepthBounds = 0; ds.stencilTestEnable = VK_FALSE; ds.front = ds.back; VkPipelineMultisampleStateCreateInfo ms; ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; ms.pNext = NULL; ms.flags = 0; ms.pSampleMask = NULL; ms.rasterizationSamples = NUM_SAMPLES; ms.sampleShadingEnable = VK_FALSE; ms.alphaToCoverageEnable = VK_FALSE; ms.alphaToOneEnable = VK_FALSE; ms.minSampleShading = 0.0; VkGraphicsPipelineCreateInfo pipeline; pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline.pNext = NULL; pipeline.layout = info.pipeline_layout; pipeline.basePipelineHandle = VK_NULL_HANDLE; pipeline.basePipelineIndex = 0; // Specify that we will be creating a derivative of this pipeline. pipeline.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; pipeline.pVertexInputState = include_vi ? &vi : NULL; pipeline.pInputAssemblyState = &ia; pipeline.pRasterizationState = &rs; pipeline.pColorBlendState = &cb; pipeline.pTessellationState = NULL; pipeline.pMultisampleState = &ms; pipeline.pDynamicState = &dynamicState; pipeline.pViewportState = &vp; pipeline.pDepthStencilState = &ds; pipeline.pStages = info.shaderStages; pipeline.stageCount = 2; pipeline.renderPass = info.render_pass; pipeline.subpass = 0; // Create the base pipeline without storing it in the info struct // NOTE: If desired, we can add timing info around pipeline creation to // demonstrate any perf benefits to derivation. VkPipeline basePipeline; res = vkCreateGraphicsPipelines(info.device, info.pipelineCache, 1, &pipeline, NULL, &basePipeline); assert(res == VK_SUCCESS); // Now create the derivative pipeline, using a different fragment shader // This shader will shade the cube faces with interpolated colors // NOTE: If this step is too heavyweight to show any benefit of derivation, // then // create a pipeline that differs in some other, simpler way. const char *fragShaderText2 = "#version 450\n" "layout (location = 0) in vec2 texcoord;\n" "layout (location = 0) out vec4 outColor;\n" "void main() {\n" " outColor = vec4(texcoord.x, texcoord.y, " "1.0 - texcoord.x - texcoord.y, 1.0f);\n" "}\n"; // Convert GLSL to SPIR-V init_glslang(); std::vector<unsigned int> fragSpv; bool U_ASSERT_ONLY retVal = GLSLtoSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fragShaderText2, fragSpv); assert(retVal); finalize_glslang(); // Replace the module entry of info.shaderStages to change the fragment // shader vkDestroyShaderModule(info.device, info.shaderStages[1].module, NULL); VkShaderModuleCreateInfo moduleCreateInfo = {}; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.flags = 0; moduleCreateInfo.codeSize = fragSpv.size() * sizeof(unsigned int); moduleCreateInfo.pCode = fragSpv.data(); res = vkCreateShaderModule(info.device, &moduleCreateInfo, NULL, &info.shaderStages[1].module); assert(res == VK_SUCCESS); // Modify pipeline info to reflect derivation pipeline.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT; pipeline.basePipelineHandle = basePipeline; pipeline.basePipelineIndex = -1; // And create the derived pipeline, assigning to info.pipeline for use by // later helpers res = vkCreateGraphicsPipelines(info.device, info.pipelineCache, 1, &pipeline, NULL, &info.pipeline); assert(res == VK_SUCCESS); /* VULKAN_KEY_END */ init_presentable_image(info); VkClearValue clear_values[2]; init_clear_color_and_depth(info, clear_values); VkRenderPassBeginInfo rp_begin; init_render_pass_begin_info(info, rp_begin); rp_begin.clearValueCount = 2; rp_begin.pClearValues = clear_values; vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); init_viewports(info); init_scissors(info); vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); vkCmdEndRenderPass(info.cmd); execute_pre_present_barrier(info); res = vkEndCommandBuffer(info.cmd); assert(res == VK_SUCCESS); VkFence drawFence = {}; init_fence(info, drawFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkSubmitInfo submit_info = {}; init_submit_info(info, submit_info, pipe_stage_flags); /* Queue the command buffer for execution */ res = vkQueueSubmit(info.queue, 1, &submit_info, drawFence); assert(res == VK_SUCCESS); /* Now present the image in the window */ VkPresentInfoKHR present = {}; init_present_info(info, present); /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); if (info.save_images) write_ppm(info, "pipeline_derivative"); vkDestroyFence(info.device, drawFence, NULL); vkDestroySemaphore(info.device, info.presentCompleteSemaphore, NULL); vkDestroyPipeline(info.device, basePipeline, NULL); destroy_pipeline(info); destroy_pipeline_cache(info); destroy_textures(info); destroy_descriptor_pool(info); destroy_vertex_buffer(info); destroy_framebuffers(info); destroy_shaders(info); destroy_renderpass(info); destroy_descriptor_and_pipeline_layouts(info); destroy_uniform_buffer(info); destroy_depth_buffer(info); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
DWORD game_loop_main(LPVOID thread_input) { struct common_vars common_vars = *(struct common_vars *)thread_input; profiler profiler = {}; profiler_create(&profiler); LARGE_INTEGER performance_frequency = {}; QueryPerformanceFrequency(&performance_frequency); memory_arena memory_arena = {}; if (!virtual_alloc_memory_arena(m_megabytes(16), common_vars.system_info.dwPageSize, &memory_arena)) { m_die("call to \"virtual_alloc_memory_arena\" failed(event_render_loop_thread memory arena)"); } vulkan vulkan = {}; { m_memory_arena_undo_allocations_at_scope_exit(&memory_arena); string info_string = { memory_arena_allocate<char>(&memory_arena, m_kilobytes(4)), 0, m_kilobytes(2) }; string err_string = { memory_arena_allocate<char>(&memory_arena, m_kilobytes(1)), 0, m_kilobytes(1) }; vulkan_create_info vulkan_create_info = {}; vulkan_create_info.win32_instance = common_vars.instance; vulkan_create_info.win32_window = common_vars.window; const char *shader_file_paths[] = { "shaders\\swap_chain_pipeline_image.vert.spv", "shaders\\swap_chain_pipeline_image.frag.spv" }; if (!read_file_into_memory_arena(shader_file_paths[0], &memory_arena, &vulkan_create_info.swap_chain_pipeline_image_code[0], &vulkan_create_info.swap_chain_pipeline_image_code_sizes[0]) || !read_file_into_memory_arena(shader_file_paths[1], &memory_arena, &vulkan_create_info.swap_chain_pipeline_image_code[1], &vulkan_create_info.swap_chain_pipeline_image_code_sizes[1])) { m_die("call to \"read_file_into_memory_arena\" failed(swap_chain_pipeline_image shaders)"); } if (!vulkan_create(vulkan_create_info, &memory_arena, &info_string, &err_string, &vulkan)) { m_die("%s", err_string.buf); } else { m_printf("%s", info_string.buf); } } game_buffer game_buffer = {}; vec4 game_buffer_viewport = {}; HANDLE game_buffer_gpk_file_handle = nullptr; HANDLE game_buffer_gpk_file_mapping = nullptr; void *game_buffer_gpk_file_mapping_ptr = nullptr; HANDLE game_buffer_mpk_import_shared_memory_mapping = nullptr; void *game_buffer_mpk_import_shared_memory_mapping_ptr = nullptr; HANDLE game_buffer_mpk_import_shared_memory_semaphore = nullptr; { game_buffer_create_info game_buffer_create_info = {}; if (!virtual_alloc_memory_arena(m_megabytes(512), common_vars.system_info.dwPageSize, &game_buffer_create_info.memory_arena)) { m_die("call to \"virtual_alloc_memory_arena\" failed(game buffer memory arena)"); } game_buffer_create_info.vulkan = &vulkan; game_buffer_create_info.vulkan_framebuffer_width = 1920; game_buffer_create_info.vulkan_framebuffer_height = 1080; if (!game_buffer_create(game_buffer_create_info, &game_buffer)) { m_die("call to \"game_buffer_create\" failed"); } #ifdef EDITOR_ENABLE game_buffer_editor_create_info game_buffer_editor_create_info = {}; game_buffer_editor_create_info.game_buffer = &game_buffer; game_buffer_editor_create_info.vulkan = &vulkan; game_buffer_editor_create_info.imgui_init_file = "assets\\gpks\\example.gpk.imgui.ini"; game_buffer_editor_create_info.imgui_font_file = "assets\\fonts\\OpenSans-Regular.ttf"; game_buffer_editor_create_info.imgui_font_size = GetSystemMetrics(SM_CXSCREEN) / 150; game_buffer_editor_create_info.set_imgui_keymap = [] (ImGuiIO *imgui_io) { imgui_io->KeyMap[ImGuiKey_Tab] = VK_TAB; imgui_io->KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; imgui_io->KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; imgui_io->KeyMap[ImGuiKey_UpArrow] = VK_UP; imgui_io->KeyMap[ImGuiKey_DownArrow] = VK_DOWN; imgui_io->KeyMap[ImGuiKey_PageUp] = VK_PRIOR; imgui_io->KeyMap[ImGuiKey_PageDown] = VK_NEXT; imgui_io->KeyMap[ImGuiKey_Home] = VK_HOME; imgui_io->KeyMap[ImGuiKey_End] = VK_END; imgui_io->KeyMap[ImGuiKey_Backspace] = VK_BACK; imgui_io->KeyMap[ImGuiKey_Enter] = VK_RETURN; imgui_io->KeyMap[ImGuiKey_Escape] = VK_ESCAPE; imgui_io->KeyMap[ImGuiKey_A] = 'A'; imgui_io->KeyMap[ImGuiKey_C] = 'C'; imgui_io->KeyMap[ImGuiKey_V] = 'V'; imgui_io->KeyMap[ImGuiKey_X] = 'X'; imgui_io->KeyMap[ImGuiKey_Y] = 'Y'; imgui_io->KeyMap[ImGuiKey_Z] = 'Z'; }; { m_memory_arena_undo_allocations_at_scope_exit(&memory_arena); const char *file_paths[] = { "shaders\\imgui.vert.spv", "shaders\\imgui.frag.spv" }; VkShaderModule shader_modules[m_countof(file_paths)] = {}; for (uint i = 0; i < m_countof(file_paths); i += 1) { void *file_data; uint file_size; if (!read_file_into_memory_arena(file_paths[i], &memory_arena, &file_data, &file_size)) { m_die("call to \"read_file_into_memory_arena\" failed(game buffer shader files)"); } VkShaderModuleCreateInfo shader_module_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; shader_module_info.codeSize = file_size; shader_module_info.pCode = (const uint32_t *)file_data; if(vkCreateShaderModule(vulkan.device, &shader_module_info, nullptr, &shader_modules[i]) != VK_SUCCESS) { m_die("game buffer creation failed\ncall to \"vkCreateShaderModule\" failed for shader file %s", file_paths[i]); } } game_buffer_editor_create_info.imgui_vulkan_shaders[0] = shader_modules[0]; game_buffer_editor_create_info.imgui_vulkan_shaders[1] = shader_modules[1]; } game_buffer.editor = memory_arena_allocate<game_buffer_editor>(&game_buffer.memory_arena, 1); *game_buffer.editor = {}; if (!game_buffer_editor_create(&game_buffer_editor_create_info, game_buffer.editor)) { m_die("call to \"game_buffer_editor_create\" failed"); } { uint shared_memory_size = m_megabytes(32); HANDLE shared_memory_mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE | SEC_COMMIT, 0, shared_memory_size, m_mpk_import_shared_memory_name); if (!shared_memory_mapping) { m_last_error_str(err_str); m_die("call to \"CreateFileMappingA\" failed\nfile: %s\nerr: %s", m_mpk_import_shared_memory_name, err_str); } void *shared_memory_mapping_ptr = MapViewOfFile(shared_memory_mapping, FILE_MAP_WRITE, 0, 0, shared_memory_size); if (!shared_memory_mapping_ptr) { m_last_error_str(err_str); m_die("call to \"MapViewOfFile\" failed\nfile: %s\nerr: %s", m_mpk_import_shared_memory_name, err_str); } ((mpk_import_shared_memory_header *)shared_memory_mapping_ptr)->total_size = shared_memory_size; ((mpk_import_shared_memory_header *)shared_memory_mapping_ptr)->mpk_size = shared_memory_size - sizeof(struct mpk_import_shared_memory_header); SetLastError(ERROR_SUCCESS); HANDLE shared_memory_semaphore = CreateSemaphore(nullptr, 1, 1, m_mpk_import_shared_memory_semaphore_name); if (!shared_memory_semaphore) { m_last_error_str(err_str); m_die("call to \"CreateSemaphore\" failed\nsemaphore: %s\nerr: %s", m_mpk_import_shared_memory_semaphore_name, err_str); } if (GetLastError() == ERROR_ALREADY_EXISTS) { m_die("call to \"CreateSemaphore\" failed\nsemaphore: %s\nerr: %s", m_mpk_import_shared_memory_semaphore_name, "named semaphore already exist"); } game_buffer_mpk_import_shared_memory_mapping = shared_memory_mapping; game_buffer_mpk_import_shared_memory_mapping_ptr = shared_memory_mapping_ptr; game_buffer_mpk_import_shared_memory_semaphore = shared_memory_semaphore; } { game_buffer_editor_job *new_job = nullptr; if (game_buffer_editor_add_mpk_job(&game_buffer, &new_job)) { mpk_import_command_line cmdl = m_mpk_import_command_line_default; cmdl.job_id = new_job->id; cmdl.import_type = mpk_import_type_fbx; strcpy(cmdl.fbx_file_path, "assets\\models\\simple_man\\simple_man.fbx"); mpk_import_create_process(&cmdl, common_vars.process_group, &memory_arena); } } #endif // EDITOR_ENABLE { char gpk_file_name[] = "assets\\gpks\\example.gpk"; HANDLE gpk_file_handle = CreateFileA(gpk_file_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (gpk_file_handle == INVALID_HANDLE_VALUE) { m_last_error_str(err_str); m_die("call to \"CreateFile\" failed\nfile: %s\nerr: %s", gpk_file_name, err_str); } uint file_size = m_megabytes(32); SetFilePointer(gpk_file_handle, file_size, nullptr, FILE_BEGIN); if (!SetEndOfFile(gpk_file_handle)) { m_last_error_str(err_str); m_die("call to \"SetEndOfFile\" failed\nfile: %s\nsize: %d\nerr: %s", gpk_file_name, file_size, err_str); } HANDLE gpk_file_mapping = CreateFileMappingA(gpk_file_handle, nullptr, PAGE_READWRITE, 0, 0, nullptr); if (!gpk_file_mapping) { m_last_error_str(err_str); m_die("call to \"CreateFileMappingA\" failed\nfile: %s\nerr: %s", gpk_file_name, err_str); } void *gpk_file_mapping_ptr = MapViewOfFile(gpk_file_mapping, FILE_MAP_WRITE, 0, 0, file_size); if (!gpk_file_mapping_ptr) { m_last_error_str(err_str); m_die("call to \"MapViewOfFile\" failed\nfile: %s\nerr: %s", gpk_file_name, err_str); } uint gpk_file_initial_state_size = 0; if (!gpk_write_initial_state(gpk_file_mapping_ptr, file_size, &gpk_file_initial_state_size)) { m_die("call to \"gpk_write_initial_state\" failed"); } if (!FlushViewOfFile(gpk_file_mapping_ptr, gpk_file_initial_state_size)) { m_last_error_str(err_str); m_die("call to \"FlushViewOfFile\" failed\nfile: %s\nerr: %s", gpk_file_name, err_str); } game_buffer_gpk_file_handle = gpk_file_handle; game_buffer_gpk_file_mapping = gpk_file_mapping; game_buffer_gpk_file_mapping_ptr = gpk_file_mapping_ptr; } { game_buffer_update_vulkan_swap_chain_image(&game_buffer, &vulkan); game_buffer_viewport = rectangle_fit_into_viewport((float)vulkan.swap_chain_info.imageExtent.width, (float)vulkan.swap_chain_info.imageExtent.height, (float)game_buffer.vulkan_framebuffer_image_width, (float)game_buffer.vulkan_framebuffer_image_height); } } uint64 last_frame_time_microsecs = 0; bool mouse_down_up_same_frame[3] = {}; for (;;) { LARGE_INTEGER frame_begin_performance_count; QueryPerformanceCounter(&frame_begin_performance_count); m_scope_exit( LARGE_INTEGER frame_end_performance_count; QueryPerformanceCounter(&frame_end_performance_count); last_frame_time_microsecs = (frame_end_performance_count.QuadPart - frame_begin_performance_count.QuadPart) * 1000000 / performance_frequency.QuadPart; ); { bool mouse_down_this_frame[3] = {}; for (uint i = 0; i < 3; i += 1) { if (mouse_down_up_same_frame[i]) { mouse_down_up_same_frame[i] = false; #ifdef EDITOR_ENABLE game_buffer_editor_handle_mouse_up(&game_buffer, i); #endif } } HANDLE iocp = common_vars.io_completion_port; DWORD iocp_num_bytes = 0; ULONG_PTR iocp_completion_key = 0; LPOVERLAPPED iocp_overlapped = nullptr; DWORD iocp_time_out = 0; while (GetQueuedCompletionStatus(iocp, &iocp_num_bytes, &iocp_completion_key, &iocp_overlapped, iocp_time_out) == TRUE) { switch (iocp_completion_key) { case quit_win_main_event : { #ifdef EDITOR_ENABLE ImGui::Shutdown(); #endif ExitThread(0); } break; case window_resize_event : { uint32 new_width = LOWORD((LPARAM)iocp_overlapped); uint32 new_height = HIWORD((LPARAM)iocp_overlapped); if (vulkan.swap_chain_info.imageExtent.width != new_width || vulkan.swap_chain_info.imageExtent.height != new_height) { if (!vulkan_resize_swap_chain_images(&vulkan, new_width, new_height)) { m_die("call to \"vulkan_resize_swap_chain_images\" failed"); } game_buffer_viewport = rectangle_fit_into_viewport((float)vulkan.swap_chain_info.imageExtent.width, (float)vulkan.swap_chain_info.imageExtent.height, (float)game_buffer.vulkan_framebuffer_image_width, (float)game_buffer.vulkan_framebuffer_image_height); } } break; case key_down_event : { } break; case key_up_event : { } break; case mouse_move_event : { #ifdef EDITOR_ENABLE game_buffer_editor_handle_mouse_move(&game_buffer, game_buffer_viewport, LOWORD((LPARAM)iocp_overlapped), HIWORD((LPARAM)iocp_overlapped)); #endif } break; case mouse_lbutton_down_event : { mouse_down_this_frame[0] = true; #ifdef EDITOR_ENABLE game_buffer_editor_handle_mouse_down(&game_buffer, 0); #endif } break; case mouse_lbutton_up_event : { if (mouse_down_this_frame[0]) { mouse_down_up_same_frame[0] = true; } else { #ifdef EDITOR_ENABLE game_buffer_editor_handle_mouse_up(&game_buffer, 0); #endif } } break; case mouse_rbutton_down_event : { mouse_down_this_frame[1] = true; #ifdef EDITOR_ENABLE game_buffer_editor_handle_mouse_down(&game_buffer, 1); #endif } break; case mouse_rbutton_up_event : { if (mouse_down_this_frame[1]) { mouse_down_up_same_frame[1] = true; } else { #ifdef EDITOR_ENABLE game_buffer_editor_handle_mouse_up(&game_buffer, 1); #endif } } break; case mpk_import_named_pipe_event : { #ifdef EDITOR_ENABLE mpk_import_named_pipe_instance *named_pipe_instance = (mpk_import_named_pipe_instance *)iocp_overlapped; if (named_pipe_instance->connected) { m_printf("got message %d bytes: %s\n", iocp_num_bytes, named_pipe_instance->message.msg); game_buffer_editor_handle_mpk_import_message(&game_buffer, &named_pipe_instance->message); if (named_pipe_instance->message.type == mpk_import_named_pipe_message_type_done) { void *mpk_ptr = ((struct mpk_import_shared_memory_header *)game_buffer_mpk_import_shared_memory_mapping_ptr) + 1; struct mpk_header *mpk_header_ptr = (struct mpk_header *)mpk_ptr; ReleaseSemaphore(game_buffer_mpk_import_shared_memory_semaphore, 1, nullptr); } ReadFile(named_pipe_instance->handle, &named_pipe_instance->message, sizeof(named_pipe_instance->message), nullptr, &named_pipe_instance->overlapped); } else { m_printf("new named pipe instance connected\n"); named_pipe_instance->connected = true; ReadFile(named_pipe_instance->handle, &named_pipe_instance->message, sizeof(named_pipe_instance->message), nullptr, &named_pipe_instance->overlapped); mpk_import_add_named_pipe_instance(&common_vars); } #else m_die("game loop main: received event \"mpk_import_named_pipe_event\", but editor is not enabled"); #endif } break; default : { m_die("game loop main: call to \"GetQueuedCompletionStatus\" returned an invalid event"); } break; } } } #ifdef EDITOR_ENABLE game_buffer.editor->imgui_io->DeltaTime = (float)(last_frame_time_microsecs / 1000000.0); ImGui::NewFrame(); game_buffer_editor_imgui_new_frame(&game_buffer, &vulkan); #endif { VkResult vk_result = {}; vkWaitForFences(vulkan.device, 1, &vulkan.swap_chain_fence, VK_TRUE, UINT64_MAX); vkResetFences(vulkan.device, 1, &vulkan.swap_chain_fence); uint swap_chain_image_index = 0; if ((vk_result = vkAcquireNextImageKHR(vulkan.device, vulkan.swap_chain, UINT64_MAX, vulkan.swap_chain_image_semaphore, VK_NULL_HANDLE, &swap_chain_image_index)) != VK_SUCCESS) { m_die("call to \"vkAcquireNextImageKHR\" failed"); } VkCommandBufferBeginInfo cmd_buffer_begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; cmd_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(vulkan.swap_chain_cmd_buffer, &cmd_buffer_begin_info); game_buffer_record_vulkan_commands(&game_buffer, &vulkan); vulkan_record_swap_chain_commands(&vulkan, swap_chain_image_index, game_buffer_viewport); vkEndCommandBuffer(vulkan.swap_chain_cmd_buffer); VkSubmitInfo queue_submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; queue_submit_info.waitSemaphoreCount = 1; queue_submit_info.pWaitSemaphores = &vulkan.swap_chain_image_semaphore; VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; queue_submit_info.pWaitDstStageMask = &wait_dst_stage_mask; queue_submit_info.commandBufferCount = 1; queue_submit_info.pCommandBuffers = &vulkan.swap_chain_cmd_buffer; queue_submit_info.signalSemaphoreCount = 1; queue_submit_info.pSignalSemaphores = &vulkan.swap_chain_queue_semaphore; if ((vk_result = vkQueueSubmit(vulkan.device_queue, 1, &queue_submit_info, vulkan.swap_chain_fence)) != VK_SUCCESS) { m_die("call to \"vkQueueSubmit\" failed"); } VkPresentInfoKHR device_queue_present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; device_queue_present_info.waitSemaphoreCount = 1; device_queue_present_info.pWaitSemaphores = &vulkan.swap_chain_queue_semaphore; device_queue_present_info.swapchainCount = 1; device_queue_present_info.pSwapchains = &vulkan.swap_chain; device_queue_present_info.pImageIndices = &swap_chain_image_index; if ((vk_result = vkQueuePresentKHR(vulkan.device_queue, &device_queue_present_info)) != VK_SUCCESS) { m_die("call to \"vkQueuePresentKHR\" failed"); } } }
void VulkanGpuProgram::initialize() { if (!isSupported()) { mIsCompiled = false; mCompileMessages = "Specified program is not supported by the current render system."; GpuProgram::initialize(); return; } if(!mBytecode || mBytecode->compilerId != VULKAN_COMPILER_ID || mBytecode->compilerVersion != VULKAN_COMPILER_VERSION) { GPU_PROGRAM_DESC desc; desc.type = mType; desc.entryPoint = mEntryPoint; desc.language = "vksl"; desc.source = mSource; mBytecode = compileBytecode(desc); } mCompileMessages = mBytecode->messages; mIsCompiled = mBytecode->instructions.data != nullptr; if(mIsCompiled) { VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance()); VulkanDevice* devices[BS_MAX_DEVICES]; // Create Vulkan module VkShaderModuleCreateInfo moduleCI; moduleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCI.pNext = nullptr; moduleCI.flags = 0; moduleCI.codeSize = mBytecode->instructions.size; moduleCI.pCode = (uint32_t*)mBytecode->instructions.data; VulkanUtility::getDevices(rapi, mDeviceMask, devices); for (UINT32 i = 0; i < BS_MAX_DEVICES; i++) { if (devices[i] != nullptr) { VkDevice vkDevice = devices[i]->getLogical(); VulkanResourceManager& rescManager = devices[i]->getResourceManager(); VkShaderModule shaderModule; VkResult result = vkCreateShaderModule(vkDevice, &moduleCI, gVulkanAllocator, &shaderModule); assert(result == VK_SUCCESS); mModules[i] = rescManager.create<VulkanShaderModule>(shaderModule); } } mParametersDesc = mBytecode->paramDesc; if (mType == GPT_VERTEX_PROGRAM) { mInputDeclaration = HardwareBufferManager::instance().createVertexDeclaration( mBytecode->vertexInput, mDeviceMask); } } BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram); GpuProgram::initialize(); }