I think there are different ways to structure things, but one option would be to create a wined3d_shader with "source_type" set to VKD3D_SHADER_SOURCE_HLSL, and then let the shader_precompile() from wined3d_shader_init_object() turn that into GLSL or SPIR-V. More generally, I don't think creating fixed-function shaders in wined3d_device_apply_stateblock() is necessarily incompatible with doing shader compilation on the CS thread or some other thread. But yes, ultimately we could get there incrementally, if desired.
That'd work. I was also concerned about HLSL generation, but then again I think we could even go one step further along the same lines, and instead of even writing HLSL from the client side, just write the wined3d_ffp_vs_settings struct, and let precompile() turn that into HLSL and then into the final format.
That's probably prettier than what I have right now; I'll look into restructuring it accordingly.
Either way though I think it's orthogonal to this patch series. The goal here is to (piecemeal) move state invalidation out of the state table and into wined3d_device_apply_stateblock(), which we need in any case—it's fundamental to the goal of getting the "legacy" states out of core wined3d.