Framebuffers · depth · samplers · textures · meshes · descriptors · mipmaps
Higher-level, non-owning building blocks composed on top of the core. Every
class here borrows core objects by reference. VCKExpansion.cpp is compiled
into every example (VKB in build.bat).
One-shot GPU command for setup work (staging copies, layout transitions).
VCK::VulkanOneTimeCommand otc;
if (otc.Begin(dev, cmd))
{
vkCmdCopyBuffer(otc.Cmd(), src, dst, 1, ®ion);
otc.End(); // submit + vkQueueWaitIdle + free
}Blocks on vkQueueWaitIdle — not for per-frame use.
One VkFramebuffer per swapchain image.
VCK::VulkanFramebufferSet fbs;
fbs.Initialize(dev, sc, pipeline);
// (with depth attachment) fbs.Initialize(dev, sc, pipeline, depth);
// on resize:
fbs.Recreate(pipeline);
// (with depth) fbs.Recreate(pipeline, depth);
// in DrawFrame():
rp.framebuffer = fbs.Get(imageIndex);VCK::VulkanDepthBuffer depth;
depth.Initialize(dev, width, height); // picks a supported D32/D24 format
// on resize:
depth.Recreate(width, height);
// pass to framebuffers:
fbs.Initialize(dev, sc, renderPass, depth.GetImageView());VCK::VulkanSampler samp;
samp.CreateLinear(dev); // trilinear, repeat, anisotropy if supported
// or samp.CreateNearest(dev); // point sampling
VkSampler handle = samp.Get();VCK::VulkanTexture tex;
tex.CreateFromPixels(dev, cmd,
pixels, width, height,
VK_FORMAT_R8G8B8A8_SRGB);
VkImageView view = tex.Image().GetView();CPU → GPU upload with hidden staging buffer + layout transitions.
struct V { float pos[3]; float uv[2]; };
V verts[3] = { /* ... */ };
uint32_t idx[3] = { 0, 1, 2 };
VCK::VulkanMesh mesh;
mesh.Upload(dev, cmd,
verts, sizeof(verts),
idx, 3);
// inside a render pass:
mesh.RecordDraw(f.PrimaryCmd());VkDescriptorSetLayout layout = VCK::VulkanDescriptorLayoutBuilder()
.AddUniformBuffer(0, VK_SHADER_STAGE_VERTEX_BIT)
.AddCombinedImageSampler(1, VK_SHADER_STAGE_FRAGMENT_BIT)
.Build(dev);VCK::VulkanDescriptorPool pool;
pool.Initialize(dev, layout, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
/*framesInFlight=*/cfg.sync.framesInFlight);
VkDescriptorSet set = pool.GetSet(frameSlot); // one set per frame slotThe pool allocates exactly framesInFlight descriptor sets — pass the
same value you set on VulkanSync / VulkanCommand so the descriptor
ring matches the frame ring exactly. framesInFlight must be in
[1, MAX_FRAMES_IN_FLIGHT]; out-of-range values return false and
emit VCKLog::Error("DescriptorPool", ...).
Per-frame typed UBO. Reads pool.GetFramesInFlight() on Initialize
and sizes its internal buffer ring to match — the user threads
framesInFlight to the pool only, never to the UBO.
struct SceneUbo { glm::mat4 view, proj; };
VCK::VulkanUniformSet<SceneUbo> ubo;
ubo.Initialize(dev, pool, /*binding=*/0);
// per frame:
ubo.Write(frameSlot, { view, proj });
vkCmdBindDescriptorSets(f.PrimaryCmd(),
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout, 0, 1,
&pool.GetSet(frameSlot),
0, nullptr);For when one pool / one type isn't enough.
VCK::VulkanDescriptorAllocator alloc;
alloc.Initialize(dev, /*maxSets=*/32, {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 16 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16 },
});
VkDescriptorSet set = alloc.Allocate(layout);Graphics pipeline tailored for a single mesh + UBO + texture.
VCK::VulkanModelPipeline modelPipeline;
modelPipeline.Initialize(dev, pipeline.GetRenderPass(), shaders, vertexInput);
// draw:
vkCmdBindPipeline(f.PrimaryCmd(),
VK_PIPELINE_BIND_POINT_GRAPHICS,
modelPipeline.GetPipeline());uint32_t mips = VCK::VulkanMipmapGenerator::MipLevels(w, h);
if (VCK::VulkanMipmapGenerator::IsFormatSupported(dev, VK_FORMAT_R8G8B8A8_SRGB))
{
VCK::VulkanMipmapGenerator gen;
gen.Generate(dev, cmd, image, w, h, mips);
}The source image must have been created with TRANSFER_SRC_BIT | TRANSFER_DST_BIT
usage.