#pragma once #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 vertexOffset = programs::gl::ShaderSource::vertexOffset; static constexpr const auto fragmentOffset = programs::gl::ShaderSource::fragmentOffset; class Instance { public: Instance(Context& context, const std::initializer_list& vertexSource, const std::initializer_list& fragmentSource) : program(context.createProgram( context.createShader(ShaderType::Vertex, vertexSource), context.createShader(ShaderType::Fragment, fragmentSource), 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 vertexSource = { programParameters.getDefines().c_str(), additionalDefines.c_str(), (programs::gl::shaderSource() + programs::gl::vertexPreludeOffset), (programs::gl::shaderSource() + vertexOffset) }; const std::initializer_list fragmentSource = { programParameters.getDefines().c_str(), additionalDefines.c_str(), (programs::gl::shaderSource() + programs::gl::fragmentPreludeOffset), (programs::gl::shaderSource() + fragmentOffset) }; return std::make_unique(context, vertexSource, fragmentSource); } 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