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