• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2023 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 // ProgramExecutableD3D.h: Implementation of ProgramExecutableImpl.
8 
9 #ifndef LIBANGLE_RENDERER_D3D_PROGRAMEXECUTABLED3D_H_
10 #define LIBANGLE_RENDERER_D3D_PROGRAMEXECUTABLED3D_H_
11 
12 #include "compiler/translator/hlsl/blocklayoutHLSL.h"
13 #include "libANGLE/ProgramExecutable.h"
14 #include "libANGLE/formatutils.h"
15 #include "libANGLE/renderer/ProgramExecutableImpl.h"
16 #include "libANGLE/renderer/d3d/DynamicHLSL.h"
17 
18 namespace rx
19 {
20 class RendererD3D;
21 class UniformStorageD3D;
22 class ShaderExecutableD3D;
23 
24 #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
25 // WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang.
26 // It should only be used selectively to work around specific bugs.
27 #    define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1
28 #endif
29 
30 enum class HLSLRegisterType : uint8_t
31 {
32     None                = 0,
33     Texture             = 1,
34     UnorderedAccessView = 2
35 };
36 
37 // Helper struct representing a single shader uniform
38 // TODO(jmadill): Make uniform blocks shared between all programs, so we don't need separate
39 // register indices.
40 struct D3DUniform : private angle::NonCopyable
41 {
42     D3DUniform(GLenum type,
43                HLSLRegisterType reg,
44                const std::string &nameIn,
45                const std::vector<unsigned int> &arraySizesIn,
46                bool defaultBlock);
47     ~D3DUniform();
48 
49     bool isSampler() const;
50     bool isImage() const;
51     bool isImage2D() const;
isArrayD3DUniform52     bool isArray() const { return !arraySizes.empty(); }
53     unsigned int getArraySizeProduct() const;
54     bool isReferencedByShader(gl::ShaderType shaderType) const;
55 
56     const uint8_t *firstNonNullData() const;
57     const uint8_t *getDataPtrToElement(size_t elementIndex) const;
58 
59     // Duplicated from the GL layer
60     const gl::UniformTypeInfo &typeInfo;
61     std::string name;  // Names of arrays don't include [0], unlike at the GL layer.
62     std::vector<unsigned int> arraySizes;
63 
64     // Pointer to a system copies of the data. Separate pointers for each uniform storage type.
65     gl::ShaderMap<uint8_t *> mShaderData;
66 
67     // Register information.
68     HLSLRegisterType regType;
69     gl::ShaderMap<unsigned int> mShaderRegisterIndexes;
70     unsigned int registerCount;
71 
72     // Register "elements" are used for uniform structs in ES3, to appropriately identify single
73     // uniforms
74     // inside aggregate types, which are packed according C-like structure rules.
75     unsigned int registerElement;
76 
77     // Special buffer for sampler values.
78     std::vector<GLint> mSamplerData;
79 };
80 
81 struct D3DInterfaceBlock
82 {
83     D3DInterfaceBlock();
84     D3DInterfaceBlock(const D3DInterfaceBlock &other);
85 
activeInShaderD3DInterfaceBlock86     bool activeInShader(gl::ShaderType shaderType) const
87     {
88         return mShaderRegisterIndexes[shaderType] != GL_INVALID_INDEX;
89     }
90 
91     gl::ShaderMap<unsigned int> mShaderRegisterIndexes;
92 };
93 
94 struct D3DUniformBlock : D3DInterfaceBlock
95 {
96     D3DUniformBlock();
97     D3DUniformBlock(const D3DUniformBlock &other);
98 
99     gl::ShaderMap<bool> mUseStructuredBuffers;
100     gl::ShaderMap<unsigned int> mByteWidths;
101     gl::ShaderMap<unsigned int> mStructureByteStrides;
102 };
103 
104 struct ShaderStorageBlock
105 {
106     std::string name;
107     unsigned int arraySize     = 0;
108     unsigned int registerIndex = 0;
109 };
110 
111 struct D3DUBOCache
112 {
113     unsigned int registerIndex;
114     int binding;
115 };
116 
117 struct D3DUBOCacheUseSB : D3DUBOCache
118 {
119     unsigned int byteWidth;
120     unsigned int structureByteStride;
121 };
122 
123 struct D3DVarying final
124 {
125     D3DVarying();
126     D3DVarying(const std::string &semanticNameIn,
127                unsigned int semanticIndexIn,
128                unsigned int componentCountIn,
129                unsigned int outputSlotIn);
130 
131     D3DVarying(const D3DVarying &)            = default;
132     D3DVarying &operator=(const D3DVarying &) = default;
133 
134     std::string semanticName;
135     unsigned int semanticIndex;
136     unsigned int componentCount;
137     unsigned int outputSlot;
138 };
139 
140 using D3DUniformMap = std::map<std::string, D3DUniform *>;
141 
142 class D3DVertexExecutable
143 {
144   public:
145     enum HLSLAttribType
146     {
147         FLOAT,
148         UNSIGNED_INT,
149         SIGNED_INT,
150     };
151 
152     typedef std::vector<HLSLAttribType> Signature;
153 
154     D3DVertexExecutable(const gl::InputLayout &inputLayout,
155                         const Signature &signature,
156                         ShaderExecutableD3D *shaderExecutable);
157     ~D3DVertexExecutable();
158 
159     bool matchesSignature(const Signature &signature) const;
160     static void getSignature(RendererD3D *renderer,
161                              const gl::InputLayout &inputLayout,
162                              Signature *signatureOut);
163 
inputs()164     const gl::InputLayout &inputs() const { return mInputs; }
signature()165     const Signature &signature() const { return mSignature; }
shaderExecutable()166     ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
167 
168   private:
169     static HLSLAttribType GetAttribType(GLenum type);
170 
171     gl::InputLayout mInputs;
172     Signature mSignature;
173     ShaderExecutableD3D *mShaderExecutable;
174 };
175 
176 class D3DPixelExecutable
177 {
178   public:
179     D3DPixelExecutable(const std::vector<GLenum> &outputSignature,
180                        const gl::ImageUnitTextureTypeMap &image2DSignature,
181                        ShaderExecutableD3D *shaderExecutable);
182     ~D3DPixelExecutable();
183 
matchesSignature(const std::vector<GLenum> & outputSignature,const gl::ImageUnitTextureTypeMap & image2DSignature)184     bool matchesSignature(const std::vector<GLenum> &outputSignature,
185                           const gl::ImageUnitTextureTypeMap &image2DSignature) const
186     {
187         return mOutputSignature == outputSignature && mImage2DSignature == image2DSignature;
188     }
189 
outputSignature()190     const std::vector<GLenum> &outputSignature() const { return mOutputSignature; }
191 
image2DSignature()192     const gl::ImageUnitTextureTypeMap &image2DSignature() const { return mImage2DSignature; }
193 
shaderExecutable()194     ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
195 
196   private:
197     const std::vector<GLenum> mOutputSignature;
198     const gl::ImageUnitTextureTypeMap mImage2DSignature;
199     ShaderExecutableD3D *mShaderExecutable;
200 };
201 
202 class D3DComputeExecutable
203 {
204   public:
205     D3DComputeExecutable(const gl::ImageUnitTextureTypeMap &signature,
206                          std::unique_ptr<ShaderExecutableD3D> shaderExecutable);
207     ~D3DComputeExecutable();
208 
matchesSignature(const gl::ImageUnitTextureTypeMap & signature)209     bool matchesSignature(const gl::ImageUnitTextureTypeMap &signature) const
210     {
211         return mSignature == signature;
212     }
213 
signature()214     const gl::ImageUnitTextureTypeMap &signature() const { return mSignature; }
shaderExecutable()215     ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable.get(); }
216 
217   private:
218     gl::ImageUnitTextureTypeMap mSignature;
219     std::unique_ptr<ShaderExecutableD3D> mShaderExecutable;
220 };
221 
222 struct D3DSampler
223 {
224     D3DSampler();
225 
226     bool active;
227     GLint logicalTextureUnit;
228     gl::TextureType textureType;
229 };
230 
231 struct D3DImage
232 {
233     D3DImage();
234     bool active;
235     GLint logicalImageUnit;
236 };
237 
238 class ProgramExecutableD3D : public ProgramExecutableImpl
239 {
240   public:
241     ProgramExecutableD3D(const gl::ProgramExecutable *executable);
242     ~ProgramExecutableD3D() override;
243 
244     void destroy(const gl::Context *context) override;
245 
246     void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
247     void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override;
248     void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override;
249     void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override;
250     void setUniform1iv(GLint location, GLsizei count, const GLint *v) override;
251     void setUniform2iv(GLint location, GLsizei count, const GLint *v) override;
252     void setUniform3iv(GLint location, GLsizei count, const GLint *v) override;
253     void setUniform4iv(GLint location, GLsizei count, const GLint *v) override;
254     void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override;
255     void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override;
256     void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override;
257     void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override;
258     void setUniformMatrix2fv(GLint location,
259                              GLsizei count,
260                              GLboolean transpose,
261                              const GLfloat *value) override;
262     void setUniformMatrix3fv(GLint location,
263                              GLsizei count,
264                              GLboolean transpose,
265                              const GLfloat *value) override;
266     void setUniformMatrix4fv(GLint location,
267                              GLsizei count,
268                              GLboolean transpose,
269                              const GLfloat *value) override;
270     void setUniformMatrix2x3fv(GLint location,
271                                GLsizei count,
272                                GLboolean transpose,
273                                const GLfloat *value) override;
274     void setUniformMatrix3x2fv(GLint location,
275                                GLsizei count,
276                                GLboolean transpose,
277                                const GLfloat *value) override;
278     void setUniformMatrix2x4fv(GLint location,
279                                GLsizei count,
280                                GLboolean transpose,
281                                const GLfloat *value) override;
282     void setUniformMatrix4x2fv(GLint location,
283                                GLsizei count,
284                                GLboolean transpose,
285                                const GLfloat *value) override;
286     void setUniformMatrix3x4fv(GLint location,
287                                GLsizei count,
288                                GLboolean transpose,
289                                const GLfloat *value) override;
290     void setUniformMatrix4x3fv(GLint location,
291                                GLsizei count,
292                                GLboolean transpose,
293                                const GLfloat *value) override;
294 
295     void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
296     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
297     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
298 
299     void updateCachedInputLayoutFromShader(RendererD3D *renderer,
300                                            const gl::SharedCompiledShaderState &vertexShader);
301     void updateCachedOutputLayoutFromShader();
302     void updateCachedImage2DBindLayoutFromShader(gl::ShaderType shaderType);
303 
304     void updateCachedInputLayout(RendererD3D *renderer,
305                                  UniqueSerial associatedSerial,
306                                  const gl::State &state);
307     void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer);
308     void updateCachedImage2DBindLayout(const gl::Context *context, const gl::ShaderType shaderType);
309     void updateUniformBufferCache(const gl::Caps &caps);
310 
311     // Checks if we need to recompile certain shaders.
312     bool hasVertexExecutableForCachedInputLayout();
313     bool hasGeometryExecutableForPrimitiveType(RendererD3D *renderer,
314                                                const gl::State &state,
315                                                gl::PrimitiveMode drawMode);
316     bool hasPixelExecutableForCachedOutputLayout();
317     bool hasComputeExecutableForCachedImage2DBindLayout();
318 
anyShaderUniformsDirty()319     bool anyShaderUniformsDirty() const { return mShaderUniformsDirty.any(); }
areShaderUniformsDirty(gl::ShaderType shaderType)320     bool areShaderUniformsDirty(gl::ShaderType shaderType) const
321     {
322         return mShaderUniformsDirty[shaderType];
323     }
324     void dirtyAllUniforms();
325     void markUniformsClean();
326 
getPixelShaderKey()327     const std::vector<PixelShaderOutputVariable> &getPixelShaderKey() { return mPixelShaderKey; }
328 
329     void assignImage2DRegisters(gl::ShaderType shaderType,
330                                 unsigned int startImageIndex,
331                                 int startLogicalImageUnit,
332                                 bool readonly);
333 
getD3DUniforms()334     const std::vector<D3DUniform *> &getD3DUniforms() const { return mD3DUniforms; }
getShaderUniformStorage(gl::ShaderType shaderType)335     UniformStorageD3D *getShaderUniformStorage(gl::ShaderType shaderType) const
336     {
337         return mShaderUniformStorages[shaderType].get();
338     }
getAttribLocationToD3DSemantics()339     const AttribIndexArray &getAttribLocationToD3DSemantics() const
340     {
341         return mAttribLocationToD3DSemantic;
342     }
343     unsigned int getAtomicCounterBufferRegisterIndex(GLuint binding,
344                                                      gl::ShaderType shaderType) const;
345     unsigned int getShaderStorageBufferRegisterIndex(GLuint blockIndex,
346                                                      gl::ShaderType shaderType) const;
347     const std::vector<D3DUBOCache> &getShaderUniformBufferCache(gl::ShaderType shaderType) const;
348     const std::vector<D3DUBOCacheUseSB> &getShaderUniformBufferCacheUseSB(
349         gl::ShaderType shaderType) const;
350     GLint getSamplerMapping(gl::ShaderType type,
351                             unsigned int samplerIndex,
352                             const gl::Caps &caps) const;
353     gl::TextureType getSamplerTextureType(gl::ShaderType type, unsigned int samplerIndex) const;
354     gl::RangeUI getUsedSamplerRange(gl::ShaderType type) const;
355 
isSamplerMappingDirty()356     bool isSamplerMappingDirty() const { return mDirtySamplerMapping; }
357     void updateSamplerMapping();
358 
359     GLint getImageMapping(gl::ShaderType type,
360                           unsigned int imageIndex,
361                           bool readonly,
362                           const gl::Caps &caps) const;
363     gl::RangeUI getUsedImageRange(gl::ShaderType type, bool readonly) const;
364 
usesPointSize()365     bool usesPointSize() const { return mUsesPointSize; }
366     bool usesPointSpriteEmulation(RendererD3D *renderer) const;
367     bool usesGeometryShader(RendererD3D *renderer,
368                             const gl::ProvokingVertexConvention provokingVertex,
369                             gl::PrimitiveMode drawMode) const;
370     bool usesGeometryShaderForPointSpriteEmulation(RendererD3D *renderer) const;
371     bool usesInstancedPointSpriteEmulation(RendererD3D *renderer) const;
372 
373     angle::Result getVertexExecutableForCachedInputLayout(d3d::Context *context,
374                                                           RendererD3D *renderer,
375                                                           ShaderExecutableD3D **outExectuable,
376                                                           gl::InfoLog *infoLog);
377     angle::Result getGeometryExecutableForPrimitiveType(
378         d3d::Context *errContext,
379         RendererD3D *renderer,
380         const gl::Caps &caps,
381         gl::ProvokingVertexConvention provokingVertex,
382         gl::PrimitiveMode drawMode,
383         ShaderExecutableD3D **outExecutable,
384         gl::InfoLog *infoLog);
385     angle::Result getPixelExecutableForCachedOutputLayout(d3d::Context *context,
386                                                           RendererD3D *renderer,
387                                                           ShaderExecutableD3D **outExectuable,
388                                                           gl::InfoLog *infoLog);
389     angle::Result getComputeExecutableForImage2DBindLayout(d3d::Context *context,
390                                                            RendererD3D *renderer,
391                                                            ShaderExecutableD3D **outExecutable,
392                                                            gl::InfoLog *infoLog);
393 
hasShaderStage(gl::ShaderType shaderType)394     bool hasShaderStage(gl::ShaderType shaderType) const
395     {
396         return mExecutable->getLinkedShaderStages()[shaderType];
397     }
398 
399     bool hasNamedUniform(const std::string &name);
400 
usesVertexID()401     bool usesVertexID() const { return mUsesVertexID; }
402 
403     angle::Result loadBinaryShaderExecutables(d3d::Context *contextD3D,
404                                               RendererD3D *renderer,
405                                               gl::BinaryInputStream *stream);
406 
getSerial()407     unsigned int getSerial() const { return mSerial; }
408 
409   private:
410     friend class ProgramD3D;
411 
412     bool load(const gl::Context *context, RendererD3D *renderer, gl::BinaryInputStream *stream);
413     void save(const gl::Context *context, RendererD3D *renderer, gl::BinaryOutputStream *stream);
414 
415     template <typename DestT>
416     void getUniformInternal(GLint location, DestT *dataOut) const;
417 
418     template <typename T>
419     void setUniformImpl(D3DUniform *targetUniform,
420                         const gl::VariableLocation &locationInfo,
421                         GLsizei count,
422                         const T *v,
423                         uint8_t *targetData,
424                         GLenum uniformType);
425 
426     template <typename T>
427     void setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType);
428 
429     template <int cols, int rows>
430     void setUniformMatrixfvInternal(GLint location,
431                                     GLsizei count,
432                                     GLboolean transpose,
433                                     const GLfloat *value);
434 
435     void initAttribLocationsToD3DSemantic(const gl::SharedCompiledShaderState &vertexShader);
436 
437     void reset();
438     void initializeUniformBlocks();
439     void initializeShaderStorageBlocks(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders);
440     void initializeUniformStorage(RendererD3D *renderer,
441                                   const gl::ShaderBitSet &availableShaderStages);
442 
443     void updateCachedVertexExecutableIndex();
444     void updateCachedPixelExecutableIndex();
445     void updateCachedComputeExecutableIndex();
446 
447     void defineUniformsAndAssignRegisters(
448         RendererD3D *renderer,
449         const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders);
450     void defineUniformBase(gl::ShaderType shaderType,
451                            const sh::ShaderVariable &uniform,
452                            D3DUniformMap *uniformMap);
453     void assignAllSamplerRegisters(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders);
454     void assignSamplerRegisters(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders,
455                                 size_t uniformIndex);
456 
457     static void AssignSamplers(unsigned int startSamplerIndex,
458                                const gl::UniformTypeInfo &typeInfo,
459                                unsigned int samplerCount,
460                                std::vector<D3DSampler> &outSamplers,
461                                gl::RangeUI *outUsedRange);
462 
463     void assignAllImageRegisters();
464     void assignAllAtomicCounterRegisters();
465     void assignImageRegisters(size_t uniformIndex);
466     static void AssignImages(unsigned int startImageIndex,
467                              int startLogicalImageUnit,
468                              unsigned int imageCount,
469                              std::vector<D3DImage> &outImages,
470                              gl::RangeUI *outUsedRange);
471 
472     void gatherTransformFeedbackVaryings(
473         RendererD3D *renderer,
474         const gl::VaryingPacking &varyings,
475         const std::vector<std::string> &transformFeedbackVaryingNames,
476         const BuiltinInfo &builtins);
477     D3DUniform *getD3DUniformFromLocation(const gl::VariableLocation &locationInfo);
478     const D3DUniform *getD3DUniformFromLocation(const gl::VariableLocation &locationInfo) const;
479 
480     gl::ShaderMap<SharedCompiledShaderStateD3D> mAttachedShaders;
481 
482     std::vector<std::unique_ptr<D3DVertexExecutable>> mVertexExecutables;
483     std::vector<std::unique_ptr<D3DPixelExecutable>> mPixelExecutables;
484     angle::PackedEnumMap<gl::PrimitiveMode, std::unique_ptr<ShaderExecutableD3D>>
485         mGeometryExecutables;
486     std::vector<std::unique_ptr<D3DComputeExecutable>> mComputeExecutables;
487 
488     gl::ShaderMap<std::string> mShaderHLSL;
489     gl::ShaderMap<CompilerWorkaroundsD3D> mShaderWorkarounds;
490 
491     FragDepthUsage mFragDepthUsage;
492     bool mUsesSampleMask;
493     bool mHasMultiviewEnabled;
494     bool mUsesVertexID;
495     bool mUsesViewID;
496     std::vector<PixelShaderOutputVariable> mPixelShaderKey;
497 
498     // Common code for all dynamic geometry shaders. Consists mainly of the GS input and output
499     // structures, built from the linked varying info. We store the string itself instead of the
500     // packed varyings for simplicity.
501     std::string mGeometryShaderPreamble;
502 
503     bool mUsesPointSize;
504     bool mUsesFlatInterpolation;
505 
506     gl::ShaderMap<std::unique_ptr<UniformStorageD3D>> mShaderUniformStorages;
507 
508     gl::ShaderMap<std::vector<D3DSampler>> mShaderSamplers;
509     gl::ShaderMap<gl::RangeUI> mUsedShaderSamplerRanges;
510     bool mDirtySamplerMapping;
511 
512     gl::ShaderMap<std::vector<D3DImage>> mImages;
513     gl::ShaderMap<std::vector<D3DImage>> mReadonlyImages;
514     gl::ShaderMap<gl::RangeUI> mUsedImageRange;
515     gl::ShaderMap<gl::RangeUI> mUsedReadonlyImageRange;
516     gl::ShaderMap<gl::RangeUI> mUsedAtomicCounterRange;
517 
518     // Cache for pixel shader output layout to save reallocations.
519     std::vector<GLenum> mPixelShaderOutputLayoutCache;
520     Optional<size_t> mCachedPixelExecutableIndex;
521 
522     AttribIndexArray mAttribLocationToD3DSemantic;
523 
524     gl::ShaderMap<std::vector<D3DUBOCache>> mShaderUBOCaches;
525     gl::ShaderMap<std::vector<D3DUBOCacheUseSB>> mShaderUBOCachesUseSB;
526     D3DVertexExecutable::Signature mCachedVertexSignature;
527     gl::InputLayout mCachedInputLayout;
528     Optional<size_t> mCachedVertexExecutableIndex;
529 
530     std::vector<D3DVarying> mStreamOutVaryings;
531     std::vector<D3DUniform *> mD3DUniforms;
532     std::map<std::string, int> mImageBindingMap;
533     std::map<std::string, int> mAtomicBindingMap;
534     std::vector<D3DUniformBlock> mD3DUniformBlocks;
535     std::vector<D3DInterfaceBlock> mD3DShaderStorageBlocks;
536     gl::ShaderMap<std::vector<ShaderStorageBlock>> mShaderStorageBlocks;
537     std::array<unsigned int, gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS>
538         mComputeAtomicCounterBufferRegisterIndices;
539 
540     gl::ShaderMap<std::vector<sh::ShaderVariable>> mImage2DUniforms;
541     gl::ShaderMap<gl::ImageUnitTextureTypeMap> mImage2DBindLayoutCache;
542     Optional<size_t> mCachedComputeExecutableIndex;
543 
544     gl::ShaderBitSet mShaderUniformsDirty;
545 
546     UniqueSerial mCurrentVertexArrayStateSerial;
547 
548     unsigned int mSerial;
549 
550     static unsigned int issueSerial();
551     static unsigned int mCurrentSerial;
552 };
553 
554 }  // namespace rx
555 
556 #endif  // LIBANGLE_RENDERER_D3D_PROGRAMEXECUTABLED3D_H_
557