Vulkan’ın bellek modeli (VK_KHR_vulkan_memory_model ile formalize
edilmiş, 1.2’de çekirdek) “invocation A’nın yazması invocation B’ye
ne zaman görünür olur” sorusunu yanıtlar. C++‘ın bellek modelinden
farklı olarak bölünmüştür: availability, visibility ve scope üç
ayrı şeydir ve varsayılan hiçbirinin gerçekleşmemesidir.
Üç bileşen
availability — yazma fiziksel olarak cache'den çıktı ve görülebilir
visibility — okuyucu gerçekten onu gözlemler (cache invalidation)
scope — sıralamanın *kime* uygulandığı:
Subgroup / Workgroup / QueueFamily / Device / InstanceAvailable yapılmayan bir yazma, yazıcının cache’inden asla çıkmaz. Visibility scope’unda olmayan bir okuma, eski cache kopyasına çarpabilir. Doğru scope‘u olmayan bir atomik, kendi subgroup’u dışında hiçbir şeyi sıralayamaz.
SPIR-V’de görünümü
OpMemoryBarrier %scope %semantics
OpAtomicStore %ptr %scope %semantics %value
OpAtomicIAdd %ptr %scope %semantics %val
scope: Workgroup | QueueFamily | Device | Invocation
semantics: Acquire | Release | AcquireRelease |
UniformMemory | SubgroupMemory | WorkgroupMemory |
ImageMemory | OutputMemoryKHR | MakeAvailable |
MakeVisible | SequentiallyConsistentMakeAvailable/MakeVisible Vulkan’a özel flag’lerdir — C++ benzeri
acquire/release’i, Vulkan’ın tüm cihaz boyunca ihtiyaç duyduğu
cache-flush semantiğiyle genişletirler.
// GLSL — derleyici SPIR-V'yi seçer ama scope+semantics'i
// bellek niteleyicileri ve barrier'larla kontrol edersiniz:
layout(set=0,binding=0) coherent buffer Counters { uint c[]; } g_cnt;
void bump() {
memoryBarrierBuffer(); // yazmalarımı görünür kıl
atomicAdd(g_cnt.c[i], 1); // relaxed atomik RMW
}Buffer’daki coherent büyük anahtardır — okuma/yazmaları bellek alt
sisteminden geçmeye zorlar (hâlâ device-scope, barrier’sız hâlâ
sıralı tutarlı değil).
API tarafında flag’lerin anlamı
vk::PhysicalDeviceVulkanMemoryModelFeatures f{};
f.vulkanMemoryModel = VK_TRUE; // temel model
f.vulkanMemoryModelDeviceScope = VK_TRUE; // cihaz boyunca scope
f.vulkanMemoryModelAvailabilityVisibilityChains= VK_TRUE; // zincir geçişliliği
vulkanMemoryModel etkin değilse eski 1.2 öncesi kurallar
geçerlidir: barrier’lar sadece bir queue submission içinde sıralar
ve çoğu çapraz-shader iletişimi teknik olarak tanımsızdır. Onu
etkinleştirmek “shader SSBO’ya yazar → başka shader acquire barrier
ile görür"ü iyi tanımlı yapar.
Her zaman işe yarayan tarif
üretici: veri yaz → OpMemoryBarrier Device|UniformMemory|Release
|MakeAvailable
tüketici: OpMemoryBarrier Device|UniformMemory|Acquire|MakeVisible
→ veri oku
queue seviyesi: vkQueueSubmit + fence/semaphore zaten availability+
visibility içerir — shader seviyesi barrier'lar sadece
*aynı submission* sıralaması için önemlidir.Pratik kurallar
coherent≠ senkronize — okuma/yazmalar L2’yi atlar ama sıralama hâlâ acquire/release ister; barrier olmadan okuyucu flag’i veriden önce görebilir.- GLSL atomiklerinde varsayılan scope Device’tir — güvenli ama
yavaş; sayaç yerelse
Workgroup‘a daraltın. SequentiallyConsistentvar ama neredeyse hiç ihtiyacınız olan şey değil — acquire/release gerçek vakaları maliyetin çok küçük bir kısmıyla kapsar.- Queue seviyesi senkron (semaphore, event, fence beklenen submit’ler) zaten availability+visibility sağlar — çapraz command-buffer sıralaması için shader barrier eklemeyin, o queue primitiflerinin işidir.
- Çapraz-queue erişim için
vkQueueFamilyOwnershipTransferveya timeline semaphore kullanın — bellek modeli queue senkronizasyonunun yerini almaz, queue-içi görünürlüğü formalize eder.