|
|
Donner SVG 0.8.0-pre
SVG editor and embeddable C++20 engine.
|
Vulkan backend of the Donner GPU runtime. More...
#include "donner/gpu/vulkan/VulkanDevice.h"
Classes | |
| struct | RecordedImageBarrierForTest |
| One image barrier the backend recorded, reported as plain numbers so this header stays free of Vulkan types. Test accessor: which barriers are emitted is the whole contract of the resource-state model, and it is not observable in the pixels a slice reads back. More... | |
| struct | RecordedSubpassDependencyForTest |
| The two halves of a render pass external dependency, as plain numbers. Test accessor. More... | |
Public Types | |
| enum class | TrackedTextureLayout : uint8_t { Undefined , General , ShaderReadOnly , TransferSrc , TransferDst , ColorAttachment , Other } |
| The image layout a texture is tracked in, as the backend's own bookkeeping records it. More... | |
| enum class | UploadFailureModeForTest : uint8_t { BeforeSubmit , AfterSubmit } |
| Where an injected upload failure happens, which is what decides whether the transitions it recorded describe anything the GPU will run. More... | |
Public Member Functions | |
| ~VulkanDevice () override | |
| Destructor; waits for in-flight submissions (vkDeviceWaitIdle), drains deferred destructions, then destroys all remaining Vulkan objects in dependency-safe order. | |
| uint64_t | completedSerial () const override |
| Serial of the most recent submission whose fence has signaled (0 if none). Polls pending fences with vkGetFenceStatus and advances a monotonic counter. | |
| bool | waitForSerial (uint64_t serial, double timeoutSeconds) |
Blocks until completedSerial reaches serial or timeoutSeconds elapses, using vkWaitForFences on the pending submission fences. | |
| Result< std::vector< uint8_t > > | readBackBuffer (const Buffer &buffer) |
Copies the full contents of buffer back to the host and returns the bytes. | |
| Result< TrackedTextureLayout > | trackedTextureLayoutForTest (const Texture &texture) const |
Returns the layout texture is tracked in. | |
| std::vector< RecordedImageBarrierForTest > | recordedImageBarriersForTest () const |
| Every image barrier recorded since the device was created, oldest first. Test accessor. | |
| Result< RecordedSubpassDependencyForTest > | lastRenderPassEntryDependencyForTest () const |
| The entry-side external dependency of the most recently created render pass. Fails closed when no render pass has been created. Test accessor. | |
| void | failNextTextureUploadForTest (UploadFailureModeForTest mode) |
Makes the next internal texture upload report failure at mode, so a test can prove what the tracker is left holding in each case. Test seam; the upload's Vulkan work is recorded either way, only its reported result is replaced. | |
| std::string | lastErrorForTest () const |
| Message of the most recent asynchronous Vulkan failure observed while polling or waiting on fences (e.g. VK_ERROR_DEVICE_LOST), or an empty string if none occurred. Test/diagnostic accessor. | |
| Public Member Functions inherited from donner::gpu::Device | |
| virtual | ~Device () |
| Destructor; expires the device-alive token (so handles that outlive the device release nothing) and frees all remaining resources. Backends that submit asynchronously must wait for in-flight submissions in their own destructor before backend state is torn down. | |
| Device (const Device &)=delete | |
| Device & | operator= (const Device &)=delete |
| Device (Device &&)=delete | |
| Device & | operator= (Device &&)=delete |
| uint64_t | deviceId () const |
| Process-unique identity of this device (starts at 1, never reused). Baked into every handle for cross-device validation. | |
| Result< Buffer > | createBuffer (const BufferDescriptor &descriptor) |
| Creates a buffer. | |
| Result< Texture > | createTexture (const TextureDescriptor &descriptor) |
| Creates a 2D texture. | |
| Result< TextureView > | createTextureView (const Texture &texture, const TextureViewDescriptor &descriptor) |
Creates a view of texture covering the whole texture. | |
| Result< Sampler > | createSampler (const SamplerDescriptor &descriptor) |
| Creates a sampler. | |
| Result< BindGroupLayout > | createBindGroupLayout (const BindGroupLayoutDescriptor &descriptor) |
| Creates a bind group layout. | |
| Result< BindGroup > | createBindGroup (const BindGroupDescriptor &descriptor) |
| Creates a bind group. | |
| Result< PipelineLayout > | createPipelineLayout (const PipelineLayoutDescriptor &descriptor) |
| Creates a pipeline layout. | |
| Result< ShaderModule > | createShaderModule (const ShaderModuleDescriptor &descriptor) |
| Creates a shader module from trusted generated source. | |
| Result< RenderPipeline > | createRenderPipeline (const RenderPipelineDescriptor &descriptor) |
| Creates a render pipeline. | |
| Result< ComputePipeline > | createComputePipeline (const ComputePipelineDescriptor &descriptor) |
| Creates a compute pipeline. | |
| Status | destroyBuffer (Buffer &&buffer) |
| Destroys a buffer (see the destroy contract above). | |
| Status | destroyTexture (Texture &&texture) |
| Destroys a texture (see the destroy contract above). | |
| Status | destroyTextureView (TextureView &&textureView) |
| Destroys a texture view (see the destroy contract above). | |
| Status | destroySampler (Sampler &&sampler) |
| Destroys a sampler (see the destroy contract above). | |
| Status | destroyBindGroupLayout (BindGroupLayout &&bindGroupLayout) |
| Destroys a bind group layout (see the destroy contract above). | |
| Status | destroyBindGroup (BindGroup &&bindGroup) |
| Destroys a bind group (see the destroy contract above). | |
| Status | destroyPipelineLayout (PipelineLayout &&pipelineLayout) |
| Destroys a pipeline layout (see the destroy contract above). | |
| Status | destroyShaderModule (ShaderModule &&shaderModule) |
| Destroys a shader module (see the destroy contract above). | |
| Status | destroyRenderPipeline (RenderPipeline &&renderPipeline) |
| Destroys a render pipeline (see the destroy contract above). | |
| Status | destroyComputePipeline (ComputePipeline &&computePipeline) |
| Destroys a compute pipeline (see the destroy contract above). | |
| Result< std::unique_ptr< CommandEncoder > > | createCommandEncoder () |
| Creates a command encoder recording against this device. The encoder must not outlive the device. | |
| Result< Surface > | createSurface (const SurfaceDescriptor &descriptor) |
| Creates a surface presenting to a platform object. | |
| Result< SurfaceCapabilities > | surfaceCapabilities (const Surface &surface) const |
What surface supports, for choosing a configuration. | |
| Status | configureSurface (const Surface &surface, const SurfaceConfiguration &configuration) |
Configures how surface presents, replacing any previous configuration. | |
| Result< SurfaceTexture > | acquireCurrentTexture (const Surface &surface) |
Acquires the texture for the next frame of surface. | |
| Result< SurfaceStatus > | presentSurface (const Surface &surface) |
Presents the texture acquired from surface and invalidates it. | |
| Status | abandonCurrentTexture (const Surface &surface) |
Releases the acquired texture of surface without presenting it, for a frame the caller decided not to show. | |
| Status | destroySurface (Surface &&surface) |
| Destroys a surface (see the destroy contract above). | |
| Result< BufferMapping > | mapBufferAsync (const Buffer &buffer, MapMode mode, uint64_t offsetBytes, uint64_t byteCount) |
Begins mapping a range of buffer for host access, and returns the handle that names the mapping. | |
| Result< MapWaitOutcome > | waitForMapping (const BufferMapping &mapping, const MapWaitParams ¶ms, const std::function< bool()> &shouldCancel, const MapWaitTestHooks &testHooks={}) |
| Result< std::span< const uint8_t > > | mappedBytes (const BufferMapping &mapping) const |
| Returns the mapped bytes of a completed mapping. | |
| Status | unmapBuffer (BufferMapping &&mapping) |
| Releases a mapping, invalidating the handle and every copy of it. | |
| Status | writeBuffer (const Buffer &buffer, uint64_t offsetBytes, std::span< const uint8_t > data) |
Writes data into buffer at offsetBytes. | |
| Status | writeTexture (const Texture &texture, std::span< const uint8_t > data, const TexelCopyBufferLayout &dataLayout, const Extent2d &writeSize) |
Writes texel rows from data into texture starting at texel (0, 0). | |
| Result< uint64_t > | submit (CommandBuffer commandBuffer) |
| Submits a finished command buffer, consuming it, and returns the assigned submission serial. | |
| void | poll () |
| Processes deferred destructions: releases the backend object of every destroyed resource whose last referencing submission has completed (completedSerial), and recycles its slot. | |
| uint64_t | lastSubmittedSerial () const |
| Serial assigned to the most recent submission (0 if none yet). | |
Static Public Member Functions | |
| static std::unique_ptr< VulkanDevice > | Create () |
| Creates a headless device: a VkInstance without surface extensions (enabling VK_LAYER_KHRONOS_validation only when the loader enumerates it), the first physical device exposing a graphics queue family, and a single VkDevice + VkQueue. | |
Protected Member Functions | |
| Status | onCreateBuffer (uint32_t slotIndex, const BufferDescriptor &descriptor) override |
Backend hook: a buffer passed validation and occupies slotIndex. | |
| Status | onCreateTexture (uint32_t slotIndex, const TextureDescriptor &descriptor) override |
Backend hook: a texture passed validation and occupies slotIndex. | |
| Status | onCreateTextureView (uint32_t slotIndex, uint32_t textureSlotIndex, const TextureViewDescriptor &descriptor) override |
Backend hook: a texture view passed validation and occupies slotIndex. | |
| Status | onCreateSampler (uint32_t slotIndex, const SamplerDescriptor &descriptor) override |
Backend hook: a sampler passed validation and occupies slotIndex. | |
| Status | onCreateBindGroupLayout (uint32_t slotIndex, const BindGroupLayoutDescriptor &descriptor) override |
Backend hook: a bind group layout passed validation and occupies slotIndex. | |
| Status | onCreateBindGroup (uint32_t slotIndex, const BindGroupDescriptor &descriptor) override |
Backend hook: a bind group passed validation and occupies slotIndex. | |
| Status | onCreatePipelineLayout (uint32_t slotIndex, const PipelineLayoutDescriptor &descriptor) override |
Backend hook: a pipeline layout passed validation and occupies slotIndex. | |
| Status | onCreateShaderModule (uint32_t slotIndex, const ShaderModuleDescriptor &descriptor) override |
Backend hook: a shader module passed validation and occupies slotIndex. | |
| Status | onCreateRenderPipeline (uint32_t slotIndex, const RenderPipelineDescriptor &descriptor) override |
Backend hook: a render pipeline passed validation and occupies slotIndex. | |
| Status | onCreateComputePipeline (uint32_t slotIndex, const ComputePipelineDescriptor &descriptor) override |
Backend hook: a compute pipeline passed validation and occupies slotIndex. | |
| void | onDestroyResource (std::string_view resourceName, uint32_t slotIndex) override |
| Backend hook: a validated resource was destroyed. | |
| Status | onWriteBuffer (uint32_t slotIndex, uint64_t offsetBytes, std::span< const uint8_t > data) override |
| Backend hook: a validated buffer write. | |
| Status | onWriteTexture (uint32_t slotIndex, std::span< const uint8_t > data, const TexelCopyBufferLayout &dataLayout, const Extent2d &writeSize) override |
| Backend hook: a validated texture write. | |
| Status | onSubmit (uint64_t submissionSerial, uint32_t commandBufferSlotIndex, std::span< const Command > commands) override |
| Backend hook: a validated command buffer was submitted. | |
| Protected Member Functions inherited from donner::gpu::Device | |
| Device () | |
| Constructor for backends; assigns the process-unique device identity. | |
| Status | validateBufferHandleForBackend (const Buffer &buffer) const |
| Validates a buffer handle for backend-provided auxiliary entry points (test readback helpers and similar), running the same null/device-identity/generation checks the template-method public API performs before its hooks. | |
| Status | validateTextureHandleForBackend (const Texture &texture) const |
| Validates a texture handle for backend-provided auxiliary entry points, running the same null/device-identity/generation checks the template-method public API performs. | |
| Status | validateTextureViewHandleForBackend (const TextureView &textureView) const |
| Validates a texture view handle for backend-provided auxiliary entry points: the view itself plus a re-resolution of its viewed texture, so a view of a destroyed (or slot-recycled) texture fails closed exactly like it does on the normal Device paths. | |
| Status | validateBufferMappingHandleForBackend (const BufferMapping &mapping) const |
| Validates a buffer-mapping handle for backend-provided auxiliary entry points, running the same null/device-identity/generation checks the template-method public API performs, so a stale handle cannot read state belonging to the slot's new occupant. | |
| virtual Status | onMapBufferAsync (uint32_t mappingSlotIndex, uint32_t bufferSlotIndex, MapMode mode, uint64_t offsetBytes, uint64_t byteCount) |
| Backend hook: begin mapping a buffer range. | |
| virtual MapSliceState | onWaitMappingSlice (uint32_t mappingSlotIndex, double sliceSeconds) |
Backend hook: wait up to sliceSeconds for a pending mapping and report what it found. | |
| virtual Result< std::span< const uint8_t > > | onMappedBytes (uint32_t mappingSlotIndex) const |
| Backend hook: bytes of a completed mapping. | |
| virtual void | onUnmapBuffer (uint32_t mappingSlotIndex) |
| Backend hook: release a mapping. | |
| virtual Status | onCreateSurface (uint32_t slotIndex, const SurfaceDescriptor &descriptor) |
| Backend hook: create a surface for a platform object. | |
| virtual Result< SurfaceCapabilities > | onSurfaceCapabilities (uint32_t slotIndex) const |
| Backend hook: what a surface supports. | |
| virtual Status | onConfigureSurface (uint32_t slotIndex, const SurfaceConfiguration &configuration) |
| Backend hook: apply a configuration. | |
| virtual Result< SurfaceStatus > | onAcquireCurrentTexture (uint32_t slotIndex, uint32_t textureSlotIndex) |
| Backend hook: acquire the next frame's texture and report the surface's state. | |
| virtual Result< SurfaceStatus > | onPresentSurface (uint32_t slotIndex) |
| Backend hook: present the acquired texture. | |
| virtual void | onAbandonCurrentTexture (uint32_t slotIndex) |
| Backend hook: drop the acquired texture without presenting. | |
Vulkan backend of the Donner GPU runtime.
Inherits every fail-closed validation check from donner::gpu::Device; the on* hooks receive only validated input and translate it to Vulkan objects. Every Vulkan call's VkResult is checked and any failure fails closed with a donner::gpu::GpuError; the backend never crashes on such failures.
Scope is exactly the solid-fill vertical slice: buffers and 2D single-sample textures, SPIR-V shader modules (from donner::gpu::shader::EmitSpirv), the solid-fill render pipeline family, render passes with color attachments, and texture-to-buffer readback copies. Bind group index N maps directly to Vulkan descriptor set N; binding numbers map directly to SPIR-V binding decorations (the SPIR-V emitter uses DescriptorSet 0 / Binding b).
Targets Vulkan 1.1 core only: classic VkRenderPass + VkFramebuffer (no dynamic rendering), per-submission VkFence completion tracking (no timeline semaphores), and the core negative-viewport-height feature (VK_KHR_maintenance1, promoted to 1.1) to present WebGPU clip-space semantics - identical SPIR-V positions land on identical pixels as the wgpu baseline.
Memory model (documented simplification for this slice): every buffer lives in HOST_VISIBLE | HOST_COHERENT memory and stays persistently mapped, so queue writes are a memcpy and readback needs no staging. Which allocation a buffer is bound into is the allocator's decision, behind the seam in VulkanBufferAllocator.h: one dedicated allocation per buffer today, with a suballocating implementation replaceable there rather than at every call site, once measurement says the driver's allocation-count cap is the constraint worth spending complexity on. Such a memory type is guaranteed by the Vulkan specification ("Device Memory": at least one memory type has both HOST_VISIBLE and HOST_COHERENT), and both the CI software rasterizer and desktop GPUs expose it. Textures are DEVICE_LOCAL (when available) with staged uploads through a transient host-visible buffer and explicit image layout transitions.
Synchronization is tracked per resource rather than assumed: every image barrier and both of every render pass's external dependencies are derived from the state model in VulkanResourceState.h, which records the stage and access that last touched each texture and names both ends of the transition to whatever uses it next. A pattern the model does not describe falls back to the maximal ALL_COMMANDS barrier, so an unrecognised usage costs precision and never correctness. Readback copies still end in a HOST-domain buffer barrier.
Barrier elision - dropping a barrier the model says is needed - is still not attempted; that would need counter and timing evidence naming the bottleneck it removes.
Threading: single-threaded use, matching donner::gpu::Device's thread affinity. Completion is tracked by polling per-submission fences from the owning thread; there are no cross-thread callbacks.
The header is pure C++ (Vulkan state lives behind a pimpl) so it is includable without the Vulkan headers on any platform; the implementation compiles against the hermetic Vulkan-Headers module everywhere but can only link and execute where a Vulkan loader exists (Linux in CI).
| struct donner::gpu::vulkan::VulkanDevice::RecordedImageBarrierForTest |
One image barrier the backend recorded, reported as plain numbers so this header stays free of Vulkan types. Test accessor: which barriers are emitted is the whole contract of the resource-state model, and it is not observable in the pixels a slice reads back.
| struct donner::gpu::vulkan::VulkanDevice::RecordedSubpassDependencyForTest |
|
strong |
The image layout a texture is tracked in, as the backend's own bookkeeping records it.
Reported through a backend-neutral enum so the header stays free of Vulkan types. This is a test accessor: a texture the backend never transitioned to the layout its descriptors declare is invalid use that a permissive driver executes anyway, so the mistake is not observable in the pixels a slice reads back.
|
strong |
Where an injected upload failure happens, which is what decides whether the transitions it recorded describe anything the GPU will run.
|
overridevirtual |
Serial of the most recent submission whose fence has signaled (0 if none). Polls pending fences with vkGetFenceStatus and advances a monotonic counter.
Implements donner::gpu::Device.
|
static |
Creates a headless device: a VkInstance without surface extensions (enabling VK_LAYER_KHRONOS_validation only when the loader enumerates it), the first physical device exposing a graphics queue family, and a single VkDevice + VkQueue.
Returns nullptr if no Vulkan 1.1 instance or graphics-capable physical device is available.
| void donner::gpu::vulkan::VulkanDevice::failNextTextureUploadForTest | ( | UploadFailureModeForTest | mode | ) |
Makes the next internal texture upload report failure at mode, so a test can prove what the tracker is left holding in each case. Test seam; the upload's Vulkan work is recorded either way, only its reported result is replaced.
| mode | Where the injected failure happens. |
|
overrideprotectedvirtual |
Backend hook: a bind group passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a bind group layout passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a buffer passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a compute pipeline passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a pipeline layout passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a render pipeline passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a sampler passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a shader module passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a texture passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a texture view passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| textureSlotIndex | Slot index of the viewed texture. |
| descriptor | Validated descriptor. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a validated resource was destroyed.
| resourceName | Resource type name, e.g. "buffer". |
| slotIndex | Slot index of the destroyed resource. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a validated command buffer was submitted.
| submissionSerial | Serial assigned to this submission. |
| commandBufferSlotIndex | Slot the command buffer occupied before being consumed. |
| commands | Validated commands, in recording order. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a validated buffer write.
| slotIndex | Destination buffer slot. |
| offsetBytes | Destination byte offset. |
| data | Payload bytes. |
Implements donner::gpu::Device.
|
overrideprotectedvirtual |
Backend hook: a validated texture write.
| slotIndex | Destination texture slot. |
| data | Payload bytes. |
| dataLayout | Row layout of data. |
| writeSize | Extent written in texels. |
Implements donner::gpu::Device.
| Result< std::vector< uint8_t > > donner::gpu::vulkan::VulkanDevice::readBackBuffer | ( | const Buffer & | buffer | ) |
Copies the full contents of buffer back to the host and returns the bytes.
Test/readback convenience for the vertical slice, pending the buffer mapping API: validates the handle (null, device identity, and generation) through the base class, then reads the persistently mapped host-visible allocation. Callers must ensure relevant GPU work has completed first (see waitForSerial); fence completion makes device writes visible to the host for HOST_COHERENT memory.
| buffer | Buffer to read back; must be a live buffer of this device. |
| Result< TrackedTextureLayout > donner::gpu::vulkan::VulkanDevice::trackedTextureLayoutForTest | ( | const Texture & | texture | ) | const |
Returns the layout texture is tracked in.
Test accessor; fails closed on a handle that does not name a live texture of this device.
| texture | Texture to query. |
| bool donner::gpu::vulkan::VulkanDevice::waitForSerial | ( | uint64_t | serial, |
| double | timeoutSeconds ) |
Blocks until completedSerial reaches serial or timeoutSeconds elapses, using vkWaitForFences on the pending submission fences.
Returns false on timeout or if any Vulkan wait call fails (see lastErrorForTest).
| serial | Submission serial to wait for. |
| timeoutSeconds | Maximum time to wait, in seconds. |