LinkResult ProgramGL::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) { preLink(); // Read the binary format, size and blob GLenum binaryFormat = stream->readInt<GLenum>(); GLint binaryLength = stream->readInt<GLint>(); const uint8_t *binary = stream->data() + stream->offset(); stream->skip(binaryLength); // Load the binary mFunctions->programBinary(mProgramID, binaryFormat, binary, binaryLength); // Verify that the program linked if (!checkLinkStatus(infoLog)) { return LinkResult(false, gl::Error(GL_NO_ERROR)); } postLink(); return LinkResult(true, gl::Error(GL_NO_ERROR)); }
LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, std::map<int, gl::VariableLocation> *outputVariables) { // Reset the program state, delete the current program if one exists reset(); ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(vertexShader); ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(fragmentShader); // Attach the shaders mFunctions->attachShader(mProgramID, vertexShaderGL->getShaderID()); mFunctions->attachShader(mProgramID, fragmentShaderGL->getShaderID()); // Link and verify mFunctions->linkProgram(mProgramID); // Detach the shaders mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID()); mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID()); // Verify the link GLint linkStatus = GL_FALSE; mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus); ASSERT(linkStatus == GL_TRUE); if (linkStatus == GL_FALSE) { // Linking failed, put the error into the info log GLint infoLogLength = 0; mFunctions->getProgramiv(mProgramID, GL_INFO_LOG_LENGTH, &infoLogLength); std::vector<char> buf(infoLogLength); mFunctions->getProgramInfoLog(mProgramID, infoLogLength, nullptr, &buf[0]); mFunctions->deleteProgram(mProgramID); mProgramID = 0; infoLog << &buf[0]; TRACE("\n%s", &buf[0]); // TODO, return GL_OUT_OF_MEMORY or just fail the link? This is an unexpected case return LinkResult(false, gl::Error(GL_NO_ERROR)); } // Query the uniform information // TODO: A lot of this logic should be done at the gl::Program level GLint activeUniformMaxLength = 0; mFunctions->getProgramiv(mProgramID, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength); std::vector<GLchar> uniformNameBuffer(activeUniformMaxLength); GLint uniformCount = 0; mFunctions->getProgramiv(mProgramID, GL_ACTIVE_UNIFORMS, &uniformCount); for (GLint i = 0; i < uniformCount; i++) { GLsizei uniformNameLength = 0; GLint uniformSize = 0; GLenum uniformType = GL_NONE; mFunctions->getActiveUniform(mProgramID, i, uniformNameBuffer.size(), &uniformNameLength, &uniformSize, &uniformType, &uniformNameBuffer[0]); std::string uniformName = gl::ParseUniformName(std::string(&uniformNameBuffer[0], uniformNameLength), nullptr); for (size_t arrayIndex = 0; arrayIndex < static_cast<size_t>(uniformSize); arrayIndex++) { std::string locationName = uniformName; if (uniformSize > 1) { locationName += "[" + Str(arrayIndex) + "]"; } GLint location = mFunctions->getUniformLocation(mProgramID, locationName.c_str()); if (location >= 0) { // Make sure the uniform index array is large enough if (static_cast<size_t>(location) >= mUniformIndex.size()) { mUniformIndex.resize(location + 1); } mUniformIndex[location] = gl::VariableLocation(uniformName, arrayIndex, static_cast<unsigned int>(mUniforms.size())); // If the uniform is a sampler, track it in the sampler bindings array if (gl::IsSamplerType(uniformType)) { SamplerLocation samplerLoc; samplerLoc.samplerIndex = mSamplerBindings.size(); samplerLoc.arrayIndex = arrayIndex; mSamplerUniformMap[location] = samplerLoc; } } } // ANGLE uses 0 to identify an non-array uniform. unsigned int arraySize = (uniformSize > 1) ? static_cast<unsigned int>(uniformSize) : 0; // TODO: determine uniform precision mUniforms.push_back(new gl::LinkedUniform(uniformType, GL_NONE, uniformName, arraySize, -1, sh::BlockMemberInfo::getDefaultBlockInfo())); // If uniform is a sampler type, insert it into the mSamplerBindings array if (gl::IsSamplerType(uniformType)) { SamplerBindingGL samplerBinding; samplerBinding.textureType = gl::SamplerTypeToTextureType(uniformType); samplerBinding.boundTextureUnits.resize(uniformSize, 0); mSamplerBindings.push_back(samplerBinding); } } // Query the attribute information GLint activeAttributeMaxLength = 0; mFunctions->getProgramiv(mProgramID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttributeMaxLength); std::vector<GLchar> attributeNameBuffer(activeAttributeMaxLength); GLint attributeCount = 0; mFunctions->getProgramiv(mProgramID, GL_ACTIVE_ATTRIBUTES, &attributeCount); for (GLint i = 0; i < attributeCount; i++) { GLsizei attributeNameLength = 0; GLint attributeSize = 0; GLenum attributeType = GL_NONE; mFunctions->getActiveAttrib(mProgramID, i, attributeNameBuffer.size(), &attributeNameLength, &attributeSize, &attributeType, &attributeNameBuffer[0]); std::string attributeName(&attributeNameBuffer[0], attributeNameLength); GLint location = mFunctions->getAttribLocation(mProgramID, attributeName.c_str()); // TODO: determine attribute precision setShaderAttribute(static_cast<size_t>(i), attributeType, GL_NONE, attributeName, attributeSize, location); } return LinkResult(true, gl::Error(GL_NO_ERROR)); }
LinkResult ProgramGL::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) { UNIMPLEMENTED(); return LinkResult(false, gl::Error(GL_INVALID_OPERATION)); }
LinkResult ProgramGL::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, int registers) { //UNIMPLEMENTED(); return LinkResult(true, gl::Error(GL_NO_ERROR)); }
LinkResult ProgramNULL::link(const gl::ContextState &data, gl::InfoLog &infoLog) { UNIMPLEMENTED(); return LinkResult(false, gl::Error(GL_INVALID_OPERATION)); }
LinkResult ProgramGL::link(const gl::ContextState &data, gl::InfoLog &infoLog) { preLink(); // Set the transform feedback state std::vector<const GLchar *> transformFeedbackVaryings; for (const auto &tfVarying : mState.getTransformFeedbackVaryingNames()) { transformFeedbackVaryings.push_back(tfVarying.c_str()); } if (transformFeedbackVaryings.empty()) { if (mFunctions->transformFeedbackVaryings) { mFunctions->transformFeedbackVaryings(mProgramID, 0, nullptr, mState.getTransformFeedbackBufferMode()); } } else { ASSERT(mFunctions->transformFeedbackVaryings); mFunctions->transformFeedbackVaryings( mProgramID, static_cast<GLsizei>(transformFeedbackVaryings.size()), &transformFeedbackVaryings[0], mState.getTransformFeedbackBufferMode()); } const ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(mState.getAttachedVertexShader()); const ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(mState.getAttachedFragmentShader()); // Attach the shaders mFunctions->attachShader(mProgramID, vertexShaderGL->getShaderID()); mFunctions->attachShader(mProgramID, fragmentShaderGL->getShaderID()); // Bind attribute locations to match the GL layer. for (const sh::Attribute &attribute : mState.getAttributes()) { if (!attribute.staticUse) { continue; } mFunctions->bindAttribLocation(mProgramID, attribute.location, attribute.name.c_str()); } // Link and verify mFunctions->linkProgram(mProgramID); // Detach the shaders mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID()); mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID()); // Verify the link if (!checkLinkStatus(infoLog)) { return LinkResult(false, gl::Error(GL_NO_ERROR)); } if (mWorkarounds.alwaysCallUseProgramAfterLink) { mStateManager->forceUseProgram(mProgramID); } postLink(); return LinkResult(true, gl::Error(GL_NO_ERROR)); }