stride3d/stride · warning · NotImplementedException

Copy region of staging resources is not supported yet

Error message

Copy region of staging resources is not supported yet

What it means

Within CopyRegion's internal CopyBetweenTextures helper, copying region-wise between two textures both created with GraphicsResourceUsage.Staging is not implemented on the D3D12 backend and throws NotImplementedException. Other usage combinations fall through to the normal GPU barrier + copy path.

Solutions

  1. Do the staging-to-staging copy on the CPU: map both textures (or copy their data pointers) and blit the region manually.
  2. Copy into an intermediate GPU (Default/Immutable-to-Default) texture instead of staging-to-staging.
  3. Set one of the textures to a non-Staging usage if a GPU copy path is acceptable.

Example fix

// before
commandList.CopyRegion(stagingA, stagingB, region); // throws

// after
if (stagingA.Usage == GraphicsResourceUsage.Staging && stagingB.Usage == GraphicsResourceUsage.Staging)
    CopyStagingRegionOnCpu(stagingA, stagingB, region); // manual CPU copy
else
    commandList.CopyRegion(stagingA, stagingB, region);
Defensive patterns

Strategy: try-catch

Validate before calling

if (source is Texture s && destination is Texture d &&
    s.Usage == GraphicsResourceUsage.Staging && d.Usage == GraphicsResourceUsage.Staging)
{
    // handle staging-to-staging on CPU instead of calling CopyRegion
}

Type guard

static bool IsStagingToStaging(Texture s, Texture d) =>
    s.Usage == GraphicsResourceUsage.Staging && d.Usage == GraphicsResourceUsage.Staging;

Try / catch

try
{
    commandList.CopyRegion(srcTex, dstTex, region);
}
catch (NotImplementedException)
{
    CopyStagingRegionOnCpu(srcTex, dstTex, region); // manual CPU blit
}

Prevention

When it happens

Trigger: Calling CommandList.CopyRegion(sourceTexture, destinationTexture, region) where both sourceTexture.Usage and destinationTexture.Usage equal GraphicsResourceUsage.Staging.

Common situations: CPU-side staging-to-staging data merges (e.g. building a texture atlas incrementally on the CPU); test code copying between two staging textures; porting GL/D3D11 staging logic expecting CPU memcpy semantics.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/Direct3D12/CommandList.Direct3D12.cs:1747

            {
                CopyBetweenTextures(sourceTexture, destinationTexture);
            }
            else if (source is Buffer sourceBuffer &&
                     destination is Buffer destinationBuffer)
            {
                CopyBetweenBuffers(sourceBuffer, destinationBuffer);
            }
            else throw new InvalidOperationException("Cannot copy data between Buffers and Textures.");

            //
            // Copies a region from a Texture to another Texture.
            //
            void CopyBetweenTextures(Texture sourceTexture, Texture destinationTexture)
            {
                if (sourceTexture.Usage == GraphicsResourceUsage.Staging &&
                    destinationTexture.Usage == GraphicsResourceUsage.Staging)
                {
                    throw new NotImplementedException("Copy region of staging resources is not supported yet"); // TODO: Implement copy region for staging resources
                }

                ResourceBarrierTransition(source, BarrierLayout.CopySource);
                ResourceBarrierTransition(destination, BarrierLayout.CopyDest);
                FlushResourceBarriers();

                if (sourceTexture.Usage == GraphicsResourceUsage.Staging)
                {
                    throw new NotImplementedException("Copy region from staging texture is not supported yet");
                }

                var srcRegion = new TextureCopyLocation
                {
                    PResource = source.NativeResource,
                    Type = TextureCopyType.SubresourceIndex,
                    SubresourceIndex = (uint) sourceSubResourceIndex
                };

View on GitHub (pinned to 96fad776d2)