#include "fiko/ui/dinamik_doku.hpp" #include #include // HANDLE (vulkan.h win32 bölümünden ÖNCE) #define VK_USE_PLATFORM_WIN32_KHR #include // VkImportMemoryWin32HandleInfoKHR (CEF accelerated OSR) #include "fiko/render/vk_kontrol.hpp" #include "fiko/render/vulkan_baglam.hpp" #include "fiko/ui/imgui_katman.hpp" #include "vk_mem_alloc.h" namespace fiko::ui { DinamikDoku::~DinamikDoku() { yikil(); } void DinamikDoku::yikil() { if (!vb_) return; // Boyut değişimi/kapanış NADİR → burada bir kez beklemek kabul edilebilir // (sıcak yolda DEĞİL; yukle() hiç beklemez). vb_->bekle(); if (doku_ && arayuz_) arayuz_->dokuKaldir(doku_); if (gorunum_) vkDestroyImageView(vb_->aygit(), (VkImageView)gorunum_, nullptr); if (gorsel_) vmaDestroyImage(vb_->ayirici(), (VkImage)gorsel_, (VmaAllocation)tahsis_); if (staging_) vmaDestroyBuffer(vb_->ayirici(), (VkBuffer)staging_, (VmaAllocation)stagingT_); gorsel_ = tahsis_ = gorunum_ = staging_ = stagingT_ = stagingPtr_ = nullptr; doku_ = 0; g_ = y_ = 0; } bool DinamikDoku::boyutla(VulkanBaglam& vb, ImGuiKatman& arayuz, int g, int y, bool d3dModu) { if (g <= 0 || y <= 0) return false; if (vb_ == &vb && g_ == g && y_ == y && doku_ && d3dModu_ == d3dModu) return true; // değişmedi → ucuz çıkış yikil(); vb_ = &vb; arayuz_ = &arayuz; d3dModu_ = d3dModu; // d3dModu: CEF D3D11 BGRA texture kalıcı görsele KOPYALANIR (aynı format, byte-birebir); // view swizzle R↔B ile ImGui doğru renk okur. Yoksa RGBA + host staging (software OSR). const VkFormat fmt = d3dModu ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8G8B8A8_UNORM; VkImage gorsel{}; VmaAllocation tahsis{}; VkImageCreateInfo gb{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; gb.imageType = VK_IMAGE_TYPE_2D; gb.format = fmt; gb.extent = {(u32)g, (u32)y, 1}; gb.mipLevels = 1; gb.arrayLayers = 1; gb.samples = VK_SAMPLE_COUNT_1_BIT; gb.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; VmaAllocationCreateInfo gt{}; gt.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; if (vmaCreateImage(vb.ayirici(), &gb, >, &gorsel, &tahsis, nullptr) != VK_SUCCESS) return false; gorsel_ = gorsel; tahsis_ = tahsis; if (!d3dModu) { // Kalıcı staging (host-mapped) — her yukle()'de yalnız memcpy. d3dModu'da GEREKMEZ // (kaynak GPU texture; kopya GPU-GPU). VkBuffer stg{}; VmaAllocation stgT{}; VmaAllocationInfo bilgi{}; VkBufferCreateInfo tb{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; tb.size = (u64)g * (u64)y * 4; tb.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; VmaAllocationCreateInfo tt{}; tt.usage = VMA_MEMORY_USAGE_AUTO; tt.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; if (vmaCreateBuffer(vb.ayirici(), &tb, &tt, &stg, &stgT, &bilgi) != VK_SUCCESS) { yikil(); return false; } staging_ = stg; stagingT_ = stgT; stagingPtr_ = bilgi.pMappedData; } // İlk geçiş: UNDEFINED → SHADER_READ (yukle()/kopya bu düzenden başlar). vb.anindaGonder([&](VkCommandBuffer kb) { VkImageMemoryBarrier b{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; b.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; b.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; b.image = gorsel; b.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; vkCmdPipelineBarrier(kb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b); }); VkImageView gorunum{}; VkImageViewCreateInfo gv{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; gv.image = gorsel; gv.viewType = VK_IMAGE_VIEW_TYPE_2D; gv.format = fmt; // d3dModu: CEF BGRA byte'ları kalıcı B8G8R8A8'de birebir; sampler'a RGBA vermek için // R↔B swizzle. (Software yolda OnPaint zaten BGRA→RGBA takas ettiği için swizzle yok.) if (d3dModu) gv.components = {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A}; gv.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; if (vkCreateImageView(vb.aygit(), &gv, nullptr, &gorunum) != VK_SUCCESS) { yikil(); return false; } gorunum_ = gorunum; doku_ = arayuz.dokuEkle(vb.viewportOrnekleyici(), gorunum); g_ = g; y_ = y; return doku_ != 0; } bool DinamikDoku::yukleD3DPaylasim(void* sharedHandle, int genislik, int yukseklik, bool paylasimNT) { if (!vb_ || !d3dModu_ || !gorsel_ || !sharedHandle) return false; if (genislik != g_ || yukseklik != y_) return false; // boyut uyumsuz → arayan resize etsin const VkDevice aygit = vb_->aygit(); const VkExternalMemoryHandleTypeFlagBits htip = paylasimNT ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT : VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT; // Extension fonksiyonları statik loader'da yok → runtime çöz (bir kez cache). static auto pGetMemProps = (PFN_vkGetMemoryWin32HandlePropertiesKHR)vkGetDeviceProcAddr( aygit, "vkGetMemoryWin32HandlePropertiesKHR"); if (!pGetMemProps) return false; // 1) CEF texture'ıyla AYNI düzende geçici VkImage (external). Format kalıcı görselle // birebir (B8G8R8A8) → vkCmdCopyImage geçerli. VkExternalMemoryImageCreateInfo dbg{VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO}; dbg.handleTypes = htip; VkImageCreateInfo ib{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; ib.pNext = &dbg; ib.imageType = VK_IMAGE_TYPE_2D; ib.format = VK_FORMAT_B8G8R8A8_UNORM; ib.extent = {(u32)genislik, (u32)yukseklik, 1}; ib.mipLevels = 1; ib.arrayLayers = 1; ib.samples = VK_SAMPLE_COUNT_1_BIT; ib.tiling = VK_IMAGE_TILING_OPTIMAL; ib.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; ib.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ib.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkImage disImage{}; if (vkCreateImage(aygit, &ib, nullptr, &disImage) != VK_SUCCESS) return false; // 2) Handle'ın memory tip maskesini al → uyumlu memoryTypeIndex seç. VkMemoryWin32HandlePropertiesKHR hp{VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR}; if (pGetMemProps(aygit, htip, (HANDLE)sharedHandle, &hp) != VK_SUCCESS) { vkDestroyImage(aygit, disImage, nullptr); return false; } VkMemoryRequirements mgerek{}; vkGetImageMemoryRequirements(aygit, disImage, &mgerek); const u32 tipMaske = hp.memoryTypeBits & mgerek.memoryTypeBits; VkPhysicalDeviceMemoryProperties mprop{}; vkGetPhysicalDeviceMemoryProperties(vb_->fizikselAygit(), &mprop); u32 tipIdx = UINT32_MAX; for (u32 i = 0; i < mprop.memoryTypeCount; ++i) if (tipMaske & (1u << i)) { tipIdx = i; break; } if (tipIdx == UINT32_MAX) { vkDestroyImage(aygit, disImage, nullptr); return false; } // 3) Shared handle'ı içe aktar + image'e bağla. dedicated allocation (external için şart). VkMemoryDedicatedAllocateInfo ded{VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO}; ded.image = disImage; VkImportMemoryWin32HandleInfoKHR imp{VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR}; imp.pNext = &ded; imp.handleType = htip; imp.handle = (HANDLE)sharedHandle; VkMemoryAllocateInfo ai{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; ai.pNext = &imp; ai.allocationSize = mgerek.size; ai.memoryTypeIndex = tipIdx; VkDeviceMemory disMem{}; if (vkAllocateMemory(aygit, &ai, nullptr, &disMem) != VK_SUCCESS) { vkDestroyImage(aygit, disImage, nullptr); return false; } if (vkBindImageMemory(aygit, disImage, disMem, 0) != VK_SUCCESS) { vkFreeMemory(aygit, disMem, nullptr); vkDestroyImage(aygit, disImage, nullptr); return false; } // 4) GPU-GPU kopya: disImage (CEF) → kalıcı görsel. Kopya SENKRON biter (fence) → // CEF texture'ı callback dönene dek okunur; keyed-mutex yok, senkron kopya yeter. const VkImage hedef = (VkImage)gorsel_; const u32 g = (u32)g_, y = (u32)y_; vb_->anindaGonder([&](VkCommandBuffer kb) { VkImageMemoryBarrier b[2]{}; b[0] = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; b[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; // external içerik zaten var; layout önemsiz b[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; b[0].srcQueueFamilyIndex = b[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; b[0].image = disImage; b[0].subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; b[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; b[1] = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; b[1].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; b[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b[1].srcQueueFamilyIndex = b[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; b[1].image = hedef; b[1].subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; b[1].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; b[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkCmdPipelineBarrier(kb, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 2, b); VkImageCopy kop{}; kop.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; kop.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; kop.extent = {g, y, 1}; vkCmdCopyImage(kb, disImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, hedef, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &kop); VkImageMemoryBarrier son{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; son.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; son.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; son.srcQueueFamilyIndex = son.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; son.image = hedef; son.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; son.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; son.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; vkCmdPipelineBarrier(kb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &son); }); // 5) Geçici import kaynaklarını serbest bırak (kopya bitti — anindaGonder fence bekledi). // Handle CEF'e ait; DuplicateHandle YAPMADIK → CloseHandle ÇAĞIRMA (CEF havuza döndürür). vkDestroyImage(aygit, disImage, nullptr); vkFreeMemory(aygit, disMem, nullptr); return true; } void DinamikDoku::yukle(const unsigned char* rgba) { if (!vb_ || !stagingPtr_ || !gorsel_ || !rgba) return; std::memcpy(stagingPtr_, rgba, (size_t)g_ * (size_t)y_ * 4); const VkImage gorsel = (VkImage)gorsel_; const VkBuffer stg = (VkBuffer)staging_; const u32 g = (u32)g_, y = (u32)y_; // Kalıcı transfer KB + fence (device-idle YOK) → küçük, öngörülebilir maliyet. vb_->anindaGonder([&](VkCommandBuffer kb) { VkImageMemoryBarrier b{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; b.image = gorsel; b.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; b.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkCmdPipelineBarrier(kb, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b); VkBufferImageCopy kopya{}; kopya.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; kopya.imageExtent = {g, y, 1}; vkCmdCopyBufferToImage(kb, stg, gorsel, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &kopya); b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; vkCmdPipelineBarrier(kb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b); }); } } // namespace fiko::ui