1 //
2 // Copyright (c) 2014 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 // ProgramD3D.h: Defines the rx::ProgramD3D class which implements rx::ProgramImpl.
8 
9 #ifndef LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
10 #define LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
11 
12 #include <string>
13 #include <vector>
14 
15 #include "compiler/translator/blocklayoutHLSL.h"
16 #include "libANGLE/Constants.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/renderer/ProgramImpl.h"
19 #include "libANGLE/renderer/d3d/DynamicHLSL.h"
20 #include "platform/WorkaroundsD3D.h"
21 
22 namespace rx
23 {
24 class RendererD3D;
25 class UniformStorageD3D;
26 class ShaderExecutableD3D;
27 
28 #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
29 // WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang.
30 // It should only be used selectively to work around specific bugs.
31 #define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1
32 #endif
33 
34 // Helper struct representing a single shader uniform
35 // TODO(jmadill): Make uniform blocks shared between all programs, so we don't need separate
36 // register indices.
37 struct D3DUniform : private angle::NonCopyable
38 {
39     D3DUniform(GLenum type,
40                const std::string &nameIn,
41                const std::vector<unsigned int> &arraySizesIn,
42                bool defaultBlock);
43     ~D3DUniform();
44 
45     bool isSampler() const;
46 
isArrayD3DUniform47     bool isArray() const { return !arraySizes.empty(); }
48     unsigned int getArraySizeProduct() const;
49 
50     bool isReferencedByVertexShader() const;
51     bool isReferencedByFragmentShader() const;
52     bool isReferencedByComputeShader() const;
53 
54     const uint8_t *firstNonNullData() const;
55     const uint8_t *getDataPtrToElement(size_t elementIndex) const;
56 
57     // Duplicated from the GL layer
58     const gl::UniformTypeInfo &typeInfo;
59     std::string name;  // Names of arrays don't include [0], unlike at the GL layer.
60     std::vector<unsigned int> arraySizes;
61 
62     // Pointer to a system copies of the data. Separate pointers for each uniform storage type.
63     uint8_t *vsData;
64     uint8_t *psData;
65     uint8_t *csData;
66 
67     // Register information.
68     unsigned int vsRegisterIndex;
69     unsigned int psRegisterIndex;
70     unsigned int csRegisterIndex;
71     unsigned int registerCount;
72 
73     // Register "elements" are used for uniform structs in ES3, to appropriately identify single
74     // uniforms
75     // inside aggregate types, which are packed according C-like structure rules.
76     unsigned int registerElement;
77 
78     // Special buffer for sampler values.
79     std::vector<GLint> mSamplerData;
80 };
81 
82 struct D3DUniformBlock
83 {
D3DUniformBlockD3DUniformBlock84     D3DUniformBlock()
85         : vsRegisterIndex(GL_INVALID_INDEX),
86           psRegisterIndex(GL_INVALID_INDEX),
87           csRegisterIndex(GL_INVALID_INDEX)
88     {
89     }
90 
vertexStaticUseD3DUniformBlock91     bool vertexStaticUse() const { return vsRegisterIndex != GL_INVALID_INDEX; }
92 
fragmentStaticUseD3DUniformBlock93     bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; }
94 
computeStaticUseD3DUniformBlock95     bool computeStaticUse() const { return csRegisterIndex != GL_INVALID_INDEX; }
96 
97     unsigned int vsRegisterIndex;
98     unsigned int psRegisterIndex;
99     unsigned int csRegisterIndex;
100 };
101 
102 struct D3DVarying final
103 {
104     D3DVarying();
105     D3DVarying(const std::string &semanticNameIn,
106                unsigned int semanticIndexIn,
107                unsigned int componentCountIn,
108                unsigned int outputSlotIn);
109 
110     D3DVarying(const D3DVarying &) = default;
111     D3DVarying &operator=(const D3DVarying &) = default;
112 
113     std::string semanticName;
114     unsigned int semanticIndex;
115     unsigned int componentCount;
116     unsigned int outputSlot;
117 };
118 
119 class ProgramD3DMetadata final : angle::NonCopyable
120 {
121   public:
122     ProgramD3DMetadata(RendererD3D *renderer,
123                        const ShaderD3D *vertexShader,
124                        const ShaderD3D *fragmentShader);
125 
126     int getRendererMajorShaderModel() const;
127     bool usesBroadcast(const gl::ContextState &data) const;
128     bool usesFragDepth() const;
129     bool usesPointCoord() const;
130     bool usesFragCoord() const;
131     bool usesPointSize() const;
132     bool usesInsertedPointCoordValue() const;
133     bool usesViewScale() const;
134     bool hasANGLEMultiviewEnabled() const;
135     bool usesViewID() const;
136     bool canSelectViewInVertexShader() const;
137     bool addsPointCoordToVertexShader() const;
138     bool usesTransformFeedbackGLPosition() const;
139     bool usesSystemValuePointSize() const;
140     bool usesMultipleFragmentOuts() const;
141     GLint getMajorShaderVersion() const;
142     const ShaderD3D *getFragmentShader() const;
143 
144   private:
145     const int mRendererMajorShaderModel;
146     const std::string mShaderModelSuffix;
147     const bool mUsesInstancedPointSpriteEmulation;
148     const bool mUsesViewScale;
149     const bool mHasANGLEMultiviewEnabled;
150     const bool mUsesViewID;
151     const bool mCanSelectViewInVertexShader;
152     const ShaderD3D *mVertexShader;
153     const ShaderD3D *mFragmentShader;
154 };
155 
156 class ProgramD3D : public ProgramImpl
157 {
158   public:
159     ProgramD3D(const gl::ProgramState &data, RendererD3D *renderer);
160     ~ProgramD3D() override;
161 
getPixelShaderKey()162     const std::vector<PixelShaderOutputVariable> &getPixelShaderKey() { return mPixelShaderKey; }
163 
164     GLint getSamplerMapping(gl::SamplerType type,
165                             unsigned int samplerIndex,
166                             const gl::Caps &caps) const;
167     GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const;
168     GLuint getUsedSamplerRange(gl::SamplerType type) const;
169 
170     enum SamplerMapping
171     {
172         WasDirty,
173         WasClean,
174     };
175 
176     SamplerMapping updateSamplerMapping();
177 
usesPointSize()178     bool usesPointSize() const { return mUsesPointSize; }
179     bool usesPointSpriteEmulation() const;
180     bool usesGeometryShader(GLenum drawMode) const;
181     bool usesGeometryShaderForPointSpriteEmulation() const;
182     bool usesInstancedPointSpriteEmulation() const;
183 
184     gl::LinkResult load(const gl::Context *context,
185                         gl::InfoLog &infoLog,
186                         gl::BinaryInputStream *stream) override;
187     void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
188     void setBinaryRetrievableHint(bool retrievable) override;
189     void setSeparable(bool separable) override;
190 
191     gl::Error getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable,
192                                                       gl::InfoLog *infoLog);
193     gl::Error getGeometryExecutableForPrimitiveType(const gl::Context *context,
194                                                     GLenum drawMode,
195                                                     ShaderExecutableD3D **outExecutable,
196                                                     gl::InfoLog *infoLog);
197     gl::Error getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExectuable,
198                                                       gl::InfoLog *infoLog);
199     gl::Error getComputeExecutable(ShaderExecutableD3D **outExecutable);
200     gl::LinkResult link(const gl::Context *context,
201                         const gl::ProgramLinkedResources &resources,
202                         gl::InfoLog &infoLog) override;
203     GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
204 
205     void setPathFragmentInputGen(const std::string &inputName,
206                                  GLenum genMode,
207                                  GLint components,
208                                  const GLfloat *coeffs) override;
209 
210     void initializeUniformStorage();
211     void updateUniformBufferCache(const gl::Caps &caps,
212                                   unsigned int reservedVertex,
213                                   unsigned int reservedFragment);
214     const std::vector<GLint> &getVertexUniformBufferCache() const;
215     const std::vector<GLint> &getFragmentUniformBufferCache() const;
216 
217     void dirtyAllUniforms();
218 
219     void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
220     void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override;
221     void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override;
222     void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override;
223     void setUniform1iv(GLint location, GLsizei count, const GLint *v) override;
224     void setUniform2iv(GLint location, GLsizei count, const GLint *v) override;
225     void setUniform3iv(GLint location, GLsizei count, const GLint *v) override;
226     void setUniform4iv(GLint location, GLsizei count, const GLint *v) override;
227     void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override;
228     void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override;
229     void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override;
230     void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override;
231     void setUniformMatrix2fv(GLint location,
232                              GLsizei count,
233                              GLboolean transpose,
234                              const GLfloat *value) override;
235     void setUniformMatrix3fv(GLint location,
236                              GLsizei count,
237                              GLboolean transpose,
238                              const GLfloat *value) override;
239     void setUniformMatrix4fv(GLint location,
240                              GLsizei count,
241                              GLboolean transpose,
242                              const GLfloat *value) override;
243     void setUniformMatrix2x3fv(GLint location,
244                                GLsizei count,
245                                GLboolean transpose,
246                                const GLfloat *value) override;
247     void setUniformMatrix3x2fv(GLint location,
248                                GLsizei count,
249                                GLboolean transpose,
250                                const GLfloat *value) override;
251     void setUniformMatrix2x4fv(GLint location,
252                                GLsizei count,
253                                GLboolean transpose,
254                                const GLfloat *value) override;
255     void setUniformMatrix4x2fv(GLint location,
256                                GLsizei count,
257                                GLboolean transpose,
258                                const GLfloat *value) override;
259     void setUniformMatrix3x4fv(GLint location,
260                                GLsizei count,
261                                GLboolean transpose,
262                                const GLfloat *value) override;
263     void setUniformMatrix4x3fv(GLint location,
264                                GLsizei count,
265                                GLboolean transpose,
266                                const GLfloat *value) override;
267 
268     void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
269     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
270     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
271 
272     void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
273 
getVertexUniformStorage()274     UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage.get(); }
getFragmentUniformStorage()275     UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage.get(); }
getComputeUniformStorage()276     UniformStorageD3D &getComputeUniformStorage() const { return *mComputeUniformStorage.get(); }
277 
278     unsigned int getSerial() const;
279 
getAttribLocationToD3DSemantics()280     const AttribIndexArray &getAttribLocationToD3DSemantics() const
281     {
282         return mAttribLocationToD3DSemantic;
283     }
284 
285     void updateCachedInputLayout(Serial associatedSerial, const gl::State &state);
286     void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer);
287 
isSamplerMappingDirty()288     bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
289 
290     // Checks if we need to recompile certain shaders.
291     bool hasVertexExecutableForCachedInputLayout();
292     bool hasGeometryExecutableForPrimitiveType(GLenum drawMode);
293     bool hasPixelExecutableForCachedOutputLayout();
294 
areVertexUniformsDirty()295     bool areVertexUniformsDirty() const { return mVertexUniformsDirty; }
areFragmentUniformsDirty()296     bool areFragmentUniformsDirty() const { return mFragmentUniformsDirty; }
areComputeUniformsDirty()297     bool areComputeUniformsDirty() const { return mComputeUniformsDirty; }
getD3DUniforms()298     const std::vector<D3DUniform *> &getD3DUniforms() const { return mD3DUniforms; }
299     void markUniformsClean();
300 
301   private:
302     // These forward-declared tasks are used for multi-thread shader compiles.
303     class GetExecutableTask;
304     class GetVertexExecutableTask;
305     class GetPixelExecutableTask;
306     class GetGeometryExecutableTask;
307 
308     class VertexExecutable
309     {
310       public:
311         enum HLSLAttribType
312         {
313             FLOAT,
314             UNSIGNED_INT,
315             SIGNED_INT,
316         };
317 
318         typedef std::vector<HLSLAttribType> Signature;
319 
320         VertexExecutable(const gl::InputLayout &inputLayout,
321                          const Signature &signature,
322                          ShaderExecutableD3D *shaderExecutable);
323         ~VertexExecutable();
324 
325         bool matchesSignature(const Signature &signature) const;
326         static void getSignature(RendererD3D *renderer,
327                                  const gl::InputLayout &inputLayout,
328                                  Signature *signatureOut);
329 
inputs()330         const gl::InputLayout &inputs() const { return mInputs; }
signature()331         const Signature &signature() const { return mSignature; }
shaderExecutable()332         ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
333 
334       private:
335         static HLSLAttribType GetAttribType(GLenum type);
336 
337         gl::InputLayout mInputs;
338         Signature mSignature;
339         ShaderExecutableD3D *mShaderExecutable;
340     };
341 
342     class PixelExecutable
343     {
344       public:
345         PixelExecutable(const std::vector<GLenum> &outputSignature,
346                         ShaderExecutableD3D *shaderExecutable);
347         ~PixelExecutable();
348 
matchesSignature(const std::vector<GLenum> & signature)349         bool matchesSignature(const std::vector<GLenum> &signature) const
350         {
351             return mOutputSignature == signature;
352         }
353 
outputSignature()354         const std::vector<GLenum> &outputSignature() const { return mOutputSignature; }
shaderExecutable()355         ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
356 
357       private:
358         std::vector<GLenum> mOutputSignature;
359         ShaderExecutableD3D *mShaderExecutable;
360     };
361 
362     struct Sampler
363     {
364         Sampler();
365 
366         bool active;
367         GLint logicalTextureUnit;
368         GLenum textureType;
369     };
370 
371     typedef std::map<std::string, D3DUniform *> D3DUniformMap;
372 
373     void defineUniformsAndAssignRegisters(const gl::Context *context);
374     void defineUniformBase(const gl::Shader *shader,
375                            const sh::Uniform &uniform,
376                            D3DUniformMap *uniformMap);
377     void defineStructUniformFields(GLenum shaderType,
378                                    const std::vector<sh::ShaderVariable> &fields,
379                                    const std::string &namePrefix,
380                                    sh::HLSLBlockEncoder *encoder,
381                                    D3DUniformMap *uniformMap);
382     void defineArrayOfStructsUniformFields(GLenum shaderType,
383                                            const sh::ShaderVariable &uniform,
384                                            unsigned int arrayNestingIndex,
385                                            const std::string &prefix,
386                                            sh::HLSLBlockEncoder *encoder,
387                                            D3DUniformMap *uniformMap);
388     void defineArrayUniformElements(GLenum shaderType,
389                                     const sh::ShaderVariable &uniform,
390                                     const std::string &fullName,
391                                     sh::HLSLBlockEncoder *encoder,
392                                     D3DUniformMap *uniformMap);
393     void defineUniform(GLenum shaderType,
394                        const sh::ShaderVariable &uniform,
395                        const std::string &fullName,
396                        sh::HLSLBlockEncoder *encoder,
397                        D3DUniformMap *uniformMap);
398     void assignAllSamplerRegisters();
399     void assignSamplerRegisters(size_t uniformIndex);
400 
401     static void AssignSamplers(unsigned int startSamplerIndex,
402                                const gl::UniformTypeInfo &typeInfo,
403                                unsigned int samplerCount,
404                                std::vector<Sampler> &outSamplers,
405                                GLuint *outUsedRange);
406 
407     template <typename DestT>
408     void getUniformInternal(GLint location, DestT *dataOut) const;
409 
410     template <typename T>
411     void setUniformImpl(const gl::VariableLocation &locationInfo,
412                         GLsizei count,
413                         const T *v,
414                         uint8_t *targetData,
415                         GLenum uniformType);
416 
417     template <typename T>
418     void setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType);
419 
420     template <int cols, int rows>
421     bool setUniformMatrixfvImpl(GLint location,
422                                 GLsizei count,
423                                 GLboolean transpose,
424                                 const GLfloat *value,
425                                 uint8_t *targetData,
426                                 GLenum targetUniformType);
427 
428     template <int cols, int rows>
429     void setUniformMatrixfvInternal(GLint location,
430                                     GLsizei count,
431                                     GLboolean transpose,
432                                     const GLfloat *value,
433                                     GLenum targetUniformType);
434 
435     gl::LinkResult compileProgramExecutables(const gl::Context *context, gl::InfoLog &infoLog);
436     gl::LinkResult compileComputeExecutable(const gl::Context *context, gl::InfoLog &infoLog);
437 
438     void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings,
439                                          const BuiltinInfo &builtins);
440     D3DUniform *getD3DUniformByName(const std::string &name);
441     D3DUniform *getD3DUniformFromLocation(GLint location);
442     const D3DUniform *getD3DUniformFromLocation(GLint location) const;
443 
444     void initAttribLocationsToD3DSemantic(const gl::Context *context);
445 
446     void reset();
447     void initializeUniformBlocks();
448 
449     void updateCachedInputLayoutFromShader(const gl::Context *context);
450     void updateCachedOutputLayoutFromShader();
451     void updateCachedVertexExecutableIndex();
452     void updateCachedPixelExecutableIndex();
453 
454     void linkResources(const gl::Context *context, const gl::ProgramLinkedResources &resources);
455 
456     RendererD3D *mRenderer;
457     DynamicHLSL *mDynamicHLSL;
458 
459     std::vector<std::unique_ptr<VertexExecutable>> mVertexExecutables;
460     std::vector<std::unique_ptr<PixelExecutable>> mPixelExecutables;
461     std::vector<std::unique_ptr<ShaderExecutableD3D>> mGeometryExecutables;
462     std::unique_ptr<ShaderExecutableD3D> mComputeExecutable;
463 
464     std::string mVertexHLSL;
465     angle::CompilerWorkaroundsD3D mVertexWorkarounds;
466 
467     std::string mPixelHLSL;
468     angle::CompilerWorkaroundsD3D mPixelWorkarounds;
469     bool mUsesFragDepth;
470     bool mHasANGLEMultiviewEnabled;
471     bool mUsesViewID;
472     std::vector<PixelShaderOutputVariable> mPixelShaderKey;
473 
474     // Common code for all dynamic geometry shaders. Consists mainly of the GS input and output
475     // structures, built from the linked varying info. We store the string itself instead of the
476     // packed varyings for simplicity.
477     std::string mGeometryShaderPreamble;
478 
479     bool mUsesPointSize;
480     bool mUsesFlatInterpolation;
481 
482     std::unique_ptr<UniformStorageD3D> mVertexUniformStorage;
483     std::unique_ptr<UniformStorageD3D> mFragmentUniformStorage;
484     std::unique_ptr<UniformStorageD3D> mComputeUniformStorage;
485 
486     std::vector<Sampler> mSamplersPS;
487     std::vector<Sampler> mSamplersVS;
488     std::vector<Sampler> mSamplersCS;
489     GLuint mUsedVertexSamplerRange;
490     GLuint mUsedPixelSamplerRange;
491     GLuint mUsedComputeSamplerRange;
492     bool mDirtySamplerMapping;
493 
494     // Cache for pixel shader output layout to save reallocations.
495     std::vector<GLenum> mPixelShaderOutputLayoutCache;
496     Optional<size_t> mCachedPixelExecutableIndex;
497 
498     AttribIndexArray mAttribLocationToD3DSemantic;
499 
500     unsigned int mSerial;
501 
502     std::vector<GLint> mVertexUBOCache;
503     std::vector<GLint> mFragmentUBOCache;
504     VertexExecutable::Signature mCachedVertexSignature;
505     gl::InputLayout mCachedInputLayout;
506     Optional<size_t> mCachedVertexExecutableIndex;
507 
508     std::vector<D3DVarying> mStreamOutVaryings;
509     std::vector<D3DUniform *> mD3DUniforms;
510     std::vector<D3DUniformBlock> mD3DUniformBlocks;
511 
512     bool mVertexUniformsDirty;
513     bool mFragmentUniformsDirty;
514     bool mComputeUniformsDirty;
515 
516     static unsigned int issueSerial();
517     static unsigned int mCurrentSerial;
518 
519     Serial mCurrentVertexArrayStateSerial;
520 };
521 }  // namespace rx
522 
523 #endif  // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
524