static void ExtractShaderStages(CompiledShader compiled, out CompiledShader compiledVertex, out CompiledShader compiledFragment)
        {
            using (var stream = new MemoryStream(compiled.shader.outputCode))
            {
                BinaryFormatter bin          = new BinaryFormatter();
                ShaderSetHeader shaderHeader = (ShaderSetHeader)bin.Deserialize(stream);

                var headerVertex = shaderHeader.shaders[(int)VKShaderType.kVKShaderVertex];
                if (headerVertex.offsetBytes == 0 || headerVertex.size == 0)
                {
                }
            }



            compiledVertex = new CompiledShader();
            compiledVertex.Init();
            compiledVertex.attributes = compiled.attributes;
            //compiledVertex.constantBuffers = compiled.constantBuffers;
            compiledVertex.shader = new Shader { /*outputCode = Encoding.UTF8.GetBytes(vertSrc)*/
            };
            compiledFragment      = new CompiledShader();
            compiledFragment.Init();
            //compiledFragment.constantBuffers = compiled.constantBuffers;
            compiledFragment.shader = new Shader { /*outputCode = Encoding.UTF8.GetBytes(fragSrc)*/
            };
        }
        // TODO can determine which uniform buffers are used in which stage based on binding index (see 'Create' in GpuProgramsVk.cpp)
        // if (binding.GetShaderStageFlags() != VK_SHADER_STAGE_FRAGMENT_BIT) // *only* used in fragment shader
        static uint SerializeUniforms(CompiledShader compiled, BinaryWriter writer)
        {
            int totalConstants = 0;

            foreach (var constantBuffer in compiled.constantBuffers)
            {
                totalConstants += constantBuffer.usedConstants;
            }
            writer.Write((ushort)totalConstants);

            int size = 0;

            foreach (var constantBuffer in compiled.constantBuffers)
            {
                for (int i = 0; i < constantBuffer.usedConstants; i++)
                {
                    var constant = constantBuffer.constants[i];
                    UnityToBgfx.ConvertBuiltInUniform(constant.name, out string uniformName);
                    writer.Write((byte)uniformName.Length);
                    writer.Write(Encoding.UTF8.GetBytes(uniformName));

                    if (constant.dataType != UnityHelper.ShaderParamType.kShaderParamFloat)
                    {
                        throw new NotSupportedException("Only float types are supported for uniforms.");
                    }

                    // Data type
                    var type = UnityToBgfx.GetBgfxUniformDataType(constant);
                    writer.Write((byte)type); // TODO bx::write(_writer, uint8_t(un.type | fragmentBit));

                    //  array size
                    writer.Write((byte)constant.arraySize); // Should be 0 if not an array

                    // regIndex - bgfx puts all constants into a single buffer
                    writer.Write((ushort)(size + constant.idx)); // TODO

                    // regCount
                    var regCount = constant.arraySize;
                    if (type == BgfxHelper.UniformType.Mat3)
                    {
                        regCount *= 3;
                    }
                    else if (type == BgfxHelper.UniformType.Mat4)
                    {
                        regCount *= 4;
                    }
                    writer.Write((ushort)regCount);

                    // TODO this is only used in renderer_webgpu.cpp?
                    // texComponent
                    // texDimension
//                    writer.Write((byte)0);
//                    writer.Write((byte)0);
                }

                size += constantBuffer.size;
            }

            return((uint)size);
        }
        internal static byte[] CreateSerializedBgfxShader(CompiledShader compiled, Stage stage)
        {
            // TODO SMOL-V compression and shader stage extraction
            throw new NotImplementedException();

#if false
            // Export bgfx file
            bool isVertexShader = stage == Stage.Vertex;
            using (var ms = new MemoryStream())
                using (var bw = new BinaryWriter(ms))
                {
                    // Header
                    bw.Write(isVertexShader ? BgfxHelper.BGFX_CHUNK_MAGIC_VSH : BgfxHelper.BGFX_CHUNK_MAGIC_FSH);

                    // Input/output hashes used for validating that vertex output matches fragment input
                    bw.Write(0u);
                    bw.Write(0u);

                    uint uniformBufferSize = SerializeUniforms(compiled, bw);

                    bw.Write((uint)compiled.shader.outputCode.Length);
                    bw.Write(compiled.shader.outputCode);
                    byte nul = 0;
                    bw.Write(nul);

                    // vertex attributes
                    if (isVertexShader)
                    {
                        bw.Write((byte)compiled.inputs.Count);
                        foreach (var input in compiled.inputs)
                        {
                            BgfxHelper.Attrib attrib = UnityToBgfx.ConvertAttribute(input.src);
                            if (attrib != BgfxHelper.Attrib.Count)
                            {
                                bw.Write(BgfxHelper.s_attribToId[attrib]);
                            }
                            else
                            {
                                bw.Write(ushort.MaxValue);
                            }
                        }
                    }
                    else
                    {
                        bw.Write((byte)0);
                    }

                    // constant buffer size
                    bw.Write(uniformBufferSize);

                    return(ms.ToArray());
                }
#endif
        }