stride3d/stride · error · NotImplementedException

Copy from Staging doesn't support source region other than…

Error message

Copy from Staging doesn't support source region other than full texture

What it means

When copying from a Staging texture on Vulkan, Stride only supports copying the entire mip level; partial source regions are unimplemented. The operand check also has a subtle precedence quirk, but the intent is: any region other than the full texture throws NotImplementedException.

Solutions

  1. Copy the full texture region (region covering the entire mip) from staging, then perform sub-region copies between GPU textures
  2. Use CopyScissor between two GPU (non-staging) textures for partial copies
  3. Upload the partial data into a properly sized staging texture matching the region instead

Example fix

// before
cmdList.Copy(stagingTex, gpuTex, subRegion); // partial staging copy
// after
cmdList.Copy(stagingTex, gpuTex); // full staging copy
cmdList.CopyScissor(gpuTex, targetTex, subRegion);
Defensive patterns

Strategy: validation

Validate before calling

if (stagingTex.Usage == GraphicsResourceUsage.Staging)
    ensureRegionCoversFullMip(region, mipWidth, mipHeight, mipDepth);

Try / catch

try { cmdList.Copy(stagingTex, gpuTex, region); } catch (NotImplementedException) { cmdList.Copy(stagingTex, gpuTex); }

Prevention

When it happens

Trigger: CommandList.Copy(region-based overload) with sourceTexture.Usage == GraphicsResourceUsage.Staging and a region whose Left/Top/Front or Right/Bottom/Back do not exactly cover the mip dimensions.

Common situations: Reading back only part of a staging texture; copying a sub-rectangle from a CPU-populated texture to a GPU texture; assuming staging copies behave like D3D11 box copies.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/4a116d9ca32a3d58. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Vulkan/CommandList.Vulkan.cs:1245

                            imageExtent = new VkExtent3D((uint)(region.Right - region.Left), (uint)(region.Bottom - region.Top), (uint)(region.Back - region.Front))
                        };
                        GraphicsDevice.NativeDeviceApi.vkCmdCopyImageToBuffer(currentCommandList.NativeCommandBuffer, sourceParent.NativeImage, VkImageLayout.TransferSrcOptimal, destinationParent.NativeBuffer, 1, &copy);
                    }

                    //// VkFence for host access
                    destinationParent.CommandListFenceValue = null;
                    destinationParent.UpdatingCommandList = this;
                    currentCommandList.StagingResources.Add(destinationParent);
                }
                else
                {
                    var destinationSubresource = GetSubresourceLayers(destinationTexture, destinationParent.NativeImageAspect, destinationSubResource);

                    if (sourceTexture.Usage == GraphicsResourceUsage.Staging)
                    {
                        if (region.Left != 0 || region.Top != 0 || region.Front != 0
                            && region.Right != mipmapDescription.Width || region.Bottom != mipmapDescription.Height || region.Back != mipmapDescription.Depth)
                            throw new NotImplementedException("Copy from Staging doesn't support source region other than full texture");

                        var copy = new VkBufferImageCopy
                        {
                            imageSubresource = destinationSubresource,
                            bufferOffset = (ulong) sourceTexture.ComputeBufferOffset(sourceSubresource, 0),
                            bufferImageHeight = (uint) sourceTexture.Height,
                            bufferRowLength = (uint) sourceTexture.Width,
                            imageOffset = new VkOffset3D(dstX, dstY, dstZ),
                            imageExtent = new VkExtent3D(region.Right - region.Left, region.Bottom - region.Top, region.Back - region.Front)
                        };
                        GraphicsDevice.NativeDeviceApi.vkCmdCopyBufferToImage(currentCommandList.NativeCommandBuffer, sourceParent.NativeBuffer, destinationParent.NativeImage, VkImageLayout.TransferDstOptimal, regionCount: 1, &copy);
                    }
                    else
                    {
                        var copy = new VkImageCopy
                        {
                            srcSubresource = GetSubresourceLayers(sourceTexture, sourceParent.NativeImageAspect, sourceSubresource),
                            srcOffset = new VkOffset3D(region.Left, region.Top, region.Front),

View on GitHub (pinned to 96fad776d2)