#include "fiko/render/gpu_tampon.hpp" #include #include #include "fiko/core/gunluk.hpp" #include "fiko/render/vk_kontrol.hpp" #include "fiko/render/vulkan_baglam.hpp" #include "vk_mem_alloc.h" namespace fiko { GpuTampon::GpuTampon(VulkanBaglam& vb, const void* veri, u64 bayt, VkBufferUsageFlags kullanim) : vb_(&vb), bayt_(bayt) { // Sıfır-boyut: vmaCreateBuffer(size=0) Vulkan spec ihlali → VK_KONTROL → std::abort(). // guncelle() zaten bunu koruyor; kurucu da korumalı (dejenere STEP: node var üçgen yok → // vertex dolu index boş → sıfır-boyut index tamponu). Üyeler default-init → güvenli boş kalır. if (bayt == 0) return; // bayt_=0 (init list); accessor'lar null/0, çizim bayt()==0'da atlar VkBufferCreateInfo hedefBilgi{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; hedefBilgi.size = bayt; hedefBilgi.usage = kullanim | VK_BUFFER_USAGE_TRANSFER_DST_BIT; VmaAllocationCreateInfo hedefTahsis{}; hedefTahsis.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; VK_KONTROL(vmaCreateBuffer(vb.ayirici(), &hedefBilgi, &hedefTahsis, &tampon_[0], &tahsis_[0], nullptr)); kapasite_[0] = bayt; VkBufferCreateInfo kaynakBilgi{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; kaynakBilgi.size = bayt; kaynakBilgi.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; VmaAllocationCreateInfo kaynakTahsis{}; kaynakTahsis.usage = VMA_MEMORY_USAGE_AUTO; kaynakTahsis.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; VkBuffer kaynak; VmaAllocation kaynakTah; VmaAllocationInfo bilgi; VK_KONTROL(vmaCreateBuffer(vb.ayirici(), &kaynakBilgi, &kaynakTahsis, &kaynak, &kaynakTah, &bilgi)); std::memcpy(bilgi.pMappedData, veri, bayt); if (vb.topluYuklemeAktif()) { // Toplu oturum: kopya açık cmd'ye kaydedilir; staging'i oturum sahiplenir, // submit+fence topluYuklemeBitir'de TEK sefer (import stall'ları silinir). vb.topluKopyaKaydet(kaynak, kaynakTah, tampon_[0], bayt); return; } vb.anindaGonder([&](VkCommandBuffer kb) { const VkBufferCopy kopya{0, 0, bayt}; vkCmdCopyBuffer(kb, kaynak, tampon_[0], 1, &kopya); }); vmaDestroyBuffer(vb.ayirici(), kaynak, kaynakTah); } void GpuTampon::guncelle(VulkanBaglam& vb, const void* veri, u64 bayt, VkBufferUsageFlags kullanim) { if (bayt == 0) { bayt_ = 0; return; } // boş veri: çizim atlanır, tamponlar durur vb_ = &vb; const u64 kare = vb.kareSayac(); const u32 hedef = gpuTamponHedefSlot(dinamik_, aktif_, kare, sonKare_); if (!dinamik_ || kapasite_[hedef] < bayt || !esli_[hedef]) { // Statik→dinamik geçiş veya kapasite yetersiz: eski tamponu emekli et (ucusta // olabilir — ertelenmiş yıkım) ve %50 paylı host-visible eşli tampon kur. if (tampon_[hedef]) { vb.tamponEmekliEt(tampon_[hedef], tahsis_[hedef]); tampon_[hedef] = VK_NULL_HANDLE; tahsis_[hedef] = nullptr; esli_[hedef] = nullptr; kapasite_[hedef] = 0; } const u64 kap = gpuTamponKapasite(bayt); VkBufferCreateInfo bi{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; bi.size = kap; bi.usage = kullanim; VmaAllocationCreateInfo ai{}; ai.usage = VMA_MEMORY_USAGE_AUTO; ai.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; VmaAllocationInfo bilgi; VK_KONTROL(vmaCreateBuffer(vb.ayirici(), &bi, &ai, &tampon_[hedef], &tahsis_[hedef], &bilgi)); esli_[hedef] = bilgi.pMappedData; kapasite_[hedef] = kap; // Nadir olay (ilk geçiş / kapasite aşımı) — oynatmada kare-başı SPAM DEĞİL. gunluk::bilgi("[perf] GpuTampon dinamik slot {} tahsis: {} bayt (istek {})", hedef, kap, bayt); } std::memcpy(esli_[hedef], veri, bayt); // Non-coherent bellek güvencesi (coherent'ta no-op). vmaFlushAllocation(vb.ayirici(), tahsis_[hedef], 0, bayt); bayt_ = bayt; aktif_ = hedef; dinamik_ = true; sonKare_ = kare; } void GpuTampon::birak() { for (u32 i = 0; i < 2; ++i) { if (tampon_[i] && vb_) vb_->tamponEmekliEt(tampon_[i], tahsis_[i]); tampon_[i] = VK_NULL_HANDLE; tahsis_[i] = nullptr; esli_[i] = nullptr; kapasite_[i] = 0; } bayt_ = 0; aktif_ = 0; dinamik_ = false; sonKare_ = ~0ull; } GpuTampon& GpuTampon::operator=(GpuTampon&& o) noexcept { if (this != &o) { birak(); vb_ = o.vb_; for (u32 i = 0; i < 2; ++i) { tampon_[i] = std::exchange(o.tampon_[i], VK_NULL_HANDLE); tahsis_[i] = std::exchange(o.tahsis_[i], nullptr); esli_[i] = std::exchange(o.esli_[i], nullptr); kapasite_[i] = std::exchange(o.kapasite_[i], 0); } bayt_ = std::exchange(o.bayt_, 0); aktif_ = std::exchange(o.aktif_, 0); dinamik_ = std::exchange(o.dinamik_, false); sonKare_ = std::exchange(o.sonKare_, ~0ull); } return *this; } GpuTampon::~GpuTampon() { birak(); } }