xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/ProgramExecutableD3D.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 
372     angle::Result getVertexExecutableForCachedInputLayout(d3d::Context *context,
373                                                           RendererD3D *renderer,
374                                                           ShaderExecutableD3D **outExectuable,
375                                                           gl::InfoLog *infoLog);
376     angle::Result getGeometryExecutableForPrimitiveType(
377         d3d::Context *errContext,
378         RendererD3D *renderer,
379         const gl::Caps &caps,
380         gl::ProvokingVertexConvention provokingVertex,
381         gl::PrimitiveMode drawMode,
382         ShaderExecutableD3D **outExecutable,
383         gl::InfoLog *infoLog);
384     angle::Result getPixelExecutableForCachedOutputLayout(d3d::Context *context,
385                                                           RendererD3D *renderer,
386                                                           ShaderExecutableD3D **outExectuable,
387                                                           gl::InfoLog *infoLog);
388     angle::Result getComputeExecutableForImage2DBindLayout(d3d::Context *context,
389                                                            RendererD3D *renderer,
390                                                            ShaderExecutableD3D **outExecutable,
391                                                            gl::InfoLog *infoLog);
392 
hasShaderStage(gl::ShaderType shaderType)393     bool hasShaderStage(gl::ShaderType shaderType) const
394     {
395         return mExecutable->getLinkedShaderStages()[shaderType];
396     }
397 
398     bool hasNamedUniform(const std::string &name);
399 
usesVertexID()400     bool usesVertexID() const { return mUsesVertexID; }
401 
402     angle::Result loadBinaryShaderExecutables(d3d::Context *contextD3D,
403                                               RendererD3D *renderer,
404                                               gl::BinaryInputStream *stream);
405 
getSerial()406     unsigned int getSerial() const { return mSerial; }
407 
408   private:
409     friend class ProgramD3D;
410 
411     bool load(const gl::Context *context, RendererD3D *renderer, gl::BinaryInputStream *stream);
412     void save(const gl::Context *context, RendererD3D *renderer, gl::BinaryOutputStream *stream);
413 
414     template <typename DestT>
415     void getUniformInternal(GLint location, DestT *dataOut) const;
416 
417     template <typename T>
418     void setUniformImpl(D3DUniform *targetUniform,
419                         const gl::VariableLocation &locationInfo,
420                         GLsizei count,
421                         const T *v,
422                         uint8_t *targetData,
423                         GLenum uniformType);
424 
425     template <typename T>
426     void setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType);
427 
428     template <int cols, int rows>
429     void setUniformMatrixfvInternal(GLint location,
430                                     GLsizei count,
431                                     GLboolean transpose,
432                                     const GLfloat *value);
433 
434     void initAttribLocationsToD3DSemantic(const gl::SharedCompiledShaderState &vertexShader);
435 
436     void reset();
437     void initializeUniformBlocks();
438     void initializeShaderStorageBlocks(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders);
439     void initializeUniformStorage(RendererD3D *renderer,
440                                   const gl::ShaderBitSet &availableShaderStages);
441 
442     void updateCachedVertexExecutableIndex();
443     void updateCachedPixelExecutableIndex();
444     void updateCachedComputeExecutableIndex();
445 
446     void defineUniformsAndAssignRegisters(
447         RendererD3D *renderer,
448         const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders);
449     void defineUniformBase(gl::ShaderType shaderType,
450                            const sh::ShaderVariable &uniform,
451                            D3DUniformMap *uniformMap);
452     void assignAllSamplerRegisters(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders);
453     void assignSamplerRegisters(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders,
454                                 size_t uniformIndex);
455 
456     static void AssignSamplers(unsigned int startSamplerIndex,
457                                const gl::UniformTypeInfo &typeInfo,
458                                unsigned int samplerCount,
459                                std::vector<D3DSampler> &outSamplers,
460                                gl::RangeUI *outUsedRange);
461 
462     void assignAllImageRegisters();
463     void assignAllAtomicCounterRegisters();
464     void assignImageRegisters(size_t uniformIndex);
465     static void AssignImages(unsigned int startImageIndex,
466                              int startLogicalImageUnit,
467                              unsigned int imageCount,
468                              std::vector<D3DImage> &outImages,
469                              gl::RangeUI *outUsedRange);
470 
471     void gatherTransformFeedbackVaryings(
472         RendererD3D *renderer,
473         const gl::VaryingPacking &varyings,
474         const std::vector<std::string> &transformFeedbackVaryingNames,
475         const BuiltinInfo &builtins);
476     D3DUniform *getD3DUniformFromLocation(const gl::VariableLocation &locationInfo);
477     const D3DUniform *getD3DUniformFromLocation(const gl::VariableLocation &locationInfo) const;
478 
479     gl::ShaderMap<SharedCompiledShaderStateD3D> mAttachedShaders;
480 
481     std::vector<std::unique_ptr<D3DVertexExecutable>> mVertexExecutables;
482     std::vector<std::unique_ptr<D3DPixelExecutable>> mPixelExecutables;
483     angle::PackedEnumMap<gl::PrimitiveMode, std::unique_ptr<ShaderExecutableD3D>>
484         mGeometryExecutables;
485     std::vector<std::unique_ptr<D3DComputeExecutable>> mComputeExecutables;
486 
487     gl::ShaderMap<std::string> mShaderHLSL;
488     gl::ShaderMap<CompilerWorkaroundsD3D> mShaderWorkarounds;
489 
490     FragDepthUsage mFragDepthUsage;
491     bool mUsesSampleMask;
492     bool mHasMultiviewEnabled;
493     bool mUsesVertexID;
494     bool mUsesViewID;
495     std::vector<PixelShaderOutputVariable> mPixelShaderKey;
496 
497     // Common code for all dynamic geometry shaders. Consists mainly of the GS input and output
498     // structures, built from the linked varying info. We store the string itself instead of the
499     // packed varyings for simplicity.
500     std::string mGeometryShaderPreamble;
501 
502     bool mUsesPointSize;
503     bool mUsesFlatInterpolation;
504 
505     gl::ShaderMap<std::unique_ptr<UniformStorageD3D>> mShaderUniformStorages;
506 
507     gl::ShaderMap<std::vector<D3DSampler>> mShaderSamplers;
508     gl::ShaderMap<gl::RangeUI> mUsedShaderSamplerRanges;
509     bool mDirtySamplerMapping;
510 
511     gl::ShaderMap<std::vector<D3DImage>> mImages;
512     gl::ShaderMap<std::vector<D3DImage>> mReadonlyImages;
513     gl::ShaderMap<gl::RangeUI> mUsedImageRange;
514     gl::ShaderMap<gl::RangeUI> mUsedReadonlyImageRange;
515     gl::ShaderMap<gl::RangeUI> mUsedAtomicCounterRange;
516 
517     // Cache for pixel shader output layout to save reallocations.
518     std::vector<GLenum> mPixelShaderOutputLayoutCache;
519     Optional<size_t> mCachedPixelExecutableIndex;
520 
521     AttribIndexArray mAttribLocationToD3DSemantic;
522 
523     gl::ShaderMap<std::vector<D3DUBOCache>> mShaderUBOCaches;
524     gl::ShaderMap<std::vector<D3DUBOCacheUseSB>> mShaderUBOCachesUseSB;
525     D3DVertexExecutable::Signature mCachedVertexSignature;
526     gl::InputLayout mCachedInputLayout;
527     Optional<size_t> mCachedVertexExecutableIndex;
528 
529     std::vector<D3DVarying> mStreamOutVaryings;
530     std::vector<D3DUniform *> mD3DUniforms;
531     std::map<std::string, int> mImageBindingMap;
532     std::map<std::string, int> mAtomicBindingMap;
533     std::vector<D3DUniformBlock> mD3DUniformBlocks;
534     std::vector<D3DInterfaceBlock> mD3DShaderStorageBlocks;
535     gl::ShaderMap<std::vector<ShaderStorageBlock>> mShaderStorageBlocks;
536     std::array<unsigned int, gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS>
537         mComputeAtomicCounterBufferRegisterIndices;
538 
539     gl::ShaderMap<std::vector<sh::ShaderVariable>> mImage2DUniforms;
540     gl::ShaderMap<gl::ImageUnitTextureTypeMap> mImage2DBindLayoutCache;
541     Optional<size_t> mCachedComputeExecutableIndex;
542 
543     gl::ShaderBitSet mShaderUniformsDirty;
544 
545     UniqueSerial mCurrentVertexArrayStateSerial;
546 
547     unsigned int mSerial;
548 
549     static unsigned int issueSerial();
550     static unsigned int mCurrentSerial;
551 };
552 
553 }  // namespace rx
554 
555 #endif  // LIBANGLE_RENDERER_D3D_PROGRAMEXECUTABLED3D_H_
556