Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 913f4f4

Browse files
timvpGoogleCommit Bot
authored andcommitted
Vulkan: Support VS, FS, and CS in the same PPO
This CL adds support for a Program Pipeline Object to have a VS, FS, and CS attached to the same PPO and then using that PPO for both draw and dispatch calls. Bug: angleproject:3570 Test: KHR-GLES31.core.compute_shader.sso* Change-Id: I262cdbdfd442f6db5ba2b45d1308003102b237cb Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2150078 Reviewed-by: Tim Van Patten <[email protected]> Reviewed-by: Courtney Goeltzenleuchter <[email protected]> Commit-Queue: Tim Van Patten <[email protected]>
1 parent 78dcba5 commit 913f4f4

22 files changed

+223
-157
lines changed

src/libANGLE/Context.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3579,6 +3579,10 @@ ANGLE_INLINE angle::Result Context::prepareForCopyImage()
35793579

35803580
ANGLE_INLINE angle::Result Context::prepareForDispatch()
35813581
{
3582+
// We always assume PPOs are used for draws, until they aren't. If we are executing a dispatch
3583+
// with a PPO, we need to convert it from a "draw"-type to "dispatch"-type.
3584+
convertPpoToComputeOrDraw(true);
3585+
35823586
ANGLE_TRY(syncDirtyObjects(mComputeDirtyObjects));
35833587
return syncDirtyBits(mComputeDirtyBits);
35843588
}
@@ -5516,11 +5520,35 @@ void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGr
55165520
}
55175521

55185522
ANGLE_CONTEXT_TRY(prepareForDispatch());
5519-
ANGLE_CONTEXT_TRY(mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ));
5523+
5524+
angle::Result result =
5525+
mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ);
5526+
5527+
// We always assume PPOs are used for draws, until they aren't. If we just executed a dispatch
5528+
// with a PPO, we need to convert it back to a "draw"-type.
5529+
convertPpoToComputeOrDraw(false);
5530+
5531+
if (ANGLE_UNLIKELY(IsError(result)))
5532+
{
5533+
return;
5534+
}
55205535

55215536
MarkShaderStorageBufferUsage(this);
55225537
}
55235538

5539+
void Context::convertPpoToComputeOrDraw(bool isCompute)
5540+
{
5541+
Program *program = mState.getProgram();
5542+
ProgramPipeline *pipeline = mState.getProgramPipeline();
5543+
if (!program && pipeline)
5544+
{
5545+
pipeline->getExecutable().setIsCompute(isCompute);
5546+
pipeline->setDirtyBit(ProgramPipeline::DirtyBitType::DIRTY_BIT_DRAW_DISPATCH_CHANGE);
5547+
mState.mDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE);
5548+
mState.mDirtyBits.set(State::DirtyBitType::DIRTY_BIT_PROGRAM_EXECUTABLE);
5549+
}
5550+
}
5551+
55245552
void Context::dispatchComputeIndirect(GLintptr indirect)
55255553
{
55265554
ANGLE_CONTEXT_TRY(prepareForDispatch());

src/libANGLE/Context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,8 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
651651
GLsizei count,
652652
const GLint *v);
653653

654+
void convertPpoToComputeOrDraw(bool isCompute);
655+
654656
State mState;
655657
bool mShared;
656658
bool mSkipValidation;

src/libANGLE/Program.cpp

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,20 +1211,12 @@ bool ProgramState::hasAttachedShader() const
12111211

12121212
ShaderType ProgramState::getFirstAttachedShaderStageType() const
12131213
{
1214-
for (const gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
1214+
if (mExecutable.getLinkedShaderStages().none())
12151215
{
1216-
if (mExecutable.hasLinkedShaderStage(shaderType))
1217-
{
1218-
return shaderType;
1219-
}
1216+
return ShaderType::InvalidEnum;
12201217
}
12211218

1222-
if (mExecutable.hasLinkedShaderStage(ShaderType::Compute))
1223-
{
1224-
return ShaderType::Compute;
1225-
}
1226-
1227-
return ShaderType::InvalidEnum;
1219+
return *mExecutable.getLinkedShaderStages().begin();
12281220
}
12291221

12301222
ShaderType ProgramState::getLastAttachedShaderStageType() const
@@ -1665,13 +1657,13 @@ void Program::resolveLinkImpl(const Context *context)
16651657

16661658
void Program::updateLinkedShaderStages()
16671659
{
1668-
mState.mExecutable.getLinkedShaderStages().reset();
1660+
mState.mExecutable.resetLinkedShaderStages();
16691661

16701662
for (const Shader *shader : mState.mAttachedShaders)
16711663
{
16721664
if (shader)
16731665
{
1674-
mState.mExecutable.getLinkedShaderStages().set(shader->getType());
1666+
mState.mExecutable.setLinkedShaderStages(shader->getType());
16751667
}
16761668
}
16771669
}
@@ -5064,13 +5056,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
50645056
stream.writeInt(mState.mNumViews);
50655057
stream.writeInt(mState.mEarlyFramentTestsOptimization);
50665058

5067-
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
5068-
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
5069-
stream.writeInt(static_cast<int>(mState.mExecutable.mAttributesTypeMask.to_ulong()));
5070-
stream.writeInt(static_cast<int>(mState.mExecutable.mAttributesMask.to_ulong()));
5071-
stream.writeInt(mState.mExecutable.getActiveAttribLocationsMask().to_ulong());
5072-
stream.writeInt(mState.mExecutable.mMaxActiveAttribLocation);
5073-
50745059
stream.writeInt(mState.getProgramInputs().size());
50755060
for (const sh::ShaderVariable &attrib : mState.getProgramInputs())
50765061
{
@@ -5216,7 +5201,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
52165201
stream.writeInt(mState.getAtomicCounterUniformRange().low());
52175202
stream.writeInt(mState.getAtomicCounterUniformRange().high());
52185203

5219-
stream.writeInt(mState.mExecutable.getLinkedShaderStages().to_ulong());
5204+
mState.mExecutable.save(&stream);
52205205

52215206
mProgram->save(context, &stream);
52225207

@@ -5265,14 +5250,6 @@ angle::Result Program::deserialize(const Context *context,
52655250
mState.mNumViews = stream.readInt<int>();
52665251
mState.mEarlyFramentTestsOptimization = stream.readInt<bool>();
52675252

5268-
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
5269-
"Too many vertex attribs for mask: All bits of mAttributesTypeMask types and "
5270-
"mask fit into 32 bits each");
5271-
mState.mExecutable.mAttributesTypeMask = gl::ComponentTypeMask(stream.readInt<uint32_t>());
5272-
mState.mExecutable.mAttributesMask = stream.readInt<gl::AttributesMask>();
5273-
mState.mExecutable.mActiveAttribLocationsMask = stream.readInt<gl::AttributesMask>();
5274-
mState.mExecutable.mMaxActiveAttribLocation = stream.readInt<unsigned int>();
5275-
52765253
unsigned int attribCount = stream.readInt<unsigned int>();
52775254
ASSERT(mState.mProgramInputs.empty());
52785255
for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
@@ -5470,13 +5447,14 @@ angle::Result Program::deserialize(const Context *context,
54705447

54715448
static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
54725449
"Too many shader types");
5473-
mState.mExecutable.getLinkedShaderStages() = ShaderBitSet(stream.readInt<uint8_t>());
54745450

54755451
if (!mState.mAttachedShaders[ShaderType::Compute])
54765452
{
54775453
mState.updateTransformFeedbackStrides();
54785454
}
54795455

5456+
mState.mExecutable.load(&stream);
5457+
54805458
postResolveLink(context);
54815459

54825460
return angle::Result::Continue;

src/libANGLE/Program.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ class ProgramState final : angle::NonCopyable
353353
return mAttachedShadersMarkedForDetach[shaderType];
354354
}
355355

356+
// A Program can only either be graphics or compute, but never both, so it
357+
// can answer isCompute() based on which shaders it has.
358+
bool isCompute() const { return mExecutable.hasLinkedShaderStage(ShaderType::Compute); }
359+
356360
private:
357361
friend class MemoryProgramCache;
358362
friend class Program;

src/libANGLE/ProgramExecutable.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,33 @@ void ProgramExecutable::reset()
4848
mActiveImagesMask.reset();
4949
}
5050

51+
void ProgramExecutable::load(gl::BinaryInputStream *stream)
52+
{
53+
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
54+
"Too many vertex attribs for mask: All bits of mAttributesTypeMask types and "
55+
"mask fit into 32 bits each");
56+
mAttributesTypeMask = gl::ComponentTypeMask(stream->readInt<uint32_t>());
57+
mAttributesMask = stream->readInt<gl::AttributesMask>();
58+
mActiveAttribLocationsMask = stream->readInt<gl::AttributesMask>();
59+
mMaxActiveAttribLocation = stream->readInt<unsigned int>();
60+
61+
mLinkedGraphicsShaderStages = ShaderBitSet(stream->readInt<uint8_t>());
62+
mLinkedComputeShaderStages = ShaderBitSet(stream->readInt<uint8_t>());
63+
}
64+
65+
void ProgramExecutable::save(gl::BinaryOutputStream *stream) const
66+
{
67+
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
68+
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
69+
stream->writeInt(static_cast<int>(mAttributesTypeMask.to_ulong()));
70+
stream->writeInt(static_cast<int>(mAttributesMask.to_ulong()));
71+
stream->writeInt(mActiveAttribLocationsMask.to_ulong());
72+
stream->writeInt(mMaxActiveAttribLocation);
73+
74+
stream->writeInt(mLinkedGraphicsShaderStages.bits());
75+
stream->writeInt(mLinkedComputeShaderStages.bits());
76+
}
77+
5178
const ProgramState *ProgramExecutable::getProgramState(ShaderType shaderType) const
5279
{
5380
if (mProgramState &&
@@ -64,6 +91,30 @@ const ProgramState *ProgramExecutable::getProgramState(ShaderType shaderType) co
6491
return nullptr;
6592
}
6693

94+
bool ProgramExecutable::isCompute() const
95+
{
96+
ASSERT(mProgramState || mProgramPipelineState);
97+
98+
if (mProgramState)
99+
{
100+
return mProgramState->isCompute();
101+
}
102+
103+
return mProgramPipelineState->isCompute();
104+
}
105+
106+
void ProgramExecutable::setIsCompute(bool isComputeIn)
107+
{
108+
// A Program can only either be graphics or compute, but never both, so it can answer
109+
// isCompute() based on which shaders it has. However, a PPO can have both graphics and compute
110+
// programs attached, so we don't know if the PPO is a 'graphics' or 'compute' PPO until the
111+
// actual draw/dispatch call, which is why only PPOs need to record the type of call here.
112+
if (mProgramPipelineState)
113+
{
114+
mProgramPipelineState->setIsCompute(isComputeIn);
115+
}
116+
}
117+
67118
int ProgramExecutable::getInfoLogLength() const
68119
{
69120
return static_cast<int>(mInfoLog.getLength());

src/libANGLE/ProgramExecutable.h

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LIBANGLE_PROGRAMEXECUTABLE_H_
1010
#define LIBANGLE_PROGRAMEXECUTABLE_H_
1111

12+
#include "BinaryStream.h"
1213
#include "libANGLE/Caps.h"
1314
#include "libANGLE/InfoLog.h"
1415
#include "libANGLE/VaryingPacking.h"
@@ -63,6 +64,9 @@ class ProgramExecutable
6364

6465
void reset();
6566

67+
void save(gl::BinaryOutputStream *stream) const;
68+
void load(gl::BinaryInputStream *stream);
69+
6670
const ProgramState *getProgramState(ShaderType shaderType) const;
6771

6872
int getInfoLogLength() const;
@@ -71,15 +75,38 @@ class ProgramExecutable
7175
std::string getInfoLogString() const;
7276
void resetInfoLog() { mInfoLog.reset(); }
7377

74-
const ShaderBitSet &getLinkedShaderStages() const { return mLinkedShaderStages; }
75-
ShaderBitSet &getLinkedShaderStages() { return mLinkedShaderStages; }
78+
void resetLinkedShaderStages()
79+
{
80+
mLinkedComputeShaderStages.reset();
81+
mLinkedGraphicsShaderStages.reset();
82+
}
83+
const ShaderBitSet &getLinkedShaderStages() const
84+
{
85+
return isCompute() ? mLinkedComputeShaderStages : mLinkedGraphicsShaderStages;
86+
}
87+
void setLinkedShaderStages(ShaderType shaderType)
88+
{
89+
if (shaderType == ShaderType::Compute)
90+
{
91+
mLinkedComputeShaderStages.set(ShaderType::Compute);
92+
}
93+
else
94+
{
95+
mLinkedGraphicsShaderStages.set(shaderType);
96+
}
97+
}
7698
bool hasLinkedShaderStage(ShaderType shaderType) const
7799
{
78100
ASSERT(shaderType != ShaderType::InvalidEnum);
79-
return mLinkedShaderStages[shaderType];
101+
return (shaderType == ShaderType::Compute) ? mLinkedComputeShaderStages[shaderType]
102+
: mLinkedGraphicsShaderStages[shaderType];
80103
}
81-
size_t getLinkedShaderStageCount() const { return mLinkedShaderStages.count(); }
82-
bool isCompute() const { return hasLinkedShaderStage(ShaderType::Compute); }
104+
size_t getLinkedShaderStageCount() const
105+
{
106+
return isCompute() ? mLinkedComputeShaderStages.count()
107+
: mLinkedGraphicsShaderStages.count();
108+
}
109+
bool isCompute() const;
83110

84111
const AttributesMask &getActiveAttribLocationsMask() const
85112
{
@@ -136,6 +163,8 @@ class ProgramExecutable
136163
mProgramPipelineState = state;
137164
}
138165

166+
void setIsCompute(bool isComputeIn);
167+
139168
private:
140169
// TODO(timvp): http://anglebug.com/3570: Investigate removing these friend
141170
// class declarations and accessing the necessary members with getters/setters.
@@ -156,7 +185,8 @@ class ProgramExecutable
156185

157186
InfoLog mInfoLog;
158187

159-
ShaderBitSet mLinkedShaderStages;
188+
ShaderBitSet mLinkedGraphicsShaderStages;
189+
ShaderBitSet mLinkedComputeShaderStages;
160190

161191
angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
162192
unsigned int mMaxActiveAttribLocation;

0 commit comments

Comments
 (0)