#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace gl { template class Program final : public gfx::Program { public: using AttributeList = typename Name::AttributeList; using UniformList = typename Name::UniformList; using TextureList = typename Name::TextureList; Program(ProgramParameters programParameters_) : programParameters(std::move(programParameters_)) { } const ProgramParameters programParameters; static constexpr const auto vertexSource = programs::gl::ShaderSource::vertexSource; static constexpr const auto fragmentSource = programs::gl::ShaderSource::fragmentSource; class Instance { public: Instance(Context& context, const std::initializer_list& vertexShaderSource, const std::initializer_list& fragmentShaderSource) : program(context.createProgram( context.createShader(ShaderType::Vertex, vertexShaderSource), context.createShader(ShaderType::Fragment, fragmentShaderSource), attributeLocations.getFirstAttribName())) { attributeLocations.queryLocations(program); uniformStates.queryLocations(program); // Texture units are specified via uniforms as well, so we need query their locations textureStates.queryLocations(program); } static std::unique_ptr createInstance(gl::Context& context, const ProgramParameters& programParameters, const std::string& additionalDefines) { // Compile the shader const std::initializer_list vertexShaderSource = { programParameters.getDefines().c_str(), additionalDefines.c_str(), programs::gl::vertexPrelude, vertexSource }; const std::initializer_list fragmentShaderSource = { programParameters.getDefines().c_str(), additionalDefines.c_str(), programs::gl::fragmentPrelude, fragmentSource }; auto result = std::make_unique(context, vertexShaderSource, fragmentShaderSource); return std::move(result); } UniqueProgram program; gl::AttributeLocations attributeLocations; gl::UniformStates uniformStates; gl::TextureStates textureStates; }; void draw(gfx::Context& genericContext, gfx::RenderPass&, const gfx::DrawMode& drawMode, const gfx::DepthMode& depthMode, const gfx::StencilMode& stencilMode, const gfx::ColorMode& colorMode, const gfx::CullFaceMode& cullFaceMode, const gfx::UniformValues& uniformValues, gfx::DrawScope& drawScope, const gfx::AttributeBindings& attributeBindings, const gfx::TextureBindings& textureBindings, const gfx::IndexBuffer& indexBuffer, std::size_t indexOffset, std::size_t indexLength) override { auto& context = static_cast(genericContext); context.setDepthMode(depthMode); context.setStencilMode(stencilMode); context.setColorMode(colorMode); context.setCullFaceMode(cullFaceMode); const uint32_t key = gl::AttributeKey::compute(attributeBindings); auto it = instances.find(key); if (it == instances.end()) { it = instances .emplace(key, Instance::createInstance( context, programParameters, gl::AttributeKey::defines(attributeBindings))) .first; } auto& instance = *it->second; context.program = instance.program; instance.uniformStates.bind(uniformValues); instance.textureStates.bind(context, textureBindings); auto& vertexArray = drawScope.getResource().vertexArray; vertexArray.bind(context, indexBuffer, instance.attributeLocations.toBindingArray(attributeBindings)); context.draw(drawMode, indexOffset, indexLength); } private: std::map> instances; }; } // namespace gl } // namespace mbgl