#include "isin_alani.hpp" #include "fiko/core/gunluk.hpp" #include "fiko/render/vulkan_baglam.hpp" #include "fiko/sahne/isin_bvh.hpp" namespace fiko { namespace { // GPU düğüm yerleşimi (32B, std430 hizalı): min.xyz + a, max.xyz + bYaprak. // bYaprak'ın en yüksek biti yaprak bayrağı, kalan 31 bit b (çocuk/üçgen sayısı). struct GpuDal { f32 minX, minY, minZ; u32 a; f32 maksX, maksY, maksZ; u32 bYaprak; }; constexpr u32 kYaprakBit = 0x80000000u; // Kalinlik sinifi (32B, std430): sinir = (min, max, nominal, tolerans), renk = rgb. struct GpuBant { f32 mn, mx, nominal, tolerans; f32 r, g, b, pad; }; } // namespace IsinAlani::IsinAlani(VulkanBaglam& vb) : vb_(vb) { const VkDevice aygit = vb_.aygit(); VkDescriptorSetLayoutBinding bag[3]{}; for (u32 i = 0; i < 3; ++i) { bag[i].binding = i; bag[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bag[i].descriptorCount = 1; bag[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; } VkDescriptorSetLayoutCreateInfo dsl{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; dsl.bindingCount = 3; dsl.pBindings = bag; if (vkCreateDescriptorSetLayout(aygit, &dsl, nullptr, &dsYerlesim_) != VK_SUCCESS) { gunluk::hata("IsinAlani: descriptor yerlesimi kurulamadi"); return; } VkDescriptorPoolSize havuz{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3}; VkDescriptorPoolCreateInfo hb{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; hb.maxSets = 1; hb.poolSizeCount = 1; hb.pPoolSizes = &havuz; if (vkCreateDescriptorPool(aygit, &hb, nullptr, &dsHavuz_) != VK_SUCCESS) return; VkDescriptorSetAllocateInfo da{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; da.descriptorPool = dsHavuz_; da.descriptorSetCount = 1; da.pSetLayouts = &dsYerlesim_; if (vkAllocateDescriptorSets(aygit, &da, &ds_) != VK_SUCCESS) { ds_ = VK_NULL_HANDLE; return; } // Kukla: shader set'i STATİK olarak referans veriyor → veri olmasa da geçerli // bir tampon bağlı kalmalı (NULL bind YASAK). kukla_ = SsboTampon(vb_, 64); kuklaBagla(); } IsinAlani::~IsinAlani() { const VkDevice aygit = vb_.aygit(); if (dsHavuz_) vkDestroyDescriptorPool(aygit, dsHavuz_, nullptr); if (dsYerlesim_) vkDestroyDescriptorSetLayout(aygit, dsYerlesim_, nullptr); } void IsinAlani::descriptorYaz(VkBuffer dal, VkBuffer ucgen, VkBuffer bant) { if (ds_ == VK_NULL_HANDLE) return; VkDescriptorBufferInfo bi[3]{}; bi[0].buffer = dal; bi[0].range = VK_WHOLE_SIZE; bi[1].buffer = ucgen; bi[1].range = VK_WHOLE_SIZE; bi[2].buffer = bant; bi[2].range = VK_WHOLE_SIZE; VkWriteDescriptorSet yaz[3]{}; for (u32 i = 0; i < 3; ++i) { yaz[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; yaz[i].dstSet = ds_; yaz[i].dstBinding = i; yaz[i].descriptorCount = 1; yaz[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; yaz[i].pBufferInfo = &bi[i]; } vkUpdateDescriptorSets(vb_.aygit(), 3, yaz, 0, nullptr); } void IsinAlani::kuklaBagla() { if (!kukla_.gecerli()) return; descriptorYaz(kukla_.tampon(), kukla_.tampon(), kukla_.tampon()); ucgenSayi_ = 0; bantSayi_ = 0; imza_ = 0; dugum_ = 0; } void IsinAlani::bosalt() { if (ucgenSayi_ == 0) return; vb_.bekle(); // uçuştaki kare bu tamponları okuyor olabilir dalSsbo_ = SsboTampon(); ucgenSsbo_ = SsboTampon(); bantSsbo_ = SsboTampon(); kuklaBagla(); } bool IsinAlani::yukle(u64 imza, u32 dugumKimlik, const IsinBvh& bvh, const std::vector& konum, const std::vector& indeks, const Mat4f& model, const std::vector& bantlar) { if (ds_ == VK_NULL_HANDLE) return false; if (imza != 0 && imza == imza_ && ucgenSayi_ > 0) return true; // zaten yüklü if (bvh.dallar.empty() || bvh.ucgen.empty() || indeks.empty()) return false; // Üçgenleri BVH YAPRAK SIRASINA düzleştir → yaprak doğrudan diziye indeksler // (ayrı bir "üçgen numarası" dolaylaması yok; shader'da bir okuma daha az). const u32 ucgenSayi = (u32)bvh.ucgen.size(); std::vector ucgenler((size_t)ucgenSayi * 3); for (u32 i = 0; i < ucgenSayi; ++i) { const u32 taban = bvh.ucgen[i] * 3u; if (taban + 2 >= indeks.size()) return false; for (int k = 0; k < 3; ++k) { const u32 vi = indeks[taban + (u32)k]; if (vi >= konum.size()) return false; const Vec3f& p = konum[vi]; const Vec4f d = model * Vec4f{p, 1.0f}; // DÜNYA uzayı (fragment ile aynı) ucgenler[(size_t)i * 3 + (size_t)k] = {d.x, d.y, d.z, 0.0f}; } } // Düğüm kutuları da DÜNYA uzayında olmalı. Yerel AABB'nin 8 KÖŞESİ dönüştürülüp // yeniden sarmalanır: dönme altında kutu bir miktar şişer (muhafazakâr = ışın // fazladan düğüm gezer, ASLA isabet kaçırmaz). Alt→üst yeniden hesap daha sıkı // olurdu ama çocuk indekslerinin ebeveynden büyük olmasına dayanırdı; isinBvhKur // alt ağaçları PARALEL kurup ofsetle birleştiriyor (isin_bvh.cpp:197) → o sıra // garantisine yaslanmak kırılgan. Doğruluk > birkaç kutu testi. std::vector dallar(bvh.dallar.size()); for (size_t i = 0; i < bvh.dallar.size(); ++i) { const IsinBvh::Dal& d = bvh.dallar[i]; GpuDal g{}; if (d.kutu.gecerliMi()) { Aabbf k; const Vec3f& mn = d.kutu.asgari; const Vec3f& mx = d.kutu.azami; for (int c = 0; c < 8; ++c) { const Vec3f kose{(c & 1) ? mx.x : mn.x, (c & 2) ? mx.y : mn.y, (c & 4) ? mx.z : mn.z}; const Vec4f dw = model * Vec4f{kose, 1.0f}; k.genislet({dw.x, dw.y, dw.z}); } g.minX = k.asgari.x; g.minY = k.asgari.y; g.minZ = k.asgari.z; g.maksX = k.azami.x; g.maksY = k.azami.y; g.maksZ = k.azami.z; } else { // boş kutu: hiçbir ışın kesişmesin g.minX = g.minY = g.minZ = 1e30f; g.maksX = g.maksY = g.maksZ = -1e30f; } g.a = d.a; g.bYaprak = d.b | (d.yaprak ? kYaprakBit : 0u); dallar[i] = g; } vb_.bekle(); // eski tamponlar uçuşta olabilir (yeniden tahsis öncesi) dalSsbo_ = SsboTampon(vb_, dallar.size() * sizeof(GpuDal)); ucgenSsbo_ = SsboTampon(vb_, ucgenler.size() * sizeof(Vec4f)); if (!dalSsbo_.gecerli() || !ucgenSsbo_.gecerli()) { kuklaBagla(); return false; } dalSsbo_.yaz(dallar.data(), dallar.size() * sizeof(GpuDal)); ucgenSsbo_.yaz(ucgenler.data(), ucgenler.size() * sizeof(Vec4f)); // Kalınlık sınıfları (varsa): her piksel ölçülen kalınlığına göre sınıfa düşer. std::vector gb; gb.reserve(bantlar.size()); for (const analiz::AnalizAralik& b : bantlar) { if (!(b.max > b.min)) continue; // dejenere bant → yok say gb.push_back({b.min, b.max, b.nominal, b.tolerans, b.renk.x, b.renk.y, b.renk.z, 0.f}); } VkBuffer bantBuf = kukla_.tampon(); if (!gb.empty()) { bantSsbo_ = SsboTampon(vb_, gb.size() * sizeof(GpuBant)); if (bantSsbo_.gecerli()) { bantSsbo_.yaz(gb.data(), gb.size() * sizeof(GpuBant)); bantBuf = bantSsbo_.tampon(); } else { gb.clear(); } } else { bantSsbo_ = SsboTampon(); } bantSayi_ = (u32)gb.size(); descriptorYaz(dalSsbo_.tampon(), ucgenSsbo_.tampon(), bantBuf); ucgenSayi_ = ucgenSayi; imza_ = imza; dugum_ = dugumKimlik; gunluk::bilgi("[kalinlik] GPU isin alani: {} ucgen, {} dugum ({:.1f} MB)", ucgenSayi, dallar.size(), (dallar.size() * sizeof(GpuDal) + ucgenler.size() * sizeof(Vec4f)) / 1048576.0); return true; } } // namespace fiko