{"record":{"id":"1d39ae46ac8df1c7","repo":"stride3d/stride","slug":"no-vertex-entry-point-and-no-fallback-vertex-shader","errorCode":null,"errorMessage":"No vertex entry point and no fallback vertex shader","messagePattern":"No vertex entry point and no fallback vertex shader","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Tests/FrameRenderer.Vulkan.cs","lineNumber":600,"sourceCode":"        // Quad geometry, same as the D3D11 renderer\n        ReadOnlySpan<float> vertices =\n        [\n            1f,  1f, 0f,  1.0f, 1.0f,\n            1f, -1f, 0f,  1.0f, 0.0f,\n            -1f,-1f, 0f,  0.0f, 0.0f,\n            -1f, 1f, 1f,  0.0f, 1.0f,\n        ];\n        ReadOnlySpan<uint> indices = [0, 1, 3, 1, 2, 3];\n        var (vertexBuffer, _) = CreateHostBuffer((ulong)(vertices.Length * sizeof(float)), VkBufferUsageFlags.VertexBuffer, MemoryMarshal.AsBytes(vertices));\n        var (indexBuffer, _) = CreateHostBuffer((ulong)(indices.Length * sizeof(uint)), VkBufferUsageFlags.IndexBuffer, MemoryMarshal.AsBytes(indices));\n\n        // Vertex shader: from the test's bytecode when present, else the quad passthrough\n        var vertexProbe = probe;\n        var vertexModule = shaderModule;\n        var vertexEntryPoint = probe.FindEntryPoint(SpirvProbe.ExecutionModelVertex);\n        if (vertexEntryPoint == null)\n        {\n            vertexProbe = fallbackVertexProbe ?? throw new InvalidOperationException(\"No vertex entry point and no fallback vertex shader\");\n            vertexModule = fallbackVertexModule;\n            vertexEntryPoint = vertexProbe.FindEntryPoint(SpirvProbe.ExecutionModelVertex);\n        }\n        var fragmentEntryPoint = probe.FindEntryPoint(SpirvProbe.ExecutionModelFragment)\n            ?? throw new InvalidOperationException(\"No fragment entry point\");\n\n        // Vertex attributes: POSITION/TEXCOORD from the quad buffer, other semantics from\n        // per-instance single-element buffers built from \"stream.SEMANTIC\" test parameters\n        var bindingDescriptions = new List<VkVertexInputBindingDescription>\n        {\n            new() { binding = 0, stride = 5 * sizeof(float), inputRate = VkVertexInputRate.Vertex },\n        };\n        var attributeDescriptions = new List<VkVertexInputAttributeDescription>();\n        var vertexBufferHandles = new List<VkBuffer> { vertexBuffer };\n        foreach (var (location, semantic) in vertexProbe.GetStageInputs(vertexEntryPoint))\n        {\n            if (semantic.StartsWith(\"POSITION\", StringComparison.OrdinalIgnoreCase))\n            {","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Tests/FrameRenderer.Vulkan.cs#L582-L618","documentation":"Thrown when preparing graphics pipelines: the test's SPIR-V bytecode has no vertex-stage entry point and no fallback vertex shader (fallbackVertexProbe) was supplied. The renderer always needs a vertex stage, either the bytecode's own or the built-in quad passthrough.","triggerScenarios":"Calling RenderFrame with a probe whose bytecode contains only fragment (or compute) entry points while fallbackVertexProbe is null, so the ?? throw fires before pipeline creation.","commonSituations":"Testing a fragment-only or compute-only shader through the graphics RenderFrame path; forgetting to pass fallbackVertexProbe/fallbackVertexModule to the renderer constructor; an entry point name mismatch so FindEntryPoint(ExecutionModelVertex) misses a vertex function that exists.","solutions":["Pass a fallbackVertexProbe (and fallbackVertexModule) constructed from the built-in quad passthrough SPIR-V when constructing VulkanFrameRenderer.","Check the bytecode actually contains an OpEntryPoint with ExecutionModel Vertex; re-export/recompile the shader with a vertex entry if not.","Route compute-only shaders through Compute() instead of RenderFrame()."],"exampleFix":"// before\nvar renderer = new VulkanFrameRenderer(probe, shaderModule, fragmentFallback: null);\n// after\nvar renderer = new VulkanFrameRenderer(probe, shaderModule, fallbackVertexProbe: quadProbe, fallbackVertexModule: quadModule);","handlingStrategy":"fallback","validationCode":"var hasVertex = probe.FindEntryPoint(SpirvProbe.ExecutionModelVertex) != null;\nvar hasFragment = probe.FindEntryPoint(SpirvProbe.ExecutionModelFragment) != null;\nif (!hasFragment || (!hasVertex && fallbackVertexProbe == null))\n    throw new InvalidOperationException(\"RenderFrame requires a fragment entry point and a vertex entry point or fallback\");","typeGuard":null,"tryCatchPattern":"try { renderer.RenderFrame(output); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"entry point\"))\n{\n    // switch to the compute path or supply fallback vertex shader and retry\n}","preventionTips":["Always construct VulkanFrameRenderer with a fallback vertex probe/module for fragment-only tests.","Use SpirvProbe to assert stage entry points exist before choosing RenderFrame vs Compute.","Name entry points predictably (VS/PS/main) so FindEntryPoint matches reliably."],"tags":["vulkan","spirv","graphics-pipeline"],"backgroundTag":"missing-required-argument","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}