stride3d/stride · error · NotImplementedException
Vulkan: only simple BorderColor are supported
Error message
Vulkan: only simple BorderColor are supported
What it means
Vulkan only accepts a fixed VkBorderColor enum (transparent/opaque black/white, float or int) for sampler border colors, while Stride's SamplerState lets you specify any Color. CreateNativeSampler maps only the well-known values (white, black, transparent) to Vulkan border colors and throws NotImplementedException for anything else, because an arbitrary color would require an integer border color setup or clamping workaround the backend doesn't implement.
Solutions
- Set SamplerStateDescription.BorderColor to one of the supported values: Color4.White, Color4.Black, or Color.Transparent.
- If a custom border color is required, implement it in-shader (e.g. detect out-of-range UVs and output the color) instead of relying on the sampler.
- Consider extending CreateNativeSampler to map nearest matching VkBorderColor (Float variants) if you control the engine code.
Example fix
// before
var desc = new SamplerStateDescription(TextureAddressMode.ClampToBorder, Filter.Linear) { BorderColor = new Color4(1f, 0f, 0f, 1f) };
// after
desc.BorderColor = Color4.Black; Defensive patterns
Strategy: validation
Validate before calling
static readonly Color4[] supported = { Color4.White, Color4.Black, Color.Transparent };
if (!supported.Contains(desc.BorderColor))
throw new NotSupportedException("BorderColor must be White, Black, or Transparent on Vulkan"); Type guard
bool HasSimpleBorderColor(SamplerStateDescription d) =>
d.BorderColor == Color4.White || d.BorderColor == Color4.Black || d.BorderColor == Color.Transparent; Try / catch
try { sampler = new SamplerState(device, desc); }
catch (NotImplementedException ex) when (ex.Message.Contains("BorderColor")) { desc.BorderColor = Color4.Black; sampler = new SamplerState(device, desc); } Prevention
- Restrict sampler border colors to White/Black/Transparent in shared config
- Remember D3D allows arbitrary border colors but this Vulkan backend does not
- Implement custom border tinting in shaders if needed
- Centralize sampler description creation so border values are validated once
When it happens
Trigger: Creating (or recreating after device loss) a SamplerState whose Description.BorderColor is not Color4.White, Color4.Black, or Color.Transparent.
Common situations: Setting a custom tinted border color (e.g. Color.Red) on a sampler for clamp-to-border addressing; porting D3D11 code where arbitrary float border colors were allowed.
Related errors
- Static Samplers can only have opaque black, opaque white or
- Vulkan: Device supports only Vulkan {Adapter.DriverInfo.ApiV
- Reset is not supported by the asset tracker.
- Serialization of nested types referencing parent's generic p
- The current event is of an unsupported type.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/21fd7bfc18262448.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/Vulkan/SamplerState.Vulkan.cs:76
mipLodBias = Description.MipMapLevelOfDetailBias,
maxAnisotropy = Description.MaxAnisotropy,
compareOp = VulkanConvertExtensions.ConvertComparisonFunction(Description.CompareFunction),
minLod = Description.MinMipLevel,
maxLod = Description.MaxMipLevel,
};
if (Description.AddressU == TextureAddressMode.Border ||
Description.AddressV == TextureAddressMode.Border ||
Description.AddressW == TextureAddressMode.Border)
{
if (Description.BorderColor == Color4.White)
createInfo.borderColor = VkBorderColor.FloatOpaqueWhite;
else if (Description.BorderColor == Color4.Black)
createInfo.borderColor = VkBorderColor.FloatOpaqueBlack;
else if (Description.BorderColor == Color.Transparent)
createInfo.borderColor = VkBorderColor.FloatTransparentBlack;
else
throw new NotImplementedException("Vulkan: only simple BorderColor are supported");
}
ConvertMinFilter(Description.Filter, out createInfo.minFilter, out createInfo.magFilter, out createInfo.mipmapMode, out createInfo.compareEnable, out createInfo.anisotropyEnable);
GraphicsDevice.CheckResult(GraphicsDevice.NativeDeviceApi.vkCreateSampler(GraphicsDevice.NativeDevice, &createInfo, null, out NativeSampler));
}
private static VkSamplerAddressMode ConvertAddressMode(TextureAddressMode addressMode)
{
switch (addressMode)
{
case TextureAddressMode.Wrap:
return VkSamplerAddressMode.Repeat;
case TextureAddressMode.Border:
return VkSamplerAddressMode.ClampToBorder;
case TextureAddressMode.Clamp:
return VkSamplerAddressMode.ClampToEdge;
case TextureAddressMode.Mirror:View on GitHub (pinned to 96fad776d2)