| 780 | } |
| 781 | |
| 782 | Napi::Value NativeEngine::CreateProgram(const Napi::CallbackInfo& info) |
| 783 | { |
| 784 | const auto vertexSource = info[0].As<Napi::String>().Utf8Value(); |
| 785 | const auto fragmentSource = info[1].As<Napi::String>().Utf8Value(); |
| 786 | |
| 787 | auto programData = std::make_unique<ProgramData>(); |
| 788 | |
| 789 | std::vector<uint8_t> vertexBytes{}; |
| 790 | std::vector<uint8_t> fragmentBytes{}; |
| 791 | std::unordered_map<std::string, uint32_t> attributeLocations; |
| 792 | |
| 793 | m_shaderCompiler.Compile(vertexSource, fragmentSource, [&](ShaderCompiler::ShaderInfo vertexShaderInfo, ShaderCompiler::ShaderInfo fragmentShaderInfo) { |
| 794 | constexpr uint8_t BGFX_SHADER_BIN_VERSION = 6; |
| 795 | |
| 796 | // These hashes are generated internally by BGFX's custom shader compilation pipeline, |
| 797 | // which we don't have access to. Fortunately, however, they aren't used for anything |
| 798 | // crucial; they just have to match. |
| 799 | constexpr uint32_t vertexOutputsHash = 0xBAD1DEA; |
| 800 | constexpr uint32_t fragmentInputsHash = vertexOutputsHash; |
| 801 | |
| 802 | { |
| 803 | const spirv_cross::Compiler& compiler = *vertexShaderInfo.Compiler; |
| 804 | const spirv_cross::ShaderResources resources = compiler.get_shader_resources(); |
| 805 | assert(resources.uniform_buffers.size() == 1); |
| 806 | const spirv_cross::Resource& uniformBuffer = resources.uniform_buffers[0]; |
| 807 | #if (BGFX_CONFIG_RENDERER_METAL) |
| 808 | // with metal, we bind images and not samplers |
| 809 | const spirv_cross::SmallVector<spirv_cross::Resource>& samplers = resources.separate_images; |
| 810 | #else |
| 811 | const spirv_cross::SmallVector<spirv_cross::Resource>& samplers = resources.separate_samplers; |
| 812 | #endif |
| 813 | size_t numUniforms = compiler.get_type(uniformBuffer.base_type_id).member_types.size() + samplers.size(); |
| 814 | |
| 815 | AppendBytes(vertexBytes, BX_MAKEFOURCC('V', 'S', 'H', BGFX_SHADER_BIN_VERSION)); |
| 816 | AppendBytes(vertexBytes, vertexOutputsHash); |
| 817 | AppendBytes(vertexBytes, fragmentInputsHash); |
| 818 | |
| 819 | AppendBytes(vertexBytes, static_cast<uint16_t>(numUniforms)); |
| 820 | AppendUniformBuffer(vertexBytes, compiler, uniformBuffer, false); |
| 821 | AppendSamplers(vertexBytes, compiler, samplers, false, programData->VertexUniformNameToInfo); |
| 822 | |
| 823 | AppendBytes(vertexBytes, static_cast<uint32_t>(vertexShaderInfo.Bytes.size())); |
| 824 | AppendBytes(vertexBytes, vertexShaderInfo.Bytes); |
| 825 | AppendBytes(vertexBytes, static_cast<uint8_t>(0)); |
| 826 | |
| 827 | AppendBytes(vertexBytes, static_cast<uint8_t>(resources.stage_inputs.size())); |
| 828 | for (const spirv_cross::Resource& stageInput : resources.stage_inputs) |
| 829 | { |
| 830 | const uint32_t location = compiler.get_decoration(stageInput.id, spv::DecorationLocation); |
| 831 | AppendBytes(vertexBytes, bgfx::attribToId(static_cast<bgfx::Attrib::Enum>(location))); |
| 832 | |
| 833 | std::string attributeName = stageInput.name; |
| 834 | if (attributeName == "a_position") |
| 835 | attributeName = "position"; |
| 836 | else if (attributeName == "a_normal") |
| 837 | attributeName = "normal"; |
| 838 | else if (attributeName == "a_tangent") |
| 839 | attributeName = "tangent"; |
nothing calls this directly
no test coverage detected