#include "fiko/render/boru_hatti.hpp" #include #include #include "fiko/render/vk_kontrol.hpp" #include "fiko/render/vulkan_baglam.hpp" namespace fiko { namespace { std::vector spvOku(const std::string& yol) { std::ifstream dosya(yol, std::ios::binary | std::ios::ate); FIKO_ASSERT(dosya.is_open(), "SPIR-V dosyasi acilamadi"); const auto bayt = (size_t)dosya.tellg(); std::vector veri(bayt / 4); dosya.seekg(0); dosya.read(reinterpret_cast(veri.data()), (std::streamsize)bayt); return veri; } VkShaderModule modulOlustur(VkDevice aygit, const std::vector& kod) { VkShaderModuleCreateInfo bilgi{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; bilgi.codeSize = kod.size() * 4; bilgi.pCode = kod.data(); VkShaderModule m; VK_KONTROL(vkCreateShaderModule(aygit, &bilgi, nullptr, &m)); return m; } } BoruHatti::BoruHatti(VulkanBaglam& vb, const BoruHattiAyar& ayar) : aygit_(vb.aygit()) { VkPushConstantRange itme{}; itme.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; itme.size = ayar.itmeSabitBayt; VkPipelineLayoutCreateInfo yerlesimBilgi{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; if (ayar.itmeSabitBayt > 0) { yerlesimBilgi.pushConstantRangeCount = 1; yerlesimBilgi.pPushConstantRanges = &itme; } VkDescriptorSetLayout setler[2]{ayar.setYerlesim, ayar.setYerlesim2}; if (ayar.setYerlesim != VK_NULL_HANDLE) { // null → setLayoutCount 0 (mevcut hatlar aynen) yerlesimBilgi.setLayoutCount = ayar.setYerlesim2 != VK_NULL_HANDLE ? 2u : 1u; yerlesimBilgi.pSetLayouts = setler; } VK_KONTROL(vkCreatePipelineLayout(aygit_, &yerlesimBilgi, nullptr, &yerlesim_)); const VkShaderModule vert = modulOlustur(aygit_, spvOku(ayar.vertexSpv)); const VkShaderModule frag = modulOlustur(aygit_, spvOku(ayar.fragmentSpv)); VkPipelineShaderStageCreateInfo asamalar[2]{}; asamalar[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; asamalar[0].stage = VK_SHADER_STAGE_VERTEX_BIT; asamalar[0].module = vert; asamalar[0].pName = "main"; asamalar[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; asamalar[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; asamalar[1].module = frag; asamalar[1].pName = "main"; VkVertexInputBindingDescription baglamalar[2] = { {0, ayar.vertexAdim, VK_VERTEX_INPUT_RATE_VERTEX}, {1, ayar.ikinciAdim, VK_VERTEX_INPUT_RATE_VERTEX}}; VkPipelineVertexInputStateCreateInfo girdi{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; if (ayar.vertexAdim > 0) { girdi.vertexBindingDescriptionCount = ayar.ikinciAdim > 0 ? 2u : 1u; girdi.pVertexBindingDescriptions = baglamalar; girdi.vertexAttributeDescriptionCount = (u32)ayar.nitelikler.size(); girdi.pVertexAttributeDescriptions = ayar.nitelikler.data(); } VkPipelineInputAssemblyStateCreateInfo birlestir{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; birlestir.topology = ayar.topoloji; VkPipelineViewportStateCreateInfo gorunumAlan{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; gorunumAlan.viewportCount = 1; gorunumAlan.scissorCount = 1; VkPipelineRasterizationStateCreateInfo tarama{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; tarama.polygonMode = VK_POLYGON_MODE_FILL; tarama.cullMode = ayar.ayiklama; tarama.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; tarama.lineWidth = ayar.cizgiKalinlik; if (ayar.derinlikEgim) { tarama.depthBiasEnable = VK_TRUE; // Reverse-Z: kameraya doğru = derinlik ARTAR (near→1) → bias işareti ters (+). tarama.depthBiasConstantFactor = 1.5f; // kameraya dogru: kenarlar yuzeyin onune tarama.depthBiasSlopeFactor = 1.5f; } else if (ayar.derinlikItme != 0.0f) { tarama.depthBiasEnable = VK_TRUE; // Reverse-Z: "geriye it" = derinlik AZALT → dışarıdan gelen işaret ters uygulanır. tarama.depthBiasConstantFactor = -ayar.derinlikItme; // pozitif girdi: kameradan uzaga tarama.depthBiasSlopeFactor = -ayar.derinlikItme; } VkPipelineMultisampleStateCreateInfo ornekleme{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; // Yalnız offscreen 3B sahne geçişine (viewportGecis) çizen pipeline'lar MSAA örnek // sayısını alır — render pass'in gerçek örnek sayısıyla EŞLEŞMEK ZORUNDA (aksi halde // doğrulama katmanı reddeder). Swapchain/gölge haritası/ID-pick gibi diğer tüm // geçişler her zaman 1 örnek (o geçişler hiç MSAA'lı kurulmuyor). const VkRenderPass hedefGecis = ayar.gecis ? ayar.gecis : vb.renderPass(); ornekleme.rasterizationSamples = (hedefGecis == vb.viewportGecis()) ? VulkanAygit::msaaOrnekSayisi() : VK_SAMPLE_COUNT_1_BIT; VkPipelineDepthStencilStateCreateInfo derinlik{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; derinlik.depthTestEnable = ayar.derinlikTest ? VK_TRUE : VK_FALSE; derinlik.depthWriteEnable = ayar.derinlikYaz ? VK_TRUE : VK_FALSE; derinlik.depthCompareOp = VK_COMPARE_OP_GREATER_OR_EQUAL; // reverse-Z (yakın→1) if (ayar.stencilTest) { derinlik.stencilTestEnable = VK_TRUE; VkStencilOpState on{}; on.failOp = VK_STENCIL_OP_KEEP; on.depthFailOp = VK_STENCIL_OP_KEEP; on.passOp = ayar.stencilGecOp; on.compareOp = ayar.stencilKarsOp; on.compareMask = 0xFF; on.writeMask = ayar.stencilYazMask; on.reference = ayar.stencilRef; VkStencilOpState arka = on; arka.passOp = ayar.stencilArkaGecOp; derinlik.front = on; derinlik.back = arka; } VkPipelineColorBlendAttachmentState harman{}; harman.colorWriteMask = ayar.renkYaz ? (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT) : 0; if (ayar.harmanEkleyici) { harman.blendEnable = VK_TRUE; harman.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; harman.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; harman.colorBlendOp = VK_BLEND_OP_ADD; harman.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; harman.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; harman.alphaBlendOp = VK_BLEND_OP_ADD; } else if (ayar.harmanla) { harman.blendEnable = VK_TRUE; harman.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; harman.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; harman.colorBlendOp = VK_BLEND_OP_ADD; harman.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; harman.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; harman.alphaBlendOp = VK_BLEND_OP_ADD; } VkPipelineColorBlendStateCreateInfo renk{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; renk.attachmentCount = ayar.renkEkiSayisi; // 0 → derinlik-only gecis (golge haritasi) renk.pAttachments = ayar.renkEkiSayisi ? &harman : nullptr; const VkDynamicState dinamikler[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; VkPipelineDynamicStateCreateInfo dinamik{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; dinamik.dynamicStateCount = 2; dinamik.pDynamicStates = dinamikler; VkGraphicsPipelineCreateInfo bilgi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; bilgi.stageCount = 2; bilgi.pStages = asamalar; bilgi.pVertexInputState = &girdi; bilgi.pInputAssemblyState = &birlestir; bilgi.pViewportState = &gorunumAlan; bilgi.pRasterizationState = &tarama; bilgi.pMultisampleState = &ornekleme; bilgi.pDepthStencilState = &derinlik; bilgi.pColorBlendState = &renk; bilgi.pDynamicState = &dinamik; bilgi.layout = yerlesim_; bilgi.renderPass = ayar.gecis ? ayar.gecis : vb.renderPass(); bilgi.subpass = 0; VK_KONTROL(vkCreateGraphicsPipelines(aygit_, VK_NULL_HANDLE, 1, &bilgi, nullptr, &hat_)); vkDestroyShaderModule(aygit_, vert, nullptr); vkDestroyShaderModule(aygit_, frag, nullptr); } BoruHatti& BoruHatti::operator=(BoruHatti&& o) noexcept { if (this != &o) { if (hat_) vkDestroyPipeline(aygit_, hat_, nullptr); if (yerlesim_) vkDestroyPipelineLayout(aygit_, yerlesim_, nullptr); aygit_ = o.aygit_; yerlesim_ = std::exchange(o.yerlesim_, VK_NULL_HANDLE); hat_ = std::exchange(o.hat_, VK_NULL_HANDLE); } return *this; } BoruHatti::~BoruHatti() { if (hat_) vkDestroyPipeline(aygit_, hat_, nullptr); if (yerlesim_) vkDestroyPipelineLayout(aygit_, yerlesim_, nullptr); } void BoruHatti::bagla(VkCommandBuffer kb) const { vkCmdBindPipeline(kb, VK_PIPELINE_BIND_POINT_GRAPHICS, hat_); } void BoruHatti::itmeSabitYaz(VkCommandBuffer kb, const void* veri, u32 bayt) const { vkCmdPushConstants(kb, yerlesim_, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, bayt, veri); } void BoruHatti::setBagla(VkCommandBuffer kb, VkDescriptorSet set, u32 indeks) const { if (set == VK_NULL_HANDLE) return; vkCmdBindDescriptorSets(kb, VK_PIPELINE_BIND_POINT_GRAPHICS, yerlesim_, indeks, 1, &set, 0, nullptr); } }