#ifndef LIBANGLE_PROGRAMPIPELINE_H_
#define LIBANGLE_PROGRAMPIPELINE_H_
#include <memory>
#include "common/angleutils.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Program.h"
#include "libANGLE/ProgramExecutable.h"
#include "libANGLE/RefCountObject.h"
namespace rx
{
class GLImplFactory;
class ProgramPipelineImpl;
}
namespace gl
{
class Context;
class ProgramPipeline;
class ProgramPipelineState final : angle::NonCopyable
{
public:
ProgramPipelineState(rx::GLImplFactory *factory);
~ProgramPipelineState();
const std::string &getLabel() const;
ProgramExecutable &getExecutable() const
{
ASSERT(mExecutable);
return *mExecutable;
}
const SharedProgramExecutable &getSharedExecutable() const
{
ASSERT(mExecutable);
return mExecutable;
}
void activeShaderProgram(Program *shaderProgram);
void useProgramStages(const Context *context,
const gl::ShaderBitSet &shaderTypes,
Program *shaderProgram,
std::vector<angle::ObserverBinding> *programObserverBindings,
std::vector<angle::ObserverBinding> *programExecutableObserverBindings);
Program *getActiveShaderProgram() { return mActiveShaderProgram; }
GLboolean isValid() const { return mValid; }
const Program *getShaderProgram(ShaderType shaderType) const { return mPrograms[shaderType]; }
const SharedProgramExecutable &getShaderProgramExecutable(ShaderType shaderType) const
{
return mExecutable->mPPOProgramExecutables[shaderType];
}
bool usesShaderProgram(ShaderProgramID program) const;
void updateExecutableTextures();
void updateExecutableSpecConstUsageBits();
private:
SharedProgramExecutable makeNewExecutable(
rx::GLImplFactory *factory,
ShaderMap<SharedProgramExecutable> &&ppoProgramExecutables);
void useProgramStage(const Context *context,
ShaderType shaderType,
Program *shaderProgram,
angle::ObserverBinding *programObserverBinding,
angle::ObserverBinding *programExecutableObserverBinding);
void destroyDiscardedExecutables(const Context *context);
friend class ProgramPipeline;
std::string mLabel;
Program *mActiveShaderProgram;
ShaderMap<Program *> mPrograms;
ShaderMap<ProgramUniformBlockArray<GLuint>> mUniformBlockMap;
std::vector<SharedProgramExecutable> mProgramExecutablesToDiscard;
GLboolean mValid;
InfoLog mInfoLog;
SharedProgramExecutable mExecutable;
bool mIsLinked;
};
class ProgramPipeline final : public RefCountObject<ProgramPipelineID>,
public LabeledObject,
public angle::ObserverInterface,
public angle::Subject
{
public:
ProgramPipeline(rx::GLImplFactory *factory, ProgramPipelineID handle);
~ProgramPipeline() override;
void onDestroy(const Context *context) override;
angle::Result setLabel(const Context *context, const std::string &label) override;
const std::string &getLabel() const override;
const ProgramPipelineState &getState() const { return mState; }
ProgramPipelineState &getState() { return mState; }
ProgramExecutable &getExecutable() const { return mState.getExecutable(); }
const SharedProgramExecutable &getSharedExecutable() const
{
return mState.getSharedExecutable();
}
rx::ProgramPipelineImpl *getImplementation() const;
Program *getActiveShaderProgram() { return mState.getActiveShaderProgram(); }
void activeShaderProgram(Program *shaderProgram);
Program *getLinkedActiveShaderProgram(const Context *context)
{
Program *program = mState.getActiveShaderProgram();
if (program)
{
program->resolveLink(context);
}
return program;
}
angle::Result useProgramStages(const Context *context,
GLbitfield stages,
Program *shaderProgram);
const Program *getShaderProgram(ShaderType shaderType) const
{
return mState.getShaderProgram(shaderType);
}
const SharedProgramExecutable &getShaderProgramExecutable(ShaderType shaderType) const
{
return mState.getShaderProgramExecutable(shaderType);
}
void resetIsLinked() { mState.mIsLinked = false; }
angle::Result link(const gl::Context *context);
InfoLog &getInfoLog() { return mState.mInfoLog; }
int getInfoLogLength() const;
void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
void resolveLink(const Context *context)
{
if (mState.mIsLinked)
{
return;
}
resolveAttachedPrograms(context);
angle::Result linkResult = link(context);
if (linkResult != angle::Result::Continue)
{
WARN() << "ProgramPipeline link failed" << std::endl;
}
return;
}
void resolveAttachedPrograms(const Context *context);
void validate(const gl::Context *context);
GLboolean isValid() const { return mState.isValid(); }
bool isLinked() const { return mState.mIsLinked; }
void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;
private:
bool linkVaryings();
void updateLinkedShaderStages();
void updateExecutableAttributes();
void updateTransformFeedbackMembers();
void updateShaderStorageBlocks();
void updateImageBindings();
void updateExecutableGeometryProperties();
void updateExecutableTessellationProperties();
void updateFragmentInoutRangeAndEnablesPerSampleShading();
void updateLinkedVaryings();
void updateExecutable();
std::unique_ptr<rx::ProgramPipelineImpl> mProgramPipelineImpl;
ProgramPipelineState mState;
std::vector<angle::ObserverBinding> mProgramObserverBindings;
std::vector<angle::ObserverBinding> mProgramExecutableObserverBindings;
};
}
#endif