CNA-BUG-107: DIRECTX9 draws a 3D ShaderEffect with the stock BasicEffect shader (16-byte vertices) or fails with a BasicEffect vertex-layout error instead of using or refusing the custom effect
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
DIRECTX9 compiles ShaderEffect HLSL and runs it for SpriteBatch, but its 3D dispatch never reads GpuDrawParams::customEffectRenderer or customEffectRequested, so a 3D ShaderEffect draw is drawn with the stock vertex-colour BasicEffect shader (16-byte vertices) or fails with a BasicEffect vertex-layout runtime_error that does not name the custom effect.
- Identifier
CNA-BUG-107- Category
- Bug
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- ShaderEffect (CNA extension) with GraphicsDevice::DrawPrimitives/DrawIndexedPrimitives on DIRECTX9; GraphicsCapability::CustomEffects; RendererCapabilityProfile
Expected behaviour
GpuDrawParams documents both fields: customEffectRenderer, when non-null, is what the renderer 'should bind/draw with ... directly instead of selecting one of its own built-in stride-dispatched shaders', and customEffectRequested is there so that 'backends without custom shaders ... refuse the draw instead of mistaking a null renderer for an ordinary fixed-function stock effect'. CNA also accepts a renderer that takes a ShaderEffect object and draws with a fixed path while ExecutesShaderEffectSourceEXT() answers false (SOFTWARE and HEADLESS), so within that contract a route that cannot run the custom program should use its fixed path consistently or refuse by name. DIRECTX11 and DIRECTX12 read customEffectRequested and run the source.
Actual behaviour at TARGET
DirectX9Renderer.cpp's CreateEffectRenderer compiles the caller's HLSL (SM2/SM3) into a D3D9EffectRenderer, and D3D9SpriteBatch.cpp binds it for SpriteBatch, so there the source does determine the pixels. For 3D, ShaderEffect::FillGpuDrawParams sets only customEffectRequested and customEffectRenderer, which D3D9EffectDraw.cpp's DrawPrimitivesExImpl never reads. With the remaining GpuDrawParams defaults (vertex colour on, texture and lighting off) the cascade reaches DrawBasicEffectEXT, which draws a 16-byte (VertexPositionColor) stream with the stock vertex-colour shader and throws std::runtime_error ("(BasicEffect): stride N ... has no matching CNA vertex layout") for every other stride. Neither outcome names the unsupported custom effect. DirectX9Renderer answers ExecutesShaderEffectSourceEXT() false; that answer is not part of this defect, because the query is renderer-wide and engine-layer passes such as PostProcessPass draw their ShaderEffect as 3D, where a true answer would over-promise.
Source locations
modules/renderers/directx9/src/DirectX9Renderer.cpp— DirectX9Renderer::CreateEffectRenderer; no capability/dialect overridesmodules/renderers/directx9/src/D3D9EffectDraw.cpp— DirectX9Renderer::DrawPrimitivesExImpl dispatch cascademodules/renderers/directx9/src/D3D9SpriteBatch.cpp— D3D9SpriteBatchRenderer::SetCustomEffect and the custom-program drawmodules/graphics/src/Xna/GraphicsDevice.cpp— GraphicsDevice::BuildRendererCapabilityProfileEXT dialect features
Evidence
Checked by reading at 009d40f5; nothing was built or executed. Read: DirectX9Renderer::CreateEffectRenderer, the SpriteBatch custom-effect flush in D3D9SpriteBatch.cpp, DirectX9Renderer::DrawPrimitivesExImpl and DrawBasicEffectEXT, ShaderEffect::FillGpuDrawParams in ShaderEffect.cpp, the GpuDrawParams defaults and the ExecutesShaderEffectSourceEXT contract in IGraphicsRenderer.hpp, and GraphicsDevice::BuildRendererCapabilityProfileEXT in GraphicsDevice.cpp. The DIRECTX9 ShaderEffect work item (plans/plan_dx9.md, D9-112) scoped the feature to SpriteBatch::Begin(effect). Because the false answer and the profile text warn callers that source does not drive pixels, the 3D fallback itself is inside CNA's documented capability contract; what remains is the inconsistent, misleadingly named failure on the 3D route and the SpriteBatch under-claim. XNA games use compiled effects, which DIRECTX9 supports separately; ShaderEffect is a CNA extension.
Independent re-verification: Checked by reading at 009d40f5; nothing was built or executed. The DIRECTX9 ShaderEffect work item (plan_dx9.md, D9-112) scoped the feature to SpriteBatch::Begin(effect), so the missing 3D execution is a known scope limit; what remains is the silent stock-effect fallback and the misleadingly named failure. XNA games use compiled effects, which DIRECTX9 supports separately; ShaderEffect is a CNA extension.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
DIRECTX9 ShaderEffect tests cover SpriteBatch; none draws 3D geometry with a ShaderEffect.
Regression test
A DIRECTX9 fixture that draws one VertexPositionColor and one VertexPositionTexture triangle with a ShaderEffect and asserts either the shader's constant colour for both (if 3D execution is implemented) or the same named NotSupportedException for both; plus a capability test that pins what ExecutesShaderEffectSourceEXT() answers against the routes it describes.
Blast radius
Engine or game code that uses ShaderEffect for 3D on DIRECTX9 without checking ExecutesShaderEffectSourceEXT(): 16-byte vertex streams draw with wrong pixels and no error, and other layouts fail with an error that points at BasicEffect rather than the custom effect. Code that consults the capability profile is told source never drives pixels and may give up SpriteBatch custom effects that do work. SpriteBatch custom effects themselves and compiled XNA effects are unaffected.
Workaround
Use compiled effects for 3D on DIRECTX9, and use ShaderEffect there only through SpriteBatch::Begin.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Known issues
- Bug index