• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // ProgramPipeline.cpp: Implements the gl::ProgramPipeline class.
8 // Implements GL program pipeline objects and related functionality.
9 // [OpenGL ES 3.1] section 7.4 page 105.
10 
11 #include "libANGLE/ProgramPipeline.h"
12 
13 #include <algorithm>
14 
15 #include "libANGLE/Context.h"
16 #include "libANGLE/ErrorStrings.h"
17 #include "libANGLE/Program.h"
18 #include "libANGLE/angletypes.h"
19 #include "libANGLE/renderer/GLImplFactory.h"
20 #include "libANGLE/renderer/ProgramPipelineImpl.h"
21 
22 namespace gl
23 {
24 
ProgramPipelineState()25 ProgramPipelineState::ProgramPipelineState()
26     : mLabel(),
27       mIsCompute(false),
28       mActiveShaderProgram(nullptr),
29       mValid(false),
30       mHasBeenBound(false),
31       mExecutable(new ProgramExecutable())
32 {
33     mExecutable->setProgramPipelineState(this);
34 
35     for (const ShaderType shaderType : gl::AllShaderTypes())
36     {
37         mPrograms[shaderType] = nullptr;
38     }
39 }
40 
~ProgramPipelineState()41 ProgramPipelineState::~ProgramPipelineState()
42 {
43     SafeDelete(mExecutable);
44 }
45 
getLabel() const46 const std::string &ProgramPipelineState::getLabel() const
47 {
48     return mLabel;
49 }
50 
activeShaderProgram(Program * shaderProgram)51 void ProgramPipelineState::activeShaderProgram(Program *shaderProgram)
52 {
53     mActiveShaderProgram = shaderProgram;
54 }
55 
useProgramStage(const Context * context,const ShaderType shaderType,Program * shaderProgram)56 void ProgramPipelineState::useProgramStage(const Context *context,
57                                            const ShaderType shaderType,
58                                            Program *shaderProgram)
59 {
60     Program *oldProgram = mPrograms[shaderType];
61     if (oldProgram)
62     {
63         oldProgram->release(context);
64     }
65 
66     // If program refers to a program object with a valid shader attached for the indicated shader
67     // stage, glUseProgramStages installs the executable code for that stage in the indicated
68     // program pipeline object pipeline.
69     if (shaderProgram && (shaderProgram->id().value != 0) &&
70         shaderProgram->getExecutable().hasLinkedShaderStage(shaderType))
71     {
72         mPrograms[shaderType] = shaderProgram;
73         shaderProgram->addRef();
74     }
75     else
76     {
77         // If program is zero, or refers to a program object with no valid shader executable for the
78         // given stage, it is as if the pipeline object has no programmable stage configured for the
79         // indicated shader stage.
80         mPrograms[shaderType] = nullptr;
81     }
82 }
83 
useProgramStages(const Context * context,GLbitfield stages,Program * shaderProgram)84 void ProgramPipelineState::useProgramStages(const Context *context,
85                                             GLbitfield stages,
86                                             Program *shaderProgram)
87 {
88     if (stages == GL_ALL_SHADER_BITS)
89     {
90         for (const ShaderType shaderType : gl::AllShaderTypes())
91         {
92             useProgramStage(context, shaderType, shaderProgram);
93         }
94     }
95     else
96     {
97         if (stages & GL_VERTEX_SHADER_BIT)
98         {
99             useProgramStage(context, ShaderType::Vertex, shaderProgram);
100         }
101 
102         if (stages & GL_FRAGMENT_SHADER_BIT)
103         {
104             useProgramStage(context, ShaderType::Fragment, shaderProgram);
105         }
106 
107         if (stages & GL_COMPUTE_SHADER_BIT)
108         {
109             useProgramStage(context, ShaderType::Compute, shaderProgram);
110         }
111     }
112 }
113 
usesShaderProgram(ShaderProgramID programId) const114 bool ProgramPipelineState::usesShaderProgram(ShaderProgramID programId) const
115 {
116     for (const Program *program : mPrograms)
117     {
118         if (program && (program->id() == programId))
119         {
120             return true;
121         }
122     }
123 
124     return false;
125 }
126 
hasDefaultUniforms() const127 bool ProgramPipelineState::hasDefaultUniforms() const
128 {
129     for (const gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
130     {
131         const Program *shaderProgram = getShaderProgram(shaderType);
132         if (shaderProgram && shaderProgram->getState().hasDefaultUniforms())
133         {
134             return true;
135         }
136     }
137 
138     return false;
139 }
140 
hasTextures() const141 bool ProgramPipelineState::hasTextures() const
142 {
143     for (const gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
144     {
145         const Program *shaderProgram = getShaderProgram(shaderType);
146         if (shaderProgram && shaderProgram->getState().hasTextures())
147         {
148             return true;
149         }
150     }
151 
152     return false;
153 }
154 
hasImages() const155 bool ProgramPipelineState::hasImages() const
156 {
157     for (const gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
158     {
159         const Program *shaderProgram = getShaderProgram(shaderType);
160         if (shaderProgram && shaderProgram->getState().hasImages())
161         {
162             return true;
163         }
164     }
165 
166     return false;
167 }
168 
ProgramPipeline(rx::GLImplFactory * factory,ProgramPipelineID handle)169 ProgramPipeline::ProgramPipeline(rx::GLImplFactory *factory, ProgramPipelineID handle)
170     : RefCountObject(factory->generateSerial(), handle),
171       mProgramPipelineImpl(factory->createProgramPipeline(mState))
172 {
173     ASSERT(mProgramPipelineImpl);
174 }
175 
~ProgramPipeline()176 ProgramPipeline::~ProgramPipeline()
177 {
178     mProgramPipelineImpl.release();
179 }
180 
onDestroy(const Context * context)181 void ProgramPipeline::onDestroy(const Context *context)
182 {
183     for (Program *program : mState.mPrograms)
184     {
185         if (program)
186         {
187             ASSERT(program->getRefCount());
188             program->release(context);
189         }
190     }
191 
192     getImplementation()->destroy(context);
193 }
194 
setLabel(const Context * context,const std::string & label)195 void ProgramPipeline::setLabel(const Context *context, const std::string &label)
196 {
197     mState.mLabel = label;
198 }
199 
getLabel() const200 const std::string &ProgramPipeline::getLabel() const
201 {
202     return mState.mLabel;
203 }
204 
getImplementation() const205 rx::ProgramPipelineImpl *ProgramPipeline::getImplementation() const
206 {
207     return mProgramPipelineImpl.get();
208 }
209 
activeShaderProgram(Program * shaderProgram)210 void ProgramPipeline::activeShaderProgram(Program *shaderProgram)
211 {
212     mState.activeShaderProgram(shaderProgram);
213 }
214 
useProgramStages(const Context * context,GLbitfield stages,Program * shaderProgram)215 void ProgramPipeline::useProgramStages(const Context *context,
216                                        GLbitfield stages,
217                                        Program *shaderProgram)
218 {
219     mState.useProgramStages(context, stages, shaderProgram);
220     updateLinkedShaderStages();
221     updateExecutable();
222 
223     mDirtyBits.set(DIRTY_BIT_PROGRAM_STAGE);
224 }
225 
updateLinkedShaderStages()226 void ProgramPipeline::updateLinkedShaderStages()
227 {
228     mState.mExecutable->resetLinkedShaderStages();
229 
230     for (const ShaderType shaderType : gl::AllShaderTypes())
231     {
232         Program *program = mState.mPrograms[shaderType];
233         if (program)
234         {
235             mState.mExecutable->setLinkedShaderStages(shaderType);
236         }
237     }
238 
239     mState.mExecutable->updateCanDrawWith();
240 }
241 
updateExecutableAttributes()242 void ProgramPipeline::updateExecutableAttributes()
243 {
244     Program *vertexProgram = getShaderProgram(gl::ShaderType::Vertex);
245 
246     if (!vertexProgram)
247     {
248         return;
249     }
250 
251     const ProgramExecutable &vertexExecutable      = vertexProgram->getExecutable();
252     mState.mExecutable->mActiveAttribLocationsMask = vertexExecutable.mActiveAttribLocationsMask;
253     mState.mExecutable->mMaxActiveAttribLocation   = vertexExecutable.mMaxActiveAttribLocation;
254     mState.mExecutable->mAttributesTypeMask        = vertexExecutable.mAttributesTypeMask;
255     mState.mExecutable->mAttributesMask            = vertexExecutable.mAttributesMask;
256 }
257 
updateTransformFeedbackMembers()258 void ProgramPipeline::updateTransformFeedbackMembers()
259 {
260     Program *vertexProgram = getShaderProgram(gl::ShaderType::Vertex);
261 
262     if (!vertexProgram)
263     {
264         return;
265     }
266 
267     const ProgramExecutable &vertexExecutable     = vertexProgram->getExecutable();
268     mState.mExecutable->mTransformFeedbackStrides = vertexExecutable.mTransformFeedbackStrides;
269     mState.mExecutable->mLinkedTransformFeedbackVaryings =
270         vertexExecutable.mLinkedTransformFeedbackVaryings;
271 }
272 
updateExecutableTextures()273 void ProgramPipeline::updateExecutableTextures()
274 {
275     for (const ShaderType shaderType : mState.mExecutable->getLinkedShaderStages())
276     {
277         const Program *program = getShaderProgram(shaderType);
278         if (program)
279         {
280             mState.mExecutable->mActiveSamplersMask |=
281                 program->getExecutable().getActiveSamplersMask();
282             mState.mExecutable->mActiveImagesMask |= program->getExecutable().getActiveImagesMask();
283             // Updates mActiveSamplerRefCounts, mActiveSamplerTypes, and mActiveSamplerFormats
284             mState.mExecutable->updateActiveSamplers(program->getState());
285         }
286     }
287 }
288 
updateHasBuffers()289 void ProgramPipeline::updateHasBuffers()
290 {
291     // Need to check all of the shader stages, not just linked, so we handle Compute correctly.
292     for (const gl::ShaderType shaderType : kAllGraphicsShaderTypes)
293     {
294         const Program *shaderProgram = getShaderProgram(shaderType);
295         if (shaderProgram)
296         {
297             const ProgramExecutable &executable = shaderProgram->getExecutable();
298 
299             if (executable.hasUniformBuffers())
300             {
301                 mState.mExecutable->mPipelineHasGraphicsUniformBuffers = true;
302             }
303             if (executable.hasStorageBuffers())
304             {
305                 mState.mExecutable->mPipelineHasGraphicsStorageBuffers = true;
306             }
307             if (executable.hasAtomicCounterBuffers())
308             {
309                 mState.mExecutable->mPipelineHasGraphicsAtomicCounterBuffers = true;
310             }
311         }
312     }
313 
314     const Program *computeProgram = getShaderProgram(ShaderType::Compute);
315     if (computeProgram)
316     {
317         const ProgramExecutable &executable = computeProgram->getExecutable();
318 
319         if (executable.hasUniformBuffers())
320         {
321             mState.mExecutable->mPipelineHasComputeUniformBuffers = true;
322         }
323         if (executable.hasStorageBuffers())
324         {
325             mState.mExecutable->mPipelineHasComputeStorageBuffers = true;
326         }
327         if (executable.hasAtomicCounterBuffers())
328         {
329             mState.mExecutable->mPipelineHasComputeAtomicCounterBuffers = true;
330         }
331     }
332 }
333 
updateExecutable()334 void ProgramPipeline::updateExecutable()
335 {
336     mState.mExecutable->reset();
337 
338     // Vertex Shader ProgramExecutable properties
339     updateExecutableAttributes();
340     updateTransformFeedbackMembers();
341 
342     // All Shader ProgramExecutable properties
343     updateExecutableTextures();
344     updateHasBuffers();
345 }
346 
getMergedVaryings() const347 ProgramMergedVaryings ProgramPipeline::getMergedVaryings() const
348 {
349     ASSERT(!mState.mExecutable->isCompute());
350 
351     // Varyings are matched between pairs of consecutive stages, by location if assigned or
352     // by name otherwise.  Note that it's possible for one stage to specify location and the other
353     // not: https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
354 
355     // Map stages to the previous active stage in the rendering pipeline.  When looking at input
356     // varyings of a stage, this is used to find the stage whose output varyings are being linked
357     // with them.
358     ShaderMap<ShaderType> previousActiveStage;
359 
360     // Note that kAllGraphicsShaderTypes is sorted according to the rendering pipeline.
361     ShaderType lastActiveStage = ShaderType::InvalidEnum;
362     for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
363     {
364         previousActiveStage[shaderType] = lastActiveStage;
365 
366         const Program *program = getShaderProgram(shaderType);
367         ASSERT(program);
368         lastActiveStage = shaderType;
369     }
370 
371     // First, go through output varyings and create two maps (one by name, one by location) for
372     // faster lookup when matching input varyings.
373 
374     ShaderMap<std::map<std::string, size_t>> outputVaryingNameToIndexShaderMap;
375     ShaderMap<std::map<int, size_t>> outputVaryingLocationToIndexShaderMap;
376 
377     ProgramMergedVaryings merged;
378 
379     // Gather output varyings.
380     for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
381     {
382         const Program *program = getShaderProgram(shaderType);
383         ASSERT(program);
384         Shader *shader = program->getState().getAttachedShader(shaderType);
385         ASSERT(shader);
386 
387         for (const sh::ShaderVariable &varying : shader->getOutputVaryings())
388         {
389             merged.push_back({});
390             ProgramVaryingRef *ref = &merged.back();
391 
392             ref->frontShader      = &varying;
393             ref->frontShaderStage = shaderType;
394 
395             // Always map by name.  Even if location is provided in this stage, it may not be in the
396             // paired stage.
397             outputVaryingNameToIndexShaderMap[shaderType][varying.name] = merged.size() - 1;
398 
399             // If location is provided, also keep it in a map by location.
400             if (varying.location != -1)
401             {
402                 outputVaryingLocationToIndexShaderMap[shaderType][varying.location] =
403                     merged.size() - 1;
404             }
405         }
406     }
407 
408     // Gather input varyings, and match them with output varyings of the previous stage.
409     for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
410     {
411         const Program *program = getShaderProgram(shaderType);
412         ASSERT(program);
413         Shader *shader = program->getState().getAttachedShader(shaderType);
414         ASSERT(shader);
415         ShaderType previousStage = previousActiveStage[shaderType];
416 
417         for (const sh::ShaderVariable &varying : shader->getInputVaryings())
418         {
419             size_t mergedIndex = merged.size();
420             if (previousStage != ShaderType::InvalidEnum)
421             {
422                 // If location is provided, see if we can match by location.
423                 if (varying.location != -1)
424                 {
425                     std::map<int, size_t> outputVaryingLocationToIndex =
426                         outputVaryingLocationToIndexShaderMap[previousStage];
427                     auto byLocationIter = outputVaryingLocationToIndex.find(varying.location);
428                     if (byLocationIter != outputVaryingLocationToIndex.end())
429                     {
430                         mergedIndex = byLocationIter->second;
431                     }
432                 }
433 
434                 // If not found, try to match by name.
435                 if (mergedIndex == merged.size())
436                 {
437                     std::map<std::string, size_t> outputVaryingNameToIndex =
438                         outputVaryingNameToIndexShaderMap[previousStage];
439                     auto byNameIter = outputVaryingNameToIndex.find(varying.name);
440                     if (byNameIter != outputVaryingNameToIndex.end())
441                     {
442                         mergedIndex = byNameIter->second;
443                     }
444                 }
445             }
446 
447             // If no previous stage, or not matched by location or name, create a new entry for it.
448             if (mergedIndex == merged.size())
449             {
450                 merged.push_back({});
451                 mergedIndex = merged.size() - 1;
452             }
453 
454             ProgramVaryingRef *ref = &merged[mergedIndex];
455 
456             ref->backShader      = &varying;
457             ref->backShaderStage = shaderType;
458         }
459     }
460 
461     return merged;
462 }
463 
464 // The attached shaders are checked for linking errors by matching up their variables.
465 // Uniform, input and output variables get collected.
466 // The code gets compiled into binaries.
link(const Context * context)467 angle::Result ProgramPipeline::link(const Context *context)
468 {
469     if (!getExecutable().isCompute())
470     {
471         InfoLog &infoLog = mState.mExecutable->getInfoLog();
472         infoLog.reset();
473         const State &state = context->getState();
474 
475         // Map the varyings to the register file
476         gl::PackMode packMode = PackMode::ANGLE_RELAXED;
477         if (state.getLimitations().noFlexibleVaryingPacking)
478         {
479             // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
480             packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
481         }
482         else if (state.getExtensions().webglCompatibility)
483         {
484             // In WebGL, we use a slightly different handling for packing variables.
485             packMode = PackMode::WEBGL_STRICT;
486         }
487 
488         if (!linkVaryings(infoLog))
489         {
490             return angle::Result::Stop;
491         }
492 
493         if (!mState.mExecutable->linkValidateGlobalNames(infoLog))
494         {
495             return angle::Result::Stop;
496         }
497 
498         GLuint maxVaryingVectors =
499             static_cast<GLuint>(context->getState().getCaps().maxVaryingVectors);
500         VaryingPacking varyingPacking(maxVaryingVectors, packMode);
501 
502         const ProgramMergedVaryings &mergedVaryings = getMergedVaryings();
503         for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
504         {
505             Program *program = mState.mPrograms[shaderType];
506             ASSERT(program);
507             program->getExecutable().getResources().varyingPacking.reset();
508             ANGLE_TRY(
509                 program->linkMergedVaryings(context, program->getExecutable(), mergedVaryings));
510         }
511     }
512 
513     ANGLE_TRY(getImplementation()->link(context));
514 
515     return angle::Result::Continue;
516 }
517 
linkVaryings(InfoLog & infoLog) const518 bool ProgramPipeline::linkVaryings(InfoLog &infoLog) const
519 {
520     ShaderType previousShaderType = ShaderType::InvalidEnum;
521     for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
522     {
523         Program *program = getShaderProgram(shaderType);
524         ASSERT(program);
525         ProgramExecutable &executable = program->getExecutable();
526 
527         if (previousShaderType != ShaderType::InvalidEnum)
528         {
529             Program *previousProgram = getShaderProgram(previousShaderType);
530             ASSERT(previousProgram);
531             ProgramExecutable &previousExecutable = previousProgram->getExecutable();
532 
533             if (!Program::linkValidateShaderInterfaceMatching(
534                     previousExecutable.getLinkedOutputVaryings(previousShaderType),
535                     executable.getLinkedInputVaryings(shaderType), previousShaderType, shaderType,
536                     previousExecutable.getLinkedShaderVersion(previousShaderType),
537                     executable.getLinkedShaderVersion(shaderType), true, infoLog))
538             {
539                 return false;
540             }
541         }
542         previousShaderType = shaderType;
543     }
544 
545     Program *vertexProgram   = mState.mPrograms[ShaderType::Vertex];
546     Program *fragmentProgram = mState.mPrograms[ShaderType::Fragment];
547     if (!vertexProgram || !fragmentProgram)
548     {
549         return false;
550     }
551     ProgramExecutable &vertexExecutable   = vertexProgram->getExecutable();
552     ProgramExecutable &fragmentExecutable = fragmentProgram->getExecutable();
553     return Program::linkValidateBuiltInVaryings(
554         vertexExecutable.getLinkedOutputVaryings(ShaderType::Vertex),
555         fragmentExecutable.getLinkedInputVaryings(ShaderType::Fragment),
556         vertexExecutable.getLinkedShaderVersion(ShaderType::Vertex), infoLog);
557 }
558 
validate(const gl::Context * context)559 void ProgramPipeline::validate(const gl::Context *context)
560 {
561     const Caps &caps = context->getCaps();
562     mState.mValid    = true;
563     InfoLog &infoLog = mState.mExecutable->getInfoLog();
564     infoLog.reset();
565 
566     for (const ShaderType shaderType : mState.mExecutable->getLinkedShaderStages())
567     {
568         Program *shaderProgram = mState.mPrograms[shaderType];
569         if (shaderProgram)
570         {
571             shaderProgram->resolveLink(context);
572             shaderProgram->validate(caps);
573             std::string shaderInfoString = shaderProgram->getExecutable().getInfoLogString();
574             if (shaderInfoString.length())
575             {
576                 mState.mValid = false;
577                 infoLog << shaderInfoString << "\n";
578                 return;
579             }
580             if (!shaderProgram->isSeparable())
581             {
582                 mState.mValid = false;
583                 infoLog << GetShaderTypeString(shaderType) << " is not marked separable."
584                         << "\n";
585                 return;
586             }
587         }
588     }
589 
590     if (!linkVaryings(infoLog))
591     {
592         mState.mValid = false;
593 
594         for (const ShaderType shaderType : mState.mExecutable->getLinkedShaderStages())
595         {
596             Program *shaderProgram = mState.mPrograms[shaderType];
597             ASSERT(shaderProgram);
598             shaderProgram->validate(caps);
599             std::string shaderInfoString = shaderProgram->getExecutable().getInfoLogString();
600             if (shaderInfoString.length())
601             {
602                 infoLog << shaderInfoString << "\n";
603             }
604         }
605     }
606 }
607 
validateSamplers(InfoLog * infoLog,const Caps & caps)608 bool ProgramPipeline::validateSamplers(InfoLog *infoLog, const Caps &caps)
609 {
610     for (const ShaderType shaderType : gl::AllShaderTypes())
611     {
612         Program *shaderProgram = mState.mPrograms[shaderType];
613         if (shaderProgram && !shaderProgram->validateSamplers(infoLog, caps))
614         {
615             return false;
616         }
617     }
618 
619     return true;
620 }
621 
syncState(const Context * context)622 angle::Result ProgramPipeline::syncState(const Context *context)
623 {
624     if (mDirtyBits.any())
625     {
626         mDirtyBits.reset();
627 
628         // If there's a Program bound, we still want to link the PPO so we don't
629         // lose the dirty bit, but, we don't want to signal any errors if it fails
630         // since the failure would be unrelated to drawing with the Program.
631         bool goodResult = link(context) == angle::Result::Continue;
632         if (!context->getState().getProgram())
633         {
634             ANGLE_CHECK(const_cast<Context *>(context), goodResult, "Program pipeline link failed",
635                         GL_INVALID_OPERATION);
636         }
637     }
638 
639     return angle::Result::Continue;
640 }
641 
642 }  // namespace gl
643