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