//============================================================================== Error Material::getProgramPipeline( const RenderingKey& key, GlPipelineHandle& out) { ANKI_ASSERT(enumToType(key.m_pass) < m_passesCount); ANKI_ASSERT(key.m_lod < m_lodsCount); Error err = ErrorCode::NONE; U tessCount = 1; if(m_tessellation) { tessCount = 2; } else { ANKI_ASSERT(!key.m_tessellation); } U idx = enumToType(key.m_pass) * m_lodsCount * tessCount + key.m_lod * tessCount + key.m_tessellation; GlPipelineHandle& ppline = m_pplines[idx]; // Lazily create it if(ANKI_UNLIKELY(!ppline.isCreated())) { Array<GlShaderHandle, 5> progs; U progCount = 0; progs[progCount++] = getProgram(key, ShaderType::VERTEX)->getGlProgram(); if(key.m_tessellation) { progs[progCount++] = getProgram( key, ShaderType::TESSELLATION_CONTROL)->getGlProgram(); progs[progCount++] = getProgram( key, ShaderType::TESSELLATION_EVALUATION)->getGlProgram(); } progs[progCount++] = getProgram(key, ShaderType::FRAGMENT)->getGlProgram(); GlDevice& gl = m_resources->_getGlDevice(); GlCommandBufferHandle cmdBuff; ANKI_CHECK(cmdBuff.create(&gl)); ANKI_CHECK(ppline.create(cmdBuff, &progs[0], &progs[0] + progCount)); cmdBuff.flush(); } out = ppline; return err; }
//============================================================================== U Material::getShaderIndex(const RenderingKey key, ShaderType type) const { ANKI_ASSERT((U)key.m_pass < m_passesCount); ANKI_ASSERT(key.m_lod < m_lodsCount); if(key.m_tessellation) { ANKI_ASSERT(m_tessellation); } U tessCount = m_tessellation ? 2 : 1; U pass = enumToType(key.m_pass); U lod = key.m_lod; U tess = key.m_tessellation; U offset = 0; switch(type) { case ShaderType::FRAGMENT: offset += countShaders(ShaderType::GEOMETRY); case ShaderType::GEOMETRY: offset += countShaders(ShaderType::TESSELLATION_EVALUATION); case ShaderType::TESSELLATION_EVALUATION: offset += countShaders(ShaderType::TESSELLATION_CONTROL); case ShaderType::TESSELLATION_CONTROL: offset += countShaders(ShaderType::VERTEX); case ShaderType::VERTEX: offset += 0; break; default: ANKI_ASSERT(0); } U idx = MAX_U32; switch(type) { case ShaderType::VERTEX: // Like referencing an array of [pass][lod][tess] idx = pass * m_lodsCount * tessCount + lod * tessCount + tess; break; case ShaderType::TESSELLATION_CONTROL: // Like an array [pass] idx = pass; break; case ShaderType::TESSELLATION_EVALUATION: // Like an array [pass] idx = pass; break; case ShaderType::GEOMETRY: idx = 0; break; case ShaderType::FRAGMENT: // Like an array [pass][lod] idx = pass * m_lodsCount + lod; break; default: ANKI_ASSERT(0); } return offset + idx; }
Error PipelineImpl::createGlPipeline() { Error err = ErrorCode::NONE; // Do checks U mask = 0; U count = 6; while(count-- != 0) { const ShaderPtr& shader = m_in.m_shaders[count]; if(shader.isCreated()) { ANKI_ASSERT(count == enumToType(shader->m_impl->m_type)); mask |= 1 << count; } } if(mask & (1 << 5)) { // Is compute m_compute = true; ANKI_ASSERT((mask & (1 << 5)) == (1 << 5) && "Compute should be alone in the pipeline"); } else { m_compute = false; const U fragVert = (1 << 0) | (1 << 4); ANKI_ASSERT((mask & fragVert) && "Should contain vert and frag"); (void)fragVert; const U tess = (1 << 1) | (1 << 2); if((mask & tess) != 0) { ANKI_ASSERT(((mask & tess) == 0x6) && "Should set both the tessellation shaders"); } } // Create and attach programs m_glName = glCreateProgram(); ANKI_ASSERT(m_glName != 0); for(U i = 0; i < m_in.m_shaders.getSize(); i++) { ShaderPtr& shader = m_in.m_shaders[i]; if(shader.isCreated()) { glAttachShader(m_glName, shader->m_impl->getGlName()); if(i == U(ShaderType::TESSELLATION_CONTROL) || i == U(ShaderType::TESSELLATION_EVALUATION)) { m_tessellation = true; } } } // Validate and check error glLinkProgram(m_glName); GLint status = 0; glGetProgramiv(m_glName, GL_LINK_STATUS, &status); if(!status) { GLint infoLen = 0; GLint charsWritten = 0; DynamicArrayAuto<char> infoLogTxt(getAllocator()); glGetProgramiv(m_glName, GL_INFO_LOG_LENGTH, &infoLen); infoLogTxt.create(infoLen + 1); glGetProgramInfoLog(m_glName, infoLen, &charsWritten, &infoLogTxt[0]); ANKI_LOGE("Ppline error log follows (vs:%u, fs:%u):\n%s", m_in.m_shaders[ShaderType::VERTEX].isCreated() ? m_in.m_shaders[ShaderType::VERTEX]->m_impl->getGlName() : -1, m_in.m_shaders[ShaderType::FRAGMENT].isCreated() ? m_in.m_shaders[ShaderType::FRAGMENT]->m_impl->getGlName() : -1, &infoLogTxt[0]); err = ErrorCode::USER_DATA; } return err; }