{"record":{"id":"f6b1a3baad3155ab","repo":"stride3d/stride","slug":"cannot-copy-data-between-buffers-and-textures-commandlist","errorCode":null,"errorMessage":"Cannot copy data between Buffers and Textures.","messagePattern":"Cannot copy data between Buffers and Textures\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Vulkan/CommandList.Vulkan.cs","lineNumber":1342,"sourceCode":"\n                var copy = new VkBufferCopy { srcOffset = srcOffset, dstOffset = dstOffset, size = size };\n                GraphicsDevice.NativeDeviceApi.vkCmdCopyBuffer(currentCommandList.NativeCommandBuffer, sourceBuffer.NativeBuffer, destinationBuffer.NativeBuffer, regionCount: 1, &copy);\n\n                if (destinationBuffer.Usage == GraphicsResourceUsage.Staging)\n                {\n                    destinationBuffer.CommandListFenceValue = null;\n                    destinationBuffer.UpdatingCommandList = this;\n                    currentCommandList.StagingResources.Add(destinationBuffer);\n                }\n\n                bufferBarriers[0] = new VkBufferMemoryBarrier(sourceBuffer.NativeBuffer, VkAccessFlags.TransferRead, sourceBuffer.NativeAccessMask);\n                bufferBarriers[1] = new VkBufferMemoryBarrier(destinationBuffer.NativeBuffer, VkAccessFlags.TransferWrite, destinationBuffer.NativeAccessMask);\n                var dstStages = FixStagesForAccess(sourceBuffer.NativePipelineStageMask | destinationBuffer.NativePipelineStageMask, sourceBuffer.NativeAccessMask | destinationBuffer.NativeAccessMask);\n                GraphicsDevice.NativeDeviceApi.vkCmdPipelineBarrier(currentCommandList.NativeCommandBuffer, VkPipelineStageFlags.Transfer, dstStages, VkDependencyFlags.None, memoryBarrierCount: 0, memoryBarriers: null, bufferMemoryBarrierCount: 2, bufferBarriers, imageMemoryBarrierCount: 0, imageMemoryBarriers: null);\n            }\n            else\n            {\n                throw new InvalidOperationException(\"Cannot copy data between Buffers and Textures.\");\n            }\n        }\n\n        /// <inheritdoc />\n        public void CopyCount(Buffer sourceBuffer, Buffer destBuffer, int offsetInBytes)\n        {\n            throw new NotImplementedException();\n        }\n\n        /// <summary>\n        ///   Copies data from memory to a sub-resource created in non-mappable memory.\n        /// </summary>\n        /// <param name=\"resource\">The destination Graphics Resource to copy data to.</param>\n        /// <param name=\"subResourceIndex\">The sub-resource index of <paramref name=\"resource\"/> to copy data to.</param>\n        /// <param name=\"sourceData\">The source data in CPU memory to copy.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"resource\"/> is <see langword=\"null\"/>.</exception>\n        /// <remarks>\n        ///   <para>","sourceCodeStart":1324,"sourceCodeEnd":1360,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Vulkan/CommandList.Vulkan.cs#L1324-L1360","documentation":"The Vulkan Copy implementation supports buffer-to-buffer and texture-to-texture copies only. If neither operand pair matches (one is a Buffer and the other a Texture), Stride throws InvalidOperationException because Vulkan requires vkCmdCopyBuffer vs vkCmdCopyImage and there is no implemented cross-type path.","triggerScenarios":"Calling CommandList.Copy passing one Buffer and one Texture (in either order), or any combination where source/destination are not both buffers or both textures.","commonSituations":"Confusing Buffer and Texture APIs when uploading data; trying to interpret a buffer as a texture without creating a Texture resource; accidental overload selection with mixed types.","solutions":["Create a Texture and copy from the Buffer into it via staging texture upload instead of direct Buffer-to-Texture copy","Use buffer-to-buffer copy into a buffer-backed resource, or texture-to-texture for image data","Use MappedResource/MapSubResource to fill a Texture directly from CPU memory"],"exampleFix":"// before\ncmdList.Copy(myBuffer, myTexture); // mixed types\n// after\nvar staging = Texture.New2D(device, w, h, fmt, data, GraphicsResourceUsage.Staging);\ncmdList.Copy(staging, myTexture);","handlingStrategy":"type-guard","validationCode":"if ((source is Buffer) != (destination is Buffer)) throw new ArgumentException(\"Copy requires both Buffer or both Texture\");","typeGuard":"bool IsSameKind(GraphicsResource a, GraphicsResource b) => (a is Buffer) == (b is Buffer);","tryCatchPattern":"try { cmdList.Copy(a, b); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"Buffers and Textures\")) { /* route to proper upload path */ }","preventionTips":["Never pass mixed Buffer/Texture pairs to Copy","Upload buffer content into textures via staging textures","Keep upload helpers strongly typed (Texture overload vs Buffer overload)"],"tags":["vulkan","type-mismatch","copy"],"backgroundTag":"incompatible-source-type","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}