{"id":3272,"date":"2026-10-19T20:49:30","date_gmt":"2026-10-19T20:49:30","guid":{"rendered":"https:\/\/yazilimperver.com\/?p=3272"},"modified":"2026-10-19T20:49:30","modified_gmt":"2026-10-19T20:49:30","slug":"sdl-painter-vulkan-backend-faz-5","status":"publish","type":"post","link":"https:\/\/yazilimperver.com\/index.php\/2026\/10\/19\/sdl-painter-vulkan-backend-faz-5\/","title":{"rendered":"sdl-painter \u2013 Vulkan Backend (faz-5)"},"content":{"rendered":"<p class=\"code-line\" dir=\"auto\" data-line=\"14\">Tekrar merhaba sevgili yaz\u0131l\u0131mperver dostlar\u0131m. Bu yaz\u0131, temel kabiliyetler a\u00e7\u0131s\u0131ndan serimin son yaz\u0131s\u0131.<\/p>\n<div>\n<div>\n<div>\n<div>\n<div><a href=\"https:\/\/yazilimperver.com\/index.php\/2026\/09\/21\/sdl-painter-metin-cizimi-faz-4\/\"><strong>sdl-painter \u2013 Metin \u00c7izimi (faz-4)<\/strong><\/a><\/div>\n<\/div>\n<div><strong><a href=\"https:\/\/yazilimperver.com\/index.php\/2026\/09\/12\/sdl-painter-resim-cizimi-faz-2\/\">sdl-painter \u2013 Resim \u00c7izimi (faz-3)<\/a><\/strong><\/div>\n<div><strong><a href=\"https:\/\/yazilimperver.com\/index.php\/2026\/09\/06\/sdl-painter-transformasyonlar-faz-2\/\">sdl-painter \u2013 Transformasyonlar (faz-2)<\/a><\/strong><\/div>\n<\/div>\n<div><strong><a href=\"https:\/\/yazilimperver.com\/index.php\/2026\/08\/29\/sdl-painter-temel-sekiller-ve-kabiliyetler-faz-1\/\">sdl-painter \u2013 Temel \u015eekiller ve Kabiliyetler (faz-1)<\/a><\/strong><\/div>\n<\/div>\n<div><strong><a href=\"https:\/\/yazilimperver.com\/index.php\/2026\/08\/04\/sdl-painter-proje-altyapisi-devam-faz-0-ci-cd\/\">sdl-painter \u2013 Proje Altyap\u0131s\u0131 (faz 0) \u2013 CI\/CD<\/a><\/strong><\/div>\n<\/div>\n<div><strong><a href=\"https:\/\/yazilimperver.com\/index.php\/2026\/07\/03\/sdl-painter-proje-altyapisi-faz-0\/\">sdl-painter \u2013 Proje Altyap\u0131s\u0131 (faz-0)<\/a><\/strong><\/div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"14\">\u0130lk yaz\u0131dan bu yana altyap\u0131y\u0131 kurduk, OpenGL backend&#8217;ini yazd\u0131k, transform stack ve tessellator&#8217;\u0131 oturttuk, g\u00f6r\u00fcnt\u00fc ve metin deste\u011fi ekledik. \u015eimdi s\u0131ra <code>IRenderer<\/code>\u00a0aray\u00fcz\u00fcn\u00fcn ikinci implementasyonunda: Vulkan.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"14\">A\u00e7\u0131k konu\u015fmak gerekirse Vulkan ilk etapta akl\u0131mda pek yoktu; fakat bu vesileyle onu biraz daha yak\u0131ndan \u00f6\u011frenme f\u0131rsat\u0131 bulurum diye d\u00fc\u015f\u00fcnd\u00fcm. Vulkan&#8217;\u0131n OpenGL&#8217;e k\u0131yasla \u00e7ok daha ayr\u0131nt\u0131l\u0131 (biraz da detayl\u0131) bir API&#8217;si var: swapchain, senkronizasyon nesneleri, descriptor set&#8217;ler, vb. Bir\u00e7ok \u015feyi sizin halletmeniz gerekiyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"14\">Bunun yan\u0131nda <code>IRenderer<\/code>\u00a0soyutlamas\u0131n\u0131n ger\u00e7ekten i\u015fe yaray\u0131p yaramad\u0131\u011f\u0131n\u0131 da bu a\u015famada g\u00f6rm\u00fc\u015f olaca\u011f\u0131z: Vulkan eklenirken\u00a0<code>Painter<\/code>\u00a0ve\u00a0<code>Tessellator<\/code>\u00a0de\u011fi\u015fmemeli, yaln\u0131zca yeni bir\u00a0<code>IRenderer<\/code>\u00a0implementasyonu ekleyerek i\u015fimiz hallolmal\u0131.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"16\">Bu yaz\u0131da, bunun ger\u00e7ekten b\u00f6yle oldu\u011funu nas\u0131l do\u011frulad\u0131\u011f\u0131m\u0131 da anlataca\u011f\u0131m. K\u0131sacas\u0131 iki backend ayn\u0131 sonucu veriyor mu, birlikte g\u00f6rece\u011fiz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"16\">tl;dr: Elbette veriyor \ud83d\ude09<\/p>\n<h2 id=\"opengl-ve-vulkan-aras\u0131nda-nas\u0131l-bir-i\u0307li\u015fki-var\" class=\"code-line\" dir=\"auto\" data-line=\"18\"><strong><span style=\"color: #0000ff;\">OpenGL ve Vulkan Aras\u0131nda Nas\u0131l Bir \u0130li\u015fki Var?<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"20\">OpenGL ve Vulkan, uygulaman\u0131n GPU&#8217;ya \u00e7izim i\u015fi yapt\u0131rmas\u0131n\u0131 sa\u011flayan iki grafik API&#8217;si. \u00dc\u00e7genler, vertex buffer&#8217;lar\u0131, dokular ve shader&#8217;lar gibi kavramlar her ikisinde de var. 2B bir aray\u00fcz\u00fc de 3B bir sahneyi de bu ara\u00e7larla \u00e7izebiliyoruz. As\u0131l fark, bu i\u015flerin ne kadar\u0131n\u0131 bizim, ne kadar\u0131n\u0131 s\u00fcr\u00fcc\u00fcn\u00fcn \u00fcstlendi\u011finde. Bunun yan\u0131nda Vulkan, OpenGL&#8217;e g\u00f6re daha modern ve sonradan sunulan, daha d\u00fc\u015f\u00fck seviyeli bir API.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"22\">OpenGL&#8217;de bir doku veya shader ba\u011fl\u0131yor, \u00e7izim ayarlar\u0131n\u0131 de\u011fi\u015ftiriyor ve \u00e7izim \u00e7a\u011fr\u0131s\u0131n\u0131 yap\u0131yoruz. S\u00fcr\u00fcc\u00fc bu \u00e7a\u011fr\u0131lar\u0131 GPU&#8217;nun \u00e7al\u0131\u015ft\u0131raca\u011f\u0131 i\u015flere d\u00f6n\u00fc\u015ft\u00fcr\u00fcyor. Bellek yerle\u015fimini ve normal \u00e7izim s\u0131ras\u0131nda gerekli beklemelerin \u00e7o\u011funu da bizim i\u00e7in hallediyor. B\u00f6ylece daha az kodla ve efor haracayarak \u00e7izim yapmaya ba\u015flayabiliyoruz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"24\">Vulkan&#8217;da ise kararlarda daha fazla s\u00f6z sahibiyiz (y\u00fck\u00fcn \u00e7o\u011fu bizde demenin daha kibar hali \ud83d\ude42 ): kaynaklar i\u00e7in bellek ay\u0131r\u0131yoruz, \u00e7izim komutlar\u0131n\u0131 <em>command buffer<\/em> denen komut listelerine kaydediyoruz ve bu listeleri GPU&#8217;ya g\u00f6nderiyoruz. Hangi i\u015fin hangi kayna\u011f\u0131 kullanaca\u011f\u0131n\u0131 ve ba\u015fka bir i\u015fi ne zaman beklemesi gerekti\u011fini de a\u00e7\u0131k\u00e7a belirtiyoruz. Vulkan&#8217;\u0131n \u201cdaha d\u00fc\u015f\u00fck seviyeli\u201d olmas\u0131yla kastedilen bu.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"24\">Vulkan, OpenGL&#8217;in yeni bir s\u00fcr\u00fcm\u00fc veya onun \u00fczerinde \u00e7al\u0131\u015fan bir katman de\u011fil; GPU \u00fczerinde daha do\u011frudan kontrol sunan <a href=\"https:\/\/docs.vulkan.org\/guide\/latest\/what_is_vulkan.html#_vulkan_and_opengl\" data-href=\"https:\/\/docs.vulkan.org\/guide\/latest\/what_is_vulkan.html#_vulkan_and_opengl\">ayr\u0131 bir API<\/a>.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"26\">Kod taraf\u0131ndaki farklar\u0131 \u00f6zetleyecek olursak:<\/p>\n<table class=\"code-line\" dir=\"auto\" data-line=\"28\">\n<thead class=\"code-line\" dir=\"auto\" data-line=\"28\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"28\">\n<th>\u0130\u015f<\/th>\n<th>OpenGL taraf\u0131nda<\/th>\n<th>Vulkan taraf\u0131nda<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"code-line\" dir=\"auto\" data-line=\"30\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"30\">\n<td>\u00c7izim komutlar\u0131n\u0131 vermek<\/td>\n<td>Ge\u00e7erli ba\u011flam\u0131n ayarlar\u0131n\u0131 de\u011fi\u015ftirip\u00a0<code>glDrawArrays<\/code>\u00a0gibi \u00e7a\u011fr\u0131lar yap\u0131yoruz.<\/td>\n<td>Komutlar\u0131 bir command buffer&#8217;a kaydedip kuyru\u011fa g\u00f6nderiyoruz.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"31\">\n<td>Buffer belle\u011fi olu\u015fturmak<\/td>\n<td><code>glBufferData<\/code>\u00a0ile boyutu ve veriyi bildiriyoruz; alttaki bellek ay\u0131rma i\u015fini s\u00fcr\u00fcc\u00fc yap\u0131yor.<\/td>\n<td>Buffer&#8217;\u0131 olu\u015fturuyor, uygun belle\u011fi ay\u0131r\u0131yor ve ikisini birbirine ba\u011fl\u0131yoruz.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"32\">\n<td>Kullan\u0131mdaki kaynaklar\u0131 yeniden kullanmak<\/td>\n<td>Normal \u00e7izim s\u0131ras\u0131nda gerekli beklemelerin \u00e7o\u011funu s\u00fcr\u00fcc\u00fc y\u00f6netiyor.<\/td>\n<td>CPU ve GPU&#8217;nun ayn\u0131 kayna\u011fa \u00e7ak\u0131\u015farak eri\u015fmemesi i\u00e7in beklemeleri biz d\u00fczenliyoruz.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"33\">\n<td>Frame&#8217;i pencerede g\u00f6stermek<\/td>\n<td>SDL \u00fczerinden\u00a0<code>SDL_GL_SwapWindow()<\/code>\u00a0\u00e7a\u011f\u0131r\u0131yoruz.<\/td>\n<td>Swapchain&#8217;den g\u00f6r\u00fcnt\u00fc al\u0131yor, ona \u00e7iziyor ve sunum iste\u011fi g\u00f6nderiyoruz.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"code-line\" dir=\"auto\" data-line=\"35\">Vulkan&#8217;\u0131n sundu\u011fu kontrol, \u00f6zellikle CPU&#8217;nun \u00e7ok say\u0131da \u00e7izim komutu haz\u0131rlad\u0131\u011f\u0131 i\u015flerde bize fayda sa\u011flayabilir. \u00d6rne\u011fin komut listelerini <a href=\"https:\/\/docs.vulkan.org\/guide\/latest\/threading.html\" data-href=\"https:\/\/docs.vulkan.org\/guide\/latest\/threading.html\">birden fazla CPU threadinde haz\u0131rlamak<\/a> m\u00fcmk\u00fcn. Bunun kar\u015f\u0131l\u0131\u011f\u0131nda daha fazla kurulum, kaynak y\u00f6netimi ve senkronizasyon kodu yaz\u0131yoruz. Dolay\u0131s\u0131yla Vulkan&#8217;a ge\u00e7mek tek ba\u015f\u0131na daha y\u00fcksek FPS garantisi de\u011fil; kazanc\u0131 g\u00f6rmek i\u00e7in uygulaman\u0131n nerede zaman harcad\u0131\u011f\u0131n\u0131 \u00f6l\u00e7mek gerekiyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"37\">SDLPainter&#8217;da bu iki API, ayn\u0131 \u00e7izim aray\u00fcz\u00fcn\u00fcn arkas\u0131ndaki iki se\u00e7enek olarak sunulmakta. <code>VulkanRenderer<\/code>, OpenGL \u00e7a\u011fr\u0131lar\u0131n\u0131 Vulkan&#8217;a \u00e7evirmiyor;\u00a0<code>Tessellator<\/code>\u00a0ve\u00a0<code>RenderBatcher<\/code> taraf\u0131ndan haz\u0131rlanan geometriyi do\u011frudan vulkan ile \u00e7iziyor. SDL3 ise her iki yolda da pencere ve platform ba\u011flant\u0131s\u0131n\u0131 sa\u011fl\u0131yor. Benim buradaki hedefim, ayn\u0131\u00a0<code>Painter<\/code> \u00e7a\u011fr\u0131lar\u0131yla hem vulkan hem de opengl kullanabilmek ve ayn\u0131 g\u00f6r\u00fcnt\u00fcy\u00fc elde edebilmekti ki bunu sa\u011flad\u0131\u011f\u0131m\u0131 d\u00fc\u015f\u00fcn\u00fcyorum.<\/p>\n<p id=\"JylAIRW\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3276 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244.png\" alt=\"\" width=\"1130\" height=\"593\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244.png 1590w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-300x157.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-1024x537.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-768x403.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-1536x806.png 1536w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-500x262.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-150x79.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-1200x629.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-400x210.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-800x420.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67b9001244-200x105.png 200w\" sizes=\"auto, (max-width: 1130px) 100vw, 1130px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"41\"><em>Geometri ayn\u0131; bellek ve di\u011fer y\u00f6netme i\u015finin daha b\u00fcy\u00fck bir k\u0131sm\u0131 vulkan taraf\u0131nda bize kal\u0131yor.<\/em><\/p>\n<h2 id=\"\u00e7izim-kodunu-de\u011fi\u015ftirmeden-vulkana-ge\u00e7mek\" class=\"code-line\" dir=\"auto\" data-line=\"43\"><strong><span style=\"color: #0000ff;\">\u00c7izim Kodunu De\u011fi\u015ftirmeden Vulkan&#8217;a Ge\u00e7mek<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"45\">Peki OpenGL yerine Vulkan kullanmak i\u00e7in \u00e7izim kodunda neyi de\u011fi\u015ftirmemiz gerekiyor? Sadece <code>Painter<\/code> olu\u015ftururken se\u00e7ti\u011fimiz backend&#8217;i de\u011fi\u015ftirmemiz yeterli:<\/p>\n<pre class=\"lang:c++ decode:true \">\/\/ OpenGL:\r\nsdl_painter::Painter painter(window, sdl_painter::RendererBackend::kOpenGL);\r\n\/\/ Vulkan tek fark bu satir:\r\nsdl_painter::Painter painter(window, sdl_painter::RendererBackend::kVulkan);\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"54\">D\u00f6ng\u00fc i\u00e7indeki\u00a0<code>Begin()<\/code>,\u00a0<code>Clear()<\/code>,\u00a0<code>FillRect()<\/code>\u00a0ve\u00a0<code>DrawCircle()<\/code>\u00a0\u00e7a\u011fr\u0131lar\u0131 ayn\u0131 kal\u0131yor.\u00a0<code>CreateRenderer<\/code> fabrika fonksiyonu, se\u00e7ime g\u00f6re <code>OpenGLRenderer<\/code>\u00a0veya\u00a0<code>VulkanRenderer<\/code>\u00a0olu\u015fturuyor.\u00a0<code>Painter<\/code>\u00a0\u00e7izim i\u015fini bu nesnenin\u00a0<code>IRenderer<\/code>\u00a0aray\u00fcz\u00fcne b\u0131rak\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"56\">Buradaki tek sat\u0131rl\u0131k de\u011fi\u015fiklik \u00e7izim API&#8217;si i\u00e7in ge\u00e7erli. Vulkan backend&#8217;inin derlemede etkin olmas\u0131 ve SDL penceresinin de OpenGL i\u00e7in kullan\u0131lan\u00a0<code>SDL_WINDOW_OPENGL<\/code>\u00a0yerine\u00a0<code>SDL_WINDOW_VULKAN<\/code>\u00a0bayra\u011f\u0131yla olu\u015fturulmas\u0131 gerekiyor.<\/p>\n<pre class=\"lang:c++ decode:true\">class VulkanRenderer final : public IRenderer {\r\n  \/\/ ...\r\n private:\r\n  std::unique_ptr&lt;VkContext&gt; mContext;\r\n  std::unique_ptr&lt;VkSwapchain&gt; mSwapchain;\r\n  std::unique_ptr&lt;VkFrameSync&gt; mFrameSync;\r\n  std::unique_ptr&lt;VulkanPipeline&gt; mPipeline;                  \/\/ duz renk icin pipeline\r\n  VertexChain mVertexChain;\r\n  std::unique_ptr&lt;VulkanTexturedPipeline&gt; mTexturedPipeline;  \/\/ dokulu gosterimler icin pipeline\r\n  VertexChain mTexturedChain;\r\n  \/\/ ...\r\n};\r\n<code data-line=\"58\" class=\"code-line language-cpp\" dir=\"auto\"><\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"73\">Bu s\u0131n\u0131flar Vulkan taraf\u0131ndaki i\u015fleri b\u00f6l\u00fc\u015f\u00fcyor:\u00a0<code>VkContext<\/code>\u00a0kurulumu yap\u0131yor,\u00a0<code>VkSwapchain<\/code>\u00a0ekrana sunulacak g\u00f6r\u00fcnt\u00fcleri y\u00f6netiyor,\u00a0<code>VkFrameSync<\/code>\u00a0ise frame&#8217;ler aras\u0131ndaki beklemeleri d\u00fczenliyor. Pipeline s\u0131n\u0131flar\u0131 \u00e7izimin GPU&#8217;da nas\u0131l yap\u0131laca\u011f\u0131n\u0131, vertex zincirleri de \u00e7izilecek geometri verisinin nerede tutulaca\u011f\u0131n\u0131 belirliyor.\u00a0<code>VulkanRenderer<\/code>\u00a0bu par\u00e7alar\u0131 bir araya getiriyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"75\"><code>VkContext<\/code>,\u00a0<code>VkSwapchain<\/code>\u00a0ve\u00a0<code>VkFrameSync<\/code>\u00a0isimleri SDLPainter&#8217;\u0131n kendi yard\u0131mc\u0131 s\u0131n\u0131flar\u0131na ait. \u00d6rne\u011fin Vulkan API&#8217;sindeki as\u0131l swapchain nesnesinin t\u00fcr\u00fc\u00a0<code>VkSwapchainKHR<\/code>; bizim\u00a0<code>VkSwapchain<\/code>\u00a0s\u0131n\u0131f\u0131m\u0131z bu nesneyi ve onunla ili\u015fkili kaynaklar\u0131 y\u00f6netiyor.<\/p>\n<h2 id=\"vkcontext-vulkan\u0131-ba\u015flatmak-ve-gpuyu-se\u00e7mek\" class=\"code-line\" dir=\"auto\" data-line=\"77\"><span style=\"color: #0000ff;\"><strong>VkContext: Vulkan&#8217;\u0131 Ba\u015flatmak ve GPU&#8217;yu Se\u00e7mek<\/strong><\/span><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"79\">OpenGL taraf\u0131nda SDL,\u00a0<code>SDL_GL_CreateContext()<\/code>\u00a0ile ba\u011flam olu\u015fturma i\u015finin \u00f6nemli bir k\u0131sm\u0131n\u0131 \u00fcstleniyor. Vulkan&#8217;da ise hangi cihaz\u0131 kullanaca\u011f\u0131m\u0131z\u0131 ve pencereye nas\u0131l g\u00f6r\u00fcnt\u00fc sunaca\u011f\u0131m\u0131z\u0131 daha a\u00e7\u0131k bi\u00e7imde tan\u0131ml\u0131yoruz.\u00a0<code>VkContext::Initialize()<\/code>, bu kurulum s\u0131ras\u0131n\u0131 a\u015fa\u011f\u0131daki gibi ger\u00e7ekle\u015ftiriyor:<\/p>\n<pre class=\"lang:c++ decode:true \">bool VkContext::Initialize(SDL_Window* window) {\r\n  mValidationEnabled = kEnableValidationDefault &amp;&amp; CheckValidationLayerSupport();\r\n\r\n  if (!CreateInstance()) return false;\r\n  if (mValidationEnabled &amp;&amp; !CreateDebugMessenger()) return false;\r\n  if (!CreateSurface(window)) return false;\r\n  if (!PickPhysicalDevice()) return false;\r\n  if (!CreateLogicalDevice()) return false;\r\n  return true;\r\n}\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"94\">Bu ad\u0131mlardaki kavramlar \u015f\u00f6yle:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"96\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"96\"><strong>Instance (<code>VkInstance<\/code>):<\/strong>\u00a0Uygulaman\u0131n Vulkan ile ba\u011flant\u0131s\u0131n\u0131 ba\u015flat\u0131yor. Kullan\u0131lacak API s\u00fcr\u00fcm\u00fc, instance uzant\u0131lar\u0131 ve do\u011frulama katmanlar\u0131 burada se\u00e7iliyor. Pencere sistemiyle ilgili gerekli uzant\u0131 listesini SDL3&#8217;ten\u00a0<code>SDL_Vulkan_GetInstanceExtensions<\/code>\u00a0ile al\u0131yoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"97\"><strong>Surface (<code>VkSurfaceKHR<\/code>):<\/strong>\u00a0SDL penceresinin Vulkan taraf\u0131ndaki sunum y\u00fczeyini temsil ediyor. Bir GPU&#8217;nun \u00e7izim yapabilmesi, bu pencereye g\u00f6r\u00fcnt\u00fc sunabildi\u011fi anlam\u0131na gelmedi\u011fi i\u00e7in surface&#8217;i cihaz se\u00e7iminden \u00f6nce olu\u015fturuyoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"98\"><strong>Physical device (<code>VkPhysicalDevice<\/code>):<\/strong>\u00a0Sistemdeki bir Vulkan cihaz\u0131n\u0131 temsil ediyor; normal kullan\u0131mda bu bir GPU. Uygun cihazlar aras\u0131ndan se\u00e7im yap\u0131yoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"99\"><strong>Logical device (<code>VkDevice<\/code>) ve queue&#8217;lar:<\/strong>\u00a0Se\u00e7ti\u011fimiz GPU&#8217;da kullanaca\u011f\u0131m\u0131z \u00f6zellikleri ve i\u015f kuyruklar\u0131n\u0131 a\u00e7\u0131yoruz. Graphics queue \u00e7izim komutlar\u0131n\u0131, present queue ise haz\u0131rlanan g\u00f6r\u00fcnt\u00fcy\u00fc pencereye sunma i\u015fini y\u00fcr\u00fct\u00fcyor. Ayn\u0131 t\u00fcr i\u015fleri destekleyen kuyruklar\u0131n grubuna\u00a0<em>queue family<\/em>\u00a0deniyor; tek bir grup hem \u00e7izimi hem sunumu destekleyebiliyor.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"101\">Debug derlemelerinde\u00a0<code>VK_LAYER_KHRONOS_validation<\/code>, sistemde kuruluysa otomatik a\u00e7\u0131l\u0131yor. Bu do\u011frulama katman\u0131, \u00f6rne\u011fin hala kullan\u0131mda olan bir kayna\u011f\u0131 yok etmek gibi Vulkan kullan\u0131m hatalar\u0131n\u0131 bildiriyor.\u00a0<code>CreateDebugMessenger()<\/code>\u00a0bu mesajlar\u0131 uygulaman\u0131n log&#8217;una aktar\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"103\">Fiziksel cihaz se\u00e7imini basit bir puanlamayla yap\u0131yoruz: ayr\u0131 ekran kart\u0131 (<em>discrete GPU<\/em>) 1000, i\u015flemciyle b\u00fct\u00fcnle\u015fik GPU (<em>integrated GPU<\/em>) 100 puan al\u0131yor. \u00c7izim ve sunum i\u00e7in gerekli queue family&#8217;ler ya da\u00a0<code>VK_KHR_swapchain<\/code>\u00a0deste\u011fi yoksa cihaz eleniyor. Bu puanlama bir performans \u00f6l\u00e7\u00fcm\u00fc de\u011fil; uygun cihazlar aras\u0131nda ayr\u0131 ekran kart\u0131na \u00f6ncelik verme yolu.<\/p>\n<pre class=\"lang:c++ decode:true \">int ScoreDevice(VkPhysicalDevice device, VkSurfaceKHR surface) {\r\n  auto q = FindQueueFamilies(device, surface);\r\n  if (!q.IsComplete()) return -1;                   \/\/ graphics + present sart\r\n  if (!DeviceSupportsSwapchain(device)) return -1;  \/\/ VK_KHR_swapchain sart\r\n\r\n  VkPhysicalDeviceProperties props{};\r\n  vkGetPhysicalDeviceProperties(device, &amp;props);\r\n  int score = 0;\r\n  if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)   score += 1000;\r\n  if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) score += 100;\r\n  return score;\r\n}\r\n<\/pre>\n<p id=\"MXfpJqC\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3277 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac.png\" alt=\"\" width=\"1070\" height=\"555\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac.png 1562w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-300x156.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-1024x531.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-768x398.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-1536x797.png 1536w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-500x259.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-150x78.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-1200x622.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-400x207.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-800x415.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67bacf25ac-200x104.png 200w\" sizes=\"auto, (max-width: 1070px) 100vw, 1070px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"122\"><em>Vulkan&#8217;da ba\u015flang\u0131\u00e7 be\u015f ad\u0131m. Surface, cihaz se\u00e7iminden \u00f6nce olu\u015fturuluyor; \u00e7\u00fcnk\u00fc present deste\u011fi bu y\u00fczeye g\u00f6re sorgulan\u0131yor.<\/em><\/p>\n<h2 id=\"vkswapchain-\u00e7izilen-framei-pencerede-g\u00f6stermek\" class=\"code-line\" dir=\"auto\" data-line=\"124\"><strong><span style=\"color: #0000ff;\">VkSwapchain: \u00c7izilen Frame&#8217;i Pencerede G\u00f6stermek<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"126\">GPU&#8217;nun bir g\u00f6r\u00fcnt\u00fc \u00e7izmesiyle o g\u00f6r\u00fcnt\u00fcn\u00fcn pencerede g\u00f6sterilmesi asl\u0131nda iki ayr\u0131 i\u015f. Ekranda bir frame g\u00f6sterilirken uygulama sonraki frame&#8217;i ba\u015fka bir g\u00f6r\u00fcnt\u00fcye \u00e7izebilir. <strong><a href=\"https:\/\/docs.vulkan.org\/tutorial\/latest\/03_Drawing_a_triangle\/01_Presentation\/01_Swap_chain.html\" data-href=\"https:\/\/docs.vulkan.org\/tutorial\/latest\/03_Drawing_a_triangle\/01_Presentation\/01_Swap_chain.html\">Swapchain<\/a><\/strong>, bu ama\u00e7la kullan\u0131lan g\u00f6r\u00fcnt\u00fcleri ve bunlar\u0131n sunum i\u00e7in dola\u015f\u0131ma girmesini y\u00f6neten s\u0131n\u0131f\u0131m\u0131z. OpenGL&#8217;de <code>SDL_GL_SwapWindow()<\/code>\u00a0ile ba\u015flatt\u0131\u011f\u0131m\u0131z sunumun ayr\u0131nt\u0131lar\u0131n\u0131 b\u00fcy\u00fck \u00f6l\u00e7\u00fcde s\u00fcr\u00fcc\u00fcye b\u0131rak\u0131rken, Vulkan&#8217;da bu yap\u0131y\u0131 kendimiz kuruyoruz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"128\">Bir frame i\u00e7in temel s\u0131ra \u015f\u00f6yle:<\/p>\n<ol class=\"code-line\" dir=\"auto\" data-line=\"130\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"130\"><strong>G\u00f6r\u00fcnt\u00fcy\u00fc al\/acquire:<\/strong>\u00a0<code>vkAcquireNextImageKHR<\/code>, kullan\u0131lacak swapchain g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fcn indeksini veriyor. G\u00f6r\u00fcnt\u00fcye ne zaman g\u00fcvenle yaz\u0131labilece\u011fini senkronizasyon nesnesiyle takip ediyoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"131\"><strong>\u00c7izim komutlar\u0131n\u0131 g\u00f6nder\/ submit:<\/strong>\u00a0O g\u00f6r\u00fcnt\u00fcy\u00fc hedefleyen komutlar\u0131 kaydedip\u00a0<code>vkQueueSubmit<\/code>\u00a0ile GPU kuyru\u011funa g\u00f6nderiyoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"132\"><strong>Sunumu iste\/present:<\/strong>\u00a0<code>vkQueuePresentKHR<\/code>\u00a0ile tamamlanan g\u00f6r\u00fcnt\u00fcn\u00fcn pencerede g\u00f6sterilmesini istiyoruz. Sunum, \u00e7izimin bitti\u011fini bildiren semaphore&#8217;u bekliyor.<\/li>\n<\/ol>\n<p id=\"lcwlqpc\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3279 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44.png\" alt=\"\" width=\"1036\" height=\"546\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44.png 1546w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-300x158.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-1024x540.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-768x405.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-1536x810.png 1536w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-500x264.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-150x79.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-1200x633.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-400x211.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-800x422.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67c070de44-200x105.png 200w\" sizes=\"auto, (max-width: 1036px) 100vw, 1036px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"136\"><em>\u00dcstte \u00fc\u00e7 g\u00f6r\u00fcnt\u00fcn\u00fcn ayn\u0131 andaki \u00f6rnek durumu, altta tek bir g\u00f6r\u00fcnt\u00fcn\u00fcn ya\u015fam d\u00f6ng\u00fcs\u00fc var. G\u00f6r\u00fcnt\u00fc say\u0131s\u0131 ve acquire s\u0131ras\u0131 sabit de\u011fil; ayn\u0131 g\u00f6r\u00fcnt\u00fcye yeniden yazmak i\u00e7in acquire beklemesinin tamamlanmas\u0131 gerekiyor.<\/em><\/p>\n<h3 id=\"render-pass-ve-framebuffer-ne-i\u0307\u015fe-yar\u0131yor\" class=\"code-line\" dir=\"auto\" data-line=\"138\"><strong><span style=\"color: #0000ff;\">Render Pass ve Framebuffer Ne \u0130\u015fe Yar\u0131yor?<\/span><\/strong><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"140\">SDLPainter&#8217;daki\u00a0<code>VkSwapchain<\/code>s\u0131n\u0131f\u0131, swapchain g\u00f6r\u00fcnt\u00fclerinin yan\u0131nda <strong>image view<\/strong>,\u00a0<strong>render pass<\/strong>\u00a0ve\u00a0<strong>framebuffer<\/strong>\u00a0nesnelerini de y\u00f6netiyor. Bu isimler ilk bak\u0131\u015fta ayn\u0131 i\u015fi yap\u0131yormu\u015f gibi g\u00f6r\u00fcnebilir; aralar\u0131ndaki fark ise \u015fu:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"142\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"142\"><strong>Image:<\/strong>\u00a0Piksellerin tutuldu\u011fu g\u00f6r\u00fcnt\u00fc kayna\u011f\u0131.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"143\"><strong>Image view:<\/strong>\u00a0Bu g\u00f6r\u00fcnt\u00fcn\u00fcn hangi b\u00f6l\u00fcm\u00fcn\u00fcn, hangi formatla kullan\u0131laca\u011f\u0131n\u0131 tan\u0131mlayan g\u00f6r\u00fcn\u00fcm. Burada her swapchain g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fcn renk b\u00f6l\u00fcm\u00fcn\u00fcn tamam\u0131n\u0131 kullan\u0131yoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"144\"><strong>Render pass:<\/strong>\u00a0\u00c7izim s\u0131ras\u0131nda hangi t\u00fcr g\u00f6r\u00fcnt\u00fclere yaz\u0131laca\u011f\u0131n\u0131 ve bu g\u00f6r\u00fcnt\u00fclerin i\u00e7eri\u011finin ba\u015flang\u0131\u00e7ta ve biti\u015fte nas\u0131l ele al\u0131naca\u011f\u0131n\u0131 tan\u0131ml\u0131yor.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"145\"><strong>Framebuffer:<\/strong>\u00a0Render pass&#8217;in kullanaca\u011f\u0131 somut image view&#8217;lar\u0131 ba\u011fl\u0131yor. Burada her swapchain g\u00f6r\u00fcnt\u00fcs\u00fc i\u00e7in bir framebuffer var; al\u0131nan\u00a0<code>image_index<\/code>\u00a0ile do\u011fru olan\u0131 se\u00e7iyoruz.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"147\">Bu 2B \u00e7izim yolu yaln\u0131zca bir renk \u00e7\u0131kt\u0131s\u0131 kullan\u0131yor; derinlik veya stencil tamponuna ihtiya\u00e7 duymuyor. Render pass&#8217;e ba\u011flanan bu renk g\u00f6r\u00fcnt\u00fcs\u00fcne <strong>color attachment<\/strong>\u00a0deniyor. Frame ba\u015f\u0131nda\u00a0<code>loadOp = CLEAR<\/code>\u00a0ile arka plan rengine temizleniyor, \u00e7izim sonunda\u00a0<code>storeOp = STORE<\/code>\u00a0ile \u00fcretilen pikseller saklan\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"149\">Bir de\u00a0<strong>image layout<\/strong>\u00a0var. Bu, g\u00f6r\u00fcnt\u00fcn\u00fcn o anda hangi kullan\u0131m i\u00e7in haz\u0131r oldu\u011funu Vulkan&#8217;a bildiriyor: \u00e7izim hedefi olmak, doku olarak okunmak veya ekrana sunulmak gibi. Ekran i\u00e7in \u00e7izim bitti\u011finde son layout\u00a0<code>VK_IMAGE_LAYOUT_PRESENT_SRC_KHR<\/code>\u00a0oluyor; yani g\u00f6r\u00fcnt\u00fc sunuma uygun duruma ge\u00e7iriliyor.<\/p>\n<p id=\"WHtOJgH\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3280 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8.png\" alt=\"\" width=\"962\" height=\"510\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8.png 1527w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-300x159.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-1024x543.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-768x407.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-500x265.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-150x80.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-1200x637.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-400x212.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-800x424.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67ca85d0b8-200x106.png 200w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"153\"><em>\u00c7izimi ba\u015flat\u0131rken hem render pass&#8217;i hem framebuffer&#8217;\u0131 veriyoruz: biri kurallar\u0131, di\u011feri kullan\u0131lacak g\u00f6r\u00fcnt\u00fcy\u00fc belirliyor.<\/em><\/p>\n<h3 id=\"renk-format\u0131-ve-sunum-modu-nas\u0131l-se\u00e7iliyor\" class=\"code-line\" dir=\"auto\" data-line=\"155\"><span style=\"color: #0000ff;\"><strong>Renk Format\u0131 ve Sunum Modu Nas\u0131l Se\u00e7iliyor?<\/strong><\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"157\">Renk format\u0131nda\u00a0<code>VK_FORMAT_B8G8R8A8_UNORM<\/code>\u00a0ve\u00a0<code>VK_COLOR_SPACE_SRGB_NONLINEAR_KHR<\/code>\u00a0birle\u015fimini tercih ediyoruz.\u00a0<code>B8G8R8A8<\/code>, mavi, ye\u015fil, k\u0131rm\u0131z\u0131 ve alfa kanallar\u0131n\u0131n sekizer bit olmas\u0131n\u0131;\u00a0<code>UNORM<\/code>\u00a0ise bu tamsay\u0131 de\u011ferlerin shader taraf\u0131nda 0\u20131 aral\u0131\u011f\u0131nda ele al\u0131nmas\u0131n\u0131 belirtiyor. Tercih edilen birle\u015fim yoksa y\u00fczeyin sundu\u011fu ilk format kullan\u0131l\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"159\"><strong><a href=\"https:\/\/docs.vulkan.org\/refpages\/latest\/refpages\/source\/VkPresentModeKHR.html\" data-href=\"https:\/\/docs.vulkan.org\/refpages\/latest\/refpages\/source\/VkPresentModeKHR.html\">Present mode<\/a><\/strong>, \u00e7izim h\u0131z\u0131m\u0131zla ekran\u0131n yenileme h\u0131z\u0131 aras\u0131ndaki ili\u015fkiyi belirliyor. SDLPainter \u00f6nce\u00a0<code>MAILBOX<\/code>\u00a0ar\u0131yor, desteklenmiyorsa\u00a0<code>FIFO<\/code>\u00a0kullan\u0131yor:<\/p>\n<table class=\"code-line\" dir=\"auto\" data-line=\"161\">\n<thead class=\"code-line\" dir=\"auto\" data-line=\"161\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"161\">\n<th>Mod<\/th>\n<th>Haz\u0131r frame&#8217;lere ne oluyor?<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"code-line\" dir=\"auto\" data-line=\"163\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"163\">\n<td><code>MAILBOX<\/code><\/td>\n<td>Ekran\u0131n sonraki yenilemesi i\u00e7in bekleyen tek bir sunum iste\u011fi var. Daha yeni bir frame haz\u0131r olursa bekleyen iste\u011fin yerini al\u0131yor; aradaki frame g\u00f6sterilmeyebiliyor.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"164\">\n<td><code>FIFO<\/code><\/td>\n<td>Sunum istekleri s\u0131raya giriyor. Ekran\u0131n her yenilemesinde s\u0131ran\u0131n ba\u015f\u0131ndaki haz\u0131r frame g\u00f6steriliyor.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p id=\"cGDaMqE\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3282 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da.png\" alt=\"\" width=\"1067\" height=\"568\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da.png 1526w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-300x160.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-1024x546.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-768x409.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-500x266.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-150x80.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-1200x639.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-400x213.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-800x426.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67d1bb57da-200x107.png 200w\" sizes=\"auto, (max-width: 1067px) 100vw, 1067px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"168\"><em>\u00d6rnekte K1, K2 ve K3 bir sonraki ekran yenilemesinden \u00f6nce haz\u0131r oluyor; ard\u0131ndan yeni istek gelmiyor. FIFO bunlar\u0131 s\u0131rayla sunuyor. MAILBOX&#8217;ta K2, K1&#8217;in; K3 de K2&#8217;nin yerini al\u0131yor ve sonraki yenilemede K3 g\u00f6steriliyor.<\/em><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"170\">\u0130ki mod da ekran yenilemesini bekleyerek g\u00f6r\u00fcnt\u00fc y\u0131rt\u0131lmas\u0131n\u0131 \u00f6nl\u00fcyor.\u00a0<code>FIFO<\/code>\u00a0deste\u011fi zorunlu,\u00a0<code>MAILBOX<\/code>\u00a0deste\u011fi ise cihaza ve y\u00fczeye ba\u011fl\u0131. Sunum modu ile g\u00f6r\u00fcnt\u00fc say\u0131s\u0131n\u0131 ayr\u0131 d\u00fc\u015f\u00fcnmek gerekiyor:\u00a0<code>MAILBOX<\/code>\u00a0bekleyen frame&#8217;lerden hangisinin g\u00f6sterilece\u011fini belirliyor, swapchain&#8217;in ka\u00e7 g\u00f6r\u00fcnt\u00fcden olu\u015faca\u011f\u0131n\u0131 de\u011fil. Kod, g\u00f6r\u00fcnt\u00fc say\u0131s\u0131 i\u00e7in y\u00fczeyin istedi\u011fi minimumun bir fazlas\u0131n\u0131 talep ediyor ve varsa maksimum s\u0131n\u0131r\u0131 g\u00f6zetiyor.<\/p>\n<h3 id=\"pencere-yeniden-boyutland\u0131r\u0131l\u0131nca-ne-oluyor\" class=\"code-line\" dir=\"auto\" data-line=\"172\"><span style=\"color: #0000ff;\"><strong>Pencere Yeniden Boyutland\u0131r\u0131l\u0131nca Ne Oluyor?<\/strong><\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"174\">\u00d6rne\u011fin 800 \u00d7 600 piksellik pencereyi 1200 \u00d7 800 yapt\u0131\u011f\u0131m\u0131zda, swapchain g\u00f6r\u00fcnt\u00fclerinin de yeni \u00e7izim boyutuna uygun olmas\u0131 gerekiyor. Bu y\u00fczden swapchain, ona ba\u011fl\u0131 image view&#8217;lar ve framebuffer&#8217;lar yeniden olu\u015fturulur.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"176\">Vulkan,\u00a0<a href=\"https:\/\/docs.vulkan.org\/tutorial\/latest\/03_Drawing_a_triangle\/04_Swap_chain_recreation.html\" data-href=\"https:\/\/docs.vulkan.org\/tutorial\/latest\/03_Drawing_a_triangle\/04_Swap_chain_recreation.html\">swapchain&#8217;in yenilenmesi gerekti\u011fini<\/a>\u00a0iki sonu\u00e7la bildirebiliyor:\u00a0<code>VK_ERROR_OUT_OF_DATE_KHR<\/code>, mevcut swapchain&#8217;in art\u0131k y\u00fczeyle uyumlu olmad\u0131\u011f\u0131n\u0131;\u00a0<code>VK_SUBOPTIMAL_KHR<\/code> ise hala kullan\u0131labildi\u011fini ama y\u00fczeye en uygun durumda olmad\u0131\u011f\u0131n\u0131 s\u00f6yl\u00fcyor. SDLPainter&#8217;da, her iki durumda da yeniden olu\u015fturma yoluna gidiyoruz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"178\">Yaln\u0131zca bu bildirimleri beklemiyoruz, baz\u0131 pencere sistemlerinde g\u00f6r\u00fcnt\u00fc boyutunu uygulama se\u00e7ebildi\u011fi i\u00e7in pencerenin de\u011fi\u015fmesi s\u00fcr\u00fcc\u00fcn\u00fcn mutlaka <code>OUT_OF_DATE<\/code>\u00a0d\u00f6nd\u00fcrmesini gerektirmiyor.\u00a0<code>BeginFrame<\/code>, SDL&#8217;den pencerenin piksel boyutunu al\u0131p son kullan\u0131lan istekle kar\u015f\u0131la\u015ft\u0131r\u0131yor. Y\u00fczey boyutu 0 \u00d7 0 olarak bildiriliyorsa, pencere simge durumuna k\u00fc\u00e7\u00fclt\u00fcld\u00fc\u011f\u00fcnde, \u00e7izim ve yeniden olu\u015fturma erteleniyor; pencere tekrar \u00e7izilebilir oldu\u011funda devam ediliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"180\"><code>Recreate()<\/code>\u00a0s\u0131ras\u0131nda eski swapchain, yenisinin olu\u015fturma bilgisine\u00a0<a href=\"https:\/\/docs.vulkan.org\/refpages\/latest\/refpages\/source\/VkSwapchainCreateInfoKHR.html\" data-href=\"https:\/\/docs.vulkan.org\/refpages\/latest\/refpages\/source\/VkSwapchainCreateInfoKHR.html\"><code>oldSwapchain<\/code><\/a>\u00a0olarak veriliyor. B\u00f6ylece s\u00fcr\u00fcc\u00fcye \u00f6nceki yap\u0131n\u0131n yerine yenisinin geldi\u011fi bildiriliyor ve kaynaklar\u0131 yeniden kullanma f\u0131rsat\u0131 sunuluyor. SDLPainter yeni swapchain&#8217;i olu\u015fturduktan sonra eskisini yok ediyor; yeni g\u00f6r\u00fcnt\u00fcler i\u00e7in image view ve framebuffer&#8217;lar\u0131 yeniden kuruyor.<\/p>\n<h2 id=\"vkframesync-cpu-ve-gpu-aras\u0131ndaki-beklemeleri-y\u00f6netmek\" class=\"code-line\" dir=\"auto\" data-line=\"182\"><strong><span style=\"color: #0000ff;\">VkFrameSync: CPU ve GPU Aras\u0131ndaki Beklemeleri Y\u00f6netmek<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"184\">CPU, \u00e7izim komutlar\u0131n\u0131 GPU&#8217;ya g\u00f6nderdi\u011finde GPU&#8217;nun i\u015fi hemen bitmi\u015f <strong>olmuyor<\/strong>. CPU bir sonraki frame&#8217;i haz\u0131rlarken GPU \u00f6nceki frame&#8217;i \u00e7iziyor olabilir. Bu y\u00fczden command buffer&#8217;\u0131 veya vertex belle\u011fini yeniden kullanmadan \u00f6nce, \u00f6nceki i\u015fin o kaynaklarla i\u015finin bitti\u011finden emin olmam\u0131z gerekiyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"186\"><strong>Command buffer<\/strong>, GPU&#8217;nun \u00e7al\u0131\u015ft\u0131raca\u011f\u0131 komutlar\u0131 kaydetti\u011fimiz nesne. SDLPainter bu nesneyi ve frame&#8217;e ait di\u011fer ge\u00e7ici kaynaklar\u0131 iki\u00a0<strong>frame slotu<\/strong>\u00a0i\u00e7inde tutuyor (<code>kMaxFramesInFlight = 2<\/code>). Slotlar s\u0131rayla kullan\u0131l\u0131yor: 0, 1, sonra tekrar 0. Slot 0&#8217;a d\u00f6nd\u00fc\u011f\u00fcm\u00fczde onun \u00f6nceki i\u015fi bitmemi\u015fse bekliyoruz. B\u00f6ylece ayn\u0131 anda en fazla iki frame&#8217;in \u00e7izim i\u015fi beklemede veya \u00e7al\u0131\u015f\u0131r durumda olabiliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"188\">Burada iki t\u00fcr senkronizasyon nesnesi kullan\u0131yoruz:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"190\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"190\"><strong>Fence:<\/strong>\u00a0CPU&#8217;nun GPU i\u015finin tamamlanmas\u0131n\u0131 beklemesini sa\u011fl\u0131yor. Bir slotu tekrar kullanmadan \u00f6nce\u00a0<code>vkWaitForFences<\/code>\u00a0\u00e7a\u011fr\u0131s\u0131yla o slotun \u00f6nceki komutlar\u0131n\u0131n bitti\u011fini do\u011fruluyoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"191\"><strong>Binary semaphore:<\/strong>\u00a0Kuyruktaki i\u015flerin ve sunumun birbirini beklemesini sa\u011fl\u0131yor.\u00a0<code>mImageAvailable<\/code>, \u00e7izimin g\u00f6r\u00fcnt\u00fc kullan\u0131labilir olana kadar ba\u015flamamas\u0131n\u0131;\u00a0<code>mRenderFinished<\/code>, sunumun \u00e7izim bitmeden ba\u015flamamas\u0131n\u0131 sa\u011fl\u0131yor.<\/li>\n<\/ul>\n<h3 id=\"frame-slotu-ve-swapchain-g\u00f6r\u00fcnt\u00fcs\u00fc\" class=\"code-line\" dir=\"auto\" data-line=\"193\"><strong><span style=\"color: #0000ff;\">Frame Slotu ve Swapchain G\u00f6r\u00fcnt\u00fcs\u00fc<\/span><\/strong><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"195\">Frame slotu, uygulaman\u0131n ge\u00e7ici kaynak grubunu se\u00e7iyor.\u00a0<code>image_index<\/code>\u00a0ise Vulkan&#8217;\u0131n o frame i\u00e7in verdi\u011fi swapchain g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fc se\u00e7iyor. Bunlar\u0131n ayn\u0131 say\u0131 olmas\u0131 gerekmiyor: iki frame slotumuz varken swapchain&#8217;de \u00fc\u00e7 g\u00f6r\u00fcnt\u00fc bulunabilir.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"197\">Bu ayr\u0131m semaphore&#8217;lar\u0131 nas\u0131l saklad\u0131\u011f\u0131m\u0131z\u0131 da etkiliyor:<\/p>\n<table class=\"code-line\" dir=\"auto\" data-line=\"199\">\n<thead class=\"code-line\" dir=\"auto\" data-line=\"199\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"199\">\n<th>Kaynak<\/th>\n<th>Say\u0131s\u0131 ve se\u00e7im y\u00f6ntemi<\/th>\n<th>Yeniden kullanmadan \u00f6nce neyi bekliyoruz?<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"code-line\" dir=\"auto\" data-line=\"201\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"201\">\n<td>Fence ve command buffer<\/td>\n<td>Frame slotu ba\u015f\u0131na bir tane; slot ile se\u00e7iliyor.<\/td>\n<td>O slotun \u00f6nceki GPU i\u015finin bitmesini.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"202\">\n<td><code>mImageAvailable<\/code><\/td>\n<td>Frame slotu ba\u015f\u0131na bir tane; slot ile se\u00e7iliyor.<\/td>\n<td>Slotun fence&#8217;ini. \u00d6nceki i\u015f tamamlan\u0131nca bu semaphore \u00fczerindeki bekleme de tamamlanm\u0131\u015f oluyor.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"203\">\n<td><code>mRenderFinished<\/code><\/td>\n<td>Swapchain g\u00f6r\u00fcnt\u00fcs\u00fc ba\u015f\u0131na bir tane;\u00a0<code>image_index<\/code>\u00a0ile se\u00e7iliyor.<\/td>\n<td>Ayn\u0131 g\u00f6r\u00fcnt\u00fcn\u00fcn yeniden al\u0131nmas\u0131n\u0131 ve acquire beklemesinin tamamlanmas\u0131n\u0131.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"code-line\" dir=\"auto\" data-line=\"205\">Son sat\u0131r\u0131n nedeni \u00f6nemli: \u00e7izimin fence&#8217;i sinyal verdi\u011finde GPU komutlar\u0131 bitmi\u015f oluyor, ama sunum i\u015fleminin\u00a0<code>mRenderFinished<\/code>\u00a0ile i\u015fi hala devam ediyor olabilir. Bu y\u00fczden onu yaln\u0131zca frame slotuna g\u00f6re tekrar kullanmak g\u00fcvenli de\u011fil. G\u00f6r\u00fcnt\u00fc ba\u015f\u0131na ayr\u0131 semaphore tutma gerek\u00e7esi\u00a0<a href=\"https:\/\/docs.vulkan.org\/guide\/latest\/swapchain_semaphore_reuse.html\" data-href=\"https:\/\/docs.vulkan.org\/guide\/latest\/swapchain_semaphore_reuse.html\">Khronos&#8217;un semaphore yeniden kullan\u0131m\u0131 rehberinde<\/a>\u00a0de anlat\u0131l\u0131yor.<\/p>\n<p id=\"aGwwjUI\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3283 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622.png\" alt=\"\" width=\"1069\" height=\"562\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622.png 1524w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-300x158.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-1024x539.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-768x404.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-500x263.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-150x79.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-1200x631.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-400x210.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-800x421.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67e2009622-200x105.png 200w\" sizes=\"auto, (max-width: 1069px) 100vw, 1069px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"211\"><em>\u0130ki frame slotu s\u0131rayla kullan\u0131l\u0131yor; slot tekrar kullan\u0131lmadan \u00f6nce fence bekleniyor. Fence ve imageAvailable frame slotuyla, renderFinished ise swapchain g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fcn indeksiyle se\u00e7iliyor.<\/em><\/p>\n<h2 id=\"pipeline-ve-push-constants-\u00e7izim-ayarlar\u0131n\u0131-gpuya-vermek\" class=\"code-line\" dir=\"auto\" data-line=\"213\"><span style=\"color: #0000ff;\"><strong>Pipeline ve Push Constants: \u00c7izim Ayarlar\u0131n\u0131 GPU&#8217;ya Vermek<\/strong><\/span><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"215\"><strong>Graphics pipeline<\/strong>, vertex verisinin nas\u0131l okunaca\u011f\u0131n\u0131, hangi shader&#8217;lar\u0131n \u00e7al\u0131\u015faca\u011f\u0131n\u0131 ve \u00e7\u0131kan renklerin hedefe nas\u0131l yaz\u0131laca\u011f\u0131n\u0131 bir araya getirir. OpenGL&#8217;de farkl\u0131 \u00e7a\u011fr\u0131larla ayarlad\u0131\u011f\u0131m\u0131z bu durumun \u00f6nemli bir k\u0131sm\u0131n\u0131 Vulkan&#8217;da pipeline olu\u015ftururken tan\u0131ml\u0131yoruz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"217\">Projeksiyon matrisi, renk \u00e7arpan\u0131 (<em>tint<\/em>) ve genel opakl\u0131k gibi \u00e7izimden \u00e7izime de\u011fi\u015fen k\u00fc\u00e7\u00fck verileri ise\u00a0<strong><a href=\"https:\/\/docs.vulkan.org\/guide\/latest\/push_constants.html\" data-href=\"https:\/\/docs.vulkan.org\/guide\/latest\/push_constants.html\">push constants<\/a><\/strong>\u00a0ile g\u00f6nderiyoruz.\u00a0<code>vkCmdPushConstants<\/code>, bu de\u011ferleri command buffer&#8217;a kaydediyor; bu veri i\u00e7in ayr\u0131ca uniform buffer ve descriptor set y\u00f6netmemiz gerekmiyor. K\u00fc\u00e7\u00fck ve s\u0131k g\u00fcncellenen de\u011ferleri bu yolla iletmek pratik oluyor.<\/p>\n<pre class=\"lang:c++ decode:true \">struct alignas(4) PushConstants {\r\n  float transform[16]{};  \/\/\/&lt; mat4 projeksiyon x model (column-major)\r\n  float tint_color[4]{};  \/\/\/&lt; vec4 tint rengi [0,1]\r\n  float opacity{1.0F};    \/\/\/&lt; global opaklik [0,1]\r\n};\r\n\r\n\/\/ 64 + 16 + 4 = 84 byte.\r\nstatic_assert(sizeof(PushConstants) &lt;= 128U,\r\n              \"Vulkan'in garanti ettigi push constant siniri 128 byte.\");\r\n<\/pre>\n<h3 id=\"blend-modlar\u0131-i\u0307\u00e7in-pipeline-se\u00e7imi\" class=\"code-line\" dir=\"auto\" data-line=\"230\"><strong><span style=\"color: #0000ff;\">Blend Modlar\u0131 \u0130\u00e7in Pipeline Se\u00e7imi<\/span><\/strong><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"232\"><strong>Blending<\/strong>, yeni \u00e7izilen rengin hedefteki mevcut renkle nas\u0131l birle\u015fece\u011fini belirler. Yar\u0131 saydam bir \u015feklin arkas\u0131n\u0131 g\u00f6stermesi bunun en tan\u0131d\u0131k \u00f6rne\u011fi. OpenGL&#8217;de kar\u0131\u015ft\u0131rma fakt\u00f6rlerini <code>glBlendFunc<\/code>\u00a0veya\u00a0<code>glBlendFuncSeparate<\/code>\u00a0ile de\u011fi\u015ftirebiliyoruz. Burada kulland\u0131\u011f\u0131m\u0131z Vulkan 1.1 yolunda ise bu ayarlar pipeline olu\u015fturulurken sabitleniyor; sonradan eklenen dinamik durum uzant\u0131lar\u0131n\u0131 kullanm\u0131yoruz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"234\">Bu y\u00fczden her blend modu i\u00e7in ayr\u0131 bir pipeline haz\u0131rlad\u0131m. Bunlar\u0131 \u00e7izim s\u0131ras\u0131nda olu\u015fturmak yerine ba\u015flang\u0131\u00e7ta haz\u0131r tutmay\u0131 tercih ettim:<\/p>\n<pre class=\"lang:c++ decode:true \">std::array&lt;VkPipeline, kBlendModeCount&gt; mPipelines{};<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"240\">D\u00f6rt blend modunun (<code>kAlpha<\/code>,\u00a0<code>kAdditive<\/code>,\u00a0<code>kMultiply<\/code>,\u00a0<code>kNone<\/code>) pipeline&#8217;lar\u0131 tek bir\u00a0<code>vkCreateGraphicsPipelines<\/code> \u00e7a\u011fr\u0131s\u0131yla olu\u015fturuluyor. \u00c7izim s\u0131ras\u0131nda yaln\u0131zca uygun olan\u0131 se\u00e7ip ba\u011fl\u0131yoruz; bu sayede mod de\u011fi\u015fti\u011finde yeni bir pipeline olu\u015fturmam\u0131z gerekmiyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"242\">Dokulu \u00e7izimde say\u0131 sekize \u00e7\u0131k\u0131yor. \u00c7\u00fcnk\u00fc normal dokular\u0131n yan\u0131nda, \u00fczerine \u00e7izim yap\u0131lm\u0131\u015f hedefleri de doku olarak kullanabiliyoruz. Bu hedeflerdeki RGB de\u011ferleri alfayla \u00f6nceden \u00e7arp\u0131lm\u0131\u015f (<em>premultiplied alpha<\/em>) olarak tutuluyor. \u00d6rne\u011fin yar\u0131 saydam k\u0131rm\u0131z\u0131,\u00a0<code>(1, 0, 0, 0.5)<\/code>\u00a0yerine\u00a0<code>(0.5, 0, 0, 0.5)<\/code>\u00a0oluyor. B\u00f6yle bir rengi kar\u0131\u015ft\u0131r\u0131rken bir daha alfayla \u00e7arparsak gere\u011finden koyu bir sonu\u00e7 \u00e7\u0131kar. \u0130kinci varyant grubu bu fark\u0131 kar\u015f\u0131l\u0131yor;\u00a0<code>kAlpha<\/code>\u00a0ve\u00a0<code>kAdditive<\/code>\u00a0i\u00e7in kaynak renk fakt\u00f6r\u00fc\u00a0<code>SRC_ALPHA<\/code>\u00a0yerine\u00a0<code>ONE<\/code>\u00a0se\u00e7iliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"244\">Vulkan taraf\u0131ndaki fakt\u00f6rler\u00a0<code>src\/vulkan\/vk_blend.h<\/code>\u00a0i\u00e7inde tan\u0131ml\u0131. Bunlar\u0131 OpenGL taraf\u0131yla ayn\u0131 sonucu verecek \u015fekilde ayarlad\u0131m; alfa kanal\u0131ndaki bir fark\u0131 ise ancak piksel kar\u015f\u0131la\u015ft\u0131rmas\u0131yla fark edebildim.<\/p>\n<h2 id=\"vulkanbuffer-vertex-belle\u011fini-frameler-aras\u0131nda-yeniden-kullanmak\" class=\"code-line\" dir=\"auto\" data-line=\"246\"><strong><span style=\"color: #0000ff;\">VulkanBuffer: Vertex Belle\u011fini Frame&#8217;ler Aras\u0131nda Yeniden Kullanmak<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"248\">Tessellator&#8217;\u0131n \u00fcretti\u011fi vertex&#8217;leri GPU&#8217;nun okuyabilece\u011fi bir belle\u011fe yazmam\u0131z gerekiyor. Her \u00e7izimde yeni buffer ve bellek ay\u0131rmak yerine, \u00f6nceden ay\u0131rd\u0131\u011f\u0131m\u0131z alan\u0131 tekrar kullan\u0131yoruz.\u00a0<code>VulkanBuffer<\/code>\u00a0i\u00e7indeki\u00a0<em>ring buffer<\/em>\u00a0d\u00fczeni bunu sa\u011fl\u0131yor: veriler s\u0131rayla yaz\u0131l\u0131yor, ilgili frame tamamland\u0131\u011f\u0131nda o frame&#8217;e ayr\u0131lm\u0131\u015f alan yeniden kullan\u0131labiliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"250\">Bellek se\u00e7imini anlatan iki bayrak var:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"252\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"252\"><strong><code>HOST_VISIBLE<\/code>:<\/strong>\u00a0CPU bu belle\u011fi adres alan\u0131na e\u015fleyip (<em>map<\/em>) bir i\u015faret\u00e7i \u00fczerinden yazabiliyor.\u00a0<code>vkMapMemory<\/code>\u00a0\u00e7a\u011fr\u0131s\u0131n\u0131 ba\u015flang\u0131\u00e7ta bir kez yap\u0131yor ve e\u015flemeyi buffer ya\u015fad\u0131\u011f\u0131 s\u00fcrece a\u00e7\u0131k tutuyoruz.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"253\"><strong><a href=\"https:\/\/docs.vulkan.org\/refpages\/latest\/refpages\/source\/VkMemoryPropertyFlagBits.html\" data-href=\"https:\/\/docs.vulkan.org\/refpages\/latest\/refpages\/source\/VkMemoryPropertyFlagBits.html\"><code>HOST_COHERENT<\/code><\/a>:<\/strong>\u00a0CPU&#8217;nun yazd\u0131\u011f\u0131 veriler i\u00e7in ayr\u0131ca\u00a0<code>vkFlushMappedMemoryRanges<\/code>\u00a0\u00e7a\u011f\u0131rmam\u0131z gerekmiyor. GPU&#8217;nun okumakta oldu\u011fu verinin \u00fczerine yazmamak i\u00e7in gereken beklemeleri ise yine yap\u0131yoruz.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"255\">Buffer iki frame slotuna b\u00f6l\u00fcn\u00fcyor. Her slotun kendi yazma konumu (<code>head<\/code>) var. CPU sonraki frame&#8217;i bir slota yazarken GPU di\u011fer slotu okumaya devam edebiliyor. Bir slotu yeniden kullanaca\u011f\u0131m\u0131zda \u00f6nce fence&#8217;ini bekliyor, sonra yaln\u0131zca o slotun yazma konumunu ba\u015fa al\u0131yoruz. Buradaki s\u0131f\u0131rlama pikselleri veya bellekteki b\u00fct\u00fcn bytelar\u0131 temizlemek de\u011fil; yeni verinin nereye yaz\u0131laca\u011f\u0131n\u0131 belirleyen sayac\u0131 s\u0131f\u0131rlamak.<\/p>\n<p id=\"MbnTQTj\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3285 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389.png\" alt=\"\" width=\"1040\" height=\"547\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389.png 1540w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-300x158.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-1024x539.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-768x404.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-1536x808.png 1536w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-500x263.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-150x79.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-1200x631.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-400x210.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-800x421.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67eea48389-200x105.png 200w\" sizes=\"auto, (max-width: 1040px) 100vw, 1040px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"259\"><em>Slot 0&#8217;\u0131 yeniden kullanmadan \u00f6nce fence&#8217;ini bekliyoruz. Slot 1 bu i\u015flemden etkilenmiyor.<\/em><\/p>\n<pre class=\"lang:c++ decode:true \">class VulkanBuffer {\r\n public:\r\n  bool Init(VkDevice device, VkPhysicalDevice phys_device,\r\n            VkDeviceSize capacity, VkBufferUsageFlags usage,\r\n            uint32_t frame_slot_count = 1);\r\n  void ResetRing(uint32_t frame_slot);  \/\/\/&lt; yalnizca bu slotun head'i\r\n  bool Write(const void* data, VkDeviceSize byte_size, VkDeviceSize alignment,\r\n             uint32_t frame_slot, VkDeviceSize&amp; out_offset_bytes);\r\n private:\r\n  void* mMapped{nullptr};            \/\/\/&lt; kalici map, Init'te bir kez cagrilir\r\n  VkDeviceSize mSlotCapacity{0};     \/\/\/&lt; slot basina kapasite\r\n  std::vector&lt;VkDeviceSize&gt; mHeads;  \/\/\/&lt; slot basina bagimsiz head\r\n};\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"277\"><code>VulkanRenderer<\/code>, d\u00fcz renkli ve dokulu \u00e7izimler i\u00e7in ayr\u0131\u00a0<code>VertexChain<\/code>\u00a0nesneleri tutuyor. Bunlar\u0131 birer buffer listesi olarak d\u00fc\u015f\u00fcnebiliriz. Listedeki her\u00a0<code>VulkanBuffer<\/code>, slot ba\u015f\u0131na 4 MB alan sa\u011fl\u0131yor; bir frame&#8217;in verisi mevcut buffer&#8217;lara s\u0131\u011fmazsa listeye yenisi ekleniyor. B\u00f6ylece 4 MB, toplam geometri i\u00e7in bir \u00fcst s\u0131n\u0131r olmuyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"279\">Bu vertex yolunda ayr\u0131ca bir staging buffer olu\u015fturup GPU&#8217;ya kopyalama komutu g\u00f6ndermiyoruz; GPU, CPU&#8217;nun yazd\u0131\u011f\u0131 buffer&#8217;\u0131 do\u011frudan okuyor. SDLPainter&#8217;\u0131n 2D geometri verisi i\u00e7in bu yakla\u015f\u0131m\u0131 se\u00e7tim.\u00a0<code>RenderBatcher<\/code>\u00a0da uyumlu \u00e7izimleri birle\u015ftirerek veriyi daha b\u00fcy\u00fck bloklar halinde g\u00f6nderiyor. Doku piksellerini y\u00fcklerken ise staging buffer kullan\u0131yoruz.<\/p>\n<h2 id=\"dokular-pikselleri-y\u00fcklemek-ve-shadera-ba\u011flamak\" class=\"code-line\" dir=\"auto\" data-line=\"281\"><span style=\"color: #0000ff;\"><strong>Dokular: Pikselleri Y\u00fcklemek ve Shader&#8217;a Ba\u011flamak<\/strong><\/span><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"283\">Bir resmi GPU belle\u011fine kopyalamak tek ba\u015f\u0131na yeterli de\u011fildir; shader&#8217;\u0131n hangi g\u00f6r\u00fcnt\u00fcy\u00fc, hangi \u00f6rnekleme kurallar\u0131yla okuyaca\u011f\u0131n\u0131 da belirtmemiz gerekiyor. Bu ba\u011flant\u0131y\u0131 <strong>descriptor set<\/strong>\u00a0ile kuruyoruz. Descriptor set pikselleri saklam\u0131yor; shader&#8217;\u0131n eri\u015fece\u011fi kaynaklar\u0131n tan\u0131mlar\u0131n\u0131 ta\u015f\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"285\">Dokulu \u00e7izimde iki nesne birlikte kullan\u0131l\u0131yor:\u00a0<strong>image view<\/strong>\u00a0okunacak g\u00f6r\u00fcnt\u00fcy\u00fc,\u00a0<strong>sampler<\/strong>\u00a0ise filtreleme ve doku koordinatlar\u0131n\u0131n g\u00f6r\u00fcnt\u00fc s\u0131n\u0131r\u0131n\u0131 a\u015fmas\u0131 gibi durumlar\u0131n nas\u0131l ele al\u0131naca\u011f\u0131n\u0131 belirliyor. \u0130kisini tek ba\u011flamada sunan descriptor t\u00fcr\u00fcne\u00a0<strong><a href=\"https:\/\/docs.vulkan.org\/tutorial\/latest\/06_Texture_mapping\/02_Combined_image_sampler.html\" data-href=\"https:\/\/docs.vulkan.org\/tutorial\/latest\/06_Texture_mapping\/02_Combined_image_sampler.html\">combined image sampler<\/a><\/strong>\u00a0deniyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"287\"><code>VulkanTexturedPipeline<\/code>, shader&#8217;daki\u00a0<code>set=0, binding=0<\/code>\u00a0konumunun bu t\u00fcr bir kaynak bekledi\u011fini belirten\u00a0<strong>descriptor set layout<\/strong>&#8216;u olu\u015fturuyor. Set&#8217;lerin ayr\u0131ld\u0131\u011f\u0131 havuzu da y\u00f6netiyor; mevcut havuz en fazla 256 set i\u00e7in ayr\u0131lm\u0131\u015f durumda ve her doku bir set al\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"289\"><code>VulkanTexture::Upload()<\/code>\u00a0s\u0131ras\u0131nda ise \u015fu ad\u0131mlar izleniyor:<\/p>\n<ol class=\"code-line\" dir=\"auto\" data-line=\"291\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"291\"><strong>Pikselleri ge\u00e7ici belle\u011fe yaz\u0131yoruz.<\/strong>\u00a0CPU&#8217;nun yazabildi\u011fi bir\u00a0<em>staging buffer<\/em>\u00a0olu\u015fturuluyor. Bir, iki veya \u00fc\u00e7 kanall\u0131 giri\u015f verisi \u00f6nce d\u00f6rt kanall\u0131 RGBA bi\u00e7imine geni\u015fletiliyor.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"292\"><strong>As\u0131l doku g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fc olu\u015fturuyoruz.<\/strong>\u00a0<code>DEVICE_LOCAL<\/code>\u00a0bellek \u00fczerinde\u00a0<code>R8G8B8A8_UNORM<\/code>\u00a0format\u0131nda bir\u00a0<code>VkImage<\/code>\u00a0ve ona ait image view olu\u015fturuluyor.\u00a0<code>TRANSFER_DST<\/code>\u00a0ve\u00a0<code>SAMPLED<\/code>\u00a0kullan\u0131m bayraklar\u0131, g\u00f6r\u00fcnt\u00fcn\u00fcn hem kopyalama hedefi hem shader&#8217;\u0131n okuyaca\u011f\u0131 doku olaca\u011f\u0131n\u0131 belirtiyor.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"293\"><strong>Kopyalamay\u0131 ve layout ge\u00e7i\u015flerini kaydediyoruz.<\/strong>\u00a0G\u00f6r\u00fcnt\u00fc \u00f6nce\u00a0<code>UNDEFINED<\/code>\u00a0durumundan\u00a0<code>TRANSFER_DST_OPTIMAL<\/code>\u00a0durumuna ge\u00e7iriliyor; staging buffer&#8217;daki pikseller g\u00f6r\u00fcnt\u00fcye kopyalan\u0131yor. Ard\u0131ndan\u00a0<code>SHADER_READ_ONLY_OPTIMAL<\/code>\u00a0durumuna ge\u00e7irilerek shader&#8217;\u0131n okumas\u0131na haz\u0131rlan\u0131yor. Tek seferlik command buffer g\u00f6nderilip fence beklendikten sonra ge\u00e7ici buffer serbest b\u0131rak\u0131l\u0131yor.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"294\"><strong>\u00d6rnekleme kurallar\u0131n\u0131 olu\u015fturuyoruz.<\/strong>\u00a0<code>VkSampler<\/code>, dokunun nas\u0131l filtrelenece\u011fini ve koordinatlar\u0131n nas\u0131l ele al\u0131naca\u011f\u0131n\u0131 belirliyor.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"295\"><strong>Shader ba\u011flant\u0131s\u0131n\u0131 kuruyoruz.<\/strong>\u00a0Image view ve sampler descriptor set&#8217;e yaz\u0131l\u0131yor; \u00e7izim s\u0131ras\u0131nda bu set ba\u011flan\u0131yor.<\/li>\n<\/ol>\n<p class=\"code-line\" dir=\"auto\" data-line=\"297\">Layout ge\u00e7i\u015fleri yaln\u0131zca bir alan\u0131n de\u011ferini de\u011fi\u015ftirmek de\u011fil. Kopyalama ile shader okumas\u0131 aras\u0131ndaki eri\u015fim s\u0131ras\u0131n\u0131 ve verinin g\u00f6r\u00fcn\u00fcrl\u00fc\u011f\u00fcn\u00fc de d\u00fczenliyoruz. B\u00f6ylece shader, kopyalanmas\u0131 hen\u00fcz tamamlanmam\u0131\u015f bir g\u00f6r\u00fcnt\u00fcy\u00fc okumuyor.<\/p>\n<p id=\"VmPQGjw\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3287 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f.png\" alt=\"\" width=\"1090\" height=\"569\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f.png 1541w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-300x157.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-1024x534.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-768x401.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-1536x801.png 1536w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-500x261.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-150x78.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-1200x626.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-400x209.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-800x417.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67f434e81f-200x104.png 200w\" sizes=\"auto, (max-width: 1090px) 100vw, 1090px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"301\"><em>CPU pikselleri ge\u00e7ici buffer&#8217;a yaz\u0131yor; GPU bunlar\u0131 doku g\u00f6r\u00fcnt\u00fcs\u00fcne kopyal\u0131yor. Descriptor set ise shader&#8217;\u0131n bu g\u00f6r\u00fcnt\u00fcy\u00fc sampler ile okuyabilmesini sa\u011fl\u0131yor.<\/em><\/p>\n<h2 id=\"shaderlar\u0131-dosyadan-okumak-yerine-k\u00fct\u00fcphaneye-g\u00f6mmek\" class=\"code-line\" dir=\"auto\" data-line=\"303\"><strong><span style=\"color: #0000ff;\">Shader&#8217;lar\u0131 Dosyadan Okumak Yerine K\u00fct\u00fcphaneye G\u00f6mmek<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"305\">Vulkan&#8217;a shader&#8217;\u0131n GLSL kaynak metnini de\u011fil, derlenmi\u015f\u00a0<strong>SPIR-V<\/strong>\u00a0kodunu veriyoruz.\u00a0<code>glslc<\/code>, bu projede GLSL dosyalar\u0131n\u0131\u00a0<code>.spv<\/code> dosyalar\u0131na d\u00f6n\u00fc\u015ft\u00fcren ara\u00e7. Faz 5&#8217;in ilk halinde bu dosyalar uygulama \u00e7al\u0131\u015f\u0131rken diskten okunuyor, normal derleme s\u0131ras\u0131nda da <code>glslc<\/code>\u00a0aran\u0131yordu. Bu durum hem shader dosyalar\u0131n\u0131n uygulamayla birlikte do\u011fru yere kopyalanmas\u0131n\u0131 hem de k\u00fct\u00fcphaneyi derleyen herkesin shader derleyicisini kurmas\u0131n\u0131 gerektiriyordu.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"307\">ADR-009 ile derlenmi\u015f SPIR-V dosyalar\u0131n\u0131\u00a0<code>src\/vulkan\/shaders\/spirv\/<\/code>\u00a0alt\u0131nda repoda tutmaya ba\u015flad\u0131k. CMake bunlardan\u00a0<code>embedded_vk_shaders.h<\/code>\u00a0ba\u015fl\u0131\u011f\u0131n\u0131 \u00fcretiyor; shader kodlar\u0131\u00a0<code>uint32_t<\/code>\u00a0dizileri olarak derlenen k\u00fct\u00fcphanenin i\u00e7ine giriyor.\u00a0<code>glslc<\/code>, art\u0131k yaln\u0131zca\u00a0<code>-DSDLPAINTER_REGENERATE_SHADERS=ON<\/code>\u00a0se\u00e7ene\u011fiyle a\u00e7\u0131lan\u00a0<code>regenerate_shaders<\/code>\u00a0hedefinde aran\u0131yor. Shader kayna\u011f\u0131n\u0131 de\u011fi\u015ftiren geli\u015ftirici bu hedefi \u00e7al\u0131\u015ft\u0131r\u0131p yeni\u00a0<code>.spv<\/code>\u00a0dosyalar\u0131n\u0131 da kaynak kontrol\u00fcne ekliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"309\">K\u00fct\u00fcphaneyi kullanan ki\u015finin art\u0131k shader dosyalar\u0131n\u0131 uygulaman\u0131n yan\u0131na kopyalamas\u0131 gerekmiyor. Normal derleme i\u00e7in Vulkan ba\u015fl\u0131klar\u0131 ve loader ba\u011f\u0131ml\u0131l\u0131klar\u0131 hala gerekli, fakat s\u0131rf shader derleyicisi i\u00e7in Vulkan SDK kurmak gerekmiyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"311\">GLSL kayna\u011f\u0131 de\u011fi\u015fti\u011fi halde SPIR-V \u00e7\u0131kt\u0131s\u0131 yenilenmezse uygulama eski shader&#8217;\u0131 \u00e7al\u0131\u015ft\u0131rmaya devam eder. Bunu yakalamak i\u00e7in\u00a0<code>cmake\/CheckShaderFreshness.cmake<\/code>, GLSL kaynaklar\u0131n\u0131n SHA-256 \u00f6zetlerini son \u00fcretimde kaydedilen\u00a0<code>sources.sha256<\/code>\u00a0ile kar\u015f\u0131la\u015ft\u0131r\u0131yor. Kaynak de\u011fi\u015fmi\u015fse kontrol ba\u015far\u0131s\u0131z oluyor. Shader derleyicisine ihtiya\u00e7 duymayan bu kontrol, CI&#8217;daki\u00a0<code>quality:shader-freshness<\/code>\u00a0i\u015finde \u00e7al\u0131\u015f\u0131yor.<\/p>\n<h2 id=\"dokuya-\u00e7izmek-ve-\u00f6nceki-i\u0307\u00e7eri\u011fi-korumak\" class=\"code-line\" dir=\"auto\" data-line=\"313\"><strong><span style=\"color: #0000ff;\">Dokuya \u00c7izmek ve \u00d6nceki \u0130\u00e7eri\u011fi Korumak<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"315\"><strong>\u00c7izim hedefi (<code>RenderTarget<\/code>)<\/strong>, sonucu do\u011frudan pencerede g\u00f6stermek yerine bir dokuya \u00e7izmemizi sa\u011fl\u0131yor. \u00d6rne\u011fin bir paneli \u00f6nce bu dokuya \u00e7izebilir, ard\u0131ndan panelin tamam\u0131n\u0131 tek g\u00f6r\u00fcnt\u00fc olarak ekrana yerle\u015ftirebiliriz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"317\">SDLPainter bu hedeflerde ekran format\u0131ndan ba\u011f\u0131ms\u0131z olarak\u00a0<code>R8G8B8A8_UNORM<\/code>\u00a0kullan\u0131yor. B\u00f6ylece hedefin piksellerini CPU&#8217;ya geri okurken RGBA kanal s\u0131ras\u0131n\u0131 sabit tutabiliyoruz. Swapchain format\u0131n\u0131 kullansayd\u0131k BGRA\/RGBA s\u0131ras\u0131 veya sRGB d\u00f6n\u00fc\u015f\u00fcm\u00fc y\u00fczeye g\u00f6re de\u011fi\u015febilirdi.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"319\">Hedef i\u00e7in ayr\u0131 render pass ve pipeline tak\u0131mlar\u0131 olu\u015fturuyoruz. \u00c7\u00fcnk\u00fc kulland\u0131\u011f\u0131m\u0131z Vulkan yolunda pipeline, birlikte kullan\u0131laca\u011f\u0131 render pass ile\u00a0<a href=\"https:\/\/docs.vulkan.org\/spec\/latest\/chapters\/renderpass.html#renderpass-compatibility\" data-href=\"https:\/\/docs.vulkan.org\/spec\/latest\/chapters\/renderpass.html#renderpass-compatibility\">uyumlu olmal\u0131<\/a>; renk attachment&#8217;\u0131n\u0131n format\u0131 da bu uyumlulu\u011fun par\u00e7as\u0131. Ekran\u0131n BGRA, hedefin RGBA olmas\u0131 bu ayr\u0131m\u0131 gerektirebiliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"321\">Hedef de\u011fi\u015ftirirken i\u00e7eri\u011fi korumak da ayr\u0131 bir konu. \u015eu s\u0131ray\u0131 d\u00fc\u015f\u00fcnelim: \u00f6nce ekrana arka plan\u0131 \u00e7iziyoruz, sonra bir dokuya ge\u00e7ip paneli haz\u0131rl\u0131yoruz, ard\u0131ndan tekrar ekrana d\u00f6n\u00fcyoruz. D\u00f6n\u00fc\u015fte ekran\u0131n ilk render pass&#8217;ini yeniden ba\u015flatsayd\u0131k\u00a0<code>loadOp = CLEAR<\/code>, az \u00f6nce \u00e7izdi\u011fimiz arka plan\u0131 silerdi.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"323\">Bu y\u00fczden her \u00e7izim yolu i\u00e7in iki render pass var: biri ba\u015flang\u0131\u00e7ta g\u00f6r\u00fcnt\u00fcy\u00fc temizliyor (<code>CLEAR<\/code>), di\u011feri mevcut pikselleri koruyarak \u00e7izime devam ediyor (<code>LOAD<\/code>). Ekrana frame ortas\u0131nda d\u00f6nerken ikinciyi kullan\u0131yoruz. Yeni olu\u015fturulan bir \u00e7izim hedefine ilk ba\u011flan\u0131\u015fta da i\u00e7eri\u011fi temizleyerek tan\u0131ml\u0131 hale getiriyoruz; sonraki ba\u011flan\u0131\u015flarda koruyoruz. Bu ilk ba\u011flan\u0131\u015f, hedefin \u00f6mr\u00fc boyunca bir kez ger\u00e7ekle\u015fiyor; her frame&#8217;de otomatik olarak tekrarlanm\u0131yor.<\/p>\n<p id=\"AzCQvmk\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3288 aligncenter\" src=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6.png\" alt=\"\" width=\"1074\" height=\"572\" srcset=\"https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6.png 1522w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-300x160.png 300w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-1024x546.png 1024w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-768x409.png 768w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-500x266.png 500w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-150x80.png 150w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-1200x639.png 1200w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-400x213.png 400w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-800x426.png 800w, https:\/\/yazilimperver.com\/wp-content\/uploads\/2026\/10\/img_6ad67fa650cb6-200x107.png 200w\" sizes=\"auto, (max-width: 1074px) 100vw, 1074px\" \/><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"327\"><em>Panel iki durumda da \u00e7iziliyor. LOAD kullan\u0131lan sa\u011f tarafta, \u00f6nceki \u015fekiller de yerinde kal\u0131yor.<\/em><\/p>\n<h2 id=\"opengl-ve-vulkan-ayn\u0131-g\u00f6r\u00fcnt\u00fcy\u00fc-\u00fcretiyor-mu-piksel-kar\u015f\u0131la\u015ft\u0131rmas\u0131\" class=\"code-line\" dir=\"auto\" data-line=\"329\"><strong><span style=\"color: #0000ff;\">OpenGL ve Vulkan Ayn\u0131 G\u00f6r\u00fcnt\u00fcy\u00fc \u00dcretiyor mu? Piksel Kar\u015f\u0131la\u015ft\u0131rmas\u0131<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"331\">Vulkan backend&#8217;ini eklerken\u00a0<code>Tessellator<\/code>&#8216;\u0131 de\u011fi\u015ftirmemiz gerekmedi. \u015eekiller yine ayn\u0131 \u00fc\u00e7genlere d\u00f6n\u00fc\u015ft\u00fcr\u00fcl\u00fcyor; fark, bu \u00fc\u00e7genleri GPU&#8217;ya g\u00f6nderen renderer&#8217;da ba\u015fl\u0131yor:<\/p>\n<pre class=\"lang:c++ decode:true \">Painter::FillCircle(cx, cy, radius)\r\n  \u2192 Tessellator::TessellateFilledCircle(...)  \u2192 std::vector&lt;Vertex&gt;\r\n  \u2192 RenderBatcher (donusum + renk, batch'leme)\r\n  \u2192 IRenderer::DrawTriangles(vertices)\r\n      \u2192 OpenGLRenderer::DrawTriangles()\r\n      \u2192 VulkanRenderer::DrawTriangles()<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"342\">Ancak iki backend&#8217;e ayn\u0131 vertex&#8217;leri g\u00f6ndermek, ayn\u0131 pikselleri \u00fcreteceklerini tek ba\u015f\u0131na g\u00f6stermiyor. Doku format\u0131 veya kar\u0131\u015ft\u0131rma ayar\u0131ndaki bir fark bile sonucu de\u011fi\u015ftirebilir.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"344\">\u0130ki backend&#8217;in \u00e7\u0131kt\u0131s\u0131n\u0131 g\u00f6zle kar\u015f\u0131la\u015ft\u0131rmakla yetinmek istemedim. Bu y\u00fczden ayn\u0131 sahneyi ikisiyle de \u00e7izdirip pikselleri kar\u015f\u0131la\u015ft\u0131ran bir test ekledim (<code>tests\/test_backend_parity.cpp<\/code>). Bu t\u00fcr bir kar\u015f\u0131la\u015ft\u0131rmaya\u00a0<strong>parite testi<\/strong>\u00a0deniyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"346\">Testte dolgu, \u00e7er\u00e7eve, kesikli \u00e7izgi, bezier yolu, gradient, doku, k\u0131rpma, d\u00f6n\u00fc\u015f\u00fcm ve opakl\u0131k i\u00e7eren ayn\u0131 sahne, iki backend&#8217;de birer \u00e7izim hedefine \u00e7iziliyor. Sonra pikseller CPU&#8217;ya okunup k\u0131rm\u0131z\u0131, ye\u015fil, mavi ve alfa kanallar\u0131 kar\u015f\u0131la\u015ft\u0131r\u0131l\u0131yor. Sabit bir referans PNG kullanmad\u0131m; burada kontrol etmek istedi\u011fim, iki backend&#8217;in birbirine uymas\u0131yd\u0131.<\/p>\n<h3 id=\"kar\u015f\u0131la\u015ft\u0131rman\u0131n-ortaya-\u00e7\u0131kard\u0131\u011f\u0131-\u00fc\u00e7-hata\" class=\"code-line\" dir=\"auto\" data-line=\"348\"><strong><span style=\"color: #0000ff;\">Kar\u015f\u0131la\u015ft\u0131rman\u0131n Ortaya \u00c7\u0131kard\u0131\u011f\u0131 \u00dc\u00e7 Hata<\/span><\/strong><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"350\">Testi ilk \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131mda, \u00f6nceki g\u00f6rsel kontrollerde fark etmedi\u011fim \u00fc\u00e7 hata ortaya \u00e7\u0131kt\u0131:<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"352\"><strong>1. Doku okunurken uygulanan renk d\u00f6n\u00fc\u015f\u00fcm\u00fc farkl\u0131yd\u0131.<\/strong>\u00a0Vulkan dokular\u0131\u00a0<code>VK_FORMAT_R8G8B8A8_SRGB<\/code>\u00a0ile olu\u015fturuluyordu. sRGB, renk de\u011ferlerinin do\u011frusal olmayan bir g\u00f6sterimi; GPU bu format\u0131 \u00f6rneklerken de\u011ferleri do\u011frusal uzaya d\u00f6n\u00fc\u015ft\u00fcr\u00fcyor. OpenGL taraf\u0131nda kullan\u0131lan\u00a0<code>GL_RGBA<\/code>\u00a0dokuda ise bu d\u00f6n\u00fc\u015f\u00fcm uygulanm\u0131yordu. Vulkan&#8217;\u0131n\u00a0<code>B8G8R8A8_UNORM<\/code>\u00a0ekran \u00e7\u0131kt\u0131s\u0131 da ters d\u00f6n\u00fc\u015f\u00fcm\u00fc otomatik yapmad\u0131\u011f\u0131 i\u00e7in ayn\u0131 PNG&#8217;nin say\u0131sal renkleri iki yolda farkl\u0131 i\u015fleniyordu. Vulkan doku format\u0131n\u0131\u00a0<code>R8G8B8A8_UNORM<\/code>\u00a0yaparak davran\u0131\u015flar\u0131 e\u015fitledik. Yaz\u0131 karakterlerinin tutuldu\u011fu glyph atlas\u0131 da doku oldu\u011fu i\u00e7in metin \u00e7izimi de bu farktan etkileniyordu.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"354\"><strong>2. Alfa kanal\u0131 farkl\u0131 hesaplan\u0131yordu.<\/strong>\u00a0OpenGL&#8217;deki\u00a0<code>glBlendFunc<\/code>, se\u00e7ilen fakt\u00f6rleri hem RGB&#8217;ye hem alfaya uyguluyor. Vulkan&#8217;da ise bu iki grubun fakt\u00f6rleri ayr\u0131 ayr\u0131 belirtiliyor ve bizim se\u00e7imlerimiz uyu\u015fmuyordu. Pencerede g\u00f6sterirken swapchain&#8217;in alfas\u0131n\u0131 yok sayd\u0131\u011f\u0131m\u0131z i\u00e7in hata belirgin de\u011fildi; \u00e7izim hedefinin alfa de\u011ferleri kar\u015f\u0131la\u015ft\u0131r\u0131ld\u0131\u011f\u0131nda ortaya \u00e7\u0131kt\u0131. OpenGL taraf\u0131n\u0131\u00a0<code>glBlendFuncSeparate<\/code>\u00a0kullanacak \u015fekilde d\u00fczelttik. Normal alfa kar\u0131\u015ft\u0131rmas\u0131nda iki backend de art\u0131k\u00a0<code>aOut = aSrc + aDst * (1 - aSrc)<\/code>\u00a0form\u00fcl\u00fcn\u00fc kullan\u0131yor: yeni \u015feklin alfas\u0131na, arkadaki i\u00e7eri\u011fin g\u00f6r\u00fcn\u00fcr kalan alfa pay\u0131 ekleniyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"356\"><strong>3. OpenGL&#8217;in ilk kar\u0131\u015ft\u0131rma ayar\u0131 eski kalm\u0131\u015ft\u0131.<\/strong>\u00a0<code>SetBlendMode<\/code>\u00a0d\u00fczeltilmi\u015fti ama\u00a0<code>Initialize()<\/code>\u00a0i\u00e7indeki ayr\u0131\u00a0<code>glBlendFunc<\/code>\u00a0\u00e7a\u011fr\u0131s\u0131 hala eski fakt\u00f6rleri se\u00e7iyordu. Uygulama sonradan mod de\u011fi\u015ftirmezse d\u00fczeltme devreye girmiyordu. Ba\u015flang\u0131\u00e7 ayar\u0131n\u0131 da ayn\u0131 hesaplamay\u0131 kullanacak \u015fekilde e\u015fitledik.<\/p>\n<h3 id=\"test-neden-k\u00fc\u00e7\u00fck-farklara-i\u0307zin-veriyor\" class=\"code-line\" dir=\"auto\" data-line=\"358\"><span style=\"color: #0000ff;\">Test Neden K\u00fc\u00e7\u00fck Farklara \u0130zin Veriyor?<\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"360\">Windows&#8217;ta nvidia s\u00fcr\u00fcc\u00fcleriyle yapt\u0131\u011f\u0131m \u00f6l\u00e7\u00fcmde fark <strong>s\u0131f\u0131rd\u0131<\/strong>: 160 \u00d7 120&#8217;lik sahnenin 19.200 pikselinin tamam\u0131 byte byte ayn\u0131 \u00e7\u0131kt\u0131. Bu sonu\u00e7 test sahnesi ve kulland\u0131\u011f\u0131m s\u00fcr\u00fcc\u00fc i\u00e7in ge\u00e7erli; farkl\u0131 s\u00fcr\u00fcc\u00fclerde k\u00fc\u00e7\u00fck farklar olabiliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"362\">Testte kanal ba\u015f\u0131na 8 birimlik tolerans var. 0\u2013255 aral\u0131\u011f\u0131ndaki herhangi bir kanalda fark 8&#8217;i a\u015farsa o piksel farkl\u0131 say\u0131l\u0131yor; farkl\u0131 say\u0131lan piksellerin oran\u0131 da en fazla %0,5 olabiliyor. Bu pay, CI&#8217;daki yaz\u0131l\u0131m tabanl\u0131 Vulkan ve OpenGL uygulamalar\u0131n\u0131n (lavapipe \/ llvmpipe) \u00f6zellikle \u015fekil kenarlar\u0131nda \u00fcretebildi\u011fi k\u00fc\u00e7\u00fck farklar i\u00e7in b\u0131rak\u0131ld\u0131. Testin buldu\u011fu \u00fc\u00e7 hatan\u0131n en k\u00fc\u00e7\u00fc\u011f\u00fc bile piksellerin %4&#8217;\u00fcn\u00fc etkiledi\u011fi i\u00e7in bu e\u015fikler onlar\u0131 yakalayabiliyor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"364\">\u00d6l\u00e7\u00fclen oran her \u00e7al\u0131\u015ft\u0131rmada yazd\u0131r\u0131l\u0131yor. Test ba\u015far\u0131s\u0131z olursa farklar\u0131n nerede topland\u0131\u011f\u0131n\u0131 g\u00f6steren metin tabanl\u0131 bir harita ve en b\u00fcy\u00fck fark\u0131n bulundu\u011fu pikselin \u00e7evresi de raporlan\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"366\">\u0130kinci test, ayn\u0131 backend&#8217;in ayn\u0131 sahneyi iki kez \u00e7izdi\u011finde birebir ayn\u0131 \u00e7\u0131kt\u0131y\u0131 verdi\u011fini kontrol ediyor. Sonu\u00e7 her \u00e7al\u0131\u015ft\u0131rmada de\u011fi\u015fseydi, backend&#8217;ler aras\u0131nda g\u00f6rd\u00fc\u011f\u00fcm\u00fcz fark\u0131 yorumlamak da zorla\u015f\u0131rd\u0131.<\/p>\n<h3 id=\"vulkan-kullan\u0131m-hatalar\u0131-da-testi-ba\u015far\u0131s\u0131z-k\u0131l\u0131yor\" class=\"code-line\" dir=\"auto\" data-line=\"368\"><span style=\"color: #0000ff;\"><strong>Vulkan Kullan\u0131m Hatalar\u0131 da Testi Ba\u015far\u0131s\u0131z K\u0131l\u0131yor<\/strong><\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"370\">Do\u011frulama katman\u0131n\u0131n bildirdi\u011fi hatalar\u0131 da test sonucuna ba\u011flad\u0131m. \u00d6nceden bu mesajlar yaln\u0131zca log&#8217;a yaz\u0131l\u0131yordu; Vulkan kurallar\u0131na ayk\u0131r\u0131 kullan\u0131m varken bile test ba\u015far\u0131l\u0131 g\u00f6r\u00fcnebiliyordu.\u00a0<code>ValidationErrorCount()<\/code>\u00a0sayac\u0131 ve testlerdeki\u00a0<code>ValidationGuard<\/code>, bildirilen hatalar\u0131n testi ba\u015far\u0131s\u0131z k\u0131lmas\u0131n\u0131 sa\u011fl\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"372\">CI&#8217;da\u00a0<code>SDLPAINTER_REQUIRE_VALIDATION=1<\/code>\u00a0de ayarl\u0131. \u00c7\u00fcnk\u00fc do\u011frulama katman\u0131 hi\u00e7 y\u00fcklenmediyse s\u0131f\u0131r hata saymak anlaml\u0131 de\u011fil. Bu ayar, katman\u0131n bulunmamas\u0131n\u0131 da test hatas\u0131 say\u0131yor.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"374\">Piksel kar\u015f\u0131la\u015ft\u0131rmas\u0131n\u0131n bir s\u0131n\u0131r\u0131 var: iki backend ayn\u0131 hatal\u0131 sonucu \u00fcretirse test bunu yakalayamaz. Bu test sonu\u00e7lar\u0131n birbirine uydu\u011funu denetliyor; \u00e7izimin do\u011frulu\u011fu i\u00e7in di\u011fer geometri ve \u00e7izim testlerine de ihtiya\u00e7 var.<\/p>\n<h2 id=\"kaynak-y\u00f6netimi-ve-hata-kontrol\u00fc\" class=\"code-line\" dir=\"auto\" data-line=\"376\"><span style=\"color: #0000ff;\"><strong>Kaynak Y\u00f6netimi ve Hata Kontrol\u00fc<\/strong><\/span><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"378\">Buffer, image ve pipeline gibi Vulkan kaynaklar\u0131n\u0131 olu\u015fturduktan sonra uygun Vulkan fonksiyonlar\u0131yla serbest b\u0131rakmam\u0131z gerekiyor. \u00d6zellikle kurulum yar\u0131da ba\u015far\u0131s\u0131z oldu\u011funda, o ana kadar olu\u015fturulan kaynaklar\u0131 unutmamak \u00f6nemli.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"380\">Bu kaynaklar\u0131n y\u00f6netimini\u00a0<strong>RAII<\/strong>\u00a0ile C++ nesnelerine b\u0131rakt\u0131m.\u00a0<code>VulkanBuffer<\/code>,\u00a0<code>VulkanPipeline<\/code>,\u00a0<code>VulkanTexturedPipeline<\/code>,\u00a0<code>VulkanTexture<\/code>\u00a0ve\u00a0<code>VulkanRenderTarget<\/code>, olu\u015fturulduklar\u0131\u00a0<code>VkDevice<\/code>&#8216;\u0131 sakl\u0131yor. C++ nesnesinin y\u0131k\u0131c\u0131s\u0131 \u00e7al\u0131\u015ft\u0131\u011f\u0131nda sahip oldu\u011fu Vulkan kaynaklar\u0131 da serbest b\u0131rak\u0131l\u0131yor. Bu nesnelerin device&#8217;tan \u00f6nce yok edilmesi ve GPU&#8217;nun art\u0131k onlar\u0131 kullanm\u0131yor olmas\u0131 gerekiyor. Yaln\u0131zca pipeline kurulurken gereken shader mod\u00fclleri gibi k\u0131sa \u00f6m\u00fcrl\u00fc kaynaklar\u0131 ise i\u015f bitince a\u00e7\u0131k\u00e7a serbest b\u0131rak\u0131yoruz.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"382\"><strong><code>VK_CHECK<\/code><\/strong>, sonu\u00e7 kodu d\u00f6nd\u00fcren Vulkan \u00e7a\u011fr\u0131lar\u0131n\u0131n hata kontrol\u00fcn\u00fc k\u0131salt\u0131yor. Bir \u00e7a\u011fr\u0131 ba\u015far\u0131s\u0131z olursa hangi fonksiyonun, hangi sonu\u00e7la ve hangi kaynak kod sat\u0131r\u0131nda ba\u015far\u0131s\u0131z oldu\u011funu log&#8217;a yaz\u0131p mevcut fonksiyondan d\u00f6n\u00fcyor. Ba\u015flatma hatas\u0131nda\u00a0<code>std::abort<\/code>\u00a0ile uygulamay\u0131 sonland\u0131rm\u0131yoruz; \u00e7a\u011f\u0131ran kodun hatay\u0131 ele almas\u0131na ve kaynaklar\u0131n\u0131 temizlemesine izin veriyoruz. Farkl\u0131 d\u00f6n\u00fc\u015f tipleri i\u00e7in \u00fc\u00e7 varyant var:\u00a0<code>VK_CHECK<\/code>,\u00a0<code>VK_CHECK_HANDLE<\/code>\u00a0ve\u00a0<code>VK_CHECK_RETURN<\/code>.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"384\">\u00d6rne\u011fin shader mod\u00fcl\u00fc i\u00e7in GPU belle\u011fi ayr\u0131lamad\u0131\u011f\u0131nda mesaj \u015f\u00f6yle:<\/p>\n<pre class=\"lang:c++ decode:true\">Vulkan call failed: vkCreateShaderModule(device, &amp;ci, nullptr, &amp;mod) -&gt; VK_ERROR_OUT_OF_DEVICE_MEMORY (...\/vulkan_pipeline.cpp:29)<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"390\"><strong><code>FindMemoryType<\/code><\/strong>, cihaz\u0131n sundu\u011fu bellek tipleri aras\u0131ndan kayna\u011fa uygun olan\u0131 buluyor. Hem buffer veya image&#8217;\u0131n destekledi\u011fi tiplerden birini se\u00e7memiz hem de\u00a0<code>HOST_VISIBLE<\/code>\u00a0ya da\u00a0<code>DEVICE_LOCAL<\/code>\u00a0gibi istedi\u011fimiz \u00f6zellikleri sa\u011flamam\u0131z gerekiyor. Bu aramay\u0131 tek yard\u0131mc\u0131 fonksiyonda tutuyoruz; vertex buffer&#8217;lar\u0131, dokular ve \u00e7izim hedefleri ayn\u0131 fonksiyonu kullan\u0131yor.<\/p>\n<h2 id=\"vulkan-deste\u011fini-be\u015f-\u00e7al\u0131\u015fan-\u00f6rnekle-geli\u015ftirmek\" class=\"code-line\" dir=\"auto\" data-line=\"392\"><strong><span style=\"color: #0000ff;\">Vulkan Deste\u011fini Be\u015f \u00c7al\u0131\u015fan \u00d6rnekle Geli\u015ftirmek<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"394\">Vulkana \u00f6zel kabiliyetler i\u00e7in ayr\u0131ca bir tak\u0131m \u00f6rnekler repo i\u00e7erisin bulunuyor. Bunlar, temelden, metin g\u00f6sterimine do\u011fru ad\u0131m ad\u0131m karma\u015f\u0131kla\u015fan \u00f6rnekler. \u00d6rneklere <code>examples\/vulkan\/<\/code>\u00a0alt\u0131ndan ula\u015fabilirsiniz:<\/p>\n<table class=\"code-line\" dir=\"auto\" data-line=\"396\">\n<thead class=\"code-line\" dir=\"auto\" data-line=\"396\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"396\">\n<th>Ad\u0131m<\/th>\n<th>\u00d6rnek<\/th>\n<th>Hedef<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"code-line\" dir=\"auto\" data-line=\"398\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"398\">\n<td>5a<\/td>\n<td><code>vulkan_clear<\/code><\/td>\n<td>Vulkan penceresi a\u00e7mak; swapchain g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fc al\u0131p temizlemek ve ekrana sunmak.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"399\">\n<td>5b<\/td>\n<td><code>vulkan_triangles<\/code><\/td>\n<td>Vertex buffer, pipeline ve push constants ile d\u00fcz renkli dikd\u00f6rtgen, daire ve \u00e7okgen \u00e7izmek.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"400\">\n<td>5c<\/td>\n<td><code>vulkan_textured<\/code><\/td>\n<td>Doku y\u00fcklemek ve descriptor set \u00fczerinden shader&#8217;a ba\u011flamak.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"401\">\n<td>5d<\/td>\n<td><code>vulkan_demo<\/code><\/td>\n<td>\u00d6zellikleri birlikte kullanmak; pencereyi yeniden boyutland\u0131r\u0131rken \u00e7izimin s\u00fcrmesini ve do\u011frulama hatas\u0131 olu\u015fmamas\u0131n\u0131 kontrol etmek.<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"402\">\n<td>5e<\/td>\n<td><code>vulkan_text<\/code><\/td>\n<td>SDL_ttf ile haz\u0131rlanan metinlerin Vulkan backend&#8217;inde de \u00e7izildi\u011fini do\u011frulamak.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"code-line\" dir=\"auto\" data-line=\"404\">CI taraf\u0131nda, piksel kar\u015f\u0131la\u015ft\u0131rmas\u0131 da dahil Vulkan testleri lavapipe ile \u00e7al\u0131\u015ft\u0131r\u0131l\u0131yor. Lavapipe \u00e7izimi GPU yerine CPU \u00fczerinde yapan bir Vulkan uygulamas\u0131; b\u00f6ylece fiziksel ekran kart\u0131na ve g\u00f6r\u00fcn\u00fcr bir pencereye ihtiya\u00e7 duymayan test ortam\u0131nda Vulkan kodunu da \u00e7al\u0131\u015ft\u0131rabiliyoruz. \u00d6rnek uygulamalar ise CI&#8217;da derleniyor, \u00e7al\u0131\u015ft\u0131r\u0131lm\u0131yor.<\/p>\n<h2 id=\"alt\u0131-yaz\u0131n\u0131n-sonunda-nereye-geldik\" class=\"code-line\" dir=\"auto\" data-line=\"406\"><strong><span style=\"color: #0000ff;\">Alt\u0131 Yaz\u0131n\u0131n Sonunda Nereye Geldik?<\/span><\/strong><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"408\">Alt\u0131 yaz\u0131da \u015funlar\u0131 yapt\u0131k:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"410\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"410\"><strong>Faz 0:<\/strong>\u00a0CMake + Conan altyap\u0131s\u0131,\u00a0<code>IRenderer<\/code>\u00a0aray\u00fcz\u00fc, temel tipler<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"411\"><strong>Faz 1:<\/strong>\u00a0OpenGL 3.3 backend: primitifler, quad tabanl\u0131 kal\u0131n \u00e7izgiler, ear clipping, batch&#8217;leme<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"412\"><strong>Faz 2:<\/strong>\u00a0Transform stack: affine matris,\u00a0<code>Save<\/code>\/<code>Restore<\/code>, scissor k\u0131rpma<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"413\"><strong>Faz 3:<\/strong>\u00a0G\u00f6r\u00fcnt\u00fc ve doku: stb_image, RAII texture, UV hesab\u0131, kar\u0131\u015ft\u0131rma modlar\u0131<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"414\"><strong>Faz 4:<\/strong>\u00a0Metin: SDL_ttf, glyph atlas\u0131, UTF-8, hizalama<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"415\"><strong>Faz 5:<\/strong>\u00a0Vulkan 1.1 backend: context, swapchain, frame senkronizasyonu, push constant pipeline, ring buffer, descriptor set&#8217;ler<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"417\">Vulkan eklerken en \u00e7ok i\u015fimize yarayan \u015fey, \u00e7izim API&#8217;siyle GPU&#8217;ya \u00f6zg\u00fc kodu ba\u015ftan ay\u0131rm\u0131\u015f olmam\u0131zd\u0131.\u00a0<code>Painter<\/code>\u00a0ayn\u0131 \u00e7a\u011fr\u0131lar\u0131 sunmaya,\u00a0<code>Tessellator<\/code>\u00a0ayn\u0131 geometriyi \u00fcretmeye devam etti.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"417\">Yeni backend&#8217;in as\u0131l i\u015fi bu geometriyi Vulkan kaynaklar\u0131 ve komutlar\u0131yla \u00e7izmek oldu.<\/p>\n<h2 id=\"alt\u0131-yaz\u0131n\u0131n-sonunda-nereye-geldik\" class=\"code-line\" dir=\"auto\" data-line=\"406\"><strong><span style=\"color: #0000ff;\">Sonu\u00e7<\/span><\/strong><\/h2>\n<p>Evet, uzun bir yaz\u0131n\u0131n daha sonuna geldik. Peki bundan sonra ne yap\u0131yor olaca\u011f\u0131z? A\u00e7\u0131k\u00e7as\u0131, \u00f6ncelikle k\u00fct\u00fcphanemi conan-center&#8217;a eklemeyi hedefliyorum, sonras\u0131nda ise biraz daha pratik uygulamalar\u0131 sizlerle payla\u015fmak istiyorum. SDLPainter&#8217;a\u00a0 y\u00f6nelik her t\u00fcrl\u00fc g\u00f6r\u00fc\u015f, \u00f6neri ve y\u0131ld\u0131zlar\u0131n\u0131z\u0131 bekliyorum. Bir sonraki yaz\u0131ma kadar bol kodlu g\u00fcnler.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Tekrar merhaba sevgili yaz\u0131l\u0131mperver dostlar\u0131m. Bu yaz\u0131, temel kabiliyetler a\u00e7\u0131s\u0131ndan serimin son yaz\u0131s\u0131. sdl-painter \u2013 Metin \u00c7izimi (faz-4) sdl-painter \u2013 Resim \u00c7izimi (faz-3) sdl-painter \u2013 Transformasyonlar (faz-2) sdl-painter \u2013 Temel \u015eekiller ve Kabiliyetler (faz-1) sdl-painter \u2013 Proje Altyap\u0131s\u0131 (faz 0) \u2013 CI\/CD sdl-painter \u2013 Proje Altyap\u0131s\u0131 (faz-0) \u0130lk yaz\u0131dan bu yana altyap\u0131y\u0131 kurduk, OpenGL backend&#8217;ini&#8230; <a class=\"more-link\" href=\"https:\/\/yazilimperver.com\/index.php\/2026\/10\/19\/sdl-painter-vulkan-backend-faz-5\/\">Continue reading <span class=\"meta-nav\">&#8594;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"","dsgo_overlay_header":false,"dsgo_overlay_header_text_color":"","dsgo_overlay_skip_top_bar":false,"_designsetgo_exclude_llms":false,"footnotes":""},"categories":[10,41,25],"tags":[1223,13,1257,1254,1232,334,1255,1259,1256,1155,1213,1258,1253,1208],"class_list":["post-3272","post","type-post","status-publish","format-standard","hentry","category-c","category-modern-c","category-oyun-gelistirme","tag-2b-grafik","tag-c","tag-descriptor-set","tag-gpu-senkronizasyonu","tag-grafik-programlama","tag-opengl","tag-push-constants","tag-render-target","tag-ring-buffer","tag-sdl3","tag-sdlpainter","tag-spir-v","tag-swapchain","tag-vulkan"],"_links":{"self":[{"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/posts\/3272","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/comments?post=3272"}],"version-history":[{"count":5,"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/posts\/3272\/revisions"}],"predecessor-version":[{"id":3291,"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/posts\/3272\/revisions\/3291"}],"wp:attachment":[{"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/media?parent=3272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/categories?post=3272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yazilimperver.com\/index.php\/wp-json\/wp\/v2\/tags?post=3272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}