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